在40岁老架构师 尼恩的读者社区(50+)中,尼恩一直指导大家写简历,做面试,最高的拿到年薪近100W。
昨天指导 一个 阿里 p6 小伙写简历,做面试。在帮他 挖掘简历亮点时,发现他项目在Java上没有什么技术亮点,他项目的核心亮点,就在大数据
没错,就是大数据。但是小伙伴对大数据有畏惧心理, 担心自己驾驭不了。
尼恩想说,其实大数据其实很简单,所以,大家不用有畏惧心理。
这里 尼恩给大家写一篇 文章,2分钟大白话,给大家讲清楚 什么是大数据架构。
比如说 尼恩曾经 主导的一个 大型大数据治理平台项目, 数据规模庞大:
比如说 尼恩曾经 主导的一个 大型搜索中台项目
数据规模一上来, 任务的执行就会很长,比如, 在 大型搜索中台项目,一个高频的、常规的、重要的 索引重刷任务,执行周期是多久呢?
面对如此庞大的数据,如何存储、如何利用大规模的服务器集群处理计算才是大数据技术的核心。
大数据技术讨论的是,如何利用更多的计算机满足大规模的数据计算要求。
大数据框架的核心, 就是分而治之, 无论在存储上、还是在计算上,都是如此。
所以,尼恩把大数据框架的核心,分为两个方面:
如何将数百TB或数百PB的数据存储起来,通过一个文件系统统一管理,这本身就是一项极大的挑战。
大规模的数据计算首先要解决的是大规模数据的存储问题。
HDFS的架构,有两个大的核心角色,如下图:
NameNode服务器充当文件控制块的角色,进行文件元数据管理,即记录文件名、访问权限、数据存储地址等信息,而真正的文件数据则存储在DataNode服务器上。
DataNode以块为单位存储文件数据。在Hadoop2.x版本中,块的大小可以通过配置参数来规定。默认为128M,但新版本中将块大小调整为256M。
NameNode 和DataNode 如何 配合?
具体如下图:
HDFS可以将数千台服务器,组成一个统一的文件存储系统。数千台服务器,中有NameNode 和DataNode 相互 配合,当然,DataNode 在数量上占了绝大数。
HDFS如何实现存储的高可靠呢? 为了保证不会因为硬盘或者服务器损坏而导致文件损坏,HDFS会对数据块进行复制,每个数据块都会存储在多台服务器上,甚至多个机架上。
超大规模 分布式 计算 框架 可以从很多维度进行划分,这里尼恩按照性能,简单划分为:
基于文件的 超大规模计算, 很简单,就是中间过程数据都输出到文档
基于内存的 超大规模计算, 很简单,就是中间过程数据都输出到内存
数据存储在HDFS上的最终目标还是为了计算,通过数据分析或者机器学习获得有益的结果。但是如果像传统的应用程序那样把HDFS当作普通文件,从文件中读取数据后进行计算,那么对于需要一次计算数百TB数据的大数据计算场景,就不知道要算到什么时候了。
MapReduce的核心思想是对数据进行分片计算。
MapReduce在多个 服务器上启动同一个计算程序,每个服务器上的程序进程,负责处理本服务器上要处理的数据块,因此,大量的数据就可以同时进行计算了。
那么,每个数据块的数据都是独立的,如果这些数据块需要进行关联计算怎么办?MapReduce 通过 shuffle洗牌 的动作去完成。
shuffle洗牌的职责也太简单:负责的来说,shuffle洗牌就是数据的传输和路由。 直观一点来说,shuffle洗牌 把计算过程的中间件数据, 传输到后面的计算所需要的节点。
所以,一般来说,一个 MapReduce 大数据的处理流程,就是三个阶段:
MapReduce将计算过程分成3个部分
MapReduce将计算过程分成3个部分:
下面以经典的WordCount,即统计所有数据中相同单词的词频数据为例,来认识map和reduce的处理过程,如图31-2所示。
假设原始数据有两个数据块,MapReduce框架启动了两个map进程进行处理,它们分别读入数据。
在这个示例中,这个value列表就是由很多个1组成的列表。reduce对这些1进行求和操作,就得到每个单词的词频结果了。
其实,大数据非常简单,只是很多小伙伴, 胆子太小
public class WordCount {
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
上面讲述了map和reduce进程合作完成数据处理的过程,那么这些进程是如何在分布式的服务器集群上启动的呢?
HDFS和MapReduce都是Hadoop的组成部分。HDFS和MapReduce是一种非常的亲密关系
如图所示。
MapReduce的任务调度主要有JobTracker和TaskTracker这两种进程角色,JobTracker是master的角色,在MapReduce集群中只有一个,而TaskTracker是worker的角色,和DataNode一起启动在集群的所有服务器上。
MapReduce应用程序JobClient启动后,会向JobTracker(master)提交作业,JobTracker根据作业中输入的文件路径分析需要在哪些DataNode服务器上启动map进程,然后就向这些服务器上的TaskTracker(worker)发送任务命令。
TaskTracker(worker)收到任务后,启动一个TaskRunner进程下载任务对应的程序,然后反射加载程序中的map函数,读取任务中分配的数据块,并进行map计算。
map计算结束后,TaskTracker(worker)会对map输出进行shuffle操作,然后目标的worke,再一次启动TaskRunner加载reduce函数进行后续计算。
MapReduce主要使用硬盘存储计算过程中的数据,虽然可靠性比较高,但是性能却较差。
此外,MapReduce只能使用map和reduce函数进行编程,虽然能够完成各种大数据计算,但是编程比较复杂。
而且受map和reduce编程模型相对简单的影响,复杂的计算必须组合多个MapReduce job才能完成,编程难度进一步增加。
总之,MapReduce是基于文件的 超大规模计算, 很简单,就是中间过程数据都输出到文档
所以,演进出来了基于内存的 超大规模计算。
基于内存的 超大规模计算, 很简单,就是中间过程数据都输出到内存
Spark在MapReduce的基础上演进出来的,基于内存的 超大规模计算、
Spark主要使用内存进行中间计算数据存储,加快了计算执行时间,在某些情况下性能可以提升上百倍。
没有了文件, Spark抽象了自己的数据模型,叫做RDD
RDD(Resilient Distributed Dataset)叫做弹性分布式数据集,是Spark 中最基本的数据抽象,它代表一个不可变、可分区、里面的元素可并行计算的集合。
在Spark 中,对数据的所有操作不外乎创建RDD、转化已有RDD 以及调用RDD 操作进行求值。
每个RDD 都被分为多个分区,这些分区运行在集群中的不同节点上。
RDD 可以包含Python、Java、Scala 中任意类型的对象, 甚至可以包含用户自定义的对象。
RDD 具有数据流模型的特点:自动容错、位置感知性调度和可伸缩性。
RDD 允许用户在执行多个查询时显式地将工作集缓存在内存中,后续的查询能够重用工作集,这极大地提升了查询速度。
RDD 支持两种操作:transformation操作和action操作。
RDD 的转化操作是返回一个新的RDD 的操作,比如map()和filter(),而action操作则是向驱动器程序返回结果或把结果写入外部系统的操作。比如count() 和first()。
Spark 采用惰性计算模式,RDD 只有第一次在一个行动操作中用到时,才会真正计算。
Spark 可以优化整个计算过程。默认情况下,Spark 的RDD 会在你每次对它们进行行动操作时重新计算。如果想在多个行动操作中重用同一个RDD , 可以使用RDD.persist() 让Spark 把这个RDD 缓存下来。
Spark的主要编程模型是RDD,即弹性数据集。在RDD上定义了许多常见的大数据计算函数,利用这些函数可以用极少的代码完成较为复杂的大数据计算。
RDD 在Spark中,替代了 文件在 mapreduce中的地位。
Spark的梳理处理模型,和mapreduce 类似,可以理解为 轻量级mapreduce函数
前面举例的WorkCount如果用Spark编程,只需要三行代码:
val textFile = sc.textFile("hdfs://...")
val counts = textFile.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
counts.saveAsTextFile("hdfs://...")
首先,从HDFS读取数据,构建出一个RDD textFile。然后,在这个RDD上执行三个操作:
上面代码中flatMap、map、reduceByKey都是Spark的RDD转换函数,RDD转换函数的计算结果还是RDD,所以上面三个函数可以写在一行代码上,最后得到的还是RDD。
Spark会根据程序中的转换函数生成计算任务执行计划,这个执行计划就是一个DAG。Spark可以在一个作业中完成非常复杂的大数据计算,Spark DAG示例如图31-8所示。
在图31-8中,A、C和E是从HDFS上加载的RDD。A经过groupBy分组统计转换函数计算后得到RDD B,C经过map转换函数计算后得到RDD D,D和E经过union合并转换函数计算后得到RDD F,B和F经过join连接转换函数计算后得到最终结果RDD G。
问题:
无论是基于文件的MapReduce,还是基于内存的spark,都需要写一大段的处理算子,还需要管理那些算子之间,复杂的先后依赖关系,所以,开发比较复杂。
传统上,主要使用SQL进行数据分析,如果能根据SQL自动生成MapReduce,就可以极大降低大数据技术在数据分析领域的应用门槛。
Hive就是这样一个工具。
Hive要做的就是:将SQL翻译成MapReduce程序代码
我们来看对于如下一条常见的SQL语句,Hive是如何将其转换成MapReduce计算的。
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;
这是一条常见的SQL统计分析语句,用于统计不同年龄的用户访问不同网页的兴趣偏好,具体数据输入和执行结果示例如图所示。
看这个示例我们就会发现,这个计算场景和WordCount很像。
事实上也确实如此,我们可以用MapReduce完成这条SQL的处理,如图所示。
map函数输出的key是表的行记录,value是1,reduce函数对相同的行进行记录,也就是针对具有相同key的value集合进行求和计算,最终得到SQL的输出结果。
实际上,Hive内置了很多Operator,每个Operator完成一个特定的计算过程,
Hive将这些Operator构造成一个有向无环图DAG,然后根据这些Operator之间是否存在shuffle将其封装到map或者reduce函数中,之后就可以提交给MapReduce执行了。
Operator组成的DAG如图
这是一个包含where查询条件的SQL,where查询条件对应一个FilterOperator。
Hive整体架构如图所示。
Hive的表数据存储在HDFS。
表的结构,比如表名、字段名、字段之间的分隔符等存储在Metastore中。
用户通过Client提交SQL到Driver,Driver请求Compiler将SQL编译成如上示例的DAG执行计划中,然后交给Hadoop执行。
大数据两个方向: 离线计算、流式计算。前面讲的,都是离线计算。 再来看 流式计算。
Spark虽然比MapReduce快很多,但是在大多数场景下计算耗时依然是分钟级别的,这种计算一般被称为大数据批处理计算。
而在实际应用中,有些时候需要在秒级别、毫秒级完成不断输入的海量数据的计算处理。
秒级别、毫秒级非常多:
早期比较著名的流式大数据计算引擎是Storm,今日头条的个性化推荐,就是一个超大规模storm集群。
后来随着Spark的火爆,Spark上的流式计算引擎Spark Streaming也逐渐流行起来。
Spark Streaming的架构原理是将实时流入的数据切分成小的一批一批的数据,然后将这些小的一批批数据交给Spark执行。
由于数据量比较小,Spark Streaming又常驻系统,不需要重新启动,因此可以在毫秒级完成计算,看起来像是实时计算一样,如图所示。
最近几年比较流行的大数据引擎Flink其架构原理和Spark Streaming很相似,它可以基于不同的数据源,根据数据量和计算场景的要求,灵活地适应流计算和批处理计算。
关于flink的学习,后面尼恩团队会给大家写一本超级牛逼的 《flink学习圣经》。
这里就不做展开了。
看完此文的2分钟大白话,大家基本也清楚 什么是大数据架构。
所以说,其实大数据其实很简单,大家不用有畏惧心理。
从此,大家 不用有 大数据 畏惧心理 。甚至,从此文开始,大家会 爱上大数据
学习的过程中,遇到问题,可以找尼恩交流
如果还要进一步学习大数据,可以翻阅一下尼恩团队即将隆重推出的《尼恩大数据面试宝典》, 具体请参见 尼恩的文末公号:技术自由圈
《尼恩大数据面试宝典专题1:史上最全Hadoop面试题》
《尼恩大数据面试宝典专题2:绝密100个Spark面试题,熟背100遍,猛拿高薪》
《尼恩大数据面试宝典专题3:史上最全Hive面试题,不断迭代,持续升级》
《从0开始,手写Redis》
《从0开始,手写MySQL事务管理器TM》
《从0开始,手写MySQL数据管理器DM》
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩 面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓