四大机制: 心跳机制, 安全模式, 机架感知, 负载均衡;
两大核心: 读写原理
master 和 slave 之间通过 ipc 服务通信, 通信有固定时间周期(默认3秒),称之为心跳。
dfs.heartbeat.interval: 配置心跳时间
slave 超时时间的计算:
timeout = 2 * dfs.namenode.heartbeat.recheck.interval + 10 * dfs.heartbeat.interval
默认值: dfs.namenode.heartbeat.recheck.interval 300000(5 min)
dfs.heartbeat.interval 3 (3 sec)
查看资料发现, datanode 的 offerService 方法中, 有着每隔3秒向 namenode 发送心跳的代码,
该代码表示, datanode 实际是对 namenode 进行调用:
public void offerService() throws Exception {
...
while (shouldRun) {
try {
long startTime = now();
// 心跳机制间隔时间判断
if (startTime - lastHeartbeat > heartBeatInterval) {
lastHeartbeat = startTime;
// 在 datanode 中执行 namenode.sendHeartbeat(...)
// 实际上 **心跳机制就是在 datanode 中 调用 namenode 的方法** !!!
DatanodeCommand[] cmds = namenode.sendHeartbeat(dnRegistration,
data.getCapacity(),
data.getDfsUsed(),
data.getRemaining(),
xmitsInProgress.get(),
getXceiverCount());
...
但是 datanode 与 namenode 是不同节点上的两个 jvm 进程, 他们具体是怎样调用的呢 ?
datanode向namenode发送heartbeat过程是这样的:
实际上是通过动态代理的方式进行调用, 以下是大佬总结步骤:
详细请移步, 一步步推理逻辑清晰 :
https://blog.csdn.net/fly542/article/details/6797139
- 在 datanode 初始化获得 namenode 的 proxy
- 在 datanode上,调用 namenode proxy 的 heartbeat 方法: namenode.sendHeartbeat ( dnRegistration,
data.getCapacity(),
data.getDfsUsed(),
data.getRemaining(),
xmitsInProgress.get(),
getXceiverCount() );- 在 datanode 上的 namenode 动态代理类将这个调用包装成 (或者叫“序列化成”) 一个Invocation对象,并调用client.call方法
- client.call 方法将 Invocation 转化为 Call 对象
- client 将 call 发送到真正的 namenode 服务器
- namenode 接收后,转化成 namenode 端的 Call,并处理后,通过 Responder 发回来!
- datanode 接收结果,并将结果转化为 DatanodeCommand[]
namenode在系统启动时会首先进入安全模式, 此时对datanode进行检查数据块的有效性.
如果 datanode 丢失的数据达到 0.1%, 则一直处于安全模式, 此时只读模式, 不可修改与删除文件;
若block丢失小于 0.1% 则自动退出.
safemode是namenode的一种状态 ( active / standby / safemode )
集群中的文件不能被操作 (安全模式是一种自我保护)
进入safemode的状况
dfs.namenode.safemode.threshold-pct ( 默认值0.999f )
即: block块丢失率达到0.1%, 自动进入, 只读不可修改删除文件
退出safemode
方法一: 修复宕机的节点(推荐),自动退出
方法二: 强制退出safemode(没有解决问题,有可能再次出现数据丢失)
强制退出命令: hdfs dfsadmin -safemode leave
问题: 为什么集群启动时会自动进入 safemode, 然后又自动退出?
block 所在的 datanode 的信息存在于内存中,而不在磁盘中。
故冷启动时,刚开始找不到 block 所在的节点的, 认为 block 丢失, 后再内存中加载, 则恢复.
安全模式常见命令
hdfs dfsadmin -safemode get:获取当前的safemode状态
hdfs dfsadmin -safemode enter:进入safemode状态
hdfs dfsadmin -safemode leave:退出safemode状态
hdfs dfsadmin -safemode wait:等待
HDFS文件块副本的放置对于系统整体的可靠性和性能有关键性影响
配置机架感知作用 : 将数据分散冗余存储, 以保证数据的可靠性和高效性
机架感知 ( 又称副本存放策略 )
当没有配置机架信息时
hadoop 默认所有的机器都在同一个默认的机架下,名为 “/default-rack”
此时,任何一台datanode机器,不管物理上是否属于同一个机架,都会被认为是在同一个机架下
容易出现问题 : 增添机架间网络负载
同时: namenode 默认将所有的slaves机器全部默认为在/default-rack下,
因此在这种情况下写 block 时,三个datanode机器的选择完全是随机的
<property>
<name>topology.script.file.name</name>
<value>/path/to/script</value> 脚本名称及路径
</property>
3.自定义脚本过程:
Namenode 启动时,会判断该配置选项是否为空,if not null,则表示已经启用机架感知的配置.
此时 namenode 会根据配置寻找该脚本:
接收到每一个datanode的heartbeat时,将该 datanode 的 ip地址 作为参数传给该脚本运行,
将得到的输出作为该 datanode 所属的机架,保存到内存的一个 map 中。
脚本的编写
需将真实网络拓朴和机架信息了解清楚后,通过脚本能将机器的ip地址正确映射到相应的机架上
官方参考: http://wiki.apache.org/hadoop/topology_rack_awareness_scripts 截图如下
在脚本编写完成后, 查看网络拓扑结构命令: hdfs dfsadmin -printTopology
至此机架感知配置完成, hadoop在选择三个 datanode 时,就会按照副本存放策略进行相应的判断.
此时这三步就进行 block 的写入:
- 得到 3个 datanode 的列表以后,从返回到客户端之前,会在 namenode 端首先根据该客户端跟每个 datanode 之间的“距离”由近到远进行一个排序,客户端根据这个顺序有近到远的进行数据块的写入
- 当根据“距离”排好序的 datanode 节点列表返回给 Client 以后,Client便会创建 Block OutputStream,并向这次 block 写入 pipeline 中的第一个节点(最近的节点)开始写入block数据
- 写完第一个block以后,依次按照datanode列表中的次远的node进行写入,直到最后一个block写入成功,Client 返回成功,该 block 写入操作结束
namenode在选择数据块的写入datanode列表时,就充分考虑到了将block副本分散在不同机架下,并同时依据从近到远避免了多余的网络开销.
需要注意的是:
修改hdfs-site.xml
dfs.replication
通过shell命令实现:
hdfs dfs -setrep 2 文件
1.数据平衡不能导致数据块减少,数据块备份丢失
2.管理员可以中止数据平衡进程
3.每次移动的数据量以及占用的网络资源,必须是可控的
4.数据均衡过程,不能影响 namenode 的正常工作
命令:
实现负载均衡,默认移动速度1m/s(出于带宽考虑,读写)
start-balancer.sh:
设置默认的移动速度
hdfs dfsadmin -setBalanacerBandwidth 10485760:
负载最高的节点和最低节点之间的数据差距比例不超过10%
stat-balancer.sh -t 10%:
读流程总结
至此 HDFS 读流程 ( 文件下载 ) 全部结束, 开始重点部分:
写流程总结
至此 HDFS 写流程 ( 文件上传 ) 全部结束.