mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2026-05-11 04:04:34 +08:00
del
This commit is contained in:
65
极客时间专栏/geek/从0开始学大数据/模块一 Hadoop大数据原理与架构/04 | 移动计算比移动数据更划算.md
Normal file
65
极客时间专栏/geek/从0开始学大数据/模块一 Hadoop大数据原理与架构/04 | 移动计算比移动数据更划算.md
Normal 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>
|
||||
|
||||
大数据技术和传统的软件开发技术在架构思路上有很大不同,大数据技术更为关注数据,所以相关的架构设计也围绕数据展开,如何存储、计算、传输大规模的数据是要考虑的核心要素。
|
||||
|
||||
传统的软件计算处理模型,都是“输入 -> 计算 -> 输出”模型。也就是说,一个程序给它传入一些数据也好,它自己从某个地方读取一些数据也好,总是先有一些输入数据,然后对这些数据进行计算处理,最后得到输出结果。
|
||||
|
||||
但是在互联网大数据时代,需要计算处理的数据量急速膨胀。一来是因为互联网用户数远远超过传统企业的用户,相应产生了更大量的数据;二来很多以往被忽视的数据重新被发掘利用,比如用户在一个页面的停留时长、鼠标在屏幕移动的轨迹都会被记录下来进行分析。在稍微大一点的互联网企业,需要计算处理的数据量常常以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可能感染病毒的程序)更划算的例子。
|
||||
|
||||
大数据技术将移动计算这一编程技巧上升到编程模型的高度,并开发了相应的编程框架,使得开发人员只需要关注大数据的算法实现,而不必关注如何将这个算法在分布式的环境中执行,这极大地简化了大数据的开发难度,并统一了大数据的开发方式,从而使大数据从原来的高高在上,变成了今天的人人参与。
|
||||
|
||||
## 思考题
|
||||
|
||||
互联网应用系统架构中有一种重要架构原则是尽量使用无状态的服务,不同服务实例之间不共享状态,也就是不持有数据,用户请求交给任何一个服务实例计算,处理的结果都是一样的,为什么要这样设计?这种架构有什么好处?
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
|
||||
|
||||
@@ -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计的数据计算问题,而一般的服务器磁盘容量通常1~2TB,那么如何存储这么大规模的数据呢?
|
||||
|
||||
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的架构。
|
||||
|
||||
## 思考题
|
||||
|
||||
传统机械磁盘进行数据连续写入的时候,比如磁盘以日志格式连续写入操作,其写入速度远远大于磁盘随机写入的速度,比如关系数据库连续更新若干条数据记录,你知道这是为什么吗?
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
|
||||
|
||||
@@ -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大数据“三驾马车”的第一驾是GFS(Google 文件系统),而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报告给NameNode,NameNode检查这些数据块还在哪些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将自己设备上的空闲存储空间共享出去,成为这个分布式文件系统存储的一部分,并收取一定费用。
|
||||
|
||||
我想问你的是,如果是你来设计这个分布式文件系统,你是怎么思考的?你的设计方案是什么?
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
|
||||
|
||||
@@ -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的主要输入是一对<Key, Value>值,经过map计算后输出一对<Key, Value>值;然后将相同Key合并,形成<Key, Value集合>;再将这个<Key, Value集合>输入reduce,经过计算输出零个或多个<Key, Value>对。
|
||||
|
||||
同时,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<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
你可以从这段代码中看到,MapReduce版本WordCount程序的核心是一个map函数和一个reduce函数。
|
||||
|
||||
map函数的输入主要是一个<Key, Value>对,在这个例子里,Value是要统计的所有文本中的一行数据,Key在一般计算中都不会用到。
|
||||
|
||||
```
|
||||
public void map(Object key, Text value, Context context
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
map函数的计算过程是,将这行文本中的单词提取出来,针对每个单词输出一个<word, 1>这样的<Key, Value>对。
|
||||
|
||||
MapReduce计算框架会将这些<word , 1>收集起来,将相同的word放在一起,形成<word , <1,1,1,1,1,1,1…>>这样的<Key, Value集合>数据,然后将其输入给reduce函数。
|
||||
|
||||
```
|
||||
public void reduce(Text key, Iterable<IntWritable> values,
|
||||
Context context
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
这里reduce的输入参数Values就是由很多个1组成的集合,而Key就是具体的单词word。
|
||||
|
||||
reduce函数的计算过程是,将这个集合里的1求和,再将单词(word)和这个和(sum)组成一个<Key, Value>,也就是<word, sum>输出。每一个输出就是一个单词和它的词频统计总和。
|
||||
|
||||
一个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计算,我们在后面还会进一步讨论。
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
|
||||
|
||||
@@ -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输出的<Key, Value> ,如何把相同的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**。那到底什么是shuffle?shuffle的具体过程又是怎样的呢?请看下图。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/d6/c7/d64daa9a621c1d423d4a1c13054396c7.png" alt="">
|
||||
|
||||
每个Map任务的计算结果都会写入到本地文件系统,等Map任务快要计算完成的时候,MapReduce计算框架会启动shuffle过程,在Map任务进程调用一个Partitioner接口,对Map产生的每个<Key, Value>进行Reduce分区选择,然后通过HTTP通信发送给对应的Reduce进程。这样不管Map位于哪个服务器节点,相同的Key一定会被发送给相同的Reduce进程。Reduce任务进程对收到的<Key, Value>进行排序和合并,相同的Key放在一起,组成一个<Key, Value集合>传递给Reduce执行。
|
||||
|
||||
map输出的<Key, Value>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() & Integer.MAX_VALUE) % numReduceTasks;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
讲了这么多,对shuffle的理解,你只需要记住这一点:**分布式计算需要将不同服务器上的相关数据合并到一起进行下一步计算,这就是shuffle**。
|
||||
|
||||
shuffle是大数据计算过程中最神奇的地方,不管是MapReduce还是Spark,只要是大数据批处理计算,一定都会有shuffle过程,只有**让数据关联起来**,数据的内在关系和价值才会呈现出来。如果你不理解shuffle,肯定会在map和reduce编程中产生困惑,不知道该如何正确设计map的输出和reduce的输入。shuffle也是整个MapReduce过程中最难、最消耗性能的地方,在MapReduce早期代码中,一半代码都是关于shuffle处理的。
|
||||
|
||||
## 小结
|
||||
|
||||
MapReduce编程相对说来是简单的,但是MapReduce框架要将一个相对简单的程序,在分布式的大规模服务器集群上并行执行起来却并不简单。理解MapReduce作业的启动和运行机制,理解shuffle过程的作用和实现原理,对你理解大数据的核心原理,做到真正意义上把握大数据、用好大数据作用巨大。
|
||||
|
||||
## 思考题
|
||||
|
||||
互联网应用中,用户从手机或者PC上发起一个请求,请问这个请求数据经历了怎样的旅程?完成了哪些计算处理后响应给用户?
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
@@ -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进程汇报。
|
||||
|
||||
应用程序管理器负责应用程序的提交、监控应用程序运行状态等。应用程序启动后需要在集群中运行一个ApplicationMaster,ApplicationMaster也需要运行在容器里面。每个应用程序启动后都会先启动自己的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 MVC,Tomcat的代码里不可能有任何一行关于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层是否按照框架的一般架构方法,遵循依赖倒转原则?
|
||||
|
||||
欢迎你写下自己的思考或疑问,与我和其他同学一起讨论。
|
||||
|
||||
|
||||
@@ -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,多个DataNode;MapReduce 1,一个JobTracker,多个TaskTracker;Yarn,一个ResourceManager,多个NodeManager。
|
||||
|
||||
事实上,很多大数据产品都是这样的架构方案:Storm,一个Nimbus,多个Supervisor;Spark,一个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="">
|
||||
Reference in New Issue
Block a user