兄弟,既然点进来了,说明你准备啃Hadoop这块硬骨头。这个系列就是干这个的,把Hadoop从里到外掰碎了讲明白。今天这篇是“002篇-简介”,是整个系列的第一篇正式内容,主要解决三个问题:Hadoop到底是什么、它解决了什么、你该怎么理解它的核心设计。我尽量用大白话加实际场景来讲,别怕听不懂,也别觉得啰嗦,基础打不牢,后面搭建集群、调优、看源码全都会卡壳。
这篇内容适合刚转大数据方向的开发、准备大数据面试的求职者,以及想系统了解Hadoop生态但被网上零散资料劝退的朋友。我把这几年用Hadoop踩过的坑和总结的经验也一起融进来讲,希望能让你少走点弯路。
1. 先把Hadoop到底是什么说清楚
1.1 一个仓库加一条流水线
很多人一上来就背概念:“Hadoop是一个开源的分布式存储和计算框架”,背完就忘。我用个生活化的例子帮你建立画面感。
假设你开了一家大型电商仓库,每天产生的货物(数据)多到一个小房间放不下。单个房间就是一台服务器,它的硬盘容量有限,CPU和内存也有限。Hadoop做的事很简单:租下整栋楼,把货物分门别类地塞进各个房间,然后安排工人按订单在整栋楼里协同干活。
对应到技术上:HDFS(分布式文件系统)负责把数据切块存到多台服务器的硬盘上,MapReduce和YARN负责调度计算任务,让多台机器一起处理数据。所以我说“Hadoop = 一个分布式存储系统 + 一个分布式计算框架”,这个理解比背官方定义管用得多。
你可能会问,为什么一定要“分布式”?因为单机存不下、算不动。一个TB的数据,单块硬盘可以勉强放下,但处理它的时候,单颗CPU跑上几天几夜也不一定能出结果。分布式核心就是“人多力量大”,把一个大问题拆成很多小问题,让一堆机器同时开工。
Hadoop的设计哲学有一条非常关键:移动计算比移动数据更划算。数据量大了之后,把几百TB数据从存储节点搬到计算节点,网络传输成本高到无法接受。所以Hadoop反过来,把计算程序发送到数据所在的节点上去执行,这就是所谓的“数据本地性”。
1.2 为什么当年非要有Hadoop
回过头看Hadoop的历史,能帮你理解它设计上的很多取舍。2003年到2004年,Google发表了三大论文:GFS(Google文件系统)、MapReduce(分布式计算模型)、BigTable(分布式存储系统)。这几篇论文解决了一个当时很棘手的问题:互联网搜索产生的海量网页数据,单机存储和计算已经完全撑不住了。
Hadoop就是根据这几篇论文的开源实现。Doug Cutting在开发中继Nutch搜索引擎项目时,发现处理上亿网页的规模,传统方案根本跑不动,于是照着GFS和MapReduce的论文实现了对应的开源版本。2006年,这个项目正式从Nutch中独立出来,成为Apache Hadoop。
为什么不用传统数据库?因为关系型数据库在海量数据面前有两个硬伤:一是单表数据量过千万、上亿之后,查询性能急剧下降,即使做了分库分表,运维复杂度也高得吓人;二是传统数据库的扩展方式是纵向扩展,也就是买更强的服务器,但最强服务器也有上限,而且贵得离谱。Hadoop走的是横向扩展,堆普通x86服务器就行,成本低很多,扩容也简单,加几台机器就够了。
Hadoop还有一点在当时非常难得:开源免费。商业大数据方案动辄几百万授权费,而Hadoop可以跑在任何一台普通服务器上。这也是它能在短短几年内迅速占领互联网公司数据平台的根本原因。
1.3 三驾马车:HDFS、MapReduce、YARN
Hadoop生态现在非常庞大,但核心底座始终是三个组件,我称之为“三驾马车”。
HDFS管存储,全称是Hadoop Distributed File System。负责把大文件切成数据块(默认128MB),分散存储在多台机器的硬盘上,同时维护这些块的副本,保证某台机器挂了,数据还在。举个例子,你有一个1GB的日志文件,HDFS会把它切成大约8个128MB的块,每个块默认存3份,分布在不同节点上。
MapReduce管计算,是一种编程模型。它把计算分成两个阶段:Map阶段负责“分而治之”,把数据拆分处理;Reduce阶段负责“合而为一”,把Map输出的中间结果汇总。经典的例子就是单词计数:统计一部小说中每个单词出现的次数,Map阶段并行统计各个章节,Reduce阶段把所有章节的结果合并成最终结果。
YARN管资源调度,全称是Yet Another Resource Negotiator。它负责把集群中每台机器的CPU、内存统一管理起来,谁有计算任务,就给它分配一部分资源。没有YARN之前,MapReduce既负责计算又负责资源管理,导致其他计算框架很难复用Hadoop集群。YARN把资源调度这一层剥离开,后来Spark、Flink这些计算框架就能直接跑在YARN上,共享同一套计算资源。
这三者的关系,你可以这样理解:HDFS是仓库,MapReduce和Spark这些计算框架是流水线工人,YARN是调度中心,负责安排工人去哪条线、什么时候开工。
2. 核心组件拆开揉碎,别光记名词
2.1 HDFS内部是怎么工作的
HDFS采用主从架构。主节点叫NameNode,从节点叫DataNode。NameNode管元数据,也就是“文件和块的对应关系、每个块在哪台机器上”这类信息,但不存真实数据。DataNode才是真正存放数据块的。
客户端要读一个文件时,先问NameNode:这个文件有哪些块、都在哪几台DataNode上?拿到地址列表后,客户端直接去对应的DataNode读数据。注意,数据在读写过程中不经过NameNode,NameNode只负责索引,这种设计避免了主节点成为数据瓶颈。
写入流程有趣一些。客户端把128MB的数据块写好之后,需要向NameNode汇报,NameNode会在元数据里登记。为了保证数据不丢,每个块默认有3个副本,放置策略是:第一个副本放在客户端所在的节点(如果客户端不在集群内,则随机选一个),第二个副本放在与第一个副本不同机架的某个节点,第三个副本放在与第二个副本同机架但不同节点的位置上。这样设计的好处是:如果整个机架断电,至少还留有分布在另一个机架上的副本;如果某个节点损坏,同机架内还有一份可以快速恢复。
很多新手不理解为什么数据块大小是128MB,不是1MB也不是1GB。这里有个权衡:HDFS在读取一个块时,磁盘寻址时间大约在10毫秒左右,磁盘顺序传输速率大约在100MB/s。如果想让寻址时间控制在传输时间的1%左右,那么块大小应该在100MB量级。如果块设置得太小,比如1MB,那么读写大量小块的寻址开销会占据很大比例,效率很低;如果块设置得太大,比如1GB,MapReduce计算时很难并行处理单个块,因为一个块只会被一个Map任务处理。128MB是一个经过实践检验的平衡值。
HDFS还有一个我必须要提的头疼问题:小文件问题。如果集群里存了几百万个几KB的小文件,每个文件都要在NameNode内存里占用一条元数据记录,NameNode的内存会很快被撑爆。所以生产环境里,小文件一定要合并成大文件再入HDFS,这是所有Hadoop工程师都知道的铁律。
2.2 MapReduce的“慢”是有原因的
MapReduce的计算过程,有点像流水线加工。
假设我们要统计一年内每个用户的购买次数。数据在HDFS上分布在上千个块中。Map阶段,每个块会被分给一个Map任务,Map任务逐行读取数据,解析出用户ID,输出一条“用户ID -> 1”的中间记录。这些中间记录会先写入本地磁盘,不是内存,因为数据量太大,内存放不下。
接下来是Shuffle,也就是把Map输出的中间记录按照用户ID进行分组,相同用户ID的记录发送到同一个Reduce节点。这个过程是MapReduce最耗时也最复杂的阶段:Map端会做一次本地排序,然后分区,Reduce端要从不同的Map节点拉取属于自己分区的数据,再合并、排序。数据在网络中传输,加上磁盘读写,速度自然快不起来。
Reduce阶段,每个Reduce任务拿到一个用户ID对应的所有“1”之后,直接累加,得到总次数,最后把结果写入HDFS。
整个过程中,数据经历了“读HDFS -> 写本地磁盘 -> 网络传输 -> 写本地磁盘 -> 写HDFS”的多次落盘。在传统MR的实现里,每个步骤之间都可能产生序列化和反序列化开销,这使得MapReduce的延迟很高,通常以分钟甚至小时计。所以MapReduce适合跑离线批处理,不适合做实时计算。
我见过不少刚入行的朋友吐槽MapReduce又慢又笨重,但它的价值在于:模型足够简单,稳定性和容错性极强,任何一台机器挂了,任务会被重新调度到其他节点继续执行,在大规模集群上是经过时间验证的可靠选择。后来Spark的一大优势就是尽量把中间结果放在内存中,减少磁盘IO,速度比MapReduce快很多,但这是建立在YARN的资源管理之上的,计算框架可以替换,底座依然是HDFS。
2.3 为什么中间非得插一个YARN
Hadoop早期版本只有两个组件:HDFS和MapReduce。1.x的时候,MapReduce承担了两份工作:一是执行计算任务,二是管理集群资源。这在当时没太大问题,但后来社区发现,很多其他计算框架也需要使用同一份数据,比如图计算、机器学习,如果每个框架都要自己管理资源,集群就会乱成一锅粥。
所以YARN在Hadoop 2.0被独立出来,它的核心是两层调度:全局有一个ResourceManager(资源管理器),每个节点上有一个NodeManager(节点管理器)。ResourceManager负责接收客户端的作业请求,分配资源,NodeManager负责管理单个节点的容器。容器就是内存和CPU的分配单位,一个作业可以在一个节点上申请多个容器。
作业提交后,YARN会先启动一个ApplicationMaster,这个家伙是作业的“项目经理”,它负责向ResourceManager申请资源,和各个NodeManager协商启动容器,并监控任务的执行进度。同一个集群可以同时跑多个不同的计算任务,互不干扰,资源还能动态调整。
打个比方,YARN就像写字楼的物业,不同的租户(计算框架)都在同一栋楼里办公,物业统一负责水电空调分配。没有物业之前,每个公司都得自己扯一根电线,一层楼可能被几个公司同时拉扯,乱到崩溃。
3. 搞明白了Hadoop,再聊那些绕不开的场景和面试题
3.1 哪些场景适合Hadoop,哪些不适合硬上
Hadoop不是万能药,我就见过有人非要用Hive跑一条只查几百条记录的小查询,结果启动任务就要几十秒,查出来还没Excel快。选型之前,先搞清楚边界。
Hadoop适合的场景有这几类:海量离线批处理、历史数据分析、数据仓库建设、大规模日志处理。比如电商平台每天产生的几十亿条行为日志,入仓后用Hive做ETL清洗,按天产出统计报表,这种模式Hadoop非常拿手。再比如推荐系统的用户行为特征计算,从海量历史数据中提取用户偏好,数据量大但处理周期长,Hadoop也完全合适。
Hadoop不适合的场景也讲清楚。第一,实时计算别用Hadoop,毫秒级延迟和它无缘,应该用Flink或Spark Streaming。第二,OLTP类型的业务查询不能用Hadoop,它不支持事务、行级更新,应该用MySQL、PostgreSQL这类数据库。第三,数据量很小的时候别用Hadoop,一台机器能搞定的事,非要搭集群,运维成本、开发成本全部翻倍,纯属自找麻烦。
3.2 大数据面试高频题,这一篇先串讲
在做面试辅导的时候,我发现Hadoop的面试题其实高度集中,核心知识点就那么几个,换着花样考。提前掌握了,面试基本不会被问倒。
面试题一:NameNode宕机怎么办?
这个问题的得分点在于:NameNode单点故障是HDFS的经典问题。在没有启用高可用(HA)的情况下,NameNode挂了,整个HDFS的读写服务就中断了。虽然有SecondaryNameNode,但它不是热备,它只定期合并NameNode的日志,无法接管服务。生产环境必须配置HA,也就是跑两个NameNode,用ZooKeeper做分布式协调,监控主NameNode的状态。一旦主的挂了,备用的NameNode自动切换,接管服务,整个集群感知不到明显中断。
这里可以顺带引出Hadoop和ZooKeeper的关系:Hadoop的HA依赖ZooKeeper做故障自动切换,HBase的HMaster选举也依赖ZooKeeper,所以在企业中搭建大数据平台,ZooKeeper几乎是必装的组件。
面试题二:HDFS副本数为什么默认是3?
存储副本的本质是为了容错。副本数为1,任何一台机器坏了数据就永久丢失;副本数为2,理论上有一定容错能力,但如果坏两台中有一台是同一份数据的副本,数据照样丢。副本数为4或5,容错性更强,但存储成本直接翻倍。3份是经过实践检验的平衡点——存储成本增加200%,换来的是比较稳妥的容错能力,加上上面提到的机架感知策略,即使整个机架宕机,数据依然安全。
面试题三:MapReduce的Shuffle过程说一下?
这个能考察求职者有没有真正研究过MR。要讲清楚四个阶段:Map端输出先写入环形缓冲区,默认大小100MB,写入超过阈值后溢写到本地磁盘并做分区和排序;Reduce端启动时,从各个Map节点拉取属于自己的分区数据;拉取的数据在Reduce端做合并和排序;最后才进入Reduce函数处理。如果能再补一句“Shuffle是MR性能瓶颈的核心”,面试官会认为你真的理解MR。
面试题四:为什么HDFS块大小不能太小?
这就回到我上面讲的原理。块太小,寻址开销占比高,NameNode元数据量大;块太大,单个Map任务处理时间长,并行度低,且任务失败重算的代价略高。所以128MB是一个经过实践平衡的参数。
3.3 别焦虑Hadoop过时的问题
我第一次接触Hadoop是2016年,那时候Spark已经火了。后来Flink又火起来了,越来越多新人问我:Hadoop是不是要被淘汰了?我的回答一直是:你看到的那些大数据技术栈,几乎全都跑在Hadoop生态之上。
Hive跑在有HDFS和YARN的集群上,Spark也是,Flink也可以。数据永远放在HDFS里,资源永远由YARN统一调度。Hadoop的核心价值在于提供了一个稳定的大数据底座,而Spark和Flink是跑在底座上的高性能引擎。你可以把Hadoop理解为操作系统,Spark和Flink是应用程序,操作系统会被很快抛弃吗?不会。
所以新手的学习路线我建议这样走:先死磕HDFS和MapReduce,理解分布式存储和分布式计算的本质;然后学Hive,用SQL的方式操作HDFS数据;下一步学Spark,理解它和MapReduce在计算模型上的差异;如果处理实时需求,学Flink。整个过程最好配合实践,只看书不敲命令是学不会的,睡觉都能梦见NameNode。
4. 动手之前,先看懂部署方式和一些必踩的坑
4.1 三种部署模式,怎么选
Hadoop有三种部署模式,网上教程很多,但很多人搞不清区别,导致照着教程搭完之后还是一头雾水。
本地模式。所有组件跑在单个Java进程中,不用HDFS,直接访问本地文件系统。一般用于开发调试和跑MapReduce测试。新手学MapReduce时,本地模式单测是最快的上手方式,比如在IDE里直接跑一个WordCount,几秒钟就能看到输出。
伪分布式模式。一台机器上模拟完整的Hadoop运行环境,多个进程分别扮演不同角色。关键配置是HDFS的复制因子设为1,YARN也在这台机器上启动ResourceManager和NodeManager。伪分布式适合学习和开发验证,能让你在一台笔记本上体验完整的“提交作业、调度、执行”流程,但完全没有高可用和性能可言。
完全分布式模式。生产环境的标准,至少三台机器起步,NameNode与DataNode分机部署,也可以配置HA提高可靠性。实际生产集群少则几十台,多则上千台。
如果你只是学习,先搭伪分布式就够了,不要直接上三台服务器,操心网卡、磁盘、内核参数,反而会分散学习精力。等伪分布式玩熟了,再考虑用多台虚拟机搭一个三节点完全分布式集群。
4.2 用Docker快速体验,是我推荐的一条捷径
我得先感谢Docker,它把Hadoop的学习门槛拉低了一大截。以前我学习时,配环境要折腾一天,现在一条命令就能启动一个单节点Hadoop。
常见做法是找一个现成的Hadoop单机镜像,比如sequenceiq/hadoop-docker这类社区镜像,启动容器后进入里面,直接使用HDFS命令和MapReduce命令。端口方面,NameNode的Web UI默认在50070端口(新版在9870),ResourceManager在8088端口,需要映射到宿主机。数据目录建议用docker -v挂载一个宿主机目录,否则容器一删数据全没了。
用Docker体验Hadoop时有个心理铺垫要做好:Docker里跑的是单节点伪分布式,NameNode和DataNode在同一台机器上,它只用来练习命令和熟悉原理,和生产集群差得很远,但作为入门体验已经足够。如果你想练习多节点集群,可以用Docker Compose定义多个容器,模拟一台NameNode加两台DataNode,不过这就是后话了。
4.3 我当年踩过的坑,提前帮你们排一排
第一个坑是JVM内存不足。伪分布式下,如果机器只有2G内存,默认参数可能撑不住三个角色同时运行,启动时直接报Java heap space。解决办法很简单,在hadoop-env.sh里设置HADOOP_HEAPSIZE,比如256MB,别贪大。
第二个坑是SSH免密没配好。完全分布式集群中,NameNode需要通过SSH免密登录到DataNode来启动和停止进程。新手第一次配集群时经常在这里卡住,启动DataNode时报错Permission denied。建议在搭建集群之前,先把所有机器之间的SSH免密配好并测试通过,不要配完了再排查。
第三个坑,也是出现频率最高的:第二次格式化NameNode。很多人在启动失败后,直接把dfs/name目录删了重新格式化。这是大忌,因为格式化NameNode会生成一个新的clusterID,而DataNode已经用旧的clusterID启动过了,两边不一致,DataNode会拒绝服务。正确的做法是:只有第一次初始化时格式化,之后如果要重置,需要把NameNode和所有DataNode的数据目录全部清掉后重新格式化,或者直接清空数据目录而不要动NameNode,再做一次更新的格式化。拿不准的时候,先想想两份元数据的clusterID,这个思路能救很多次命。
第四个坑是端口冲突或没开防火墙端口。NameNode RPC端口9000(新版本是8020)、NameNode Web UI端口9870、DataNode端口9864、ResourceManager Web UI端口8088,这些端口容易和集群里其他应用冲突。在云服务器上跑集群的话,安全组也要把这些端口放行,不然从本机网页上访问不到管理界面,会误以为服务没起来。
第五个坑是小文件堆积。我见过有人把清洗后的明细数据不做合并直接丢进HDFS,结果NameNode Web UI上显示文件数量几十万,单个文件都不到1KB,NameNode内存压力巨大。后来我养成了习惯:凡是清洗结果,能合并就合并输出,控制HDFS里的小文件数量,这个习惯救了我很多次。
5. 关于这个系列,我再说几句掏心窝的话
写这一篇简介,其实比我预想的花了更多心思。因为“简介”听起来简单,但真正要把Hadoop的来龙去脉讲清楚、讲透,又不变成百科搬运,很难。我尽量把技术原理用生活化的比喻和真实场景串起来,你如果读到这里,说明已经对Hadoop有了一个整体的框架感。
✅ 在后续的系列文章中,我会逐步带你走一遍完整的实操流程。从HDFS命令行操作开始,到上传文件、查看块分布,到编写一个MapReduce程序并用三种模式跑通,再到配置伪分布式、搭一个三节点的完全分布式集群,然后深入Hive数据仓库、Hadoop与ZooKeeper的HA整合、Hadoop常用调优参数、面试高频题集,Step by Step,不是干讲概念,而是边做边学,遇到坑就记录下来,给出排查思路。
我个人在实际操作中的体会是:Hadoop最难的地方不在技术本身,而在抽象能力的建立。当你第一次在几台机器上成功跑通一个分布式单词计数,看到一堆日志在屏幕上滚动,作业进度从map 0%走到reduce 100%的时候,那种“原来分布式是这个意思”的顿悟感,是任何文档都给不了的。希望这个系列能成为你大数据路上的第一块垫脚石。