1. 背景:
线上HDFS的DataNode中频繁出现Slow write日志
从日志分析来看,Slow write分为write to mirror和write to disk两类
为便于分析网络或者磁盘写入的情况,设计了HDFS的写入监控链路,采集DataNode中出现的slow日志收集,供后续分析。
2. HDFS的源码分析
下面从源码角度简要分析下HDFS的block写入流程:
如图所示,写入的大致流程如下:
1) DFSClient通过Sender.writeBlock方法触发一个写数据块请求;
2) 该请求通过数据流管道传送到每一个数据节点,最后一个数据节点回复请求确认,该确认消息通过数据流管道逆向送回DFSClient;
3) DFSClient收到确认消息后,将待写入的数据切分成若干个数据包(packet),然后依次向数据流管道发送这些数据包;
4) 数据包首先到达DataNode1,写入磁盘之后,再发送给DataNode2,依次类推;
5) 当数据包到达DataNode3时,DataNode3会对数据包进行校验,如果校验成功,则发送确认消息,并且逆向通过数据流管道传回DFSClient;
6) 当所有的数据包都发送完毕之后,DFSClient会发送一个空的数据包标识当前数据快发送完毕,至此,整个数据块流程发送完毕。
写入过程涉及到的主要类包括:
1) DataNode启动时会创建一个DataXceiverServer类用于监听客户端的读写请求:
在其run方法中,对于每个客户端连接创建一个DataXceiver用于处理读写请求。
2) DataXceiver中写入数据块的逻辑在writeBlock方法中:
首先创建一个blockReceiver对象:
连接到下游节点:
调用blockReceiver的receiveBlock方法接收数据块
3) BlockReceiver类负责接收上游的数据块,保存到当前节点,并写入到下游节点,核心逻辑在receiveBlock方法中:
首先读取packet至本地缓存
写入数据流到下一个节点:
如果接收到了完整的数据块,并且启动了sync标识,则写入数据到本地磁盘
否则验证数据包的校验和
将数据写入本地磁盘
3. 写入链路埋点设计
DataNode中对以下四种slow情况(超过300ms)进行了warning:
1) Slow BlockReceiver write packet to mirror
2) Slow BlockReceiver write data to disk
3) Slow flushOrSync
4) Slow manageWriterOsCache
为了追踪记录这4种耗时情况,在BlockReceiver类中对这四种耗时的地方打印出日志,字段格式如下:
{
blkId: block的id
time: 时间戳
srcAddress: 当前节点地址
dstAddress: 目标节点地址
slowType: 四种slow的类型
duration: slow write的耗时
}
在BlockReceiver类中添加以下代码打印日志:
将日志打印到单独的文件中,通过filebeat收集到kafka中,再通过spark-streaming写入到es中,打印出的日志如下图所示:
收集到es之后,通过相关的聚合条件可以查询出不同slow write的耗时情况:
4. 部署方式:
将修改后的hadoop源码重新打包,得到hadoop-hdfs-2.6.0-cdh5.5.0.jar包,替换掉hadoop路径中的jar包。
在CDH的DataNode高级配置中的日志记录高级配置代码段中添加以下配置:
log4j.appender.PACKET_TRACE=org.apache.log4j.RollingFileAppender
log4j.appender.PACKET_TRACE.Threshold=INFO
log4j.appender.PACKET_TRACE.File=${hadoop.log.dir}/packet_trace.log
log4j.appender.PACKET_TRACE.Append=true
log4j.appender.PACKET_TRACE.MaxFileSize=30MB
log4j.appender.PACKET_TRACE.MaxBackupIndex=10
log4j.appender.PACKET_TRACE.layout=org.apache.log4j.PatternLayout
log4j.logger.packet-trace = INFO, PACKET_TRACE
log4j.additivity.packet-trace = false
重启该DataNode,则日志信息会记录到packet_trace.log文件中。
同时在该节点上部署filebeat,收集packet_trace.log文件的信息,写入到kafka中。