博客
关于我
clickhouse集群zookeeper平滑搬迁实践
阅读量:463 次
发布时间:2019-03-06

本文共 3369 字,大约阅读时间需要 11 分钟。

Zk 集群跨洲迁移方案

背景

自去年年底,我们开始规划从香港到新加坡机房迁移ClickHouse(简称“ck”)集群。目前,ck集群所有实例已成功迁移到新加坡机房,仅留下依赖的Zookeeper(简称“zk”)集群在香港机房。近期,我们计划将zk集群平滑迁移到新加坡机房。

目标与挑战

1.1 Zk 跨洲迁移需对用户基本无感知

ck集群承载公司实时数据分析需求,支持多线上服务。ck集群不可停机,任何时刻都需保持可用状态。ck的架构设计高度依赖zk进行元数据存储、副本同步及表变更管理。一旦zk不可用,ck的读写都会受到影响。在zk集群迁移期间,leader切换会导致读写问题,这是一个不小的挑战。

1.2 热升级+动态配置更新

为实现目标,我们在迁移过程中采取以下措施:

  • 从写入层做好重试,避免zk切主过程中的失败。
  • 尽量缩短zk不可用的时间。
  • 对zk操作采用热升级方式,滚动操作。
  • 因为zk集群IP全部更换,需更改大量配置,尽量采用reload方式,而非重启服务。

整体方案

2.1 第一步:Zk从静态配置版本升级到动态配置版本

zk 3.5.0版本后支持动态配置特性,可方便扩容和缩容操作,无需对整个zk集群进行滚动重启。然而,当前ck所用的zk集群尚未采用动态配置,因此迁移的第一步是将zk集群从静态配置版本平滑升级到动态配置版本。升级详情可参考相关文档。

2.2 第二步:Zk扩缩容实现搬迁

在ck集群升级到动态配置版本后,通过扩容和缩容操作实现zk集群从香港老机房到新加坡新机房的平滑迁移。具体步骤如下:

  • 扩容:将新加坡机房的新机器一台一台加入到zk集群中。

    • 通过reconfig -add命令逐步添加新机器,确保每台机器加入后检查集群状态和ck读写情况。
    • 新机器配置包含香港老机房和新加坡新机房的所有zk实例。
  • 修改ck配置:将ck配置中的zk服务器列表全部更换为新加坡新机房的IP地址。

    • 检查所有ck实例是否成功连接到新配置的zk实例,确保无异常。
  • 缩容:将香港老机房的老机器一台一台从zk集群中摘除。

    • 优先缩容Follower实例,最后缩容Leader实例。
    • 每次缩容后检查集群状态和ck读写情况,确保无异常。
  • 遇到的问题和解决方案

    2.1 Zk静态配置版本与动态配置版本不兼容

    在升级Follower实例时,发现升级过程中Follower实例会报错:

    Follower报错日志如下:java.io.EOFException    at java.io.DataInputStream.readInt(DataInputStream.java:392)    at org.apache.jute.BinaryInputArchive.readInt(BinaryInputArchive.java:63)    at org.apache.zookeeper.server.quorum.QuorumPacket.deserialize(QuorumPacket.java:85)    at org.apache.jute.BinaryInputArchive.readRecord(BinaryInputArchive.java:99)    at org.apache.zookeeper.server.quorum.Learner.readPacket(Learner.java:158)    at org.apache.zookeeper.server.quorum.Learner.registerWithLeader(Learner.java:336)    at org.apache.zookeeper.server.quorum.Follower.followLeader(Follower.java:78)    at org.apache.zookeeper.server.quorum.QuorumPeer.run(QuorumPeer.java:1271)

    此外,尚未升级的Leader实例也会报错:

    Leader报错日志如下:java.io.IOException: Follower is ahead of the leader (has a later activated configuration)    at org.apache.zookeeper.server.quorum.LearnerHandler.run(LearnerHandler.java:398)

    问题原因:

    • 升级过程中,静态版本的Leader与动态版本的Follower实例同时存在,导致config version不一致。
    • Follower启动后会请求Leader,Leader发现Follower的config version大于自身,抛异常并关闭连接。

    解决方案:

    • 采用方案二:先将静态版本升级为不带config version检查的静态版本,再升级为动态版本。
    • 该版本中去掉Leader对Follower的config version检查,绕过问题。

    2.2 Ck无法动态加载zk配置

    在线下演练过程中发现,修改clickhouse配置文件中的zk服务器列表后,配置变更无法动态加载。

    解决方案:

    • 增加clickhouse对zk配置动态加载的支持,目前已合并至社区,相关PR已完成。

    2.3 Zk实例重启导致少量ck查询失败

    CK查询通常不涉及zk交互,因此zk迁移大部分情况下不影响ck查询。

    但在开启optimize_trivial_count_query后,对应的select count查询会受到影响。
    解决方案:

    • 在zk迁移前,将optimize_trivial_count_query设置为0,迁移完成后再重新开启。

    2.4 Zk实例重启导致写入ck失败

    CK写入数据时依赖zk集群分配blockid并同步数据。

    解决方案:

    • 确保写入入口(如Flink、Spark、clickhouse_sinker)具有重试机制。
    • 在zk迁移期间,监控写入过程,确保异常情况下能快速恢复。

    2.5 Zk实例重启导致ck表变更失败

    ck表变更操作(如创建/删除表、新增/删除/修改字段)会访问zk集群。

    解决方案:

    • 在zk迁移期间,对ck平台进行功能降级,禁用表变更操作。

    最终的搬迁方案

    3.0 初始状态

    香港机房:A1, A2, A3, A4, A5

    新加坡机房:B1, B2, B3, B4, B5

    初始状态下,zk集群部署于香港机房,初始版本为静态配置版本。

    3.1 升级到动态配置版本

    升级路线:静态版本 → 不带config version检查的静态版本 → 动态版本。

    3.1.1 静态版本 → 不带config version检查的静态版本

    • 串行升级,先升级Follower,再升级Leader。
    • 每升级完一台机器,检查集群状态和ck读写情况。
    • 升级完成后,启动zk实例并等待其稳定。

    3.1.2 不带config version检查的静态版本 → 动态版本

    • 串行升级,步骤与3.1.1相同。
    • 升级完成后,启动zk实例并等待其稳定。

    3.2 动态扩缩容

    3.2.1 扩容:将新加坡新机器加入到zk集群中

    • 串行扩容,逐台添加新机器。
    • 使用reconfig -add命令添加新机器,确保每台机器加入后检查集群状态和ck读写情况。
    • 新机器配置包含香港老机房和新加坡新机房的所有zk实例。

    3.2.2 修改ck配置:将zk配置改成新加坡新机器

    • 修改ck配置文件,将zookeeper-servers列表从旧机器A1-A5更换为新机器B1-B5。
    • 检查ck实例是否成功连接到新配置的zk实例,确保无异常。

    3.2.3 缩容:将香港老机器从zk集群中摘掉

    • 串行缩容,优先缩容Follower实例,最后缩容Leader实例。
    • 使用reconfig -remove命令逐台摘除老机器,确保每台机器下线后检查集群状态和ck读写情况。

    总结

    通过线下环境中的充分演练,我们及时发现了zk迁移中的各种问题,并采取了相应的解决方案。最终,在ck用户基本无感知的情况下,完成了zk集群从香港到新加坡的平滑迁移。

    转载地址:http://ksmfz.baihongyu.com/

    你可能感兴趣的文章
    Openlayers中设置定时绘制和清理直线图层
    查看>>
    Openlayers图文版实战,vue项目从0到1做基础配置
    查看>>
    Openlayers实战:modifystart、modifyend互动示例
    查看>>
    Openlayers实战:判断共享单车是否在电子围栏内
    查看>>
    Openlayers实战:绘制图形,导出geojson文件
    查看>>
    Openlayers实战:绘制图形,导出KML文件
    查看>>
    Openlayers实战:绘制多边形,导出CSV文件
    查看>>
    Openlayers实战:输入WKT数据,输出GML、Polyline、GeoJSON格式数据
    查看>>
    Openlayers高级交互(10/20):绘制矩形,截取对应部分的地图并保存
    查看>>
    Openlayers高级交互(11/20):显示带箭头的线段轨迹,箭头居中
    查看>>
    Openlayers高级交互(14/20):汽车移动轨迹动画(开始、暂停、结束)
    查看>>
    Openlayers高级交互(15/20):显示海量多边形,10ms加载完成
    查看>>
    Openlayers高级交互(16/20):两个多边形的交集、差集、并集处理
    查看>>
    Openlayers高级交互(17/20):通过坐标显示多边形,计算出最大幅宽
    查看>>
    Openlayers高级交互(19/20): 地图上点击某处,列表中显示对应位置
    查看>>
    Openlayers高级交互(2/20):清除所有图层的有效方法
    查看>>
    Openlayers高级交互(3/20):动态添加 layer 到 layerGroup,并动态删除
    查看>>
    Openlayers高级交互(6/20):绘制某点,判断它是否在一个电子围栏内
    查看>>
    Openlayers高级交互(7/20):点击某点弹出窗口,自动播放视频
    查看>>
    Openlayers高级交互(8/20):选取feature,平移feature
    查看>>