简单理解 Hadoop 架构原理
一、前奏
Hadoop是目前大数据领域最主流的一套技术体系,包含了多种技术。
包括HDFS(分布式文件系统),YARN(分布式资源调度系统),MapReduce(分布式计算系统),等等。
有些朋友可能听说过 Hadoop,但是却不太清楚他到底是个什么东西,这篇文章就用大白话给各位阐述一下。
假如你现在公司里的数据都是放在MySQL里的,那么就全部放在一台数据库服务器上,我们就假设这台服务器的磁盘空间有 2T 吧,大家先看下面这张图。
现在问题来了,你不停的往这台服务器的 MySQL 里放数据,结果数据量越来越大了,超过了 2T 的大小了,现在咋办?
你说,我可以搞多台 MySQL 数据库服务器,分库分表啊! 每台服务器放一部分数据不就得了。如上图所示!
好,没问题,那咱们搞 3 台数据库服务器,3 个 MySQL 实例,然后每台服务器都可以 2T 的数据。
现在我问你一个问题,所谓的大数据是在干什么?
我们来说一下大数据最初级的一个使用场景。假设你有一个电商网站,现在要把这个电商网站里所有的用户在页面和APP上的点击、购买、浏览的行为日志都存放起来分析。
你现在把这些数据全都放在了 3 台 MySQL 服务器,数据量很大,但还是勉强可以放的下。
某天早上,你的 boss 来了。要看一张报表,比如要看每天网站的 X 指标、Y 指标、Z 指标,等等,二三十个数据指标。
好了,兄弟,现在你尝试去从那些点击、购买、浏览的日志里,通过写一个SQL来分析出那二三十个指标试试看?
我跟你打赌,你绝对会写出来一个几百行起步,甚至上千行的超级复杂大 SQL。这个 SQL,你觉得他能运行在分库分表后的 3 台 MySQL 服务器上么?
如果你觉得可以的话,那你一定是不太了解 MySQL 分库分表后有多坑,几百行的大 SQL 跨库 join,各种复杂的计算,根本不现实。
所以说,大数据的存储和计算压根儿不是靠 MySQL 来搞的,因此,Hadoop、Spark 等大数据技术体系才应运而生。
本质上,Hadoop、Spark 等大数据技术,其实就是一系列的分布式系统。
比如 hadoop 中的 HDFS,就是大数据技术体系中的核心基石,负责分布式存储数据,这是啥意思? 别急,继续往下看。
HDFS 全称是 Hadoop Distributed File System,是 Hadoop 的分布式文件系统。
它由很多机器组成,每台机器上运行一个 DataNode 进程,负责管理一部分数据。
然后有一台机器上运行了 NameNode 进程,NameNode 大致可以认为是负责管理整个 HDFS 集群的这么一个进程,他里面存储了 HDFS 集群的所有元数据。
然后有很多台机器,每台机器存储一部分数据! 好,HDFS 现在可以很好的存储和管理大量的数据了。
这时候你肯定会有疑问:MySQL 服务器也不是这样的吗? 你要是这样想,那就大错特错了。
这个事情不是你想的那么简单的,HDFS 天然就是分布式的技术,所以你上传大量数据,存储数据,管理数据,天然就可以用 HDFS 来做。
如果你硬要基于 MySQL 分库分表这个事儿,会痛苦很多倍,因为 MySQL 并不是设计为分布式系统架构的,他在分布式数据存储这块缺乏很多数据保障的机制。
好,你现在用 HDFS 分布式存储了数据,接着不就是要分布式来计算这些数据了吗?
对于分布式计算:
很多公司用 Hive 写几百行的大 SQL( 底层基于MapReduce)
也有很多公司开始慢慢的用 Spark 写几百行的大 SQL(底层是 Spark Core 引擎)。
总之就是写一个大 SQL,人家会拆分为很多的计算任务,放到各个机器上去,每个计算任务就负责计算一小部分数据,这就是所谓的分布式计算。
这个,绝对比你针对分库分表的MySQL来跑几百行大SQL要靠谱的多。
对于上述所说的分布式存储与分布式计算,老规矩,同样给大家来一张图,大伙儿跟着图来仔细捋一下整个过程。
二、HDFS 的 NameNode 架构原理
好了,前奏铺垫完之后,进入正题。本文其实主要就是讨论一下 HDFS 集群中的 NameNode 的核心架构原理。
NameNode 有一个很核心的功能:管理整个 HDFS 集群的元数据,比如说文件目录树、权限的设置、副本数的设置,等等。
下面就用最典型的文件目录树的维护,来给大家举例说明,我们看看下面的图。现在有一个客户端系统要上传一个 1TB 的大文件到 HDFS 集群里。
此时他会先跟 NameNode 通信,说:大哥,我想创建一个新的文件,他的名字叫“/usr/hive/warehouse/access_20180101.log”,大小是 1TB,你看行不?
然后 NameNode 就会在自己内存的文件目录树里,在指定的目录下搞一个新的文件对象,名字就是“access_20180101.log”。
这个文件目录树不就是 HDFS 非常核心的一块元数据,维护了 HDFS 这个分布式文件系统中,有哪些目录,有哪些文件,对不对?
但是有个问题,这个文件目录树是在 NameNode 的内存里的啊!
这可坑爹了,你把重要的元数据都放在内存里,万一 NameNode 不小心宕机了可咋整? 元数据不就全部丢失了?
可你要是每次都频繁的修改磁盘文件里的元数据,性能肯定是极低的啊! 毕竟这是大量的磁盘随机读写!
没关系,我们来看看 HDFS 优雅的解决方案。
每次内存里改完了,写一条 edits log,元数据修改的操作日志到磁盘文件里,不修改磁盘文件内容,就是顺序追加,这个性能就高多了。
每次 NameNode 重启的时候,把 edits log 里的操作日志读到内存里回放一下,不就可以恢复元数据了?
大家顺着上面的文字,把整个过程,用下面这张图跟着走一遍。
但是问题又来了,那 edits log 如果越来越大的话,岂不是每次重启都会很慢? 因为要读取大量的 edits log 回放恢复元数据!
所以 HDFS 说,我可以这样子啊,我引入一个新的磁盘文件叫做 fsimage,然后呢,再引入一个JournalNodes 集群,以及一个StandbyNameNode(备节点)。
每次ActiveNameNode(主节点) 修改一次元数据都会生成一条 edits log,除了写入本地磁盘文件,还会写入 JournalNodes 集群。
然后 Standby NameNode 就可以从JournalNodes 集群拉取 edits log,应用到自己内存的文件目录树里,跟 Active NameNode 保持一致。
然后每隔一段时间,Standby NameNode 都把自己内存里的文件目录树写一份到磁盘上的 fsimage,这可不是日志,这是完整的一份元数据。这个操作就是所谓的 checkpoint 检查点操作。
然后把这个 fsimage 上传到到 Active NameNode,接着清空掉 Active NameNode 的旧的 edits log 文件,这里可能都有 100 万行修改日志了!
然后 Active NameNode 继续接收修改元数据的请求,再写入 edits log,写了一小会儿,这里可能就几十行修改日志而已!
如果说此时,Active NameNode 重启了,bingo! 没关系,只要把 Standby NameNode 传过来的 fsimage 直接读到内存里,这个 fsimage 直接就是元数据,不需要做任何额外操作,纯读取,效率很高!
然后把新的 edits log 里少量的几十行的修改日志回放到内存里就 ok 了!
这个过程的启动速度就快的多了! 因为不需要回放大量上百万行的 edits log 来恢复元数据了! 如下图所示。
此外,大家看看上面这张图,现在咱们有俩 NameNode。
一个是主节点对外提供服务接收请求
另外一个纯就是接收和同步主节点的 edits log 以及执行定期 checkpoint 的备节点。
大家有没有发现! 他们俩内存里的元数据几乎是一模一样的啊!
所以呢,如果ActiveNameNode 挂了,是不是可以立马切换成StandbyNameNode 对外提供服务?
这不就是所谓的 NameNode 主备高可用故障转移机制么!
接下来大家再想想,HDFS 客户端在 NameNode 内存里的文件目录树,新加了一个文件。
但是这个时候,人家要把数据上传到多台 DataNode 机器上去啊,这可是一个 1TB 的大文件! 咋传呢?
很简单,把 1TB 的大文件拆成 N 个 block,每个 block 是 128MB。1TB = 1024GB = 1048576MB,一个 block 是 128MB,那么就是对应着 8192 个 block。
这些 block 会分布在不同的机器上管理着,比如说一共有 100 台机器组成的集群,那么每台机器上放 80 个左右的 block 就 ok 了。
但是问题又来了,那如果这个时候 1 台机器宕机了,不就导致 80 个 block 丢失了?
也就是说上传上去的 1TB 的大文件,会丢失一小部分数据啊。没关系!HDFS 都考虑好了!
它会默认给每个 block 搞 3 个副本,一模一样的副本,分放在不同的机器上,如果一台机器宕机了,同一个 block 还有另外两个副本在其他机器上呢!
大伙儿看看下面这张图。每个 block 都在不同的机器上有 3 个副本,任何一台机器宕机都没事! 还可以从其他的机器上拿到那个 block。
这下子,你往HDFS上传一个 1TB 的大文件,可以高枕无忧了吧!
OK,上面就是大白话加上一系列手绘图,给大家先聊聊小白都能听懂的Hadoop的基本架构原理