大数据计算资源基础知识,以及5个核心技术讲解(hadoop、mapreduce、hive、spark、flink)_hadoop spark hive
大数据计算资源基础知识
大数据处理基本背景
大数据处理面临的主要挑战是数据量太大,无法在单台机器上高效处理。因此,需要分布式系统将数据和计算任务分散到多台机器上协同完成。根据处理方式和应用场景的不同,发展出了不同类型的计算资源。
批处理计算资源
背景:最早的大数据处理方式,主要处理已经存储好的大量历史数据。
-
MapReduce:
- 背景:由Google在2004年提出的分布式计算模型,Hadoop是其开源实现
- 工作原理:将数据处理拆分为\"映射(Map)\"和\"归约(Reduce)\"两个阶段,可以在大量普通计算机上并行处理
- 适用场景:如每日的销售报表、网站访问日志分析等不需要实时结果的场景
-
Hive:
- 背景:由Facebook开发,为了让不懂编程的数据分析师也能处理大数据
- 工作原理:提供类SQL语言(HQL)接口,底层转换为MapReduce任务执行
- 适用场景:数据仓库建设、复杂数据查询、报表生成
-
Spark Batch:
- 背景:为克服MapReduce的局限性而开发,最初由UC Berkeley开发
- 工作原理:采用内存计算,避免中间结果写入磁盘,大幅提高处理速度
- 适用场景:需要多次迭代的复杂计算,如机器学习算法训练
流处理计算资源
背景:随着实时性需求的增加,开始出现处理实时数据流的技术。
-
Flink:
- 背景:起源于欧洲的研究项目,后成为Apache顶级项目
- 工作原理:设计为真正的流处理引擎,以事件为单位处理数据
- 适用场景:银行交易欺诈实时检测、网站实时用户行为分析
-
Spark Streaming:
- 背景:Spark生态的一部分,为满足实时计算需求而设计
- 工作原理:将数据流分割成小批次,利用Spark批处理能力处理
- 适用场景:社交媒体情感分析、物联网数据实时处理
-
Storm:
- 背景:最早由Twitter开发和使用的流处理系统
- 工作原理:通过\"拓扑\"定义处理流程,保证毫秒级响应
- 适用场景:实时计数、系统异常监控告警
交互式查询资源
背景:为满足数据分析师对大数据的快速查询需求而产生。
-
Presto/Trino:
- 背景:最初由Facebook开发,为了解决Hive查询速度慢的问题
- 工作原理:采用内存处理查询,不依赖MapReduce,支持多数据源
- 适用场景:业务人员即席查询、跨数据源的数据分析
-
Impala:
- 背景:由Cloudera开发,受Google Dremel启发
- 工作原理:采用MPP(大规模并行处理)架构,直接访问HDFS数据
- 适用场景:交互式BI工具、数据探索分析
-
Kylin:
- 背景:最初由eBay开发,用于加速OLAP分析
- 工作原理:预先计算并存储多维数据立方体,实现超快查询
- 适用场景:销售数据多维分析、用户行为分析报表
机器学习/AI计算资源
背景:随着人工智能的发展,需要专门的框架处理机器学习任务。
-
Spark MLlib:
- 背景:Spark生态的机器学习库,统一在Spark平台上开发
- 工作原理:利用Spark分布式计算能力,实现常见机器学习算法
- 适用场景:客户分群、产品推荐、风险评估
-
TensorFlow/PyTorch:
- 背景:分别由Google和Facebook开发的深度学习框架
- 工作原理:通过计算图或动态图定义模型,支持GPU加速
- 适用场景:图像识别、语音转文字、自然语言处理、智能客服
弹性计算资源
背景:为优化资源利用率、降低成本而产生的资源调度系统。
-
K8s集群:
- 背景:由Google开源的容器编排平台,现已成为云原生标准
- 工作原理:管理容器化应用的部署、扩展和运行
- 适用场景:微服务架构应用、DevOps持续集成部署
-
Yarn集群:
- 背景:Hadoop 2.0引入的资源管理器,解决Hadoop 1.0的资源利用问题
- 工作原理:负责集群资源分配和作业调度
- 适用场景:在同一集群上运行多种计算框架(MapReduce、Spark等)
大数据核心技术详解
Hadoop
核心概念
Hadoop是一个开源的分布式计算框架,设计用来处理无法在单台机器上高效处理的大数据。
两大核心组件
-
HDFS (存储)
- 分布式文件系统,将大文件分块存储在多台机器上
- 一个中心管理器(NameNode)和多个存储节点(DataNode)
- 自动多副本机制确保数据安全
-
MapReduce (计算)
- 分布式计算模型,分为Map和Reduce两个阶段
- Map:将任务分解为小块并行处理
- Reduce:汇总处理结果
工作原理简图
[大数据] → [HDFS分块存储] → [MapReduce计算] | | [多台服务器] [并行处理] | | [自动容错] [结果汇总] → [最终结果]
Hadoop优势
- 可扩展性:从几台到上千台服务器
- 容错性:自动处理节点故障
- 成本效益:可使用普通硬件
- 生态系统丰富:Hive、HBase、Spark等工具集成
适用场景
- 日志处理分析
- 数据仓库建设
- 搜索引擎索引构建
- 机器学习数据准备
理解Hadoop就是理解\"分而治之\"的思想——将大问题拆分为小问题并行解决。
MapReduce
核心概念
- 一种分布式计算模型,由Google在2004年提出
- 设计用于在大型计算机集群上并行处理海量数据
两大核心阶段
-
Map阶段
- 将输入数据分片,每片由一个Mapper处理
- 每个Mapper输出键值对
- 例如:文本分割成的形式
-
Reduce阶段
- 接收具有相同Key的所有Value
- 合并计算后输出最终结果
- 例如:统计
工作原理简图
[输入数据分片] → [Map处理] → [Shuffle] → [Reduce处理] → [结果] | | | | [多台服务器] [转化为K-V] [分组] [聚合计算]
适用场景
- 日志分析
- 搜索索引
- 数据转换
- 简单统计计算
编程模型示例
// WordCount示例// WordCount示例 - MapReduce框架下统计文本中单词出现频率的标准实现/* ===== MapReduce工作流程 ===== * 1. 输入分片: HDFS将输入文件分成固定大小的块(通常128MB) * 2. Map阶段: 每个分片由一个Map任务处理,产生中间键值对 * 3. Shuffle阶段: 系统自动对Map输出进行排序、分区、合并,相同key的值被发送到同一个Reducer * 4. Reduce阶段: 对每个key的所有值进行处理,产生最终结果 * 5. 输出: 将Reduce结果写入HDFS */public class WordCount { // Mapper类实现 - MapReduce第一阶段 // Mapper public static class TokenizerMapper extends Mapper<Object, Text, Text, IntWritable> { // 静态常量值1,在所有map调用间共享,避免重复创建对象 private final static IntWritable one = new IntWritable(1); // 可重用的Text对象,避免垃圾回收压力 private Text word = new Text(); // map方法 - 此方法会被框架对每条输入记录调用一次 // 每个map任务会处理一个输入分片(split)的多条记录 //context是一个非常重要的对象,它代表了map或reduce任务的执行h环境,是Mapper/Reducer与MapReduce框架之间的桥梁 public void map(Object key, Text value, Context context) throws IOException, InterruptedException {// 在MapReduce中,map(20, Text(\"Hello Hadoop\"), context) 中的\"20\"是输入键(key),代表该文本行在原始输入文件中的字节偏移量(byte offset)。// 详细解释:// 当MapReduce处理文本文件时,它会:// 将文件分割成行// 对每一行调用一次map方法// 第一个参数是这一行在文件中的起始位置(偏移量)// 例如:// map(0, Text(\"Hello World\"), context) - 第一行从文件的第0个字节开始// map(20, Text(\"Hello Hadoop\"), context) - 第二行从文件的第20个字节开始(假设第一行加上换行符共20字节)// 在实际的map函数实现中:// 这个偏移量很少被直接使用,大多数WordCount实现中会忽略它// 它的主要作用是提供数据来源的位置信息,在某些应用中可能有用// 对于WordCount,我们只关心文本内容(map方法的第二个参数)// 这就是为什么Mapper类通常定义为Mapper,而不是Mapper,因为通常不关心这个偏移量的具体类型,只把它视为一个Object。 /* Map阶段核心逻辑: * 1. 接收键值对, * 2. 处理并输出中间结果 * 3. MapReduce框架会收集所有Mapper输出 */ StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); // 输出键值对到Context,将触发Partitioner将数据发送到对应的Reducer context.write(word, one); } // Map任务结束后,框架自动进行Shuffle阶段: // - Partitioning: 决定数据发送到哪个Reducer // - Sorting: 按键排序 // - Combining: 可选的本地合并(类似于迷你Reduce) // - Grouping: 将相同key的值分组// IntWritable(1) 中的\"1\"表示单词出现了一次。// 在WordCount算法中,我们的目标是统计每个单词在文本中出现的总次数。处理过程是:// Map阶段:每发现一个单词,就输出(单词, 1)的键值对// 这个\"1\"就是表示\"该单词在当前位置出现了1次\"// 例如处理\"Hello World Hello\"会输出三对:(Hello, 1), (World, 1), (Hello, 1)// Reduce阶段:将同一单词的所有计数值(1)累加// 例如:(Hello, [1,1]) 累加后变成 (Hello, 2) } } // Reducer类实现 - MapReduce第三阶段 // Reducer public static class IntSumReducer extends Reducer<Text, IntWritable, Text, IntWritable> { private IntWritable result = new IntWritable(); // reduce方法 - 框架为每个唯一的key调用一次此方法 public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { /* Reduce阶段核心逻辑: * 1. 接收来自Shuffle阶段的 * 2. 聚合计算得到 * 3. 输出最终结果 */ int sum = 0; // 遍历该key的所有值(被框架分组后的) for (IntWritable val : values) { sum += val.get(); } result.set(sum); // 输出最终结果到HDFS context.write(key, result); } } /* 完整作业配置(通常在main方法中): * Job job = Job.getInstance(conf, \"word count\"); * job.setJarByClass(WordCount.class); * job.setMapperClass(TokenizerMapper.class); * job.setCombinerClass(IntSumReducer.class); // 优化: 使用Combiner减少网络传输 * job.setReducerClass(IntSumReducer.class); * job.setOutputKeyClass(Text.class); * job.setOutputValueClass(IntWritable.class); * FileInputFormat.addInputPath(job, new Path(args[0])); * FileOutputFormat.setOutputPath(job, new Path(args[1])); * System.exit(job.waitForCompletion(true) ? 0 : 1); */}
优缺点
-
优点:
- 高度容错性
- 适合大规模数据处理
- 编程模型简单
-
缺点:
- 性能较慢(磁盘IO频繁)
- 不适合迭代计算和实时处理
- 编程复杂度高
Hive
-
核心概念
- 构建在Hadoop上的数据仓库工具
- 提供类SQL接口(HiveQL)处理结构化数据
- 自动将SQL转换为MapReduce作业执行
主要组件
-
元数据存储
- 保存表结构、分区等信息
- 通常存储在关系数据库中
-
查询处理器
- 解析HiveQL语句
- 生成执行计划
- 优化查询
-
执行引擎
- MapReduce (传统)
- Tez/Spark (优化)
工作原理简图
[HiveQL查询] → [解析和优化] → [转换为MapReduce] → [执行] → [结果] | | | | [类SQL语法] [生成计划] [物理执行] [返回数据]
适用场景
- 数据仓库
- 报表生成
- 离线数据分析
- 结构化数据查询
HiveQL示例
-- HiveQL示例 - 将SQL语句转换为MapReduce作业执行/* ===== Hive查询执行流程 ===== * 1. 解析: HiveQL被解析成抽象语法树(AST) * 2. 语义分析: 验证表、列是否存在,类型检查 * 3. 逻辑计划生成: 转换为操作符树 * 4. 优化: 应用各种规则优化查询计划 * 5. 物理计划生成: 转换为MapReduce/Tez/Spark作业 * 6. 执行: 在集群上运行生成的作业 */-- 创建表 - 定义数据结构和存储格式CREATE TABLE page_views ( user_id STRING, -- 用户ID timestamp INT, -- 访问时间戳 page_url STRING, -- 页面URL referrer_url STRING -- 来源URL)-- 定义存储格式 - 这会影响Hive如何读取数据ROW FORMAT DELIMITED -- 行格式为分隔符文本FIELDS TERMINATED BY \'\\t\'; -- 字段间用制表符分隔/* 表创建过程: * 1. 元数据存储: 表定义存入Metastore(通常是MySQL等关系数据库) * 2. 不会移动或处理实际数据,只创建元数据 */-- 分析查询 - 此SQL将被转换为MapReduce作业SELECT user_id, -- 输出字段1 COUNT(DISTINCT page_url) AS page_count -- 聚合计算FROM page_views -- 输入表WHERE timestamp > 1420070400 -- 过滤条件GROUP BY user_id -- 分组字段HAVING page_count > 10; -- 分组后过滤/* 查询转换为MapReduce过程: * 1. Map阶段: * - 读取表数据并应用WHERE过滤(timestamp > 1420070400) * - 提取需要的字段(user_id, page_url) * - 输出键值对 * * 2. Shuffle: * - 按user_id分区和排序 * - 相同user_id的所有page_url分组在一起 * * 3. Reduce阶段: * - 计算每个user_id下不同page_url的数量 * - 应用HAVING过滤(page_count > 10) * - 输出最终结果 * * 注: 复杂查询可能会转换为多个MapReduce作业串联执行 */
特点
- 适合批处理查询分析
- 支持复杂的ETL流程
- 类SQL语法降低了学习门槛
- 查询延迟较高,不适合低延迟应用
Spark
-
核心概念
- 快速通用的分布式计算引擎
- 内存计算,比MapReduce快10-100倍
- 支持批处理、流处理、机器学习等多种计算
主要组件
-
Spark Core
- RDD (弹性分布式数据集)
- 内存计算框架
- 任务调度
-
生态系统
- Spark SQL:结构化数据处理
- Spark Streaming:实时数据处理
- MLlib:机器学习库
- GraphX:图计算
工作原理简图
[数据源] → [创建RDD] → [转换操作] → [触发动作] → [结果] | | | |[多种来源] [内存缓存] [惰性操作] [实际计算]
【Spark集群架构】
Driver Program (SparkContext)
↓
↙ ↓ ↘
Executor Executor Executor
(内存) (内存) (内存)
tasks tasks tasks
- Driver程序:包含main函数和SparkContext,负责作业调度- Executor:在工作节点上执行具体任务的进程- Task:被送到Executor上执行的最小工作单元### Spark优势- **速度快**:内存计算- **易用性**:支持Java、Scala、Python、R- **统一平台**:一个框架满足多种需求- **丰富生态**:可无缝对接多种数据源### 适用场景- **日志分析**:分析网站访问日志,计算PV/UV- **推荐系统**:基于用户行为构建推荐模型- **实时监控**:处理传感器实时数据,检测异常- **ETL处理**:数据清洗、转换和加载- **机器学习**:训练预测模型,如客户流失预测### 优缺点- **优点**:- 高性能(内存计算)- 多语言支持(Java, Scala, Python, R)- 统一的多种应用场景支持- 丰富的算子和API- **缺点**:- 内存管理复杂- 调优难度大- 对内存需求高### Spark核心编程模型#### 1. RDD (弹性分布式数据集)```scala// 创建RDDval lines = sc.textFile(\"hdfs://...\")// 转换操作(Transformation)val words = lines.flatMap(_.split(\" \"))val pairs = words.map(word => (word, 1))val wordCounts = pairs.reduceByKey(_ + _)// 行动操作(Action)wordCounts.collect()
特点:
- 分区(Partitioned):数据分布在集群多个节点
- 不可变(Immutable):创建后不能修改
- 弹性(Resilient):失败自动恢复
- 延迟计算(Lazy Evaluation):转换操作不立即执行
2. DataFrame和Dataset
// DataFrame示例val df = spark.read.json(\"customer.json\")df.filter($\"age\" > 25).groupBy(\"city\").count()// Dataset示例case class Person(name: String, age: Int)val ds = spark.read.json(\"people.json\").as[Person]ds.filter(_.age > 25).show()
优势:
- 结构化数据处理
- 优化执行计划
- 与SQL无缝集成
Spark与其他技术对比
【执行速度对比】MapReduce处理10TB数据: ~1小时30分钟Spark处理10TB数据: ~10分钟【迭代计算】MapReduce: 每次迭代都要读写HDFSSpark: 中间结果保留在内存中
Spark编程示例
1. WordCount实现对比
// MapReduce实现public void map(Object key, Text value, Context context) { StringTokenizer itr = new StringTokenizer(value.toString()); while (itr.hasMoreTokens()) { word.set(itr.nextToken()); context.write(word, one); }}public void reduce(Text key, Iterable<IntWritable> values, Context context) { int sum = 0; for (IntWritable val : values) { sum += val.get(); } result.set(sum); context.write(key, result);}
// Spark实现val wordCounts = sc.textFile(\"hdfs://...\") .flatMap(line => line.split(\" \")) .map(word => (word, 1)) .reduceByKey(_ + _) wordCounts.saveAsTextFile(\"hdfs://...\")
2. Spark SQL查询
// 注册临时表df.createOrReplaceTempView(\"people\")// 执行SQL查询val teenagersDF = spark.sql(\"SELECT name FROM people WHERE age BETWEEN 13 AND 19\")
Spark生态系统
1. 主要组件
- Spark Core:基础计算引擎
- Spark SQL:SQL和结构化数据处理
- Spark Streaming:实时数据处理
- MLlib:机器学习库
- GraphX:图计算引擎
2. 数据源支持
- 文件格式:Text, CSV, JSON, Parquet, ORC, Avro等
- 数据库:HDFS, HBase, MySQL, MongoDB等
- 消息队列:Kafka, Flume等
Flink
基本概念
- 真正的流处理框架,由欧洲研究项目发展而来
- 同时支持批处理和流处理
- 以\"无界数据流\"为核心设计理念
架构特点
- JobManager:协调任务分配和检查点
- TaskManager:执行任务的工作节点
- 事件时间处理:支持按数据生成时间而非处理时间处理
- 状态管理:支持强一致性的有状态计算
处理模型
- 数据流:所有数据都被视为流
- 窗口操作:可以在流上定义时间窗口
- 检查点机制:保证故障恢复时的一致性
代码示例
// Flink流式WordCount - 实时统计数据流中的词频/* ===== Flink流处理模型 ===== * 1. 数据源(Source): 从外部系统读取数据流 * 2. 转换(Transformation): 对数据流进行处理 * 3. 接收器(Sink): 将结果写入外部系统 * 4. 执行: 惰性评估,构建执行图后整体优化执行 * 5. 状态管理: 维护计算状态并支持容错 */// 创建源(Source) - 从TCP套接字读取文本流// socketTextStream包含4个参数: 主机名、端口、分隔符、最大尝试次数DataStream<String> text = env.socketTextStream(\"localhost\", 9999);// 定义转换操作链DataStream<Tuple2<String, Integer>> counts = text // 转换1: flatMap - 将每行文本分割成单词并输出(单词,1)的二元组 .flatMap(new FlatMapFunction<String, Tuple2<String, Integer>>() { /* 流处理特点: * - 一次处理一个事件(此处是一行文本) * - 立即产生输出,不等待批次完成 */ @Override public void flatMap(String value, Collector<Tuple2<String, Integer>> out) { // 对每个输入字符串应用分词 for (String word : value.split(\"\\\\s\")) { // 收集器输出(类似于生产者-消费者模式) out.collect(new Tuple2<>(word, 1)); } } }) // 转换2: keyBy - 按单词分组,创建KeyedStream // keyBy与Spark的groupByKey类似,但Flink会维护状态而不是收集所有数据 .keyBy(0) // 按元组第一个字段(单词)分组 // 转换3: sum - 对分组后的流计算滚动总和 // 这涉及有状态计算: // - 为每个key维护一个状态 // - 每当新事件到来,更新对应key的状态 // - 自动处理状态持久化和恢复 .sum(1); // 累加元组第二个字段(计数)/* 流式处理区别于批处理: * 1. 无界数据: 流是无限的,不像批处理有明确的开始和结束 * 2. 实时处理: 数据到达即处理,延迟通常为毫秒级 * 3. 状态管理: 需要维护计算状态(如每个单词当前的计数) * 4. 容错机制: 通过检查点(Checkpoint)保证精确一次处理语义 */// 定义接收器(Sink) - 将结果输出到控制台// 在生产环境中,通常会输出到Kafka、数据库等外部系统counts.print(); // print()是一个内置的Sink/* 执行流程: * 1. 以上代码只是构建了执行图,没有实际执行 * 2. 调用env.execute()后,Flink才会: * - 优化执行计划 * - 分配任务到TaskManager * - 建立数据流通道 * - 开始连续处理数据流 */
优缺点
-
优点:
- 低延迟、高吞吐
- 精确一次(exactly-once)语义保证
- 强大的时间处理能力
- 有状态计算支持
-
缺点:
- 生态系统相对较新
- 学习曲线较陡
- 调优和运维复杂度高
各技术之间的关系
- Hadoop是基础平台,提供分布式存储(HDFS)和资源管理(YARN)
- MapReduce是Hadoop上的原生计算模型
- Hive构建在Hadoop之上,提供数据仓库功能和SQL接口
- Spark最初也是构建在Hadoop上,但提供了比MapReduce更高效的计算模型
- Flink是独立的流处理框架,但通常也与Hadoop生态集成
实际应用选择
- 需要简单批处理:Hadoop MapReduce
- 需要类SQL分析:Hive
- 需要混合批处理和机器学习:Spark
- 需要低延迟流处理:Flink
- 完整方案通常组合使用多种技术