记一次 Cassandra 在 k8s 环境下的数据中心迁移
背景
之前使用 cass-operator 在 k8s 上搭建了一个 cassandra 集群用来做存储,随着业务数据的增长,之前申请的 100 G 的 PVC 大小已经是捉襟见肘
急需更换到更大的磁盘空间上
最开始的时候其实有考虑到 pvc 扩容的可能,特地申请了一个允许扩展容量的存储类型(storage class)
但是后来发现,如果直接修改对应 pvc, 整个集群的资源实际上还是由 cass-operator 管理的,这意味着一旦重启、修改 datacenter 配置项,可能会把容量给改回去,有不小的可能性直接翻车。
cass-operator 本身提供添加 node 来横向扩容的特性,我们可以直接添加集群中 cassandra 实例的数量, cass-operator 会帮我们把数据重新平衡到新的节点上,并在数据移动完成后自动执行 nodetool cleanup
任务,从而清理出磁盘空间。
不幸的是,目前 cass-operator 还没有提供一个简单的方式来扩容 pvc
但这个方法只是缓兵之计,因为这会造成 cpu/内存 资源上的浪费,这两个资源并没有到达瓶颈。当我们调整完磁盘的容量后,其实是可以通过这个方式来扩容的。
当然我们也可以通过手动导出 sstable 的方式,在同一拓扑的其他集群上装载数据,但是这个方法有需要先停机维护,可能需要几个小时的时间,会影响生产环境的正常使用
所以,经过广泛的查阅文档 / google / stackoverflow ,对比后发现还是使用迁移数据中心的方式比较轻松
- 创建新 dc 集群
- 修改keyspace配置参数, 迁移数据
- 修改客户端连接参数
- 验证数据,清理旧集群
开始迁移
首先准备新 dc 文件,和旧 dc 文件基本相同,修改的部分只有 metadata
中的 datacenter 名称,以及 pvc 申请的容量
部分和业务相关的信息用中括号标明,实际使用时请按自己的情况做替换
这里旧集群是 dc1, 新集群是 dc2
1 | apiVersion: cassandra.datastax.com/v1beta1 |
将上述文件 kubectl applly -f
应用到集群中,等待 cassandra 新的实例都启动后,我们就可以尝试连接新 dc 的实例了。
用户名和密码都是使用之前 secret 里面的同一套
直接连接的话,大概率会报错
1 | Cannot achieve consistency level LOCAL_ONE info={required_replicas 1 alive_replicas: 0, consistency: QUORUM } |
参见对应文档:https://docs.datastax.com/en/security/5.1/security/secSystemKeyspace.html
我们需要修改系统认证用到的 keyspace 的副本分布
1 | ALTER KEYSPACE system_auth |
修改完成后,需要手动运行 repair 任务
1 | nodetool repair --full system_auth |
这样我们就能正常登录到新 dc 的实例了。
迁移数据
将自己定义的 keyspace 分配副本的策略进行修改,我是在 akka projection 场景下使用,所以会涉及到这么几个 keyspace 需要修改
原来的分布是在 dc1 集群上存储有3个副本,现在需要在 dc2 上面也存储 3 个副本
1 | ALTER KEYSPACE akka |
同样地,我们在修改完 keyspace 之后也需要做修复工作
1 | nodetool repair --full -tr akka |
当然也可以直接 nodetool repair --full -tr
修复所有 keyspace, 但是在实际过程中,修复的时候老是有 k8s node 重启,引发修复失败,所以我拆成较小的部分修复。
修复过程中可以通过 nodetool status
观察各个节点加载的数据大小,用来检验数据是否被正常加载到新集群。
数据修复的时间,和数据大小已经网速有关,我这里迁移 240 G 数据大约花费了一个小时
客户端配置修改
通过 java-driver 连接需要修改连接的数据中心
对于 datastax-java-driver 需要修改
datastax-java-driver.basic.load-balancing-policy.local-datacenter
对于 quill 需要修改
session.basic.load-balancing-policy.local-datacenter
这两个配置项需要指定到新的 dc2 ,配置修改后重启 deployment 以生效
重启完成后,保险起见可以再次运行一遍 nodetool repair
以确保数据完整
此时可以观察到 dc1 的网络流量,cpu使用情况应该都比较低了,因为所有的请求都是从 dc2 走
验证和清理
我们首先把修改业务表副本拓扑分配
1 | ALTER KEYSPACE akka |
这次修改就不用运行修复任务了,因为之后我们会把整个旧集群都直接删除。
临时停用旧集群节点以验证服务可用性,这里我没有想到好办法能不删除 pvc 停用,用的是手动替换镜像的方式,比如把 /cass-management-api:4.0.1
替换成一个可用的 aws-cli:2.4.17
镜像,这样 pod 能启动,但是对应的健康检查过不去,外部请求到旧集群实际不可用
临时停用节点
1 | <docker-registry-url>/k8ssandra/cass-management-api:4.0.1 |
在此情况下调用接口以验证数据是否正常
验证完毕后,修改认证使用到的 keyspace ,移除 dc1 的副本
1 | ALTER KEYSPACE system_auth |
以上验证完毕后就可以回收资源了
使用 kubectl delete -f
删除对应的 dc
使用 nodetool 删除节点
1 | cassandra@dc2-default-sts-0:/$ nodetool status |
1 | nodetool removenode 821d2534-0ea9-4c7c-a312-0e6047569503 |
至此,所有迁移工作完成撒花
2023 更新
之后由于其他需求,需要把部分 cassandra 里面的数据垂直迁移,又做了一遍迁移的步骤。
发现这里其实不应该使用 nodetool repair
,因为 repair 会把对比新旧两个数据中心的数据以后再开始数据传输。
然而,新的数据中心里面的数据是空的,根本没有需要进行数据对比的必要
这里的数据量比较大,所以会很慢,而且会占用很多的网络带宽
所以这里应该使用 nodetool rebuild
,这个命令只会把缺失的数据读取过来,不会读取已经存在的数据,所以会快很多
1 | # 注意此处一定要指定 nodetool rebuild 的数据中心 |
还有一点需要注意的是,在执行迁移操作时,一定要确保客户端的读、写一致性级别正确被设置
要防止客户端过早连接到新数据中心,并确保读取或写入的一致性级别不会查询新数据中心:
确保客户端配置为使用 DCAwareRoundRobinPolicy
。
确保客户端指向现有数据中心,这样他们就不会尝试访问新的数据中心,因为新数据中心可能没有任何数据。
如果使用QUORUM
一致性级别,需要更改为LOCAL_QUORUM
。
如果使用ONE
一致性级别,需要设置为LOCAL_ONE
。
如果客户端应用程序未正确配置,它们可能会在数据中心就绪之前连接到新的数据中心。这会导致连接异常、超时和/或数据不一致。
以 akka projection 的默认配置为例, 默认的一致性级别是 QUORUM
, 就需要设置成 LOCAL_QUORUM
1 | datastax-java-driver { |
数据迁移完成后,可以手动执行 nodetool compact
来压实数据,这样可以节省一些磁盘空间
参考链接
版权声明:
除另有声明外,本博客文章均采用 知识共享(Creative Commons) 署名-非商业性使用-相同方式共享 3.0 中国大陆许可协议 进行许可。
分享