TongSearch跨集群复制CCR原理与数据同步实践
先聊个实际场景你手上有两个 TongSearch 集群一个在主中心承载线上写入另一个在异地机房平时只读、用于查询和灾备。业务量上来之后主库压力越来越大你想把一部分读流量切到异地机房却发现两边数据根本对不上。或者更惨一点主中心某台机器磁盘坏了索引分片丢失你想从异地集群把数据再拉回来结果发现只能重新灌数据。这些问题的标准解法就是跨集群复制Cross-Cluster ReplicationCCR。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_shards1 { 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_requests和max_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_shards1 { remote_cluster: leader01, leader_index: product_orders }返回结果中acknowledged为true且分片状态转为active说明初始同步已经启动。等待一段时间后查看同步状态GET /product_orders_replica/_ccr/info返回信息中会包含每个分片的同步状态、检查点位置、延迟时间等关键信息。注意观察follower_index的remote_cluster和leader_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_shards1 { 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_read和read_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 能帮你省掉大量跨机房数据同步的烦恼做不好它会变成生产环境新的不稳定源。