4. Elasticsearch跨集群迁移(CCR):跨集群复制原理、配置CCR、故障切换与恢复
跨集群复制,简称CCR。说白了,就是让两个Elasticsearch集群之间,能实时同步数据。
我最早接触CCR,是在一次数据中心迁移的项目里。老集群在北京,新集群在上海。业务要求零停机,数据不能丢。嗯,那时候我就开始研究CCR了。
4.1 CCR的核心原理
CCR基于Elasticsearch的soft.deletes机制。你可能会问,什么是soft deletes?
简单说,就是文档被删除或更新时,旧版本不会立即物理删除。而是标记为“已删除”,保留一段时间。这个保留期,由index.soft_deletes.retention_lease.period控制,默认12小时。
CCR的工作流程,其实就三步:
- 初始同步:从集群(Follower)先做一次全量恢复,把主集群(Leader)的索引数据完整拉过来。
- 实时跟踪:Follower持续读取Leader的translog(事务日志),获取增量变更。
- 重放操作:Follower把读取到的变更,在自己的索引上重放一遍。
这里有个关键点——CCR是拉模式。Follower主动去Leader拉数据,而不是Leader推给Follower。这样做的好处是,Follower可以控制节奏,不会把集群压垮。
核心概念速查表
| 角色 | 说明 | 我见过的坑 |
|---|---|---|
| Leader索引 | 数据源,可写 | 别在Leader上做force merge,会破坏soft deletes |
| Follower索引 | 副本,只读 | 有人试图直接写Follower,报错后一脸懵 |
| CCR任务 | 复制管道 | 一个Follower只能跟一个Leader,不能多对一 |
4.2 配置CCR的实战步骤
配置CCR之前,有几个前提条件你得先确认:
- 两个集群版本必须一致。我见过有人用7.10和7.17配CCR,结果各种诡异报错。
- Leader集群必须开启soft deletes。7.x之后默认开启,但如果你是从6.x升上来的,记得检查一下。
- 网络要通。Follower能访问Leader的9300端口(transport层)。
4.2.1 在Leader集群上注册Follower
先在Leader集群上,把Follower集群的信息注册进去:
PUT /_cluster/settings
{
"persistent": {
"cluster.remote.follower_cluster.seeds": ["192.168.1.101:9300", "192.168.1.102:9300"]
}
}
我个人习惯把集群别名起得有意义一点。比如dc_shanghai、dc_beijing,别用cluster1、cluster2这种。时间久了你自己都分不清。
4.2.2 在Follower集群上创建CCR任务
有两种方式:
方式一:手动创建Follower索引
PUT /my_index/_ccr/follow
{
"remote_cluster": "leader_cluster",
"leader_index": "my_index"
}
方式二:自动跟随模式
如果你有一堆索引要复制,一个个手动创建太累了。可以用自动跟随:
PUT /_ccr/auto_follow/my_auto_pattern
{
"remote_cluster": "leader_cluster",
"leader_index_patterns": ["logs-*", "metrics-*"],
"follow_index_pattern": "{{leader_index}}-copy"
}
我曾经在一个项目里,用自动跟随模式一次性复制了200多个索引。省了不少事。但要注意,自动跟随只对新创建的索引生效。已有的索引,你还是得手动处理。
4.2.3 监控CCR状态
配置完之后,怎么知道它跑得好不好?
GET /my_index/_ccr/info
重点关注这几个字段:
leader_index_operations:Leader上总操作数follower_index_operations:Follower上已复制的操作数follower_time_since_last_read:上次读取Leader的时间。如果这个值持续增长,说明复制卡住了。read_exceptions:读取异常次数。不为0就要查原因了。
我的小技巧:写一个定时脚本,每小时检查一次follower_time_since_last_read。如果超过5分钟没更新,就发告警。这样能第一时间发现复制延迟。
4.3 故障切换与恢复
CCR最让人头疼的,就是故障切换。说白了,就是Leader挂了,怎么让Follower顶上。
4.3.1 手动故障切换
当Leader集群彻底不可用时,你需要手动把Follower提升为新的Leader:
- 暂停CCR任务:
POST /my_index/_ccr/pause_follow - 关闭只读:
PUT /my_index/_settings { "index.blocks.write": false } - 更新应用配置:把写入地址从Leader改成Follower
嗯,这里有个坑。我曾经在切换时忘了暂停CCR任务,结果Leader恢复后,Follower还在尝试连接,导致数据冲突。所以顺序很重要——先暂停,再切写。
4.3.2 故障恢复后的数据回迁
Leader恢复后,你想把数据迁回去。怎么做?
我的建议是:
- 在原来的Leader上,创建一个新的CCR任务,从Follower复制数据回来。
- 等数据追平后,再切一次写入。
- 删除旧的CCR任务。
说白了,就是角色互换。原来的Leader变成Follower,原来的Follower变成Leader。等数据同步完了,再换回来。
警告:千万不要在故障切换后,直接删除Leader索引重建CCR。那样会丢失未同步的数据。正确的做法是,保留Leader索引,等数据追平后再做切换。
4.3.3 自动故障切换(收费功能)
如果你用的是Elasticsearch白金版,可以配置自动跟随和自动切换。但说实话,我建议你还是手动操作更稳妥。自动切换虽然方便,但一旦出问题,排查起来很麻烦。
你想想看,自动切换的逻辑是:检测到Leader不可用 → 自动提升Follower → 通知应用切换写入。这个链条上任何一个环节出问题,都可能导致数据不一致。而手动操作,至少每一步你都知道发生了什么。
4.4 避坑指南
最后,分享几个我踩过的坑:
- 版本不一致:CCR要求主从集群版本完全一致。小版本不同也不行。我吃过7.10.0和7.10.1的亏。
- 磁盘空间:Follower需要跟Leader一样多的磁盘空间。别以为Follower只存增量数据,初始同步是全量拷贝。
- 网络延迟:跨机房复制时,网络延迟会导致复制延迟。如果延迟超过soft deletes保留期(默认12小时),复制会失败。建议跨机房场景下,把保留期改成24小时。
- Mapping变更:Leader索引的mapping变了,Follower不会自动同步。你得手动更新Follower的mapping,否则新字段的数据会丢失。
CCR是个好东西,但也不是银弹。它适合做灾备、做读写分离、做数据中心迁移。但如果你需要双向同步,或者需要跨版本迁移,那CCR就不太合适了。选工具之前,先想清楚自己的场景。