TongSearch跨集群复制CCR原理与数据同步实践
2026/9/10 9:32:01 网站建设 项目流程

先聊个实际场景:你手上有两个 TongSearch 集群,一个在主中心承载线上写入,另一个在异地机房,平时只读、用于查询和灾备。业务量上来之后,主库压力越来越大,你想把一部分读流量切到异地机房,却发现两边数据根本对不上。或者更惨一点,主中心某台机器磁盘坏了,索引分片丢失,你想从异地集群把数据再拉回来,结果发现只能重新灌数据。这些问题的标准解法,就是跨集群复制(Cross-Cluster Replication,CCR)。TongSearch 作为兼容 Elasticsearch 生态的分布式搜索系统,把 CCR 作为核心高级特性内置了进来。

这篇内容我会完整拆解 TongSearch 跨集群复制的数据同步流程,从底层原理、配置参数、创建步骤到常见的坑,一次性讲清楚。适合正在部署多地多中心架构的运维、中间件负责人、后端开发,以及所有被“集群间数据同步”折磨过的人。

1. 内容整体设计与思路拆解

1.1 跨集群复制到底解决什么问题

先说需求,跨集群复制本质上解决的是“数据在多个集群之间如何保持一致”的问题,但它和普通的消息同步、ETL 同步不同,CCR 工作在一个更底层的维度——分片级别。

TongSearch 的索引由多个分片组成,每个分片底层是 Lucene 索引。CCR 做的事情,就是在两个集群之间建立“领导索引”和“跟随索引”的对应关系,让跟随索引的每个分片持续从领导索引的对应分片拉取操作日志,然后重放到本地。这个过程用户无感知,业务方就像操作一个普通索引一样去读跟随索引。

主要解决以下三类问题:

  • 灾备:主集群整体故障时,从集群拥有完整的数据副本,可以随时切换读流量甚至升级为写集群。
  • 读写分离:写入集中到主集群,查询分散到从集群,降低主集群压力。
  • 就近访问:不同地域的用户访问最近机房的集群,减少跨机房 RT。

和基于主从复制实现的方案比,CCR 的最大特点就是“跨集群”。它不需要两个集群在同一个集群内,也不要求集群间有共享存储,只要求网络层面能互相访问。这个灵活性很关键,因为它把复制能力从“单集群内部”扩展到了“多集群架构”。

1.2 同步流程的底层原理

CCR 的核心机制,是跟随集群(Follower)主动从领导集群(Leader)拉数据,而不是领导集群主动推数据过来。

完整流程可以拆成两段:

第一段是初始同步。创建跟随索引时,底层会先做一次全量数据拷贝。TongSearch 会把领导索引的 Lucene 分片文件通过快照方式拉到跟随集群,生成分片副本。这个阶段的数据量取决于索引大小,如果索引很大,耗时可能很长。

第二段是增量同步。全量拷贝完成后,跟随集群会持续从领导集群拉取领导索引的 translog(事务日志),把增量操作重放到本地分片。每次重放之前,会先记录一个检查点(checkpoint),标记“我已经同步到哪条日志了”。下次拉取就从这个 checkpoint 往后继续。

这里有一个容易被忽略的细节:CCR 是“从跟随端拉取”,不是“领导端推送”。这意味着领导集群不需要额外配置任何推送逻辑,甚至不知道有跟随集群存在。这个设计带来的好处很实际——领导集群不会因为下游同步而增加性能负担,也避免了推模式下的复杂流量控制。

1.3 为什么是“从端主动拉”而不是“主端推送”

我见过不少人第一次接触 CCR 时会问:为什么不是主集群直接推给从集群,这样实时性不是更好?

答案是:推模式在实际运维中很难控。主集群一旦承担推送职责,就要同时管理所有下游集群的状态、速率、失败重试,下游集群的数量一变多,主集群的负担和复杂度都会上升。而拉模式把控制权完全放在从端,从集群根据自己的处理能力决定拉取速率,主集群只需要像对待普通读请求一样处理从集群的拉取请求。

这个设计还带来一个额外优势:网络策略简单。只需要从集群能够访问主集群,不需要主集群反向访问从集群,也不用开放额外的入站端口,安全策略可以收敛得很干净。

1.4 复制延迟的组成

说完了整体架构,再说延迟。CCR 的复制不是实时的,必然存在一个“从写入领导索引到在跟随索引可见”的时间差,主要由三部分组成:

  • 轮询间隔:跟随集群周期性去领导集群拉取新日志的间隔。
  • 网络传输耗时:日志数据从领导集群传到跟随集群的时间。
  • 重放耗时:跟随集群把日志写入本地索引的时间。

理解延迟组成很重要,因为后面排查“为什么从集群数据一直追不上主集群”的问题时,基本上就是从这三个方向去定位。

2. 核心细节解析与实操要点

2.1 集群白名单配置

真正开始配置 CCR 之前,需要先确认 TongSearch 的集群配置里打开了远程集群访问的白名单。这一步容易漏,漏掉之后配置远程集群时会一直报连接失败。

在 TongSearch 的elasticsearch.yml中,需要设置:

cluster.remote.connect: true

如果集群启用了安全认证,还需要配置跨集群访问的用户名密码等信息。另外,TongSearch 支持通过search.remote.connections_per_cluster控制每个远程集群的连接数,这个参数默认值一般够用,但如果两个集群之间索引数量较多,可以适当调大。

配置完成后需要重启集群生效,注意这一步务必要做,否则后面配置 remote cluster 即使返回成功,实际同步请求也会报错。

2.2 远程集群注册

远程集群注册使用的是动态配置,不需要重启集群。TongSearch 兼容 Elasticsearch 的上游 API,标准做法是通过_cluster/settings接口写入远程集群地址信息。

PUT /_cluster/settings { "persistent": { "cluster.remote.leader01.seeds": ["192.168.1.10:9300", "192.168.1.11:9300"] } }

这里的leader01是远程集群别名,后续创建跟随索引时要用到。seeds写的是领导集群的 transport 端口地址,不是 HTTP 端口。

配置生效后,可以先用下面的命令验证远程集群是否已连接:

GET /_remote/info

返回结果里会列出已配置的远程集群和节点信息。这一步实测下来非常有用,能第一时间确认网络连通性和集群命名是否对得上。

2.3 创建跟随索引的参数解读

远程集群注册好之后,就可以创建跟随索引了。创建跟随索引的请求格式如下:

PUT /logs_replica/_ccr/follow?wait_for_active_shards=1 { "remote_cluster": "leader01", "leader_index": "logs" }

请求里面两个核心参数,remote_cluster指定远程集群别名,leader_index指定远程集群上的源索引名。跟随索引的名称就是请求路径中的logs_replica,可以自定义,不需要和领导索引一致。

这个接口还有一批可选参数用来控制复制行为和性能,这一块是优化数据同步流程的关键。

以下参数建议重点关注:

参数名默认值作用说明
max_read_request_operation_count5120单次从领导端拉取的最大操作数
max_read_request_size32mb单次拉取的最大数据量
max_outstanding_read_requests12允许同时处于读取状态的最大请求数,决定读取并发度
max_write_request_operation_count5120单次写入跟随端的最大操作数
max_outstanding_write_requests9允许同时处于写入状态的最大请求数
max_write_buffer_count2147483647写入缓冲区最大请求数限制
max_write_buffer_size512mb写入缓冲区最大内存限制
max_retry_delay500ms同步失败后的最大重试延迟,会指数退避增长
read_poll_timeout1分钟当没有新数据可拉取时,长轮询等待的时间

这些参数不需要每次创建都调,但如果遇到同步性能瓶颈,调整空间就在这里。比如需要提高吞吐时,可以把max_outstanding_read_requestsmax_outstanding_write_requests一起调大。如果带宽有限,应该限制单次读取大小和并发度,避免拉取速度过快导致网络拥塞。

2.4 弹性扩展操作:恢复、暂停、取消

CCR 机制还提供了几个日常运维经常用到的操作:

  • 暂停同步:POST /<index>/_ccr/pause
  • 恢复同步:POST /<index>/_ccr/resume
  • 取消同步:DELETE /<index>/_ccr/follow

暂停和恢复的典型场景是集群升级。比如跟随集群需要滚动重启时,可以先把同步暂停,等所有节点恢复后再开启同步。CCR 有 checkpoint 机制,暂停期间产生的增量日志不会丢,恢复后会自动从上次的检查点继续拉取。

取消同步的操作要谨慎,取消后跟随索引变成一个独立的普通索引,不再从领导集群拉取数据,这个操作不可逆。

3. 实操过程与核心环节实现

3.1 环境准备

为了把流程讲清楚,我这里用两个集群的测试环境作为示例:

  • 领导集群:集群名leader01,三个节点,IP 分别是 192.168.1.10 / 192.168.1.11 / 192.168.1.12
  • 跟随集群:集群名follower01,三个节点,IP 分别是 192.168.1.20 / 192.168.1.21 / 192.168.1.22

两个集群版本保持一致,TongSearch 版本选择当前稳定版本。领导集群有一个用于业务写入的索引product_orders,需要同步到跟随集群供查询使用。

先确认领导集群上索引状态正常:

GET /product_orders/_count

返回结果能正常显示文档数,说明领导索引可用。

3.2 配置跟随集群的远程连接

在跟随集群的elasticsearch.yml中加上:

cluster.remote.connect: true

重启跟随集群的所有节点。

然后向跟随集群发起远程集群注册:

PUT /_cluster/settings { "persistent": { "cluster.remote.leader01.seeds": ["192.168.1.10:9300", "192.168.1.11:9300", "192.168.1.12:9300"] } }

建议 seeds 里写多个节点地址,这样即使其中一台节点短暂不可用,连接也能自动切换。

注册后检查连接状态:

GET /_remote/info

返回结果中connected字段为true时,说明远程集群连接正常。这一步实测下来经常遇到connected: false的情况,多半是 transport 端口不通,或者集群名不匹配,需要先排查这两项。

3.3 创建跟随索引

执行创建跟随索引的请求:

PUT /product_orders_replica/_ccr/follow?wait_for_active_shards=1 { "remote_cluster": "leader01", "leader_index": "product_orders" }

返回结果中acknowledgedtrue,且分片状态转为active,说明初始同步已经启动。

等待一段时间后,查看同步状态:

GET /product_orders_replica/_ccr/info

返回信息中会包含每个分片的同步状态、检查点位置、延迟时间等关键信息。注意观察follower_indexremote_clusterleader_index是否正确指向目标集群和索引。

3.4 验证同步结果

为了验证同步是否正常,我在领导集群上写入一条新数据:

POST /product_orders/_doc { "order_id": "20250118001", "amount": 199.00, "status": "PAID" }

然后查询跟随索引:

GET /product_orders_replica/_search { "query": { "term": { "order_id": "20250118001" } } }

如果查询能返回刚写入的数据,说明增量同步链路是通的。

再做一个简单的断点验证。暂停同步:

POST /product_orders_replica/_ccr/pause

再往领导集群写入几条数据,然后恢复同步:

POST /product_orders_replica/_ccr/resume

等待一段时间后查询跟随索引,确认暂停期间的数据也补齐了。这个验证非常值得做,有实际生产价值,我每次配置完 CCR 都会做一遍。

3.5 同步状态监控

要说真正维护 CCR,日常要盯的还是同步监控。TongSearch 提供了一套专门的 CCR 监控接口:

GET /product_orders_replica/_ccr/stats

这个接口返回的字段非常多,核心关注这些:

  • operations_received:接收的操作总数
  • operations_indexed:已写入跟随索引的操作总数
  • failed_read_requests:读取失败请求数
  • failed_write_requests:写入失败请求数
  • read_exceptions:读取异常信息
  • time_since_last_read:距上次读取的时间,是判断延迟的核心指标

如果time_since_last_read持续增大,说明跟随集群已经有很长时间没有从领导集群拉取数据,复制链路可能已中断。这种情况下需要检查网络、领导集群节点状态、以及远程集群连接是否正常。

另外集群维度还有一个全量查看接口:

GET /_ccr/stats

可以一次看到所有跟随索引的同步状况,适合做整体巡检。

3.6 参数调优实测

默认参数下,小数据量的索引同步基本无感,但数据量一旦上来,就需要根据实际场景调整参数。

我在测试环境做过一次调优实验。领导集群有一个约 200GB 的索引,业务高峰期每分钟写入约 2 万条文档。默认参数下,跟随索引的延迟会逐渐累积,从最初的秒级延迟漂移到分钟级。

随后我调整了以下参数:

PUT /product_orders_replica/_ccr/follow?wait_for_active_shards=1 { "remote_cluster": "leader01", "leader_index": "product_orders", "max_read_request_operation_count": 10000, "max_read_request_size": "64mb", "max_outstanding_read_requests": 24, "max_write_request_operation_count": 10000, "max_outstanding_write_requests": 18, "max_write_buffer_size": "1024mb" }

调整后,延迟逐渐回落并稳定在秒级。这个实验验证了一个经验:默认参数比较保守,适合小索引和低写入压力;高写入场景下,主要瓶颈通常不是网络,而是单次拉取的数据量和并发度不够,适当调高并发能明显改善同步延迟。

但也要提醒一点,调参不是无脑调大。max_outstanding_write_requests过大会导致跟随集群本地写入队列堆积,反而加重节点负担。建议调参时同步观察集群的 CPU、内存和磁盘写入延迟,找到平衡点。

4. 常见问题与排查技巧实录

4.1 复制延迟持续增大

这是 CCR 日常运维里遇到最多的问题。延迟持续增大的原因一般有三种:

  • 跟随集群写入能力不足。检查跟随集群节点的 CPU、IO、磁盘水位,如果资源使用率已经很高,先扩容或削减查询压力。
  • 网络带宽受限。拉取的数据量超过带宽上限,传输速度跟不上写入速度。这种情况通过监控网络流量可以确认,解决思路是限制同步并发,或者升级带宽。
  • 单个分片的数据量过大,导致分片内重放耗时高。解决思路是在领导索引设计阶段就把分片数规划好,避免单个分片过大。

排查工具方面,GET /<index>/_ccr/stats返回的time_since_last_readread_exceptions是最直接的定位入口。

4.2 创建跟随索引后一直处于初始化状态

初始化状态卡住,通常和网络或权限有关。先检查远程集群连接:

GET /_remote/info

如果连接正常,再看领导集群的日志,确认是否有拉取请求到达。如果领导集群开启了安全认证,还需要检查跨集群访问的用户是否有权限读取源索引。

另一个容易被忽略的原因是源索引状态异常。如果领导索引是red状态,部分分片不可用,初始同步也会卡住。这时候优先修复领导集群的分片分配问题。

4.3 mapping 变更不同步

这是一个设计上的限制:CCR 不会自动同步领导索引的 mapping 变更,也不会同步aliases等索引元数据变更。

也就是说,如果业务在领导集群上给某个字段新增了一个子字段、修改了分词器,跟随索引那边不会自动更新 mapping,查询里用到新字段时会直接报错。

目前可行的做法是:在领导集群执行 mapping 更新后,手动在跟随索引上执行同样的 mapping 更新操作。建议把 mapping 变更流程纳入工单系统,在源端变更后同步通知跟随集群执行变更。

4.4 领导索引被删除后跟随索引不会自动删除

CCR 有一个需要重点关注的行为:当领导索引被删除时,跟随索引不会自动删除。这是因为删除操作本身不会写入 translog 的同步链路,CCR 机制感知不到源端索引的删除。

这意味着如果业务在领导集群上删了索引,跟随集群上的副本仍然存在,会持续占用磁盘空间。如果你的运维规范里有定期清理索引的流程,记得在清理领导索引之后,同步清理掉对应的跟随索引。

4.5 CCR 与备份的关系

最后提一个非常重要的原则:跨集群复制不是备份。

CCR 保证的是“数据在多个集群间的一致性”,但如果你在领导集群上执行了错误的批量删除或 update,这个错误操作会通过同步链路放大到所有跟随集群。而且跟随集群保存的是和领导集群一样的逻辑数据,不具备数据恢复功能。

生产环境一定要在 CCR 之外,另外配置快照备份机制。TongSearch 支持将索引备份到远端对象存储或共享文件系统,建议把快照备份作为最后一道防线,CCR 作为高可用和读写分离的手段,两者各司其职。

4.6 网络抖动导致的同步中断

最后分享一个实际案例。之前遇到过一台领导集群节点因为磁盘 IO 飙升,导致网络请求大量超时,跟随集群的同步任务反复失败,虽然系统会自动重试,但重试期间积累的数据较多,恢复后同步延迟飙升到十几分钟。

排查后确认是领导集群的单节点问题,故障节点恢复后同步自动追平。但整个过程中如果业务在跟随集群上做实时查询,会看到明显的延迟波动。

这类问题很难彻底避免,能做的是在架构层面加一层保护:在应用层对跟随集群的查询设置“允许的最大数据延迟”检查,当延迟超过阈值时自动切换到领导集群查询,避免业务读到明显过期的数据。

5. 后续扩展:更多复制模式

TongSearch 的跨集群复制除了单索引复制之外,还支持自动跟随模式,可以在远程集群上配置一个索引模板匹配规则,远程集群只要新建了符合条件的索引,跟随集群就会自动创建对应的跟随索引。

比如可以这样配置:

PUT /_ccr/auto_follow/leader01_auto { "remote_cluster": "leader01", "leader_index_patterns": ["logs-*", "metrics-*"], "follow_index_pattern": "{{leader_index}}-copy" }

这个功能特别适合日志和监控类场景,索引按天或按小时滚动创建,手动逐个配置跟随索引不现实,自动跟随可以省掉大量重复操作。

需要留意的是,自动跟随配置本身也要纳入运维管理。每次新增的索引是否符合预期,需要定期巡检,避免某些索引被自动复制了但业务并不需要。

写在后面一点实操经验

跨集群复制这套东西,难的不是配置那几步 API,而是理解它背后的同步模型和边界条件。我在实际部署里总结了几条经验,简单写一下供参考。

第一,资源配置上,跟随集群的规格不要低于领导集群。很多人会觉得跟随集群只是“读”,配置差一点没关系,但 CCR 的同步要执行和领导集群等量的写操作,同时还要承担查询流量,资源不够的话延迟会持续累积,最后变成一个怎么调都追不上的烂摊子。

第二,监控一定要提前做,不要等出了问题再去看。把 CCR 的同步延迟、失败请求数、网络流量纳入现有监控体系,设定延迟阈值的告警,比如超过 60 秒就报警。同步沉默性故障太害人了,表层一切正常,实际上数据已经落后很久了。

第三,版本升级要谨慎。跨集群复制的两个集群版本必须保持兼容,升级时先升跟随集群,再升领导集群,避免出现跨大版本复制不兼容的情况。升级前先暂停同步,等两边集群都稳定再恢复。

跨集群复制是一个越用越觉得顺手的能力,但它的前提是稳定可靠的网络、足够的资源冗余,以及一个不依赖人工盯守的监控体系。把这三件事做好,CCR 能帮你省掉大量跨机房数据同步的烦恼;做不好,它会变成生产环境新的不稳定源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询