写点什么

删了 HDFS 又能怎样?记一次删库不跑路事件,kafka 的架构图

用户头像
极客good
关注
发布于: 刚刚

BlockManager中有个方法invalidateWorkForOneNode()专门用于定时删除InvalidateBlocks中存储的待删除的快,此方法会在 NameNode 启动时在BlockManager的内部线程类ReplicationMonitor定时轮循把要删除的块放入DatanodeDescriptor中的逻辑,方法的调用路径如下:


org.apache.hadoop.hdfs.server.namenode.NameNode#initialize(Configuration conf)org.apache.hadoop.hdfs.server.namenode.NameNode#startCommonServices(Configuration conf)org.apache.hadoop.hdfs.server.namenode.FSNamesystem#startCommonServices(Configuration conf, HAContext haContext)org.apache.hadoop.hdfs.server.blockmanagement.BlockManager#activate(Configuration conf)org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.ReplicationMonitor#run()org.apache.hadoop.hdfs.server.blockmanagement.BlockManager#computeDatanodeWork()org.apache.hadoop.hdfs.server.blockmanagement.BlockManager#computeDatanodeWorkcomputeInvalidateWork(int nodesToProcess)org.apache.hadoop.hdfs.server.blockmanagement.BlockManager#invalidateWorkForOneNode(DatanodeInfo dn)org.apache.hadoop.hdfs.server.blockmanagement.InvalidateBlocks#invalidateWork(final DatanodeDescriptor dn)


BlockManager维护了InvalidateBlocks,存放了待删除的 block,BlockManager在 NameNode 启动时会单独启动一个线程,定时把要删除的块信息放入InvalidateBlocks中,每次会从InvalidateBlocks队列中为每个 DataNode 取出 blockInvalidateLimit(由配置项 dfs.block.invalidate.limit,默认 1000)个块逻辑在BlockManager.computeInvalidateWork()方法里会把要删除的块信息放入DatanodeDescriptor中的 invalidateBlocks 数组,DatanodeManager再通过 DataNode 与 NameNode 心跳时,构建删除块的指令集,NameNode 再把指令下发给 DataNode,心跳由DatanodeProtocol调用,方法的调用路径如下:


org.apache.hadoop.hdfs.server.protocol.DatanodeProtocol#sendHeartbeat()org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer#sendHeartbeat()org.apache.hadoop.hdfs.server.namenode.FSNamesystem#handleHeartbeat()org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager#handleHeartbeat()


DatanodeMan


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


ager.handleHeartbeat()中构建删除的指令给 DataNode,待 NameNode 发送,的代码如下:


/** Handle heartbeat from datanodes. */public DatanodeCommand[] handleHeartbeat(形参略){// ....其余代码逻辑略//check block invalidationBlock[] blks = nodeinfo.getInvalidateBlocks(blockInvalidateLimit);if (blks != null) {cmds.add(new BlockCommand(DatanodeProtocol.DNA_INVALIDATE,blockPoolId, blks));}// ....其余代码逻辑略 return new DatanodeCommand[0];}


定时轮循+limit 1000 个块删除的特性决定了 hdfs 删除数据并不会立即真正的执行物理删除,并且一次删除的数量也有限,所以上面的应急措施中立即停止 HDFS 集群是最明智的选择,虽然有的数据在轮循中已被删除,所以事发后停止 HDFS 集群越早,被删的数据越少,损失越小!

EditLog

恢复数据的另一个关键是 EditLog,EditLog 记录了 hdfs 操作的每一条日志记录,包括当然包括删除,我们所熟知的文件操作类型只有增、删、改,但是在 HDFS 的领域里,远远不止这些操作,我们看看 EditLog 操作类型的枚举类 org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes



总计 40 多种操作类型!打破了人们印象中文件只有增删改读的几种操作,有木有突破你的想象?


EditLog 长啥样呢?在 hadoop 的配置参数dfs.namenode.name.dir可以找到路径



这里 EditLog 文件是序列化后的二进制文件不能直接查看,hdfs 自带了解析的命令,可以解析成 xml 明文格式,我们解析一个看看


hdfs oev -i edits_0000000000035854978-0000000000035906741 -o edits.xml


查看文件



对 hdfs 的每一个操作都会记录一串 RECORD,RECORD 里面不同的操作包含的字段属性也不同,但是所有操作都具备的属性是 OPCODE,对应上面的枚举类org.apache.hadoop.hdfs.server.namenode.FSEditLogOpCodes中 40 多种操作

hdfs 元数据的加载

hdfs 启动时,NameNode 会加载 Fsimage,Fsimage 记录了 hdfs 现有的全量的路径信息,启动过程中仅仅加载 Fsimage?这句话不完全正确!启动的同时,还会加载未被合并成 fsimage 的 EditLog。关于 fsimage 具体细节这里不展开。举个栗子:


假设 Hadoop 3 分钟 checkpoint 一次生成 Fsimage 文件,EditLog 1 分钟生成一个文件,下面是依次生成的文件:


fsimage_1editlog_1editlog_2editlog_3fsimage_2editlog_4editlog_5


当 NameNode 启动时,会加载后缀时间戳最大的那个 fsimage 文件和它后面产生的 editlog 文件,也就是会加载 fsimage_2、editlog_4、editlog_5 进 NameNode 内存。假设我们执行hadoop fs -rmr xxx命令的操作记录在了 editlog_5 上面,那么,重启 NameNode 后,我们查看 hdfs 无法再查看到xxx路径,如果我们把 fsimage_2 删掉,NameNode 则会加载 fsimage_1、editlog_1、editlog_2,此时的元数据里面xxx还未被删除,如果此时 DataNode 未物理删除 block,则数据可以恢复,但是 editlog_4、editlog_5 对应的 hdfs 操作会丢失。有没有更好的方法呢?

方案确定

方案一:删掉 fsimage_2,从上一次 checkpoint 的地方也就是 fsimage_1 恢复,我们集群的实际配置,是一个小时生成一次 fsimage 文件,也就是说,这种恢复方案会导致近一小时 hdfs 新增的文件全部丢失,集群日工作流的的量 2w 左右,这一个小时不知道发生了多少事情,可想而知的后果是恢复之后一堆报错,显然不是最好的方案


方案二:修改 editlog_5,把删除xxx那条操作改成其它安全的操作类型,这样重启 NameNode 后,又可以看到这个路径。good idea!就这么干!

四、灾难重演

为了完整的演示一遍恢复过程,我找了个测试环境重新演示一遍。请勿随意在生产环境演示!!!


  • 删除路径


bash-4.2 hadoop fs -rmr -skipTrash /tmp/user/hive/warehousermr: DEPRECATED: Please use '-rm -r' instead.Deleted /tmp/user/hive/warehousebash-4.2 hadoop fs -ls /tmp/user/hivebash-4.2$


  • 关闭 HDFS 集群

  • 解析 editlog


找到删除操作时间点范围内所属的 editlog 文件,解析


hdfs oev -i edits_0000000000005827628-0000000000005827630 -o editlog.xml


查看 editlog.xml,执行删除操作的日志已经记录在里面了



  • 替换删除操作


把 OP_DELETE 操作替换成比较安全的操作,例如:


<RECORD><OPCODE>OP_SET_OWNER</OPCODE><DATA><TXID>5827629</TXID><SRC>/tmp/user/hive/warehouse</SRC><USERNAME>hadoop</USERNAME></DATA></RECORD>



注意:TXID 一定要一样!!!


  • 反解析成 editlog

反解析更改后的 xml 文件成 editlog

hdfs oev -i editlog.xml -o edits_0000000000005827628-0000000000005827630.tmp -p binary

重命名掉之前的 editlog

mv edits_0000000000005827628-0000000000005827630 edits_0000000000005827628-0000000000005827630.bak

替换反解析后的 editlog

mv edits_0000000000005827628-0000000000005827630.tmp edits_0000000000005827628-0000000000005827630

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
删了HDFS又能怎样?记一次删库不跑路事件,kafka的架构图