hadoop基础知识点

一、hadoop核心组件

hadoop由HDFS(分布式文件系统)、YARN(资源管理系统)和MapReduce(计算引擎)等核心组件组成


1.HDFS(分布式文件系统)

HDFS是Hadoop生态系统的核心组件之一,负责大规模数据存储设计,具有高容错性、高吞吐量和可扩展性。它的架构采用主从(Master-Slave)模式,主要包含以下核心组件,各组件分工明确,共同保障分布式文件系统的稳定运行:


1). NameNode(主节点)

  • 核心作用:
    • 存储数据的元数据信息(MetaData)
    • 管理HDFS命名空间(文件名称、路径、大小、权限、与块的映射关系)
    • 管理数据块的映射信息(块的数量、每个块的存储位置、块的副本数等)
    • 配置副本策略(加载配置文件hdfs-site.xml,解析记录监控持久化副本,根据机架感知选择Dataode)
    • 处理与客户端读写请求(检查客户端权限,提供元数据信息以及对坏的Dataode进行处理)
  • 特点:
    • 通常只有1个活跃的Namenode(避免分布式一致性问题),存在单点故障风险(可通过HA高可用机制解决)
    • 元数据会定期持久化到磁盘的fsimage(文件系统镜像)和edits log(操作日志)文件中,防止数据丢失

Namenode启动时的操作:
    首次启动:
        1.格式化系统文件:为了生成fsimage镜像文件
        2.启动Namenode:读取fsimage文件,将文件内容加载进内存,等待Datanode注册与发送block report(当前存储的所有数据块信息)
        3.启动Datanode:发送block report,检查fsimage记录的块数量和block report中的块总数是否相同
        4.在文件操作后,将内存中的改变操作信息写入edits文件
    再次启动后:
        1.从磁盘中加载最新的fsimage和未合并的增量edits文件 
        2.在内存中应用edits的所有操作,获得最新元数据,已恢复上一次关闭时的元数据状态,创建新的空edits文件,在经过操作后实时将增量edits写回磁盘
        3.由 Secondary NameNode 从磁盘拉取异步完成合并且回传fsimage文件到磁盘上,Namenode接收并替换旧文件
        4.启动Datanode

这里的磁盘是Namenode所在的本地磁盘而不是hdfs


  • 单点故障:Namenode损坏,导致整个系统崩坏

  • 脑裂:HA中的两个Namenode之间网络中断,都认为自己是活跃主节点,两者独立修改元数据(如各自记录不同的 EditLog),最终导致元数据混乱,HDFS 无法正常工作。

  • HA高可用机制:是hadoop2.x引入的双Namenode功能,一个active,一个standby,之间通过Journalnode进行元数据同步

    HA 的核心组件与角色
    1.两个 NameNode(Active + Standby)
    - Active NameNode:对外提供服务的主节点,负责处理客户端的读写请求、管理元数据(如创建文件、删除目录等),是集群的 "活跃" 节点
    - Standby NameNode:备用节点,实时同步 Active NameNode 的元数据,处于 "待命" 状态。当 Active 节点故障时,Standby 节点能快速切换为 Active 状态,接管服务
    两个 NameNode 的硬件配置需完全一致(如内存、CPU),确保 Standby 能无缝接管工作
    2.JournalNode 集群(JN 集群)
    一组独立的进程(通常 3 个或更多节点,奇数个以避免脑裂),负责存储 NameNode 的元数据编辑日志(EditLog),是 Active 与 Standby 之间元数据同步的核心组件
    作用:替代 Hadoop 1.x 中的 Secondary NameNode,实现 Active 节点的 EditLog 实时同步到 Standby 节点,确保两者元数据一致
    3.ZooKeeper 集群(ZK)
    用于监控 NameNode 的健康状态,并协调 Active/Standby 的切换(通过 ZKFC 组件实现)
    存储集群的状态信息(如哪个 NameNode 是 Active),确保切换过程的一致性
    4.ZKFC(ZooKeeper Failover Controller)
    每个 NameNode 节点上部署的守护进程,负责监控本地 NameNode 的健康状态,并与 ZooKeeper 通信:
    向 ZK 注册 NameNode 的状态(如 "健康" 或 "故障")
    当 Active 节点故障时,通过 ZK 竞争 "锁",触发 Standby 节点切换为 Active
    

HA 机制的工作原理

  • 元数据同步过程(Active → Standby)

    • 元数据组成:NameNode 的元数据包括两部分 —— 内存中的元数据(实时状态)和磁盘上的元数据(fsimage快照 + editlog编辑日志)
    • fsimage:元数据的完整快照(定期生成)
    • editlog:记录 NameNode 接收的所有元数据修改操作(如创建文件、删除目录等),是元数据增量更新的关键
  • 元数据同步机制(基于共享存储的 JournalNode 集群)

    1. Active NameNode 处理客户端请求并写入共享存储
    • 当 Active NN 接收到元数据修改请求(如创建文件)时,先将操作记录写入本地 editlog(确保本地持久化)
    • 同时,强制将该操作同步到 JournalNode 集群(共享存储):通过多数派写入机制(如 3 个 JN 节点需至少 2 个成功写入),确保 editlog 在共享存储中不丢失,这个步骤成功才认定文件写入成功
    1. Standby NameNode 从共享存储读取并应用日志
    • Standby NN 定期从 JournalNode 集群(共享存储)读取最新的 editlog。
    • 将读取到的 editlog 操作应用到自己的内存元数据中,确保与 Active NN 的内存状态一致
    • 定期合并 fsimage(如每小时或 editlog 达到阈值):将内存中的最新元数据状态保存为新的 fsimage 文件,写入本地磁盘(此时 Standby 的磁盘元数据与 Active 保持同步)
  • 共享存储确保一致性与高可用
    JournalNode 集群作为共享存储,是Active与Standby通信的唯一通道,确保两者获取的 editlog 完全一致
    若 Active 故障时ZKFC会向ZK申请释放锁,Standby通过创建一个临时锁节点来切换为 Active后,可直接从共享存储继续读取未处理的editlog,无缝接管服务

  • 这种同步方式确保:当 Active 故障时,Standby 已拥有最新的元数据,切换后无需依赖 Secondary NameNode 的快照恢复,极大缩短恢复时间。


2). DataNode(从节点)

  • 核心作用:
    • 存储实际的数据块
    • 直接处理客户端的数据读写请求(在获取NameNode的元数据后)
  • 特点:
    • 数据以块(默认128MB)为单位存储,每个块会根据配置保存多个副本(默认3个),分布在不同的DataNode上,提高容错性和读写效率
    • 定期向NameNode发送心跳信息,汇报自身状态(如是否存活、存储的块信息等)。若NameNode长时间未收到某个DataNode的心跳,会将其标记为死亡,并重新复制该节点上的块到其他存活节点

3). Secondary NameNode(辅助主节点)

  • 核心作用:
    • 辅助NameNode管理元数据,不是NameNode的备份
    • 负责定期合并fsimage和edits文件,以减轻 NameNode 的负担并优化元数据管理,合并过程不影响NameNode的正常工作
  • 局限性:
    • 是hadoop1.x的组件,无法解决NameNode的单点故障问题,2.x被Journalnode取代

合并细节:
1.Secondary NameNode按配置周期或edits大小达到阈值时,拉取fsimage和edits合并,并回传NameNode
2.通过定期合并,edits被截断,Namenode下次启动时只需加载较小的fsimage和较短的edits,减少启动时间
合并条件
1.时间触发:根据配置的间隔时间(默认 1 小时,由 dfs.namenode.checkpoint.period 控制)
2.日志大小触发:当edits文件达到一定大小(默认 64MB,由 dfs.namenode.checkpoint.txns 控制)

4). Client(客户端)

  • 核心作用:
    • 提供用户与HDFS交互的接口,负责数据的读写和文件管理
    • 读写文件时,先与NameNode通信获取元数据(如文件的块分布),再直接与对应的DataNode交互进行数据传输
    • 文件写入HDFS的时候,Client将文件切分成一个一个的block,然后进行存储并实现副本管理(确保写入的块有足够副本)
    • Client提供一些命令来管理HDFS,比如启动关闭HDFS、访问HDFS目录及内容等

5). Block(数据块)

  • 核心作用:
    • HDFS的基本存储单位,类似磁盘的“扇区”,但尺寸更大(默认128MB)
    • 大文件会被拆分为多个块,独立存储;小文件不会占用整个块的空间(仅用实际大小)
    • 块的副本机制:每个块的多个副本分布在不同机架的DataNode上(默认3个副本:1个在本地机架,1个在同机架其他节点,1个在异机架节点),既保证容错性,又减少跨机架数据传输的开销

6). FsImage(文件系统镜像)

  • 核心作用:
    • NameNode元数据的持久化快照,存储某一时刻HDFS的完整元数据(如文件目录结构、块信息等)
  • 特点:
    • 仅在NameNode启动时加载到内存,之后的操作不会实时更新fsimage,而是记录到edits日志中

7). Edits Log(操作日志)

  • 核心作用:
    • 记录NameNode启动后所有对HDFS的修改操作(如创建文件、删除文件、修改权限等),是元数据的增量日志
  • 特点:
    • 操作先写入edits,再更新内存中的元数据,确保数据一致性(即使NameNode宕机,重启后可通过Scendary namenode恢复上一次合并时的元数据)

总结:各组件协同流程
1. 客户端上传文件时,先向NameNode请求存储路径,NameNode返回可存储的DataNode列表(基于副本策略)
2. 客户端将文件拆分为块,按顺序写入指定DataNode,每个DataNode会将块复制到其他节点以满足副本数
3. DataNode完成写入后,向NameNode汇报块信息,NameNode更新元数据(记录块与DataNode的映射)
4. 客户端读取文件时,先向NameNode请求文件的块分布,然后并行从多个DataNode读取块并拼接

2.YARN(资源管理系统)

yarn是负责资源管理和作业调度的核心组件,由 ResourceManager、NodeManager 和 ApplicationMaster 构成。
ResourceManager 是 “全局指挥官”,掌控集群总资源,决定资源分配策略。
NodeManager 是 “节点执行者”,管理单个节点的资源和 Container,执行具体任务。
ApplicationMaster 是 “应用协调者”,代表应用程序向 RM 申请资源,向 NM 分配任务,并监控任务执行。
三者通过高效通信(如心跳机制)协同工作,实现 YARN 对集群资源的动态管理和多应用程序的并发调度,确保资源利用率最大化和任务稳定运行。


1).ResourceManager(资源管理器):全局资源的 “总调度”

ResourceManager 是 YARN 集群的核心管理者,运行在单独的节点上(通常是主节点),负责对整个集群的资源(CPU、内存等)进行全局分配和调度,同时协调应用程序与资源的匹配,核心作用:

  • 资源分配与调度
    • 维护集群中所有节点的资源总视图(如总 CPU 核数、总内存容量),并根据应用程序的需求(由 ApplicationMaster 申请),将资源以 “容器(Container)” 为单位分配给应用
    • 通过内置的调度器(如 FIFO 调度器、Capacity 调度器、Fair 调度器)决定资源分配的优先级和策略,确保资源在多应用间公平、高效地共享
  • 接收应用程序提交
    • 接收客户端提交的应用程序(如 MapReduce 作业、Spark 任务等),并为其启动第一个 Container 来运行 ApplicationMaster
    • 负责监控 ApplicationMaster 的生命周期,若其异常退出,可根据配置决定是否重新启动
  • 集群资源监控
    • 与所有 NodeManager 保持通信,实时接收节点的资源使用报告(如剩余 CPU、内存),掌握集群资源的动态变化
    • 当节点故障时,及时标记该节点不可用,并回收其分配的资源,重新分配给其他节点

2). NodeManager(节点管理器):单节点资源的 “执行者”

NodeManager 是 YARN 集群中每个从节点上的代理,负责管理当前节点的资源(CPU、内存、磁盘、网络等),以及执行具体的应用程序任务。其主要作用包括:

  • 节点资源管理
    • 监控当前节点的硬件资源(如总内存、CPU 核数),并根据 ResourceManager 的配置(如每个节点可分配的最大资源),将资源划分为若干 “容器(Container)”
    • 严格限制每个 Container 的资源使用(如防止某个任务占用过多内存导致节点崩溃),确保节点资源的隔离和稳定
  • Container 生命周期管理
    • 接收 ResourceManager 或 ApplicationMaster 的指令,创建、启动、停止节点上的 Container(Container 是运行任务的最小资源单位,包含 CPU、内存等资源)
    • 向 ResourceManager 定期汇报节点的资源使用情况和 Container 的运行状态(如是否正常运行、是否完成)
  • 节点健康监控
    • 检查节点的硬件和软件状态(如磁盘是否满、进程是否正常),若发现节点异常(如磁盘损坏),及时向 ResourceManager 报告,避免新任务被分配到该节点

3). ApplicationMaster(应用程序管理器):单应用的 “协调者”

ApplicationMaster 是每个应用程序(如一个 MapReduce 作业、一个 Spark 应用)的专属管理者,由 ResourceManager 为应用程序启动,运行在某个 NodeManager 的 Container 中。其主要作用是协调应用程序的资源需求和任务执行,具体包括:

  • 资源申请与分配
    • 根据应用程序的任务需求(如 Map 任务、Reduce 任务的数量和资源需求),向 ResourceManager 申请合适的 Container 资源(指定 CPU、内存大小等)。
    • 接收 ResourceManager 分配的 Container 后,与对应的 NodeManager 通信,启动 Container 并运行具体任务(如 Map 任务、Shuffle 任务)。
  • 任务监控与容错
    • 实时监控应用程序中所有任务的运行状态(如是否完成、是否失败),若某个任务失败,可向 ResourceManager 重新申请资源,在其他节点上重启任务。
    • 当自身(ApplicationMaster)故障时,ResourceManager 会检测到并重新启动一个新的 ApplicationMaster,确保应用程序继续运行。
  • 任务结果汇总与汇报
    • 收集所有任务的执行结果,完成应用程序的最终处理(如 MapReduce 的结果合并)。
    • 应用程序完成后,向 ResourceManager 汇报任务完成状态,并释放所有占用的 Container 资源。

3.MapReduce(计算引擎):

Mapreduce是一种分布式计算框架,包含 JobTracker 和 TaskTracker。
JobTracker 负责调度和监控作业;
TaskTracker 负责执行具体的任务。不过在 YARN 出现后,MapReduce 已经迁移到 YARN 上运行。

1).JobTracker

  • 作业调度(Job Scheduling)
    • JobTracker会将用户提交的作业分解成多个map和reduce任务,并为每个任务分配唯一标识符。根据集群资源和任务优先级决定任务队列执行顺序,优先将map任务分配到数据所在Datanode,减少传输开销
  • 资源分配(Resource Allocation)
    • 全局资源感知:跟踪集群中所有 TaskTracker 的可用资源(CPU、内存),维护资源总视图。
    • 任务资源分配:为每个任务分配资源槽(Slot),例如,一个 TaskTracker 可能被配置为同时运行 2 个 Map Slot 和 2 个 Reduce Slot。
    • 资源隔离:通过固定数量的 Slot 限制每个节点的并发任务数,避免资源竞争。
  • 状态监控(Status Monitoring)
    • 心跳机制:定期接收 TaskTracker 的心跳信息(默认 3 秒一次),包含节点健康状态、 已完成 / 运行中的任务进度。
    • 任务失败处理:若 TaskTracker 长时间未发送心跳或任务失败,JobTracker 会重新调度任务到其他节点。
    • 作业生命周期管理:跟踪作业的整体进度(如 Map 完成百分比、Reduce 完成百分比),并向用户提供可视化监控界面。

2).TaskTracker

  • 任务执行(Task Execution)
    • 容器管理:创建和管理任务执行的容器(Container),每个容器对应一个 Map 或 Reduce 任务。
    • 任务启动:从 HDFS 下载任务所需的程序代码(如 JAR 文件)和配置,启动任务进程。
      资源隔离:通过 Linux 进程限制任务的资源使用(如内存上限),但隔离性较弱(无 cgroups 等机制)。
  • 状态汇报(Status Reporting)
    • 定期向 JobTracker 发送心跳,包含:
      节点健康状态(如磁盘使用率、内存使用率)。
      已完成任务的输出信息(如 Map 任务的中间结果位置)。
      正在运行任务的进度(如已处理数据量、百分比)。
      任务完成通知:任务成功或失败时,立即向 JobTracker 汇报结果。
  • 本地资源管理
    • 磁盘空间管理:为任务分配本地磁盘空间,存储中间结果(如 Map 输出),任务完成后清理临时文件。
    • 任务优先级控制:根据 JobTracker 的指示,调整任务执行的优先级(如抢占低优先级任务的资源)。

JobTracker 与 TaskTracker 的协作流程
作业提交:用户向 JobTracker 提交 MapReduce 作业。
任务分配:JobTracker 将作业分解为 Map/Reduce 任务,并根据数据本地化原则,向合适的 TaskTracker 发送任务分配请求。
任务执行:TaskTracker 接收到任务后,创建容器并执行任务,并定期向 JobTracker 汇报进度。
中间结果处理:Map 任务的输出结果存储在本地磁盘,并通知 Reduce 任务所在的 TaskTracker 拉取数据(Shuffle 阶段)。
作业完成:所有任务完成后,JobTracker 更新作业状态为 “成功”,并释放资源

各组件的部署文件目录:cd software/hadoop-3.2.1/etc/hadoop
core - site.xml:用于指定 NameNode 节点的位置等核心信息
hdfs - site.xml:该文件主要用于配置 HDFS 相关的参数,会指定 HDFS 的副本数、SecondaryNameNode 的位置等信息。
yarn - site.xml:用于配置 YARN 相关的内容,主要指定 ResourceManager 的位置等
mapred - site.xml:如果使用 MapReduce 框架,该文件可以用来配置 MapReduce 任务运行的相关参数

二、hdfs操作相关的命令


1.文件与目录操作

  • 查看目录内容(类似 Linux 的 ls)
    hdfs dfs -ls /path # 查看指定路径下的文件和目录
    hdfs dfs -ls -R /path # 递归查看所有子目录

  • 创建目录(类似 Linux 的 mkdir)
    hdfs dfs -mkdir /new_dir # 创建单层目录
    hdfs dfs -mkdir -p /a/b/c # 创建多级目录(自动补全父目录)

  • 上传文件到 HDFS(从本地)
    hdfs dfs -put local_file.txt /hdfs/path/ # 上传单个文件
    hdfs dfs -put local_dir/ /hdfs/path/ # 上传目录(递归)

  • 从 HDFS 下载文件到本地
    hdfs dfs -get /hdfs/file.txt local_path/ # 下载单个文件

  • 删除文件/目录(类似 Linux 的 rm)
    hdfs dfs -rm /file.txt # 删除单个文件
    hdfs dfs -rm -r /dir/ # 递归删除目录(慎用!)


2.文件内容查看

  • 查看文件内容
    hdfs dfs -cat /file.txt # 打印整个文件内容
    hdfs dfs -head /file.txt # 查看文件前几行
    hdfs dfs -tail /file.txt # 查看文件后几行

3.文件属性与权限

  • 查看文件大小和存储信息
    hdfs dfs -du -h /path # 显示目录/文件大小(-h 为可读格式)
    hdfs dfs --stat /file.txt # 查看文件详细信息(权限、所有者、修改时间)

  • 修改文件权限(类似 Linux 的 chmod)
    hdfs dfs -chmod 755 /dir/ # 修改目录权限
    hdfs dfs --chmod -R 644 /dir/ # 递归修改目录及所有子文件权限


4.集群状态与管理

  • 查看集群整体状态
    hdfs dfsadmin -report # 显示集群健康状态、容量使用情况

  • 检查文件系统完整性
    hdfs fsck /path # 检查指定路径下文件的块状态(是否丢失或损坏)

  • 安全模式操作(维护集群时使用)
    hdfs dfsadmin --safemode enter # 进入安全模式(禁止数据修改)
    hdfs dfsadmin -safemode leave # 退出安全模式


5.其他命令

  • 移动/重命名文件(类似 Linux 的 mv)
    hdfs dfs -mv /old_path /new_path # 重命名或移动文件/目录

  • 追加内容到已有文件
    hdfs dfs -appendToFile local_file.txt /hdfs/file.txt # 追加本地文件内容

  • 查看文件块分布
    hdfs fsck /file.txt -files -blocks -locations # 显示文件的块位置信息

  • 集群数据均衡(平衡各节点存储)
    hdfs balancer # 启动数据均衡器(需管理员权限)


向hdfs中写入数据

1.创建shell脚本与写入

touch test.sh

#!/bin/bash
# 写入 100 行测试数据到 HDFS
hdfs dfs -touchz /data0/liuzz/test1.txt  # 先创建空文件(避免覆盖已有文件)
for i in $(seq 1 100); do
echo "Line $i" | hdfs dfs -appendToFile - /data0/liuzz/test1.txt
done

echo "写入完成!"

2.启动脚本

./test.sh      #需要有执行权限 chmod +x test.sh
sh test.sh     #不需要权限就能执行

3.查看与输入(后面是结果)

hdfs dfs -cat /data0/liuzz/test1.txt   #Line1 ...... Line100
hdfs dfs -text /data0/liuzz/test1.txt  #Line1 ...... Line100

三、hdfs权限类型和规则

文件示例:

权限字符串副本数所有者所属组文件大小修改时间文件/目录的 HDFS 路径
drwxr-xr-x - bdp supergroup 0 2025-05-08 16:35 /hbase

1). 权限字符串(首字符+权限部分)总共有 10 个字符,格式为:[d/-][rwx][rwx][rwx]
第 1 位:文件类型
d:目录(Directory)
-:普通文件
l:符号链接(Link)
b:块设备(如硬盘)
c:字符设备(如键盘)
p:管道文件(pipe)
s:套接字文件(socket)
第 2-4 位:所有者(User) 的权限
第 5-7 位:所属组(Group) 的权限
第 8-10 位:其他用户(Others) 的权限
每种权限代表一种数字:r=4,w=2,x=1,-=0
示例

权限字符串数字含义
drwxr-xr-x 755 目录,所有用户可浏览,但只有所有者可修改。
drwxrwxrwx 777 目录,所有者、所属组、其他用户都可以修改。
drwx------ 700 目录,只有所有者有所有权限,其他用户无法访问。
-rwxr-xr-x 755 文件,所有用户可执行,但只有所有者可修改。
-rw-r--r-- 644 文件,只有所有者可修改,其他用户只能读取。

2).副本数
对于目录,通常会使用-表示,因为目录没有副本的概念,只有文件才会有副本数的设置,文件的副本数可以通过 dfs.replication 配置项来设置


3).所有者(root)
该文件的所有者用户名(本例中为root用户)。


4).所属组(root)
该文件所属的用户组名(本例中为root组)。


5).文件大小(7)
对于普通文件,单位为字节(Byte);
对于符号链接,此值为目标路径的字符串长度(本例中usr/bin共 7 个字符)。


6).修改时间(Jan 9 2023)
表示文件内容最后一次被修改的时间,格式为月 日 年或月 日 时:分(超过 6 个月会显示年份)。


7).文件/目录的 HDFS 路径
表示该文件或目录的路径


与linux不同的地方

执行权限(x)的意义:
Linux 中,文件的 x 权限是执行的必要条件;
HDFS 中,文件的 x 权限无实际意义(因为 HDFS 不直接执行文件),仅目录的 x 权限用于控制是否允许进入目录。 
超级用户:
Linux 的超级用户是 root;
HDFS 的超级用户是启动 HDFS 进程的用户(通常是 hdfs 或 yarn),拥有所有文件的权限。  
权限检查时机:
HDFS 的权限检查仅在客户端通过 hdfs dfs 命令或 API 操作时生效,不影响 HDFS 内部进程(如 NameNode、DataNode)的操作。

  • 修改权限的命令:hdfs dfs -chmod +x <权限模式> <路径>
    • 符号模式(如 u+rwx、g-w、o+x):
      u(user):所有者;
      g(group):所属组;
      o(others):其他用户;
      a(all):所有用户。
      +:添加权限;-:移除权限;=:设置权限。
      示例(注释是结果):

         hdfs dfs -chmod u+x /data0/liuzz/test1.txt  # -rwxr--r--   1 bdp supergroup       1015 2025-07-08 16:57 /data0/liuzz/test1.txt
      
    • 数字模式(如 755、644):
      r=4,w=2,x=1,组合相加(如 7=4+2+1,5=4+1)
      示例(注释是结果):

          hdfs dfs -chmod 755 /data0/liuzz  #drwxr-xr-x   - bdp supergroup          0 2025-07-08 16:52 /data0/liuzz
      

四、hadoop-streaming组件

Hadoop Streaming 是 Hadoop 生态系统中的一个重要组件,它允许用户使用任何可执行文件或脚本(如 Python、Perl、Shell 等)作为 Map 和 Reduce 函数,让非 Java 开发者也能轻松处理大规模数据


1.Hadoop Streaming 的核心原理

  • Hadoop Streaming 基于 标准输入(stdin)和标准输出(stdout) 实现 Map 与 Reduce 过程的通信:

    • Map 阶段:脚本从标准输入stdin读取数据,处理后将结果以key \t value格式(键值对,用制表符分隔)输出到标准输出
    • Shuffle 阶段:Hadoop 自动对 Map 输出的键值对进行排序、分组(相同 key 的 value 聚集),这一步由 Hadoop 框架内部完成,无需用户干预
    • Reduce 阶段:脚本从标准输入stdin读取Shuffle后的键值对(格式为key \t value1,value2,...),处理后将最终结果输出到标准输出

2.使用hadoop streaming的要点:

一、必须指定的核心参数

    hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-*.jar \
    -input  /Map阶段的输入数据路径 \        #\后不能有空格,否则会报错
    -output /Reduce 阶段的输出路径 \        #必须是不存在的文件,会自动创建新文件,否则会报错          
    -mapper "/map脚本地址" \
    -reducer "/reducer脚本地址" \
    -file /data0/liuzz/mapper.sh \         #分发map和reduce脚本到集群的每个节点
    -file /data0/liuzz/reducer.sh

-file 参数的作用是将本地文件分发到集群的每个节点,可以是脚本、配置文件、字典、Python模块等

-file ./dict.txt  # 分发依赖的字典文件

二、脚本相关注意事项

  • 脚本的可执行性
    • 若使用 Shell 或 Python 脚本,需确保脚本有可执行权限(本地脚本执行 chmod +x script.sh
    • Python 脚本需在开头指定解释器(如 #!/usr/bin/env python),否则可能因找不到解释器报错
    • 脚本中避免使用绝对路径(如 /usr/local/bin/python),建议用环境变量(如 python 或 #!/usr/bin/env python),兼容不同节点的环境
  • 输入输出格式
    • Mapper/Reducer 必须通过 标准输入(stdin)读取数据、标准输出(stdout)输出数据,且输出的键值对必须用 制表符(\t)分隔(默认分隔符,可通过参数修改)
    • 若输出格式错误(如用空格分隔),Shuffle 阶段会无法正确识别 Key,导致排序 / 分组错误
  • 处理特殊字符
    • 若数据中包含制表符(\t)、换行符等,需在脚本中提前处理(如替换),否则可能被误判为键值对分隔符

三、Shuffle 阶段的可选配置

  • 默认情况下,Shuffle 按 Key 的 ASCII 码排序,但可通过参数自定义:

  • -jobconf mapreduce.map.output.key.class=org.apache.hadoop.io.Text:指定 Map 输出 Key 的类型(默认 Text)

  • -jobconf mapreduce.partitioner.class=org.apache.hadoop.mapred.libHashPartitioner:指定分区器(默认哈希分区,确保相同 Key 到同一个 Reduce)

  • -jobconf mapreduce.reduce.sort.keycomparator.class=...:自定义 Key 比较器(如需特殊排序规则)

  • -jobconf mapreduce.job.reduces=N:指定 Reduce 任务数量(默认 1,可根据数据量调整)


四、其他实用参数

  • -combiner <脚本>:指定 Combiner(本地聚合,逻辑同 Reducer,可减少 Shuffle 数据量)。
  • -inputformat / -outputformat:自定义输入 / 输出格式(默认 TextInputFormat/TextOutputFormat)。
  • -jobconf mapreduce.job.name="MyJob":指定任务名称,方便在 YARN 控制台识别。
    -verbose:打印详细日志,方便调试。

五、常见错误与避坑点

  • 输出路径已存在:-output 指定的路径若已存在,任务会直接失败,需提前删除(hdfs dfs -rm -r /path)。
  • 权限问题:HDFS 输入路径无读权限、输出路径无写权限,或脚本无执行权限。
  • 集群环境差异:不同节点的 Python/Shell 版本不一致(如 Python2 vs Python3),建议在脚本中明确版本(如 #!/usr/bin/env python3)。
  • 数据倾斜:Reduce 任务数量设置不合理,导致某一 Reduce 处理过多数据,可通过调整 -jobconf mapreduce.job.reduces 优化

示例wordcount:

  • 输入文件(/data0/liuzz/input.txt)

          Hello world  
          Hello Hadoop 
          world is big
          hadoop is cool 
    
  • Map 脚本(/data0/liuzz/mapper.sh)

      #!/bin/bash
    
      while IFS= read -r line; do
          # 去除每行首尾空格
          line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
          # 按空格拆分单词并输出
          for word in $line; do
              echo -e "$word\t1"  # 键值对用制表符分隔
          done
      done
    
  • 启动脚本的代码

      hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-3.2.1.jar \
      -input /data0/liuzz/input \
      -output /data0/liuzz/output \           #\后不能带空格,会报错
      -mapper "/data0/liuzz/mapper.sh" \
      -reducer "/data0/liuzz/reducer.sh" \
      -file /data0/liuzz/mapper.sh \
      -file /data0/liuzz/reducer.sh
    
  • 经Map脚本后得到stdout

      Hello   1  
      world   1  
      Hello   1
      Hadoop  1
      world   1
      is      1
      big     1
      hadoop  1
      is      1
      cool    1
    
  • 中间经过shuffle得到stdout

      Hello	    1
      Hello	    1
      Hadoop	1
      big	    1
      cool	    1
      hadoop	1
      is	    1
      is	    1
      world	    1
      world	    1
    
  • Reduce 脚本(/data0/liuzz/reducer.sh)

      #!/bin/bash
    
      current_word=""
      current_count=0
    
      while IFS= read -r line; do
          # 提取键(单词)和值(计数)
          word=$(echo "$line" | cut -f1)
          count=$(echo "$line" | cut -f2)
    
          # 累加相同单词的计数
          if [[ "$word" != "$current_word" ]]; then
              if [[ -n "$current_word" ]]; then
                  echo -e "$current_word\t$current_count"  # 输出上一个单词的结果
              fi
              current_word="$word"
              current_count="$count"
          else
              current_count=$((current_count + count))  # 计数累加
          fi
      done
    
      # 输出最后一个单词的结果
      if [[ -n "$current_word" ]]; then
          echo -e "$current_word\t$current_count"
      fi
    
  • 经过Reduce脚本得到stdout

      #hdfs dfs -cat /data0/liuzz/output/part-00000的结果
      Hadoop  2
      Hello   2
      big     1
      cool    1
      is      2
      world   2 
    
  •  
posted @ 2025-07-10 13:59  许魔  阅读(71)  评论(0)    收藏  举报