1. 背景

公司为了快速上线,几个月前通过docker镜像 kafka 部署了一台kafka-borker。

Dockerfile如下




docker集群 openstack docker集群动态扩容_docker集群 openstack


随着业务的增长,单节点的kafka-broker已经成为一个潜在的可靠性隐患。所以借着N年难得一遇的停机维护,决定把kafka-broker扩容为主备集群模式,提升稳定性,并为日后的分区扩容提供可能(不停服)。

2. 问题

除了单节点问题,docker的镜像配置也存在几个问题。

2.1 未指定broker.id

broker.id是kafka-broker的唯一标识,选举、服务查找等操作都是基于此标识。如果没有显式的指定,kafka-broker会由zk生成并下发一个大于1000的id,如:(1001),并保存在kafka-broker本地的meta.properties文件中。如果手动指定broker.id是无法指定大于1000的值。测试环境每次会执行rm -rf操作,但是zk不会同时操作。所以每次重启的brokerId都会+1。为了方便后续管理,需要指定brokerId。


docker集群 openstack docker集群动态扩容_docker修改command_02


2.2 开启自动创建topic

通过KAFKA_AUTO_CREATE_TOPICS_ENABLE开启自动创建topic,会在producer发送消息时创建topic,但是不会指定partition和replica。需要关闭此配置,统一由运维人员审核创建。

2.3 镜像采用了latest标签

开发环境可以使用到最近的镜像,但是生产环境使用此tag,容易造成版本不一致。本次升级过程中遇到的问题,就是基于此,后面会详细介绍。

3. 方案

  1. 制作Dockerfile,修改环境变量。
  2. 停止producer应用
  3. 观察consumer应用消费完成
  4. 部署broker2
  5. 修改测试topic的replica并同步数据
  6. 观察测试topic在broker2中的数据及zk节点元数据
  7. 测试producer及consumer
  8. 批量执行replica脚本
  9. 删除broker1数据并重新部署
  10. 启动应用

3. 1 制作Dockerfile,修改环境变量。


docker集群 openstack docker集群动态扩容_kafka_03


3.2 停止producer应用 & 观察consumer应用消费完成

进入broker docker容器


docker集群 openstack docker集群动态扩容_数据_04


查看group列表


docker集群 openstack docker集群动态扩容_Dockerfile_05


查看group的消费情况


docker集群 openstack docker集群动态扩容_Dockerfile_06


可以看到


docker集群 openstack docker集群动态扩容_docker集群 openstack_07


LAG = LOG-END-OFFSET - CURRENT-OFFSET,如果LAG=0,则表示消息已经消费完成。

3.3 部署broker2

可以将BROKER_ID_COMMAND等环境变量信息,通过 docker run -e的形式执行,本次通过Dockerfile设置,每个broker对应一个Dockerfile。

3.4 修改测试topic的replica并同步数据

通过kafka-reassign-partitions.sh脚本进行replica重分配,分配规则以json文件保存。


docker集群 openstack docker集群动态扩容_数据_08


docker集群 openstack docker集群动态扩容_docker修改command_09


此时出现了故障,因为Dockerfile使用了lastest标签FROM wurstmeister/kafka:latest导致获取到的版本高于生产环境的broker版本,此时日志提示版本问题,无法同步,且kafka-reassign-partitions一直处于pending状态,无法再次执行。


docker集群 openstack docker集群动态扩容_数据_10


解决方案

查找kafka-reassign-partitions强制终止命令

查看源码ReassignPartitionsCommand,只找到verify,没有关闭操作。

删除zk对应节点

kafka-reassign-partitions指定了zk地址,查找在zk中保存的元数据信息,并删除。

kafka/core/src/main/scala/kafka/zk/ZkData.scala


docker集群 openstack docker集群动态扩容_数据_11


zk命令


docker集群 openstack docker集群动态扩容_docker修改command_12


修改dockerfile版本后重新执行kafka-reassign-partitions

再次执行kafka-reassign-partitions,很快执行完成,并在broker2中观察到对应数据。

3.5 批量执行replica脚本

批量脚本内容如下


docker集群 openstack docker集群动态扩容_docker集群 openstack_13


需要提前准备好分配json,并已topic命名,如 __consumer_offsets.json


docker集群 openstack docker集群动态扩容_kafka_14


3.6 删除broker1数据并重新部署

删除broker1镜像数据并重新制作Dockerfile升级。一定要删除镜像数据,否者会优先读取本地的meta.properties,环境变量不会生效。

4. 结论

至此,docker下单节点kafka扩容有惊无险的完成了。