Hadoop或者HBase相关的文章,欢迎关注微信公众号:iteblog_hadoop
详情参见:Hadoop 官方文档
目前HDFS 最新版本为3.3.x ,但是3.3.x 刚出不具备在生产环境部署的条件。初步调研发现,HDFS 版本小于 3.1.3 和 3.2.1 时,在Namenode滚动升级和滚动降级时存在因为EC导致的兼容性问题(详见 HDFS-14396 ,HDFS-13596 ),所以小于3.1.3 和 3.2.1 的不予考虑。 综合考虑需求后,在3.2.1 和 3.1.3 中选用了更稳定的3.1.3 版本。
我们当前Hadoop版本为HDP-2.6.5,和3.1.3版本之间存在较大的差距,升级存在较多风险。我们在兼容性方面进行了深入研究,主要有以下几个方面需要考虑:
经调研测试,主要有两处不兼容:
1、 DatanodeProtocol.proto 协议不兼容
// hdfs-3.1.3 版本 message HeartbeatResponseProto { repeated DatanodeCommandProto cmds = 1; // Returned commands can be null required NNHAStatusHeartbeatProto haStatus = 2; optional RollingUpgradeStatusProto rollingUpgradeStatus = 3; optional RollingUpgradeStatusProto rollingUpgradeStatusV2 = 4; optional uint64 fullBlockReportLeaseId = 5 [ default = 0 ]; } // hdp-2.6.5 版本 message HeartbeatResponseProto { repeated DatanodeCommandProto cmds = 1; // Returned commands can be null required NNHAStatusHeartbeatProto haStatus = 2; optional RollingUpgradeStatusProto rollingUpgradeStatus = 3; optional uint64 fullBlockReportLeaseId = 4 [ default = 0 ]; optional RollingUpgradeStatusProto rollingUpgradeStatusV2 = 5; }
我们可以看到两个版本 HeartbeatResponseProto 的第4、5个参数不同。 当 Datanode 向 Namenode 发送心跳时,携带了requestBlockReportLease=true 参数, Namenode 根据自身忙碌程度决定是否在心跳中返回 fullBlockReportLeaseId 来接收Datanode 的BlockReport ,从而实现Datanode 的BlockReport 限速(详情参见: HDFS-7923)。 当新版本 Namenode 返回一个fullBlockReportLeaseId 时,被旧版本Datanode 当成rollingUpgradeStatusV2 来解析,最终导致Datanode BlockReport 无法进行。
这个问题的原因在于, 3.1.3 版本 commit 了 HDFS-9788 ,用来解决低版本升级时兼容问题,而 HDP-2.6.5 没有commit 。
解决这个问题主要有两个办法:
综合考虑,HDFS-9788 只是为了解决hdfs升级时兼容低版本的问题,我们当前目标是升级到HDFS 3.x , 至于兼容低版本的功能我们不需要。所以我们选择了第二种方法。
2、 Datanode 数据存储格式不兼容
社区自 HDFS-2.8.0 commit HDFS-8791 后,基于blockid的Block Pool数据块目录存储结构从256x256个目录变成了32x32个目录,数据存储格式发生了变化。这个特性导致了HDP-2.6.5 可以滚动升级到 HDFS-3.1.3 但是不能滚动降级。 HDFS-8791 主要解决Datanode在ext4文件系统中用256x256个目录存储数据块的性能问题。考虑这个问题在我们集群并不明显,决定暂时回退 HDFS-8791 的修改,保持Datanode 数据格式的兼容,保证我们在升级Datanode异常时还能降级。至于后续有需要时,可单独升级Datanode。
1、升级过程中,DataNode 在删除 Block 时,是不会真的将 Block 删除的,而是先将Block 文件放到磁盘BlockPool 目录下一个 Trash 目录中,为了能够使用原来的 rollback_fsimage 恢复升级过程中删除的数据。我们集群磁盘的水位一直在80%,本来就很紧张,升级期间Trash 中的大量Block文件会对集群稳定造成很大威胁。考虑到我们的方案是的回退方式是滚动降级而非Rollback,并不会用到Trash 中的Block。所以我们使用脚本定时对 Trash 中的 Block 文件进行删除,这样可以大大减少 Datanode 上磁盘的存储压力。
2、升级观察过程中发现旧版本HDFS 在 Kerberos 认证后去连接 3.1.3 建立连接失败,导致一条数据链路故障。因为在3.1.3 版本中增加了 hadoop.security.auth_to_local.mechanism 默认值为hadoop , 不接受带有 ‘@’ 或者 o'/' 的用户名 ,而旧版本Client 在kinit 之后会携带 ‘test@HADOOP.COM’ 这样的用户名去建立连接,所以连接失败。 在修改 hadoop.security.auth_to_local.mechanism = MIT 后解决,详见:HADOOP-15996 。 反思:考虑集群本身没有开启 Kerberos 认证,在升级测试过程并未把 Kerberos 相关内容划到测试范围内,导致一个故障。以后在测试时要 Involve 更多的依赖方,做更全面的Testing。
3、升级后手动 Failover Namenode 失败,引发Standby Namenode 挂掉。 Namenode Failover 时,Standby Namenode 转变成 Active 过程中初始化 Quota 的时间超过了zkfc超时时间,所以Standby Namenode 挂掉。初始化 Quota 线程数默认值为4 ,增加dfs.namenode.quota.init-threads 后解决。 详见 :HDFS-8865
1、分析升级原理 & 版本差异
在这个过程中,我们详细阅读分析了滚动升级的源码,确定升级中 NameNode,DataNode 会做哪些动作,以明确风险点。由于 HDP-2.6.5 基于Apache-2.7.3 增加了近 2000个Patch ,HDFS-3.1.3 相比 2.7.3 增加了近4000 个 Patch ,我们需要找出可能存在兼容性问题的点进行分析,以确保对升级没有影响。
2、对比新旧版本配置
新旧版本在配置方面有很大不同,尤其是3.1.3 新增了很多配置,都可能成为升级失败的关键点。这里需要我们过滤出新旧版本的不同配置进行研究,确保配置参数兼容。
3、模拟线上环境全量组件测试
HDFS 是众多组件的依赖,HDFS的运行状况随时影响着其他各种链路的稳定。为了尽可能的避免升级风险,保证集群升级的顺利我们模拟线上集群节点压力搭建了一套全量组件测试环境。组织所有相关组件admin 模拟线上场景搭建任务链路,在任务正常运行情况下,开始按步骤进行升级,并每个步骤进行Check ,直升级完成后所有任务都无异常。
4、多次的演练
升级方案验证完成形成Checklist 后,逐步在Dev环境、Test环境、Stage 环境进行演练,在增加操作的熟练度同时通过不同环境的大量测试任务检验升级方案健壮性。
5、正式升级
商定一个升级时间窗口,并通知用户注意升级期间任务运行情况。 升级完成观察一周没问题后执行 Finalize 操作。
HDFS 在 3.1.3 版本运行稳定,我们计划在今年完成集群冷数据的转EC操作,降低HDFS存储成本,并在计算组件支持EC文件读写上投入精力调研。后续逐步开启3.1.3版本新特性,包括RBF、Namenode 一致性读、DN的维护状态等功能,来提升HDFS的读写性能,继续为降本增效努力。
参考资料:
[1]https://blog.csdn.net/DiDi_Tech/article/details/103849694
[2]https://issues.apache.org/jira/browse/HDFS-14831
[3]https://issues.apache.org/jira/browse/HDFS-14509
[4]https://issues.apache.org/jira/browse/HDFS-11096
[5] https://issues.apache.org/jira/browse/HDFS-14753