项目背景
我们团队负责维护的Kafka集群承载了公司大部分实时数据的收集与传输任务。然而,目前存在一些问题,严重影响了集群的稳定性、用户体验以及管理员的运维效率:
- 当前集群版本较低,且低版本的bug频繁出现,导致集群稳定性受到威胁。例如,violet集群最近因触发bug而出现不可用的情况。
- 多个集群版本不一致,用户在使用时受到版本限制,管理员需要关注不同版本之间的差异,增加了问题排查的时间和复杂度。
因此,我们决定启动集群升级项目,将所有集群统一升级至较高的2.2版本,以提升集群的稳定性,改善用户体验,并降低运维成本。我们参考了Kafka官网、主流企业服务提供商(如:Confluent、Cloudera)以及国内其他公司的升级方案,结合公司现有集群的实际情况,制定了本方案。
项目目标
根据“尽量减少对用户的影响,确保操作高效、安全”的原则,细化为“分批次、分阶段、不停服”的目标:
- 不停服:采取 滚动升级 的方式,避免出现整个集群不可用的情况,尽可能降低用户感知;
- 分批次:将当前所有集群按优先级划分为多个批次,当前批次执行升级且持续运行一周无异常后,再升级下一批次;
- 分阶段:将升级操作流程拆解为多个阶段,每个阶段的checklist确认无误后,再执行下一阶段操作,同时,提前准备好相应的预案 (回滚和线上服务恢复步骤) 以应对异常情况。
方案描述
作为C/S架构,Kafka集群的完整升级过程涵盖了broker侧和client侧。 按照执行次序,完整的升级过程可划分为5个阶段,如下:
- [broker侧] 代码升级;
- [broker侧] broker间通信协议版本 (配置项) 升级;
- [client侧] Consumer升级;
- [broker侧] 消息格式版本 (配置项) 升级;
- [client侧] Producer升级。
执行流程
集群升级的整体执行流程可分为7个环节,如下:
组内集群现状
主要关注点包括:
- 当前版本
- 部署方式:不同方式部署的集群,升级操作过程可能不同 (取决于测试验证的结果,如果可以通过同一种方案对所有部署方式下的集群执行同等高效安全的操作,最好不过);
- 监控:考虑到后续的监控会全部对接Mon/AXE,借助此次梳理机会,对AXE节点和主机基础监控信息进行规整和完善。
目前,我们的Kafka集群共有14个,按照部署方式分为两类:
- Cloudera部署的集群(8个):版本0.8.2(4个)、0.10.2(3个)、0.10.0(1个);
- 手工部署的集群(6个):版本0.8.2.2(2个)、0.10.2(1个)、1.0.0(1个)、2.1.0(1个)、2.2.1(1个)。
各集群详细信息如下:
测试
测试目标
从可行性、安全性和操作便利性三个方面对所有备选方案进行测试,选出综合最优的方案作为最终执行方案。
测试方案
手工部署的集群测试方案:
Cloudera部署的集群测试方案,流程与上述方案大体一致,不同点如下:
- 复用当前的Cloudera manager服务进行操作;
- 测试环境zookeeper和kafka的搭建,以及配置项的修改,都是在Cloudera Manager UI上操作完成的;
- 官方推荐采用parcel方式进行升级 (即,新版本代码的下载和部署由Cloudera Manager UI上的parcel操作完成),根据操作复杂度决定是否需要进行手动后台操作。
测试验证选择方案的过程,实际上是不断解决上述方案中的各项“如果”“尝试”的过程。随着这些项的全部解决和确定,最终的执行方案也就确定了。
测试过程及用例记录
快速搭建测试集群
- 安装包:为了搭建多个版本的集群,提前下载所有需要的安装包(包括Kafka、Zookeeper、相关插件及依赖的Jar包),并以FTP形式提供,方便测试时随时使用。
- 安装流程自动化:手工部署集群的流程相对固定,通过自动化脚本处理,节省大量时间,降低人为误操作的风险。
相关脚本包括:
- __download_scrpits.sh: 下载所有脚本
- download_kafka.sh: 特定版本kafka安装包的下载与前置处理
- download_zookeeper.sh: zookeeper安装包的下载与前置处理
- init_before_download.sh: 安装环境的初始化 (包括服务和数据路径的创建、权限更改等操作,需要在下载安装包之前且以有root权限的账号运行)
测试环境:
- 三台机器分别为
- 10.103.17.55
- 10.103.17.56
- 10.103.17.57
- kafka manager上“test-inner”集群
测试验证执行流程 (测试用例)
结论:经过测试,方案1满足目标,因此选定为最终升级方案。
Cloudera部署集群的搭建与测试
以当前生产环境下Cloudera部署集群的最低版本0.8.2.0进行测试。
方案的选型与验证策略:优先验证手工升级方式,同时解耦Cloudera环境,因Cloudera部署和日常运维操作中存在以下问题:
- 通过yum部署带来的不便,各机器的yum缓存差异引入不确定性;
- 部署过程中需在Cloudera Manager页面和目标机器之间频繁切换处理异常;
- Cloudera对服务目录和数据目录有特定权限设置;
- 集群日常增减机器的操作较为繁琐。
测试环境:
- 两台机器分别为:
- 10.120.187.33
- 10.120.187.34
- kafka manager上“test-inner-cloudera”集群
测试过程:在Cloudera部署的测试集群下验证方案1,未发现新问题。
结论:经测试,可以手工通过方案1对Cloudera部署的集群进行升级,升级后Cloudera Manager上的broker将全部被替换。
极端异常场景测试
MirrorMaker相关场景测试
由于线上环境的MirrorMaker仅涉及从blue集群(0.8.2)到violet集群(0.8.2)的复制,测试过程基于该版本的集群进行,MirrorMaker部署在源集群上。
和线上环境保持一致,MirrorMaker部署在源集群上。 名词解释:
- 低版本:本节特指0.8.2版本
- 高版本:本节特指目标版本2.2.1
测试结果显示:
- 源集群维持低版本,目标集群升级,MirrorMaker正常工作;
- 目标集群为高版本,源集群升级,MirrorMaker保持不变,正常工作;
- 目标集群维持低版本,源集群升级,且MirrorMaker升级,MirrorMaker工作异常。
MirrorMaker实质上是一组与其所在broker版本相同的Producer和Consumer。测试结果表明,高版本集群能够兼容低版本客户端,反之则不行。
升级过程需要注意事项:
- 在升级blue/violet集群过程中,需随时关注MirrorMaker的工作状态;
- 本次集群broker侧升级过程中,MirrorMaker保持现状(包括版本和运行路径),由于MirrorMaker使用Cloudera工作路径和代码,因此blue集群的Cloudera工作路径和代码需保留,直至后续MirrorMaker版本升级完成。
其它关注点: 新旧版本的元信息记录文件(如checkpoint)内容和格式是否有变更?升级前后是否存在差异?
- 0.8版本的元信息记录文件仅包含recovery-point-offset-checkpoint和replication-offset-checkpoint;
- 2.2版本的元信息记录文件在保持上述两个文件内容格式不变的情况下,新增meta.properties、log-start-offset-checkpoint和cleaner-offset-checkpoint三个文件。
线上集群升级
批次划分
可能的影响方
- 外部门用户
- 组内
- CJV数据
- 数据同步
- MirrorMaker
- xxx平台topic监听功能
升级方案
配置项 1.基本配置项,需要根据实际集群进行修改:
- broker.id:配置文件server.properties及数据路径下的meta.properties文件;
- listeners:对于使用机器名(非IP)配置的broker,需验证机器IP和机器名映射的IP是否一致,如不一致,则需使用IP进行配置。
2.broker配置项中值得关注的变更:
3.其余配置项,直接追加到新版本配置文件中,并加以注释分割和说明。
手工部署集群升级方案
说明:
- 序号1-8的工作,可以提前操作完成,待正式操作线上前再校验一次;
- 升级broker间通信协议前一定要完全确认集群运行正常!
Cloudera部署集群升级方案
Cloudera部署集群的升级方案,与手工部署集群的升级方案流程大体相同,不同点如下:
- 旧版本服务的启停,是通过Cloudera manager进行操作的;
- 在停止旧版本服务后,必须对数据目录权限进行调整以增加worker账号的读写权限,原因是Cloudera部署的服务是通过kafka账号进行读写的;
- “更新新版本的配置项”步骤中,新增内容“根据brokerId调整预留brokerId范围”,原因是Cloudera自动生成的brokerId是在预留范围以外的
说明:
- 序号1-8的工作,可以提前操作完成,待正式操作线上前再校验一次;
- 升级broker间通信协议前一定要完全确认集群运行正常!
注意事项
- 升级操作应避开集群流量高峰时段;
- 开始操作前,需在用户群中提前通知预计操作时长和潜在影响;
- 先在线上创建测试topic,并启动Producer和Consumer,用于随时观察集群可用性。
升级方案演练
目标 在测试环境对即将进行升级的集群操作进行全流程演练,主要目的有两点:
- 以文档的形式固化操作步骤 (包括每一步的执行人、执行的具体命令/操作、执行耗时 (作为线上操作预计耗时)、检查点,以及可能的回滚方案),供线上操作使用;
- 演练执行并确认回滚步骤的有效性。
其它问题
Cloudera manager操作
- Cloudera manager的部署和操作细节,可能需要多请教佳哥和玉才
- 如果在Cloudera manager UI上操作,需要关注每一步操作对应的后台变更 (可以随手记录积累经验)
集群与Cloudera环境剥离 在本期升级完成后,对Cloudera环境的依赖将仅剩zookeeper,可考虑在后续进行迁移,以完全脱离Cloudera环境
副本数为1 / ISR中只有一个 的topic的处理 这种情况下是否可能有数据丢失,取决于写入的数据是否含key:
- 如果不含key,则某个broker重启过程中,数据会写到其它broker分区中,理论上不会丢失数据;
- 如果含有key,则某些key对应的数据必须写到某个broker,这样,该broker重启过程中,这些数据丢失的可能性就较大,需要提前和用户沟通。
如何判断数据中是否含key呢?使用命令 bin/kafka-run-class.sh kafka.tools.DumpLogSegments -print-data-log -files xxx.log | more 查看落盘的消息格式。
- 具有key的消息内容格式:
offset: 0 position: 0 NoTimestampType: -1 size: 184 magic: 0 compresscodec: NONE crc: 510549616 isvalid: true
| offset: 0 NoTimestampType: -1 keysize: 7 valuesize: 151 crc: 510549616 isvalid: true key: k_abc payload: {"host":{"name":"c-httpserver-te
st-sh-2.ops.prod.bj1"},"env":"prod","source":"/log/httpserver.log","message":"logline - 2","service":"httpserver-test"}
- 没有key的消息内容格式:
offset: 0 position: 0 NoTimestampType: -1 size: 177 magic: 0 compresscodec: NONE crc: 839977979 isvalid: true
| offset: 0 NoTimestampType: -1 keysize: -1 valuesize: 151 crc: 839977979 isvalid: true payload: {"host":{"name":"c-httpserver-test-sh-3.ops.
prod.bj1"},"env":"prod","source":"/log/httpserver.log","message":"logline - 3","service":"httpserver-test"}
数据路径下meta.properties文件中brokerId与集群配置文件中不一致
影响:如果上述两种文件中记录的brokerId不一致,服务会启动失败 原因:之前brokerId有变更 解决:启动服务前修改meta.properties文件中的brokerId,以匹配集群配置文件server.properties中的brokerId;或者,全部删除数据路径下的meta.properties文件
低版本 (0.8.x) 集群中的topic __consumer_offsets 不健康
影响:集群升级到高版本后,高版本consumer API依然不可用 原因:之前brokerId有变更 解决:最好在升级之前删除该topic (执行相关命令进行删除 删除zookeeper元数据 删除数据文件),滚动重启集群,然后再进行升级操作
机器IP和机器名的双向映射不一致
影响:如果broker配置中绑定机器名,则会导致服务无法启动 原因:机器IP变更 解决:修改broker配置项"listeners",绑定机器IP来替换机器名
思考:一个大集群 VS 多个小集群 [TODO]
考虑因素:稳定性 (如,集群之间相互隔离)、运维 (如,便捷程度、重启对客户端的影响) 等 大集群重启broker会慢,在加载数据过程中broker是不可用的。