This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
<audio id="audio" title="04 | 移动计算比移动数据更划算" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/fc/27/fc874d06d24308935180b8a313271e27.mp3"></audio>
大数据技术和传统的软件开发技术在架构思路上有很大不同,大数据技术更为关注数据,所以相关的架构设计也围绕数据展开,如何存储、计算、传输大规模的数据是要考虑的核心要素。
传统的软件计算处理模型,都是“输入 -&gt; 计算 -&gt; 输出”模型。也就是说,一个程序给它传入一些数据也好,它自己从某个地方读取一些数据也好,总是先有一些输入数据,然后对这些数据进行计算处理,最后得到输出结果。
但是在互联网大数据时代需要计算处理的数据量急速膨胀。一来是因为互联网用户数远远超过传统企业的用户相应产生了更大量的数据二来很多以往被忽视的数据重新被发掘利用比如用户在一个页面的停留时长、鼠标在屏幕移动的轨迹都会被记录下来进行分析。在稍微大一点的互联网企业需要计算处理的数据量常常以PB计10<sup>15</sup> Byte
正因为如此传统的计算处理模型不能适用于大数据时代的计算要求。你能想象一个程序读取PB级的数据进行计算是怎样一个场景吗一个程序所能调度的网络带宽通常数百MB、内存容量通常几十GB 、磁盘大小通常数TB、CPU运算速度是不可能满足这种计算要求的。
那么如何解决PB级数据进行计算的问题呢
这个问题的解决思路其实跟大型网站的分布式架构思路是一样的采用分布式集群的解决方案用数千台甚至上万台计算机构建一个大数据计算处理集群利用更多的网络带宽、内存空间、磁盘容量、CPU核心数去进行计算处理。关于分布式架构你可以参考我写的《大型网站技术架构核心原理与案例分析》这本书但是大数据计算处理的场景跟网站的实时请求处理场景又有很大不同。
网站实时处理通常针对单个用户的请求操作,虽然大型网站面临大量的高并发请求,比如天猫的“双十一”活动。但是每个用户之间的请求是独立的,只要网站的分布式系统能将不同用户的不同业务请求分配到不同的服务器上,只要这些分布式的服务器之间耦合关系足够小,就可以通过添加更多的服务器去处理更多的用户请求及由此产生的用户数据。这也正是网站系统架构的核心原理。
我们再回过头来看大数据。**大数据计算处理通常针对的是网站的存量数据**,也就是刚才我提到的全部用户在一段时间内请求产生的数据,这些数据之间是有大量关联的,比如购买同一个商品用户之间的关系,这是使用协同过滤进行商品推荐;比如同一件商品的历史销量走势,这是对历史数据进行统计分析。**网站大数据系统要做的就是将这些统计规律和关联关系计算出来,并由此进一步改善网站的用户体验和运营决策**。
为了解决这种计算场景的问题技术专家们设计了一套相应的技术架构方案。最早的时候由Google实现并通过论文的方式发表出来随后根据这些论文开源社区开发出对应的开源产品并得到业界的普遍支持和应用。这段历史我们在前面的“预习”中已经讨论过了。
这套方案的核心思路是,既然数据是庞大的,而程序要比数据小得多,将数据输入给程序是不划算的,那么就反其道而行之,**将程序分发到数据所在的地方进行计算,也就是所谓的移动计算比移动数据更划算**。
有一句古老的谚语,说的是“当一匹马拉不动车的时候,用两匹马拉”。听起来是如此简单的道理,但是在计算机这个最年轻的科技领域,在很长一段时间里却并没有这样做。当一台计算机的处理能力不能满足计算要求的时候,我们并没有想办法用两台计算机去处理,而是换更强大的计算机。
商业级的服务器不够用,就升级小型机;小型机不够用,就升级中型机;还不够,升级大型机,升级超级计算机。
在互联网时代之前这种不断升级计算机硬件的办法还是行得通的凭借摩尔定律计算机硬件的处理能力每18个月增强一倍越来越强大的计算机被制造出来。传统企业虽然对计算机的处理需求越来越高但是工程师和科学家总能制造出满足需求的计算机。
但是这种思路并不适合互联网的技术要求。Google、Facebook、阿里巴巴这些网站每天需要处理数十亿次的用户请求、产生上百PB的数据不可能有一台计算机能够支撑起这么大的计算需求。
于是互联网公司不得不换一种思路解决问题当一台计算机的计算能力不能满足需求的时候就增加一台计算机还不够的话就再增加一台。就这样由一台计算机起家的小网站逐渐成长为百万台服务器的巨无霸。Google、Facebook、阿里巴巴这些公司的成长过程都是如此。
但是买一台新计算机和一台老计算机放在一起,就能自己开始工作了吗?两台计算机要想合作构成一个系统,必须要在技术上重新架构。这就是现在互联网企业广泛使用的负载均衡、分布式缓存、分布式数据库、分布式服务等种种分布式系统。
当这些分布式技术满足互联网的日常业务需求时,对离线数据和存量数据的处理就被提了出来,当时这些分布式技术并不能满足要求,于是大数据技术就出现了。
现在我们来看,移动计算程序到数据所在位置进行计算是如何实现的呢?
1.将待处理的大规模数据存储在服务器集群的所有服务器上主要使用HDFS分布式文件存储系统将文件分成很多块Block以块为单位存储在集群的服务器上。
2.大数据引擎根据集群里不同服务器的计算能力,在每台服务器上启动若干分布式任务执行进程,这些进程会等待给它们分配执行任务。
3.使用大数据计算框架支持的编程模型进行编程比如Hadoop的MapReduce编程模型或者Spark的RDD编程模型。应用程序编写好以后将其打包MapReduce和Spark都是在JVM环境中运行所以打包出来的是一个Java的JAR包。
4.用Hadoop或者Spark的启动命令执行这个应用程序的JAR包首先执行引擎会解析程序要处理的数据输入路径根据输入数据量的大小将数据分成若干片Split每一个数据片都分配给一个任务执行进程去处理。
5.任务执行进程收到分配的任务后,检查自己是否有任务对应的程序包,如果没有就去下载程序包,下载以后通过反射的方式加载程序。走到这里,最重要的一步,也就是移动计算就完成了。
6.加载程序后,任务执行进程根据分配的数据片的文件地址和数据在文件内的偏移量读取数据,并把数据输入给应用程序相应的方法去执行,从而实现在分布式服务器集群中移动计算程序,对大规模数据进行并行处理的计算目标。
这只是大数据计算实现过程的简单描述具体过程我们会在讲到HDFS、MapReduce和Spark的时候详细讨论。
## 小结
移动程序到数据所在的地方去执行这种技术方案其实我们并不陌生。从事Java开发的同学可能有过用反射的方式热加载代码执行的经验如果这个代码是从网络其他地方传输过来的那就是在移动计算。杀毒软件从服务器更新病毒库然后在Windows内查杀病毒也是一种移动计算病毒库比移动数据Windows可能感染病毒的程序更划算的例子。
大数据技术将移动计算这一编程技巧上升到编程模型的高度,并开发了相应的编程框架,使得开发人员只需要关注大数据的算法实现,而不必关注如何将这个算法在分布式的环境中执行,这极大地简化了大数据的开发难度,并统一了大数据的开发方式,从而使大数据从原来的高高在上,变成了今天的人人参与。
## 思考题
互联网应用系统架构中有一种重要架构原则是尽量使用无状态的服务,不同服务实例之间不共享状态,也就是不持有数据,用户请求交给任何一个服务实例计算,处理的结果都是一样的,为什么要这样设计?这种架构有什么好处?
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,81 @@
<audio id="audio" title="05 | 从RAID看垂直伸缩到水平伸缩的演化" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/df/73/df27c26d8308d583464fb6a4645fd373.mp3"></audio>
经过前面的预习和上一期我们聊的,大数据技术主要是要解决大规模数据的计算处理问题,但是我们要想对数据进行计算,首先要解决的其实是大规模数据的存储问题。我这里有一个直观又现实的问题想问你:如果一个文件的大小超过了一张磁盘的大小,你该如何存储?
我的答案是单机时代主要的解决方案是RAID分布式时代主要解决方案是分布式文件系统。
其实不论是在单机时代还是分布式时代,大规模数据存储都需要解决几个核心问题,这些问题都是什么呢?总结一下,主要有以下三个方面。
1.**数据存储容量的问题**。既然大数据要解决的是数以PB计的数据计算问题而一般的服务器磁盘容量通常12TB那么如何存储这么大规模的数据呢
2.**数据读写速度的问题**。一般磁盘的连续读写速度为几十MB以这样的速度几十PB的数据恐怕要读写到天荒地老。
3.**数据可靠性的问题**。磁盘大约是计算机设备中最易损坏的硬件了,通常情况一块磁盘使用寿命大概是一年,如果磁盘损坏了,数据怎么办?
在大数据技术出现之前我们就需要面对这些关于存储的问题对应的解决方案就是RAID技术。今天我们就先从RAID开始一起看看大规模数据存储方式的演化过程。
RAID独立磁盘冗余阵列技术是将多块普通磁盘组成一个阵列共同对外提供服务。主要是为了改善磁盘的存储容量、读写速度增强磁盘的可用性和容错能力。在RAID之前要使用大容量、高可用、高速访问的存储系统需要专门的存储设备这类设备价格要比RAID的几块普通磁盘贵几十倍。RAID刚出来的时候给我们的感觉像是一种黑科技但其原理却不复杂下面我慢慢道来。
目前服务器级别的计算机都支持插入多块磁盘8块或者更多通过使用RAID技术实现数据在多块磁盘上的并发读写和数据备份。
常用RAID技术有图中下面这几种光看图片你可能觉得它们都差不多下面我给你讲讲它们之间的区别。
<img src="https://static001.geekbang.org/resource/image/54/af/54e170b7438fe3b8f8196dbfbc943baf.jpg" alt="">
首先我们先假设服务器有N块磁盘**RAID 0**是数据在从内存缓冲区写入磁盘时根据磁盘数量将数据分成N份这些数据同时并发写入N块磁盘使得数据整体写入速度是一块磁盘的N倍读取的时候也一样因此RAID 0具有极快的数据读写速度。但是RAID 0不做数据备份N块磁盘中只要有一块损坏数据完整性就被破坏其他磁盘的数据也都无法使用了。
**RAID 1**是数据在写入磁盘时,将一份数据同时写入两块磁盘,这样任何一块磁盘损坏都不会导致数据丢失,插入一块新磁盘就可以通过复制数据的方式自动修复,具有极高的可靠性。
结合RAID 0和RAID 1两种方案构成了**RAID 10**它是将所有磁盘N平均分成两份数据同时在两份磁盘写入相当于RAID 1但是平分成两份在每一份磁盘也就是N/2块磁盘里面利用RAID 0技术并发读写这样既提高可靠性又改善性能。不过RAID 10的磁盘利用率较低有一半的磁盘用来写备份数据。
一般情况下,一台服务器上很少出现同时损坏两块磁盘的情况,在只损坏一块磁盘的情况下,如果能利用其他磁盘的数据恢复损坏磁盘的数据,这样在保证可靠性和性能的同时,磁盘利用率也得到大幅提升。
顺着这个思路,**RAID 3**可以在数据写入磁盘的时候将数据分成N-1份并发写入N-1块磁盘并在第N块磁盘记录校验数据这样任何一块磁盘损坏包括校验数据磁盘都可以利用其他N-1块磁盘的数据修复。
但是在数据修改较多的场景中任何磁盘数据的修改都会导致第N块磁盘重写校验数据。频繁写入的后果是第N块磁盘比其他磁盘更容易损坏需要频繁更换所以RAID 3很少在实践中使用因此在上面图中也就没有单独列出。
相比RAID 3**RAID 5**是使用更多的方案。RAID 5和RAID 3很相似但是校验数据不是写入第N块磁盘而是螺旋式地写入所有磁盘中。这样校验数据的修改也被平均到所有磁盘上避免RAID 3频繁写坏一块磁盘的情况。
如果数据需要很高的可靠性,在出现同时损坏两块磁盘的情况下(或者运维管理水平比较落后,坏了一块磁盘但是迟迟没有更换,导致又坏了一块磁盘),仍然需要修复数据,这时候可以使用**RAID 6**。
RAID 6和RAID 5类似但是数据只写入N-2块磁盘并螺旋式地在两块磁盘中写入校验信息使用不同算法生成
从下面表格中你可以看到在相同磁盘数目N的情况下各种RAID技术的比较。
<img src="https://static001.geekbang.org/resource/image/e2/2f/e2fb7ec97e6127c1b03e83daeff0232f.jpg" alt="">
RAID技术有硬件实现比如专用的RAID卡或者主板直接支持也可以通过软件实现在操作系统层面将多块磁盘组成RAID从逻辑上视作一个访问目录。RAID技术在传统关系数据库及文件系统中应用比较广泛是改善计算机存储特性的重要手段。
现在我来总结一下看看RAID是如何解决我一开始提出的关于存储的三个关键问题。
1.数据存储容量的问题。RAID使用了N块磁盘构成一个存储阵列如果使用RAID 5数据就可以存储在N-1块磁盘上这样将存储空间扩大了N-1倍。
2.数据读写速度的问题。RAID根据可以使用的磁盘数量将待写入的数据分成多片并发同时向多块磁盘进行写入显然写入的速度可以得到明显提高同理读取速度也可以得到明显提高。不过需要注意的是由于传统机械磁盘的访问延迟主要来自于寻址时间数据真正进行读写的时间可能只占据整个数据访问时间的一小部分所以数据分片后对N块磁盘进行并发读写操作并不能将访问速度提高N倍。
3.数据可靠性的问题。使用RAID 10、RAID 5或者RAID 6方案的时候由于数据有冗余存储或者存储校验信息所以当某块磁盘损坏的时候可以通过其他磁盘上的数据和校验数据将丢失磁盘上的数据还原。
我们对更强计算能力和更大规模数据存储的追求几乎是没有止境的,这似乎是源于人类的天性。神话里人类试图建立一座通天塔到神居住的地方,就是这种追求的体现。
我在上一期提到过在计算机领域实现更强的计算能力和更大规模的数据存储有两种思路一种是升级计算机一种是用分布式系统。前一种也被称作“垂直伸缩”scaling up通过升级CPU、内存、磁盘等将一台计算机变得更强大后一种是“水平伸缩”scaling out添加更多的计算机到系统中从而实现更强大的计算能力。
<img src="https://static001.geekbang.org/resource/image/0e/80/0ea550a24ac70d39cabafa52c3257080.png" alt="">
在计算机发展的早期我们获得更强大计算能力的手段主要依靠垂直伸缩。一方面拜摩尔定律所赐每18个月计算机的处理能力提升一倍另一方面由于不断研究新的计算机体系结构小型机、中型机、大型机、超级计算机不断刷新我们的认知。
但是到了互联网时代这种垂直伸缩的路子走不通了一方面是成本问题互联网公司面对巨大的不确定性市场无法为一个潜在的需要巨大计算资源的产品一下投入很多钱去购买大型计算机另一方面对于Google这样的公司和产品而言即使是世界上最强大的超级计算机也无法满足其对计算资源的需求。
所以互联网公司走向了一条新的道路:**水平伸缩**,在一个系统中不断添加计算机,以满足不断增长的用户和数据对计算资源的需求。这就是最近十几年引导技术潮流的分布式与大数据技术。
RAID可以看作是一种垂直伸缩一台计算机集成更多的磁盘实现数据更大规模、更安全可靠的存储以及更快的访问速度。而HDFS则是水平伸缩通过添加更多的服务器实现数据更大、更快、更安全存储与访问。
RAID技术只是在单台服务器的多块磁盘上组成阵列大数据需要更大规模的存储空间和更快的访问速度。将RAID思想原理应用到分布式服务器集群上就形成了Hadoop分布式文件系统HDFS的架构思想。
垂直伸缩总有尽头水平伸缩理论上是没有止境的在实践中数万台服务器的HDFS集群已经出现我会在下一期谈谈HDFS的架构。
## 思考题
传统机械磁盘进行数据连续写入的时候,比如磁盘以日志格式连续写入操作,其写入速度远远大于磁盘随机写入的速度,比如关系数据库连续更新若干条数据记录,你知道这是为什么吗?
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,93 @@
<audio id="audio" title="06 | 新技术层出不穷HDFS依然是存储的王者" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/92/1c/9295674fde0f0fb0d8a83cb3d900c71c.mp3"></audio>
我们知道Google大数据“三驾马车”的第一驾是GFSGoogle 文件系统而Hadoop的第一个产品是HDFS可以说分布式文件存储是分布式计算的基础也可见分布式文件存储的重要性。如果我们将大数据计算比作烹饪那么数据就是食材而Hadoop分布式文件系统HDFS就是烧菜的那口大锅。
厨师来来往往食材进进出出各种菜肴层出不穷而不变的则是那口大锅。大数据也是如此这些年来各种计算框架、各种算法、各种应用场景不断推陈出新让人眼花缭乱但是大数据存储的王者依然是HDFS。
为什么HDFS的地位如此稳固呢在整个大数据体系里面最宝贵、最难以代替的资产就是数据大数据所有的一切都要围绕数据展开。HDFS作为最早的大数据存储系统存储着宝贵的数据资产各种新的算法、框架要想得到人们的广泛使用必须支持HDFS才能获取已经存储在里面的数据。所以大数据技术越发展新技术越多HDFS得到的支持越多我们越离不开HDFS。**HDFS也许不是最好的大数据存储技术但依然最重要的大数据存储技术**。
那我们就从HDFS的原理说起今天我们来聊聊HDFS是如何实现大数据高速、可靠的存储和访问的。
Hadoop分布式文件系统HDFS的设计目标是管理数以千计的服务器、数以万计的磁盘将这么大规模的服务器计算资源当作一个单一的存储系统进行管理对应用程序提供数以PB计的存储容量让应用程序像使用普通文件系统一样存储大规模的文件数据。
如何设计这样一个分布式文件系统?其实思路很简单。
我们先复习一下专栏上一期我讲了RAID磁盘阵列存储RAID将数据分片后在多块磁盘上并发进行读写访问从而提高了存储容量、加快了访问速度并通过数据的冗余校验提高了数据的可靠性即使某块磁盘损坏也不会丢失数据。将RAID的设计理念扩大到整个分布式服务器集群就产生了分布式文件系统Hadoop分布式文件系统的核心原理就是如此。
和RAID在多个磁盘上进行文件存储及并行读写的思路一样HDFS是在一个大规模分布式服务器集群上对数据分片后进行并行读写及冗余存储。因为HDFS可以部署在一个比较大的服务器集群上集群中所有服务器的磁盘都可供HDFS使用所以整个HDFS的存储空间可以达到PB级容量。
<img src="https://static001.geekbang.org/resource/image/65/d7/65efd126cbcf3930a706f64c6e6457d7.jpg" alt="">
上图是HDFS的架构图从图中你可以看到HDFS的关键组件有两个一个是DataNode一个是NameNode。
**DataNode负责文件数据的存储和读写操作HDFS将文件数据分割成若干数据块Block每个DataNode存储一部分数据块这样文件就分布存储在整个HDFS服务器集群中**。应用程序客户端Client可以并行对这些数据块进行访问从而使得HDFS可以在服务器集群规模上实现数据并行访问极大地提高了访问速度。
在实践中HDFS集群的DataNode服务器会有很多台一般在几百台到几千台这样的规模每台服务器配有数块磁盘整个集群的存储容量大概在几PB到数百PB。
**NameNode负责整个分布式文件系统的元数据MetaData管理也就是文件路径名、数据块的ID以及存储位置等信息相当于操作系统中文件分配表FAT的角色**。HDFS为了保证数据的高可用会将一个数据块复制为多份缺省情况为3份并将多份相同的数据块存储在不同的服务器上甚至不同的机架上。这样当有磁盘损坏或者某个DataNode服务器宕机甚至某个交换机宕机导致其存储的数据块不能访问的时候客户端会查找其备份的数据块进行访问。
下面这张图是数据块多份复制存储的示意,图中对于文件/users/sameerp/data/part-0其复制备份数设置为2存储的BlockID分别为1、3。Block1的两个备份存储在DataNode0和DataNode2两个服务器上Block3的两个备份存储DataNode4和DataNode6两个服务器上上述任何一台服务器宕机后每个数据块都至少还有一个备份存在不会影响对文件/users/sameerp/data/part-0的访问。
<img src="https://static001.geekbang.org/resource/image/6f/ac/6f2faa48524251ad77e55e3565095bac.jpg" alt="">
和RAID一样数据分成若干数据块后存储到不同服务器上可以实现数据大容量存储并且不同分片的数据可以并行进行读/写操作进而实现数据的高速访问。你可以看到HDFS的大容量存储和高速访问相对比较容易实现但是HDFS是如何保证存储的高可用性呢
我们尝试从不同层面来讨论一下HDFS的高可用设计。
1.数据存储故障容错
磁盘介质在存储过程中受环境或者老化影响其存储的数据可能会出现错乱。HDFS的应对措施是对于存储在DataNode上的数据块计算并存储校验和CheckSum。在读取数据的时候重新计算读取出来的数据的校验和如果校验不正确就抛出异常应用程序捕获异常后就到其他DataNode上读取备份数据。
2.磁盘故障容错
如果DataNode监测到本机的某块磁盘损坏就将该块磁盘上存储的所有BlockID报告给NameNodeNameNode检查这些数据块还在哪些DataNode上有备份通知相应的DataNode服务器将对应的数据块复制到其他服务器上以保证数据块的备份数满足要求。
3.DataNode故障容错
DataNode会通过心跳和NameNode保持通信如果DataNode超时未发送心跳NameNode就会认为这个DataNode已经宕机失效立即查找这个DataNode上存储的数据块有哪些以及这些数据块还存储在哪些服务器上随后通知这些服务器再复制一份数据块到其他服务器上保证HDFS存储的数据块备份数符合用户设置的数目即使再出现服务器宕机也不会丢失数据。
4.NameNode故障容错
NameNode是整个HDFS的核心记录着HDFS文件分配表信息所有的文件路径和数据块存储信息都保存在NameNode如果NameNode故障整个HDFS系统集群都无法使用如果NameNode上记录的数据丢失整个集群所有DataNode存储的数据也就没用了。
所以NameNode高可用容错能力非常重要。NameNode采用主从热备的方式提供高可用服务请看下图。
<img src="https://static001.geekbang.org/resource/image/7c/89/7cb2668644c32364beab0b69e60b3689.png" alt="">
集群部署两台NameNode服务器一台作为主服务器提供服务一台作为从服务器进行热备两台服务器通过ZooKeeper选举主要是通过争夺znode锁资源决定谁是主服务器。而DataNode则会向两个NameNode同时发送心跳数据但是只有主NameNode才能向DataNode返回控制信息。
正常运行期间主从NameNode之间通过一个共享存储系统shared edits来同步文件系统的元数据信息。当主NameNode服务器宕机从NameNode会通过ZooKeeper升级成为主服务器并保证HDFS集群的元数据信息也就是文件分配表信息完整一致。
对于一个软件系统而言,性能差一点,用户也许可以接受;使用体验差,也许也能忍受。但是如果可用性差,经常出故障导致不可用,那就比较麻烦了;如果出现重要数据丢失,那开发工程师绝对是摊上大事了。
而分布式系统可能出故障地方又非常多内存、CPU、主板、磁盘会损坏服务器会宕机网络会中断机房会停电所有这些都可能会引起软件系统的不可用甚至数据永久丢失。
所以在设计分布式系统的时候,软件工程师一定要绷紧可用性这根弦,思考在各种可能的故障情况下,如何保证整个软件系统依然是可用的。
根据我的经验一般说来常用的保证系统可用性的策略有冗余备份、失效转移和降级限流。虽然这3种策略你可能早已耳熟能详但还是有一些容易被忽略的地方。
比如**冗余备份**,任何程序、任何数据,都至少要有一个备份,也就是说程序至少要部署到两台服务器,数据至少要备份到另一台服务器上。此外,稍有规模的互联网企业都会建设多个数据中心,数据中心之间互相进行备份,用户请求可能会被分发到任何一个数据中心,即所谓的异地多活,在遭遇地域性的重大故障和自然灾害的时候,依然保证应用的高可用。
当要访问的程序或者数据无法访问时,需要将访问请求转移到备份的程序或者数据所在的服务器上,这也就是**失效转移**。失效转移你应该注意的是失效的鉴定像NameNode这样主从服务器管理同一份数据的场景如果从服务器错误地以为主服务器宕机而接管集群管理会出现主从服务器一起对DataNode发送指令进而导致集群混乱也就是所谓的“脑裂”。这也是这类场景选举主服务器时引入ZooKeeper的原因。ZooKeeper的工作原理我将会在后面专门分析。
当大量的用户请求或者数据处理请求到达的时候,由于计算资源有限,可能无法处理如此大量的请求,进而导致资源耗尽,系统崩溃。这种情况下,可以拒绝部分请求,即进行**限流**;也可以关闭部分功能,降低资源消耗,即进行**降级**。限流是互联网应用的常备功能,因为超出负载能力的访问流量在何时会突然到来,你根本无法预料,所以必须提前做好准备,当遇到突发高峰流量时,就可以立即启动限流。而降级通常是为可预知的场景准备的,比如电商的“双十一”促销,为了保障促销活动期间应用的核心功能能够正常运行,比如下单功能,可以对系统进行降级处理,关闭部分非重要功能,比如商品评价功能。
## 小结
我们小结一下看看HDFS是如何通过大规模分布式服务器集群实现数据的大容量、高速、可靠存储、访问的。
1.文件数据以数据块的方式进行切分数据块可以存储在集群任意DataNode服务器上所以HDFS存储的文件可以非常大一个文件理论上可以占据整个HDFS服务器集群上的所有磁盘实现了大容量存储。
2.HDFS一般的访问模式是通过MapReduce程序在计算时读取MapReduce对输入数据进行分片读取通常一个分片就是一个数据块每个数据块分配一个计算进程这样就可以同时启动很多进程对一个HDFS文件的多个数据块进行并发访问从而实现数据的高速访问。关于MapReduce的具体处理过程我们会在专栏后面详细讨论。
3.DataNode存储的数据块会进行复制使每个数据块在集群里有多个备份保证了数据的可靠性并通过一系列的故障容错手段实现HDFS系统中主要组件的高可用进而保证数据和整个系统的高可用。
## 思考题
今天留一道有意思的思考题你可以先想象一个场景我们想利用全世界的个人电脑、手机、平板上的空闲存储空间构成一个可以付费共享的分布式文件系统希望用户可以安装一个App在自己的个人设备上将个人资料安全地存储到这个分布式文件系统中并支付一定费用用户也可以用这个App将自己设备上的空闲存储空间共享出去成为这个分布式文件系统存储的一部分并收取一定费用。
我想问你的是,如果是你来设计这个分布式文件系统,你是怎么思考的?你的设计方案是什么?
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,162 @@
<audio id="audio" title="07 | 为什么说MapReduce既是编程模型又是计算框架" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1b/59/1b709f44fdde73c451b0a1b5a526af59.mp3"></audio>
在Hadoop问世之前其实已经有了分布式计算只是那个时候的分布式计算都是专用的系统只能专门处理某一类计算比如进行大规模数据的排序。很显然这样的系统无法复用到其他的大数据计算场景每一种应用都需要开发与维护专门的系统。而Hadoop MapReduce的出现使得大数据计算通用编程成为可能。我们只要遵循MapReduce编程模型编写业务处理逻辑代码就可以运行在Hadoop分布式集群上无需关心分布式计算是如何完成的。也就是说我们只需要关心业务逻辑不用关心系统调用与运行环境这和我们目前的主流开发方式是一致的。
请你先回忆一下,在前面[专栏第4期](http://time.geekbang.org/column/article/65106)我们讨论过大数据计算的核心思路是移动计算比移动数据更划算。既然计算方法跟传统计算方法不一样移动计算而不是移动数据那么用传统的编程模型进行大数据计算就会遇到很多困难因此Hadoop大数据计算使用了一种叫作MapReduce的编程模型。
其实MapReduce编程模型并不是Hadoop原创甚至也不是Google原创但是Google和Hadoop创造性地将MapReduce编程模型用到大数据计算上立刻产生了神奇的效果看似复杂的各种各样的机器学习、数据挖掘、SQL处理等大数据计算变得简单清晰起来。
今天我们就来聊聊Hadoop解决大规模数据分布式计算的方案——MapReduce。
在我看来,**MapReduce既是一个编程模型又是一个计算框架**。也就是说开发人员必须基于MapReduce编程模型进行编程开发然后将程序通过MapReduce计算框架分发到Hadoop集群中运行。我们先看一下作为编程模型的MapReduce。
为什么说MapReduce是一种非常简单又非常强大的编程模型
简单在于其编程模型只包含Map和Reduce两个过程map的主要输入是一对&lt;Key, Value&gt;经过map计算后输出一对&lt;Key, Value&gt;然后将相同Key合并形成&lt;Key, Value集合&gt;;再将这个&lt;Key, Value集合&gt;输入reduce经过计算输出零个或多个&lt;Key, Value&gt;对。
同时MapReduce又是非常强大的不管是关系代数运算SQL计算还是矩阵运算图计算大数据领域几乎所有的计算需求都可以通过MapReduce编程来实现。
下面我以WordCount程序为例一起来看下MapReduce的计算过程。
WordCount主要解决的是文本处理中词频统计的问题就是统计文本中每一个单词出现的次数。如果只是统计一篇文章的词频几十KB到几MB的数据只需要写一个程序将数据读入内存建一个Hash表记录每个词出现的次数就可以了。这个统计过程你可以看下面这张图。
<img src="https://static001.geekbang.org/resource/image/fc/1d/fc8d1ca01c9a81bb75c16dcd504c281d.png" alt="">
如果用Python语言单机处理WordCount的代码是这样的。
```
# 文本前期处理
strl_ist = str.replace('\n', '').lower().split(' ')
count_dict = {}
# 如果字典里有该单词则加1否则添加入字典
for str in strl_ist:
if str in count_dict.keys():
count_dict[str] = count_dict[str] + 1
else:
count_dict[str] = 1
```
简单说来就是建一个Hash表然后将字符串里的每个词放到这个Hash表里。如果这个词第一次放到Hash表就新建一个Key、Value对Key是这个词Value是1。如果Hash表里已经有这个词了那么就给这个词的Value + 1。
小数据量用单机统计词频很简单但是如果想统计全世界互联网所有网页数万亿计的词频数而这正是Google这样的搜索引擎的典型需求不可能写一个程序把全世界的网页都读入内存这时候就需要用MapReduce编程来解决。
WordCount的MapReduce程序如下。
```
public class WordCount {
public static class TokenizerMapper
extends Mapper&lt;Object, Text, Text, IntWritable&gt;{
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&lt;Text,IntWritable,Text,IntWritable&gt; {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable&lt;IntWritable&gt; values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
}
```
你可以从这段代码中看到MapReduce版本WordCount程序的核心是一个map函数和一个reduce函数。
map函数的输入主要是一个&lt;Key, Value&gt;在这个例子里Value是要统计的所有文本中的一行数据Key在一般计算中都不会用到。
```
public void map(Object key, Text value, Context context
)
```
map函数的计算过程是将这行文本中的单词提取出来针对每个单词输出一个&lt;word, 1&gt;这样的&lt;Key, Value&gt;对。
MapReduce计算框架会将这些&lt;word , 1&gt;收集起来将相同的word放在一起形成&lt;word , &lt;1,1,1,1,1,1,1…&gt;&gt;这样的&lt;Key, Value集合&gt;数据然后将其输入给reduce函数。
```
public void reduce(Text key, Iterable&lt;IntWritable&gt; values,
Context context
)
```
这里reduce的输入参数Values就是由很多个1组成的集合而Key就是具体的单词word。
reduce函数的计算过程是将这个集合里的1求和再将单词word和这个和sum组成一个&lt;Key, Value&gt;,也就是&lt;word, sum&gt;输出。每一个输出就是一个单词和它的词频统计总和。
一个map函数可以针对一部分数据进行运算这样就可以将一个大数据切分成很多块这也正是HDFS所做的MapReduce计算框架为每个数据块分配一个map函数去计算从而实现大数据的分布式计算。
假设有两个数据块的文本数据需要进行词频统计MapReduce计算过程如下图所示。
<img src="https://static001.geekbang.org/resource/image/55/ba/5571ed29c5c2254520052adceadf9cba.png" alt="">
以上就是MapReduce编程模型的主要计算过程和原理但是这样一个MapReduce程序要想在分布式环境中执行并处理海量的大规模数据还需要一个计算框架能够调度执行这个MapReduce程序使它在分布式的集群中并行运行而这个计算框架也叫MapReduce。
所以当我们说MapReduce的时候可能指编程模型也就是一个MapReduce程序也可能是指计算框架调度执行大数据的分布式计算。关于MapReduce计算框架我们下期再详细聊。
## 小结
总结一下今天我们学习了MapReduce编程模型。这个模型既简单又强大简单是因为它只包含Map和Reduce两个过程强大之处又在于它可以实现大数据领域几乎所有的计算需求。这也正是MapReduce这个模型令人着迷的地方。
说起模型,我想跟你聊聊我的体会。
模型是人们对一类事物的概括与抽象,可以帮助我们更好地理解事物的本质,更方便地解决问题。比如,数学公式是我们对物理与数学规律的抽象,地图和沙盘是我们对地理空间的抽象,软件架构图是软件工程师对软件系统的抽象。
通过抽象,我们更容易把握事物的内在规律,而不是被纷繁复杂的事物表象所迷惑,更进一步深刻地认识这个世界。通过抽象,伽利略发现力是改变物体运动的原因,而不是使物体运动的原因,为全人类打开了现代科学的大门。
这些年,我自己认识了很多优秀的人,他们各有所长、各有特点,但是无一例外都有个共同的特征,就是**对事物的洞察力**。他们能够穿透事物的层层迷雾,直指问题的核心和要害,不会犹豫和迷茫,轻松出手就搞定了其他人看起来无比艰难的事情。有时候光是看他们做事就能感受到一种美感,让人意醉神迷。
**这种洞察力就是来源于他们对事物的抽象能力**,虽然我不知道这种能力缘何而来,但是见识了这种能力以后,我也非常渴望拥有对事物的抽象能力。所以在遇到问题的时候,我就会停下来思考:这个问题为什么会出现,它揭示出来背后的规律是什么,我应该如何做。甚至有时候会把这些优秀的人带入进思考:如果是戴老师、如果是潘大侠,他会如何看待、如何解决这个问题。通过这种不断地训练,虽然和那些最优秀的人相比还是有巨大的差距,但是仍然能够感受到自己的进步,这些小小的进步也会让自己产生大大的快乐,一种不荒废光阴、没有虚度此生的感觉。
我希望你也能够不断训练自己,遇到问题的时候,停下来思考一下:这些现象背后的规律是什么。有时候并不需要多么艰深的思考,仅仅就是停一下,就会让你察觉到以前不曾注意到的一些情况,进而发现事物的深层规律。这就是洞察力。
## 思考题
对于这样一张数据表
<img src="https://static001.geekbang.org/resource/image/a6/76/a699fae32164f0c37e03e50bfeec6e76.png" alt="">
如果存储在HDFS中每一行记录在HDFS对应一行文本文本格式是
```
1,25
2,25
1,32
2,25
```
根据上面WordCount的示例请你写一个MapReduce程序得到下面这条SQL的计算结果。
```
SELECT pageid, age, count(1) FROM pv_users GROUP BY pageid, age;
```
TIPS如何用MapReduce实现SQL计算我们在后面还会进一步讨论。
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,100 @@
<audio id="audio" title="08 | MapReduce如何让数据完成一次旅行" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/82/51/82b3ab794870bd95d2be0f8e23f3a551.mp3"></audio>
上一期我们聊到MapReduce编程模型将大数据计算过程切分为Map和Reduce两个阶段先复习一下在Map阶段为每个数据块分配一个Map计算任务然后将所有map输出的Key进行合并相同的Key及其对应的Value发送给同一个Reduce任务去处理。通过这两个阶段工程师只需要遵循MapReduce编程模型就可以开发出复杂的大数据计算程序。
那么这个程序是如何在分布式集群中运行起来的呢MapReduce程序又是如何找到相应的数据并进行计算的呢答案就是需要MapReduce计算框架来完成。上一期我讲了MapReduce既是编程模型又是计算框架我们聊完编程模型今天就来讨论MapReduce如何让数据完成一次旅行也就是MapReduce计算框架是如何运作的。
首先我想告诉你,在实践中,这个过程有两个关键问题需要处理。
<li>
如何为每个数据块分配一个Map计算任务也就是代码是如何发送到数据块所在服务器的发送后是如何启动的启动以后如何知道自己需要计算的数据在文件什么位置BlockID是什么
</li>
<li>
处于不同服务器的map输出的&lt;Key, Value&gt; 如何把相同的Key聚合在一起发送给Reduce任务进行处理。
</li>
那么这两个关键问题对应在MapReduce计算过程的哪些步骤呢根据我上一期所讲的我把MapReduce计算过程的图又找出来你可以看到图中标红的两处这两个关键问题对应的就是图中的两处“MapReduce框架处理”具体来说它们分别是MapReduce作业启动和运行以及MapReduce数据合并与连接。
<img src="https://static001.geekbang.org/resource/image/f3/9c/f3a2faf9327fe3f086ec2c7eb4cd229c.png" alt="">
## MapReduce作业启动和运行机制
我们以Hadoop 1为例MapReduce运行过程涉及三类关键进程。
1.大数据应用进程。这类进程是启动MapReduce程序的主入口主要是指定Map和Reduce类、输入输出文件路径等并提交作业给Hadoop集群也就是下面提到的JobTracker进程。这是由用户启动的MapReduce程序进程比如我们上期提到的WordCount程序。
2.JobTracker进程。这类进程根据要处理的输入数据量命令下面提到的TaskTracker进程启动相应数量的Map和Reduce进程任务并管理整个作业生命周期的任务调度和监控。这是Hadoop集群的常驻进程需要注意的是JobTracker进程在整个Hadoop集群全局唯一。
3.TaskTracker进程。这个进程负责启动和管理Map进程以及Reduce进程。因为需要每个数据块都有对应的map函数TaskTracker进程通常和HDFS的DataNode进程启动在同一个服务器。也就是说Hadoop集群中绝大多数服务器同时运行DataNode进程和TaskTracker进程。
JobTracker进程和TaskTracker进程是主从关系主服务器通常只有一台或者另有一台备机提供高可用服务但运行时只有一台服务器对外提供服务真正起作用的只有一台从服务器可能有几百上千台所有的从服务器听从主服务器的控制和调度安排。主服务器负责为应用程序分配服务器资源以及作业执行的调度而具体的计算操作则在从服务器上完成。
具体来看MapReduce的主服务器就是JobTracker从服务器就是TaskTracker。还记得我们讲HDFS也是主从架构吗HDFS的主服务器是NameNode从服务器是DataNode。后面会讲到的Yarn、Spark等也都是这样的架构这种一主多从的服务器架构也是绝大多数大数据系统的架构方案。
可重复使用的架构方案叫作架构模式,一主多从可谓是大数据领域的最主要的架构模式。主服务器只有一台,掌控全局;从服务器有很多台,负责具体的事情。这样很多台服务器可以有效组织起来,对外表现出一个统一又强大的计算能力。
讲到这里我们对MapReduce的启动和运行机制有了一个直观的了解。那具体的作业启动和计算过程到底是怎样的呢我根据上面所讲的绘制成一张图你可以从图中一步一步来看感受一下整个流程。
<img src="https://static001.geekbang.org/resource/image/2d/27/2df4e1976fd8a6ac4a46047d85261027.png" alt="">
如果我们把这个计算过程看作一次小小的旅行,这个旅程可以概括如下:
1.应用进程JobClient将用户作业JAR包存储在HDFS中将来这些JAR包会分发给Hadoop集群中的服务器执行MapReduce计算。
2.应用程序提交job作业给JobTracker。
3.JobTracker根据作业调度策略创建JobInProcess树每个作业都会有一个自己的JobInProcess树。
4.JobInProcess根据输入数据分片数目通常情况就是数据块的数目和设置的Reduce数目创建相应数量的TaskInProcess。
5.TaskTracker进程和JobTracker进程进行定时通信。
6.如果TaskTracker有空闲的计算资源有空闲CPU核心JobTracker就会给它分配任务。分配任务的时候会根据TaskTracker的服务器名字匹配在同一台机器上的数据块计算任务给它使启动的计算任务正好处理本机上的数据以实现我们一开始就提到的“移动计算比移动数据更划算”。
7.TaskTracker收到任务后根据任务类型是Map还是Reduce和任务参数作业JAR包路径、输入数据文件路径、要处理的数据在文件中的起始位置和偏移量、数据块多个备份的DataNode主机名等启动相应的Map或者Reduce进程。
8.Map或者Reduce进程启动后检查本地是否有要执行任务的JAR包文件如果没有就去HDFS上下载然后加载Map或者Reduce代码开始执行。
9.如果是Map进程从HDFS读取数据通常要读取的数据块正好存储在本机如果是Reduce进程将结果数据写出到HDFS。
通过这样一个计算旅程MapReduce可以将大数据作业计算任务分布在整个Hadoop集群中运行每个Map计算任务要处理的数据通常都能从本地磁盘上读取到。现在你对这个过程的理解是不是更清楚了呢你也许会觉得这个过程好像也不算太简单啊
其实你要做的仅仅是编写一个map函数和一个reduce函数就可以了根本不用关心这两个函数是如何被分布启动到集群上的也不用关心数据块又是如何分配给计算任务的。**这一切都由MapReduce计算框架完成**是不是很激动这也是我们反复讲到的MapReduce的强大之处。
## MapReduce数据合并与连接机制
**MapReduce计算真正产生奇迹的地方是数据的合并与连接**
让我先回到上一期MapReduce编程模型的WordCount例子中我们想要统计相同单词在所有输入数据中出现的次数而一个Map只能处理一部分数据一个热门单词几乎会出现在所有的Map中这意味着同一个单词必须要合并到一起进行统计才能得到正确的结果。
事实上几乎所有的大数据计算场景都需要处理数据关联的问题像WordCount这种比较简单的只要对Key进行合并就可以了对于像数据库的join操作这种比较复杂的需要对两种类型或者更多类型的数据根据Key进行连接。
在map输出与reduce输入之间MapReduce计算框架处理数据合并与连接操作这个操作有个专门的词汇叫**shuffle**。那到底什么是shuffleshuffle的具体过程又是怎样的呢请看下图。
<img src="https://static001.geekbang.org/resource/image/d6/c7/d64daa9a621c1d423d4a1c13054396c7.png" alt="">
每个Map任务的计算结果都会写入到本地文件系统等Map任务快要计算完成的时候MapReduce计算框架会启动shuffle过程在Map任务进程调用一个Partitioner接口对Map产生的每个&lt;Key, Value&gt;进行Reduce分区选择然后通过HTTP通信发送给对应的Reduce进程。这样不管Map位于哪个服务器节点相同的Key一定会被发送给相同的Reduce进程。Reduce任务进程对收到的&lt;Key, Value&gt;进行排序和合并相同的Key放在一起组成一个&lt;Key, Value集合&gt;传递给Reduce执行。
map输出的&lt;Key, Value&gt;shuffle到哪个Reduce进程是这里的关键它是由Partitioner来实现MapReduce框架默认的Partitioner用Key的哈希值对Reduce任务数量取模相同的Key一定会落在相同的Reduce任务ID上。从实现上来看的话这样的Partitioner代码只需要一行。
```
/** Use {@link Object#hashCode()} to partition. */
public int getPartition(K2 key, V2 value, int numReduceTasks) {
return (key.hashCode() &amp; Integer.MAX_VALUE) % numReduceTasks;
}
```
讲了这么多对shuffle的理解你只需要记住这一点**分布式计算需要将不同服务器上的相关数据合并到一起进行下一步计算这就是shuffle**。
shuffle是大数据计算过程中最神奇的地方不管是MapReduce还是Spark只要是大数据批处理计算一定都会有shuffle过程只有**让数据关联起来**数据的内在关系和价值才会呈现出来。如果你不理解shuffle肯定会在map和reduce编程中产生困惑不知道该如何正确设计map的输出和reduce的输入。shuffle也是整个MapReduce过程中最难、最消耗性能的地方在MapReduce早期代码中一半代码都是关于shuffle处理的。
## 小结
MapReduce编程相对说来是简单的但是MapReduce框架要将一个相对简单的程序在分布式的大规模服务器集群上并行执行起来却并不简单。理解MapReduce作业的启动和运行机制理解shuffle过程的作用和实现原理对你理解大数据的核心原理做到真正意义上把握大数据、用好大数据作用巨大。
## 思考题
互联网应用中用户从手机或者PC上发起一个请求请问这个请求数据经历了怎样的旅程完成了哪些计算处理后响应给用户
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,79 @@
<audio id="audio" title="09 | 为什么我们管Yarn叫作资源调度框架" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/38/f1/38ae0f1e2585ad75a62922fbad6855f1.mp3"></audio>
我们知道Hadoop主要是由三部分组成除了前面我讲过的分布式文件系统HDFS、分布式计算框架MapReduce还有一个是分布式集群资源调度框架Yarn。但是Yarn并不是随Hadoop的推出一开始就有的Yarn作为分布式集群的资源调度框架它的出现伴随着Hadoop的发展使Hadoop从一个单一的大数据计算引擎成为一个集存储、计算、资源管理为一体的完整大数据平台进而发展出自己的生态体系成为大数据的代名词。
所以在我们开始聊Yarn的实现原理前有必要看看Yarn发展的过程这对你理解Yarn的原理以及为什么被称为资源调度框架很有帮助。
先回忆一下我们学习的MapReduce的架构在MapReduce应用程序的启动过程中最重要的就是要把MapReduce程序分发到大数据集群的服务器上在Hadoop 1中这个过程主要是通过TaskTracker和JobTracker通信来完成。
这个方案有什么缺点吗?
这种架构方案的主要缺点是,**服务器集群资源调度管理和MapReduce执行过程耦合在一起如果想在当前集群中运行其他计算任务比如Spark或者Storm就无法统一使用集群中的资源了**。
在Hadoop早期的时候大数据技术就只有Hadoop一家这个缺点并不明显。但随着大数据技术的发展各种新的计算框架不断出现我们不可能为每一种计算框架部署一个服务器集群而且就算能部署新集群数据还是在原来集群的HDFS上。所以我们需要把MapReduce的资源管理和计算框架分开这也是Hadoop 2最主要的变化就是将Yarn从MapReduce中分离出来成为一个独立的资源调度框架。
Yarn是“Yet Another Resource Negotiator”的缩写字面意思就是“另一种资源调度器”。事实上在Hadoop社区决定将资源管理从Hadoop 1中分离出来独立开发Yarn的时候业界已经有一些大数据资源管理产品了比如Mesos等所以Yarn的开发者索性管自己的产品叫“另一种资源调度器”。这种命名方法并不鲜见曾经名噪一时的Java项目编译工具Ant就是“Another Neat Tool”的缩写意思是“另一种整理工具”。
下图是Yarn的架构。
<img src="https://static001.geekbang.org/resource/image/af/b1/af90905013e5869f598c163c09d718b1.jpg" alt="">
从图上看Yarn包括两个部分一个是资源管理器Resource Manager一个是节点管理器Node Manager。这也是Yarn的两种主要进程ResourceManager进程负责整个集群的资源调度管理通常部署在独立的服务器上NodeManager进程负责具体服务器上的资源和任务管理在集群的每一台计算服务器上都会启动基本上跟HDFS的DataNode进程一起出现。
具体说来,资源管理器又包括两个主要组件:调度器和应用程序管理器。
调度器其实就是一个资源分配算法根据应用程序Client提交的资源申请和当前服务器集群的资源状况进行资源分配。Yarn内置了几种资源调度算法包括Fair Scheduler、Capacity Scheduler等你也可以开发自己的资源调度算法供Yarn调用。
Yarn进行资源分配的单位是容器Container每个容器包含了一定量的内存、CPU等计算资源默认配置下每个容器包含一个CPU核心。容器由NodeManager进程启动和管理NodeManger进程会监控本节点上容器的运行状况并向ResourceManger进程汇报。
应用程序管理器负责应用程序的提交、监控应用程序运行状态等。应用程序启动后需要在集群中运行一个ApplicationMasterApplicationMaster也需要运行在容器里面。每个应用程序启动后都会先启动自己的ApplicationMaster由ApplicationMaster根据应用程序的资源需求进一步向ResourceManager进程申请容器资源得到容器以后就会分发自己的应用程序代码到容器上启动进而开始分布式计算。
我们以一个MapReduce程序为例来看一下Yarn的整个工作流程。
1.我们向Yarn提交应用程序包括MapReduce ApplicationMaster、我们的MapReduce程序以及MapReduce Application启动命令。
2.ResourceManager进程和NodeManager进程通信根据集群资源为用户程序分配第一个容器并将MapReduce ApplicationMaster分发到这个容器上面并在容器里面启动MapReduce ApplicationMaster。
3.MapReduce ApplicationMaster启动后立即向ResourceManager进程注册并为自己的应用程序申请容器资源。
4.MapReduce ApplicationMaster申请到需要的容器后立即和相应的NodeManager进程通信将用户MapReduce程序分发到NodeManager进程所在服务器并在容器中运行运行的就是Map或者Reduce任务。
5.Map或者Reduce任务在运行期和MapReduce ApplicationMaster通信汇报自己的运行状态如果运行结束MapReduce ApplicationMaster向ResourceManager进程注销并释放所有的容器资源。
MapReduce如果想在Yarn上运行就需要开发遵循Yarn规范的MapReduce ApplicationMaster相应地其他大数据计算框架也可以开发遵循Yarn规范的ApplicationMaster这样在一个Yarn集群中就可以同时并发执行各种不同的大数据计算框架实现资源的统一调度管理。
细心的你可能会发现我在今天文章开头的时候提到Hadoop的三个主要组成部分的时候管HDFS叫分布式文件**系统**管MapReduce叫分布式计算**框架**管Yarn叫分布式集群资源调度**框架**。
为什么HDFS是系统而MapReduce和Yarn则是框架
框架在架构设计上遵循一个重要的设计原则叫“**依赖倒转原则**”,依赖倒转原则是**高层模块不能依赖低层模块,它们应该共同依赖一个抽象,这个抽象由高层模块定义,由低层模块实现。**
所谓高层模块和低层模块的划分简单说来就是在调用链上处于前面的是高层后面的是低层。我们以典型的Java Web应用举例用户请求在到达服务器以后最先处理用户请求的是Java Web容器比如Tomcat、Jetty这些通过监听80端口把HTTP二进制流封装成Request对象然后是Spring MVC框架把Request对象里的用户参数提取出来根据请求的URL分发给相应的Model对象处理再然后就是我们的应用程序负责处理用户请求具体来看还会分成服务层、数据持久层等。
在这个例子中Tomcat相对于Spring MVC就是高层模块Spring MVC相对于我们的应用程序也算是高层模块。我们看到虽然Tomcat会调用Spring MVC因为Tomcat要把Request交给Spring MVC处理但是Tomcat并没有依赖Spring MVCTomcat的代码里不可能有任何一行关于Spring MVC的代码。
那么Tomcat如何做到不依赖Spring MVC却可以调用Spring MVC如果你不了解框架的一般设计方法这里还是会感到有点小小的神奇是不是
秘诀就是Tomcat和Spring MVC都依赖J2EE规范Spring MVC实现了J2EE规范的HttpServlet抽象类即DispatcherServlet并配置在web.xml中。这样Tomcat就可以调用DispatcherServlet处理用户发来的请求。
同样Spring MVC也不需要依赖我们写的Java代码而是通过依赖Spring MVC的配置文件或者Annotation这样的抽象来调用我们的Java代码。
所以Tomcat或者Spring MVC都可以称作是框架它们都遵循依赖倒转原则。
现在我们再回到MapReduce和Yarn。实现MapReduce编程接口、遵循MapReduce编程规范就可以被MapReduce框架调用在分布式集群中计算大规模数据实现了Yarn的接口规范比如Hadoop 2的MapReduce就可以被Yarn调度管理统一安排服务器资源。所以说MapReduce和Yarn都是框架。
相反地HDFS就不是框架使用HDFS就是直接调用HDFS提供的API接口HDFS作为底层模块被直接依赖。
## 小结
Yarn作为一个大数据资源调度框架调度的是大数据计算引擎本身。它不像MapReduce或Spark编程每个大数据应用开发者都需要根据需求开发自己的MapReduce程序或者Spark程序。而现在主流的大数据计算引擎所使用的Yarn模块也早已被这些计算引擎的开发者做出来供我们使用了。作为普通的大数据开发者我们几乎没有机会编写Yarn的相关程序。但是这是否意味着只有大数据计算引擎的开发者需要基于Yarn开发才需要理解Yarn的实现原理呢
恰恰相反我认为理解Yarn的工作原理和架构对于正确使用大数据技术理解大数据的工作原理是非常重要的。在云计算的时代一切资源都是动态管理的理解这种动态管理的原理对于理解云计算也非常重要。Yarn作为一个大数据平台的资源管理框架简化了应用场景对于帮助我们理解云计算的资源管理很有帮助。
## 思考题
Web应用程序的服务层Service和数据持久层DAO也是上下层模块关系你设计的Service层是否按照框架的一般架构方法遵循依赖倒转原则
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。

View File

@@ -0,0 +1,98 @@
<audio id="audio" title="10 | 模块答疑我们能从Hadoop学到什么" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/01/5b/01242e5b1b8ab72fd094efda7efbdb5b.mp3"></audio>
你好,我是李智慧。专栏的模块一已经更新完毕,按照计划,今天是我们答疑的时间。首先要感谢订阅专栏的同学给我留言,每条留言我都看过了,有些留言对我的启发也很大,希望同学们可以多多跟我互动。我在每个模块都设置了一个答疑的主题,想跟你聊聊我在学习这个模块时的心得体会。另外,我也会贴出一些同学的疑问,跟你聊聊我的想法。
今天的主题是我们能从Hadoop学到什么
最近几年,我跟很多创业者交流,发现创业最艰难的地方,莫过于创业项目难以实现商业价值。很多时候技术实现了、产品做好了,然后千辛万苦做运营,各种补贴、各种宣传,但是用户就是不买账,活跃差、留存低。
很多时候,我们不是不够努力,可是如果方向错了,再多努力似乎也没有用。阿里有句话说的是“方向对了,路就不怕远”,雷军也说过“不要用你战术上的勤奋,掩盖你战略上的懒惰”。这两句话都是说,要找好方向、找准机会,不要为了努力而努力,要为了目标和价值而努力。而王兴则更加直言不讳:“很多人为了放弃思考,什么事情都干得出来”。
说了那么多我们再回过来看看Hadoop的成长历程。从2004年Google发表论文到2008年Hadoop成为Apache的开源项目历时4年。当时世界上那么多搜索引擎公司似乎都对这件事熟视无睹Yahoo、百度、搜狐是的搜狐曾经是一家搜索引擎公司都任由这个机会流失。只有Doug Cutting把握住机会做出了Hadoop开创了大数据行业甚至引领了一个时代。
所以,**我们能从Hadoop中学到的第一个经验就是识别机会、把握机会**。有的时候,你不需要多么天才的思考力,也不需要超越众人去预见未来,你只需要当机会到来的时候,能够敏感地意识到机会,全力以赴付出你的才智和努力,就可以脱颖而出了。
结合大数据来说,**虽然大数据技术已经成熟,但是和各种应用场景的结合正方兴未艾,如果你能看到大数据和你所在领域结合的机会,也许你就找到了一次出人头地的机会。**
另一方面你看一下Hadoop几个主要产品的架构设计就会发现它们都有相似性都是一主多从的架构方案。HDFS一个NameNode多个DataNodeMapReduce 1一个JobTracker多个TaskTrackerYarn一个ResourceManager多个NodeManager。
事实上很多大数据产品都是这样的架构方案Storm一个Nimbus多个SupervisorSpark一个Master多个Slave。
大数据因为要对数据和计算任务进行统一管理,所以和互联网在线应用不同,需要一个全局管理者。而在线应用因为每个用户请求都是独立的,而且为了高性能和便于集群伸缩,会尽量避免有全局管理者。
所以**我们从Hadoop中可以学到大数据领域的一个架构模式也就是集中管理分布存储与计算**。我在思考题里提出如何利用个人设备构建一个存储共享的应用,很多同学也都提到了类似的架构方案。
最后我想说使用Hadoop要先了解Hadoop、学习Hadoop、掌握Hadoop要做工具的主人而不是工具的奴隶不能每天被工具的各种问题牵着走。最终的目标是要超越Hadoop打造适合自己业务场景的大数据解决方案。
正好提到了每期文章后留给你的思考题,在这里也分享一下**我是如何设置思考题的**。
关于思考题,你会发现,我留的思考题很多都是和当期内容没有直接关联的,甚至和大数据无关的。它们或是相似的问题场景,或是有类似的解决思路,或是引申的一些场景。
其实我是希望你在学习大数据的时候,不要仅局限在大数据技术这个领域,能够用更开阔的视野和角度去看待大数据、去理解大数据。这样一方面可以更好地学习大数据技术本身,另一方面也可以把以前的知识都融会贯通起来。
计算机知识更新迭代非常快速如果你只是什么技术新就学什么或者什么热门学什么就会处于一种永远在学习永远都学不完的境地。前一阵子有个闹得沸沸扬扬的事件有个程序员到GitHub上给一个国外的开源软件提了个Issue“不要再更新了老子学不动了”就是一个典型例子。
如果这些知识点对于你而言都是孤立的,新知识真的就是新的知识,你无法触类旁通,无法利用过往的知识体系去快速理解这些新知识,进而掌握这些新知识。你不但学得累,就算学完了,忘得也快。
所以不要纠结在仅仅学习一些新的技术和知识点上了,构建起你的知识和思维体系,不管任何新技术出现,都能够快速容纳到你的知识和思维体系里面。这样你非但不会惧怕新技术、新知识,反而会更加渴望,因为你需要这些新知识让你的知识和思维体系更加完善。
关于学习新知识我有一点心得体会想与你分享。我在学习新知识的时候会遵循一个**5-20-2法则**用5分钟的时间了解这个新知识的特点、应用场景、要解决的问题用20分钟理解它的主要设计原理、核心思想和思路再花2个小时看关键的设计细节尝试使用或者做一个demo。
如果5分钟不能搞懂它要解决的问题我就会放弃20分钟没有理解它的设计思路我也会放弃2个小时还上不了手我也会放一放。你相信我一种真正有价值的好技术你这次放弃了它过一阵子还会换一种方式继续出现在你面前。这个时候你再尝试用5-20-2法则去学习它也许就能理解了。我学Hadoop实际上就是经历了好几次这样的过程才终于入门。而有些技术当时我放弃了它们再也没有出现在我面前后来它们被历史淘汰了我也没有浪费自己的时间。
还有的时候,你学一样新技术却苦苦不能入门,可能仅仅就是因为你看的文章、书籍本身写得糟糕,或者作者写法跟你的思维方式不对路而已,并不代表这个技术有多难,更不代表你的能力有问题,如果换个方式、换个时间、换篇文章重新再看,可能就豁然开朗了。
接下来我们看一下同学们的具体问题。
<img src="https://static001.geekbang.org/resource/image/56/1c/561902bcb03fc5a1b56b318f9f4e8f1c.jpg" alt="">
我的判断是大数据与业务的结合,在每个垂直领域、每个垂直领域的细分领域,将大数据和业务场景结合起来,利用大数据发现新的业务增长点。
对技术人员而言,其实挑战更高了,一方面要掌握大数据的知识,这正是专栏想要输出的;另一方面,要掌握业务知识,甚至得成为业务领域的专家,能发现业务中可以和大数据结合的点,利用大数据和业务结合构建起技术驱动业务的增长点,这需要你在业务中有敏锐的观察力和领悟力。
<img src="https://static001.geekbang.org/resource/image/01/8f/01b5f93ebc03b8682fd506dbe30d2e8f.jpg" alt="">
实时计算的结果一般通过两种方式输出一个是写入到数据库里和离线计算的结果组成全量数据供业务使用一个是通过Kafka之类的实时队列给业务比如你提到的监控展示。关于大数据怎么和业务结合我会在专栏第四模块与你讨论请继续关注。
<img src="https://static001.geekbang.org/resource/image/58/27/584400b14e8e1a173cb1d5670efffb27.jpg" alt="">
事实上并不会慢影响文件读写速度的是磁盘的速度。同样的数据量、同样类型的磁盘HDFS可以将数据分布在更多的服务器和磁盘上肯定比单机上的几块磁盘速度更快。
HDFS常用的使用方式是结合MapReduce或者Spark这样的大数据计算框架进行计算这些计算框架会在集群中启动很多的分布式计算进程同时对HDFS上的数据进行读写操作数据读写的速度是非常快的甚至能支撑起Impala这样的准实时计算引擎。
<img src="https://static001.geekbang.org/resource/image/39/1e/3920b3871cec5ed548b225409e15501e.jpg" alt="">
我在专栏第8期留了一个思考题我看了大家的留言发现很多同学可能没有意识到互联网处理一个请求的复杂性这里我来谈谈我的理解。
这个思考题其实并不简单,考察的是一个典型的互联网应用,比如淘宝的架构是怎样的。简化描述下,这个过程是:
首先一个请求从Web或者移动App上发起请求的URL是用域名标识的比如taobao.com这样而HTTP网络通信需要得到IP地址才能建立连接所以先要进行域名解析访问域名解析服务器DNS得到域名的IP地址。
得到的这个IP地址其实也不是淘宝的服务器的IP地址而是CDN服务器的IP地址CDN服务器提供距离用户最近的静态资源缓存服务比如图片、JS、CSS这些。如果CDN有请求需要的资源就直接返回如果没有再把请求转发给真正的淘宝数据中心服务器。
请求到达数据中心后,首先处理请求的是负载均衡服务器,它会把这个请求分发给下面的某台具体服务器处理。
这台具体的服务器通常是反向代理服务器,这里同样缓存着大量的静态资源,淘宝也会把一些通常是动态资源的数据,比如我们购物时经常访问的商品详情页,把整个页面缓存在这里,如果请求的数据在反向代理服务器,就返回;如果没有,请求将发给下一级的负载均衡服务器。
这一级的负载均衡服务器负责应用服务器的负载均衡将请求分发给下面某个具体应用服务器处理淘宝是用Java开发的也就是分发被某个Java Web容器处理。事实上淘宝在Java Web容器之前还前置了一台Nginx服务器做一些前置处理。
应用服务器根据请求,调用后面的微服务进行逻辑处理。如果是一个写操作请求,比如下单请求,应用服务器和微服务之间通过消息队列进行异步操作,避免对后面的数据库造成太大的负载压力。
微服务如果在处理过程中需要读取数据会去缓存服务器查找如果没有找到就去数据库查找或者NoSQL数据库甚至用搜索引擎查找得到数据后进行相关计算将结果返回给应用服务器。
应用服务器将结果包装成前端需要的格式后继续返回,经过前面的访问通道,最后到达用户发起请求的地方,完成一次互联网请求的旅程。如果用架构图表示的话,就是下面的样子。
<img src="https://static001.geekbang.org/resource/image/68/32/68c614319d3044e686fd86b727b62132.png" alt="">
这张图来自我写的《大型网站技术架构:核心原理与案例分析》一书,对互联网实时业务处理感兴趣的同学,欢迎阅读这本书。大数据的数据来源最主要的就是网站数据,了解网站架构对学习大数据、用好大数据也很有帮助。
最后我在今天的文章里贴了陈晨、虎虎、您的好友William、lyshrine、不求、Panmax、wmg、西贝木土的留言我认为是比较精彩很有深度的也把它们分享给你希望其他同学的思考也能对你有所启发也欢迎你给我留言与我一起讨论。
<img src="https://static001.geekbang.org/resource/image/44/0a/44041ebf1de5064287f660fa61d4150a.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/30/0f/30b1f37a78cb4a19bb5f1ee9b246120f.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/40/af/401aaa638e68d4ea8598af1459531faf.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/be/67/be00bae9b7bea9681186c7c60650fd67.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/1c/53/1ce5e73cfb94c4759d125485653b4b53.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/c7/b9/c71b9c4053d03e04ec0831b0aa3678b9.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/78/2e/78b2d0f58d8a53eca81654c7e1fb652e.jpg" alt=""><br>
<img src="https://static001.geekbang.org/resource/image/3c/db/3c4e844a810965447df7085d420788db.jpg" alt="">