导语

本文整理自 Pulsar Summit Asia 2022 技术峰会上腾讯云中间件高档研制工程师韩明泽的分享《根据跨地域仿制完成租户跨集群搬迁》。本文首要介绍根据跨地域数据仿制和订阅进展同步的完成及优化,以及腾讯云在跨集群搬迁进程中遇到的问题及租户跨集群搬迁处理计划。

作者简介

韩明泽

结业于武汉大学,腾讯云中间件高档研制工程师,拥有多年音讯中间件开发与运维经历,RoP (RocketMQ-on-Pulsar) Maintainer,Apache Pulsar 贡献者。

订阅进展同步的完成及优化

跨地域仿制简介

跨地域仿制是 Apache Pulsar 供给的跨机房数据仿制才能。其典型的运用场景有:

  • 多机房数据仿制,即数据容灾备份
  • 异地读写

下图为典型的异地读写事例,假定在北京生产与写入,而在上海消费,在对从生产到消费整体链路耗时要求不高的情况下,即可选用跨地域仿制的才能。同地域写入的时刻本钱相对较低,而比较耗时的消费能够在内部经过跨地域仿制屏蔽。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

跨地域仿制集群仿制功用完成原理

假如 Apache Pulsar 不供给跨集群仿制功用,怎么在运维 RocketMQ 或许 Kafka 等情况下完成跨地域数据仿制、容灾者备份和集群间数据搬迁的作业?

通常情况下,服务中有生产者和顾客两个角色,顾客衔接上游集群,生产者衔接下游集群。上游集群的消费数据经过生产者发送到下游方针集群。Apache Pulsar 在跨地域仿制的设计中选用了类似思路,跨地域仿制完成的流程如下图所示。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

在每个主题内部设置了 Replication 模块。假如敞开数据仿制,此模块则会建议内部订阅(或游标进展)。在任一主题内消费音讯时,生产者向对端集群投递音讯来完成跨集群数据的仿制功用,不影响本集群的生产消费。在上述的进程中,音讯的读取与发送彻底异步处理。

订阅进展同步的完成原理

数据仿制与同步的完成比较简单,但在一些场景中,除了同步音讯,还需求同步订阅的消费进展。

以异地容灾为例,假定原本事务的生产消费均在北京,当北京集群事务呈现毛病时,事务端想快速将集群切换到上海集群,以继续从北京集群现已消费到的方位开端做生产和消费。

假如没有订阅进展同步的才能,那么用户很难确定在北京集群里哪些音讯现已消费过;假如从最新的方位开端消费,可能会导致音讯丢掉;假如从最早的方位开端消费,会形成许多的重复消费。在实际操作中,稍微折中的办法是经过时刻回溯退回到较近的时刻点。然而,这种办法无法从根本上处理音讯丢掉或许重复消费的问题。

而 Apache Pulsar 所供给的订阅进展同步的功用,则能够让用户滑润地完成异地容灾的切换,不必忧虑音讯的丢掉或许重复。Pulsar 一起支撑数据同步和订阅进展同步,如下图所示。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

消费进展

消费进展由 markDeletePosition 和 individuallyDeletedMessages 两部分组成。在 RocketMQ 和 Kafka 中,消费进展在分区上经过 Offset 标识。Offset 对应 Pulsar 中的概念能够理解为 markDeletePosition。

Pulsar 一起支撑多种消费形式,它的音讯承认机制/签收机制支撑单条承认。因此,在 Pulsar 中除了需求记载 markDeletePosition,还需求 Individual Acks 记载单条被承认的音讯。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

如上图,在同享消费形式下有许多顾客实例。由于每个顾客的消费速度不一样,音讯的推送次序和音讯 Ack 次序并不彻底相同。假定咱们需求把标号为 0 到 9 的音讯一起推送给不同的顾客实例,音讯 0、1、2、3、4、6、9 现已承认,可是 5、7、8 并没有承认。markDeletePosition 的游标方位,即 Offset 标识的消费进展只能标识到 4 的方位,表明 4(包括 4)之前的音讯都现已被消费。音讯 5、7、8 现已被消费,需求单独承认。Pulsar 经过 individuallyDeletedMessages 数组对象范围去标识哪些音讯现已被承认过。咱们能够将上述音讯的承认理解为几个开闭区间,从中能够明显得出 5、7、8 没有被消费。

Message ID 对应联系

在 Pulsar 中,订阅进展同步的复杂性在于同一条音讯在不同集群中的 Message ID 不一致,这也是 Pulsar 相较于 Kafka 和 Rocket MQ 而言比较复杂的地方。在 Kafka 分区里只有 Offset 一个概念,而在 Pulsar 中,Message ID 由 Entry ID 和 Ledger ID 组成。同一条音讯在不同集群里存储的 Entry ID 和 Ledger ID 无法保持一致。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

如上图所示,在 A 和 B 两个集群中,音讯 1 在集群 A 中的 ID 是 1:0,而在集群 B 中的 ID 是 3:0;音讯 2 在集群 A 中的 ID 是 1:1,在集群 B 中的 ID 是 3:1。假如同一条音讯在两个集群中的 ID 彻底一致,同步消费进展非常容易,比方 ID 为 1:2 的音讯在集群 A 中被消费,集群 B 同步承认音讯 1:2 即可。可是由于 Message ID 不一致,或许在不知道 Message ID 间对应联系的情况下,没有办法直接将不同集群间的音讯对应起来。

所以关键问题就在于,怎么知道 Message ID 间的对应联系?其实这也是最为复杂的地方,咱们只有清楚集群间同一 Message ID 的对应联系,才能在集群 A 承认音讯 1:2 之后,同步在集群 B 承认音讯 3:2,或许更新其markDeletePosition。

构建 Cursor Snapshot

在原生 Pulsar 里经过守时结构 Cursor Snapshot 的机制来完成 Message ID 间的彼此对应。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

"ReplicatedSubscriptionSnapshotRequest":{
"snapshot_id":"444D3632-F96C-48D7-83DB-041C32164EC1",
"source_cluster":"a"
}

以上图为例,集群 A 承认音讯 1:2 时经过快速构建 Snapshot 向集群 B 和 C 发送恳求,恳求其告知集群 A 此音讯在其集群中的方位信息。

集群 A 会守时向其他集群发送 Replicate Subscription Snapshot Request。集群 B 在收到集群 A 的恳求之后会回发响应,将当时仿制到的最新音讯方位发送给集群 A。

"ReplicatedSubscriptionSnapshotResponse":{
"snapshotid":"444D3632-F96C-48D7-83DB-041C32164EC1",
"cluster":{
"cluster":"b",
"message_id":{
"ledger_id":1234,
"entry_id":45678
}
}
}

集群 A 收到对端集群 B 和 C 回来的当时音讯的方位后,就会结构起 Message ID 间对应联系。如下图所示,集群 A 中 Message ID 为 192.123123 的音讯,在集群 B 中对应 ID 为 1234.45678,在集群 C 中对应 ID 为 7655.13421。

代码如下:

{
"snapshot_id":"44403632-F96C-48D7-83DB-041C32164EC1",
"local_message_id":{
"ledger_id":192,
"endtry_id":123123
},
 "clusters":[
{
"cluster":"b",
"message_id":{
"ledger_id":1234,
"endtry_id":45678
}
},
{
"cluster":"c",
"message_id";{
"ledger_id":7655,
"endtry_id":13421
}
}
],
}

Message ID 间对应联系的构建并不复杂,可是完成逻辑会相对复杂。Cursor Snapshot 结构完成之后会构成一种对应联系作为 Cursor Snapshot Maker 写入到原主题。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

如上图,阿拉伯数字表明事务主题里的事务音讯,字母 S 表明不同集群间结构出来的 Cursor Snapshot 数据。当消费到 Snapshot Marker 时会把对应的 Snapshot Marker 加载到内存里。比方,咱们在集群 A 中 Mark Delete 到音讯 3 的方位时,能够根据 S 里边记载的集群 B 中的音讯方位来更新集群 B 的 markDeletePosition。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

以上图为例,在集群 A 中音讯 1:2 和音讯 1:6 的方位分别有一个 Snapshot,音讯 1:1、1:3、1:4、1:5 和 1:7 是一般音讯。当集群 A 中 markDeletePosition 更新到 1:4 时,音讯 1:2 在 1:4 之前而且有 Snapshot,就能够快速到集群 B 去承认音讯 3:4,并更新该方位的 markDeletePosition。

订阅进展同步

订阅进展同步进程中存在的问题

订阅进展同步进程中存在的问题也是租户跨集群搬迁进程中卡点的问题:

  • 只同步 markDeletePosition,不同步 individuallyDeletedMessages。

这会导致在单条音讯承认时存在许多音讯承认空泛,对存在守时音讯的场景也会产生较大的影响。假定一个主题里有守时音讯和一般音讯,守时音讯的时刻是在一天后,也就意味着守时音讯的承认时刻需求推迟一天。由于 markDeletePosition 只能记载此刻现已被全部承认过的音讯的方位,因此在守时音讯被承认时,markDeletePosition 还是一天前的方位。假如用户此刻切换集群,就会形成音讯重复消费,至少一天的音讯会被重复消费。

  • 音讯堆积会导致无法同步消费进展。这与 Cursor Snapshot 的创建机制有关。

如前文提到的,经过集群 A 构建与集群 B 和 C 之间的 Snapshot 时的恳求并不是经过 RPC 接口宣布的,而是借由咱们此前提到的 “S” 带入。在订阅进展或许音讯同步的进程中,音讯堆积不可避免,导致恳求也被写入到本地主题。由于对端音讯堆积,且主题内部都会设置超时机制,假如在规守时刻内收不到构建 Snapshot 的恳求,Snapshot 就无法构建成功,从而无法同步订阅进展,markDeletePosition 也无法同步。

  • 守时 Cursor Snapshot 机制。

沿用前面咱们在讲同步消费进展时所提到的事例,在集群 A 和集群 B 中,集群 A 中音讯 1:2 与音讯 1:6 与集群 B 之间有 Snapshot,一般音讯间没有 Snapshot。假如此刻集群 A 的 markDeletePosition 更新到 1:4,由于此方位上两个集群之间并不存在 Snapshot,所以集群 A 无法承认该条音讯在集群 B 中对应音讯方位,这也是当时机制中存在的问题。

综上所述,订阅进展同步进程中存在的问题首要在于只同步 markDeletePosition 而不同步 individuallyDeletedMessages,有时尽管同步了 markDeletePosition,但由于自身机制的问题会影响准确性或许呈现音讯堆积的情况。

订阅进展同步优化

上述问题在租户搬迁进程中会形成许多的重复消费,常见且难解。在一些真实用户在线事务场景中,少数、短暂且可控范围内的重复消费能够接受,许多的重复消费不允许存在。

为了处理上面的问题,咱们优化了订阅进展同步的逻辑,在集群搬迁之前需求同步 markDeletePosition 和 individuallyDeletedMessages。在同步进程中,最大的问题依然是同一音讯在不同集群中 Message ID 的对应。即使集群 A 的 markDeletePosition 和 individuallyDeletedMessages 全部都同步到集群 B,可是集群 B 依然无法确定 individuallyDeletedMessages 对应的本集群的 Message ID。

为了处理这个问题,咱们在原始集群(集群 A)发送音讯到集群 B 时,在音讯的 Metadata 里加入了集群 A 里的 Entry Position(Message ID)和 originalClusterPosition 的特点来带着音讯写入的方位。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

这样,当咱们在集群 B 进行消费时,能够快捷地从 originalClusterPosition 特点中获取到集群 A 的 Message ID,将其与集群 A 同步到集群 B 的 individuallyDeletedMessages 进行比较。假如音讯现已被承认过就直接越过此条音讯,不再发送给顾客。经过这样的办法完成对已承认音讯的过滤。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

具体完成逻辑如上图。在搬迁集群搬迁之前,需求先将集群 1 中 individuallyDeletedMessages 的订阅同步到集群 2。在将音讯推送给顾客之前,音讯会先经过 Filter Entries For Consumer 过滤掉集群 1 中现已消费过的音讯,将未消费的音讯推送给集群 2 中的顾客。

上述完成逻辑仅仅一种思路的转化。由于在 Pulsar 中,进展同步完成在集群 1 上,集群 2 中的音讯不断同步到集群 1,经过不断构建 Snapshot 记载集群 1 和集群 2 方位对应联系,这样在集群 1 承认音讯时,能够同步承认集群 2 对应方位。咱们的优化办法是把集群 1 中音讯的方位信息放在音讯里,经过同步 individuallyDeletedMessages 和 markDeletePosition 将进展同步到集群 2,在集群 2 实际消费时过滤。经过这种方法将重复消费控制在用户可接受范围内。

租户跨集群搬迁的完成

前期腾讯云内部的集群是同享集群,不同事务场景的用户运用同一套物理集群。有大规模音讯队列运维经历的同学知道,不同用户混用同一集群会运用户之间相互影响。用户对服务的要求不同,需求为对服务质量要求比较高的用户建立独占集群,物理资源阻隔来削减对其他用户的影响。这时需求有滑润的搬迁计划完成集群的顺利搬迁。

租户搬迁整体架构

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

上图为腾讯云内部完成租户跨集群搬迁的架构图,其中最核心的模块 Lookup Service 是腾讯云内部署理客户端 Lookup 恳求的服务模块,保存每个租户到物理集群的映射联系。咱们根据租户将用户客户端 Lookup 恳求转发到对应的物理集群,从而获取用户客户端收发音讯时所需求衔接的 Broker 节点。需求留意的是,Lookup Service 不仅仅署理 Lookup 恳求,还署理 getPartitionState、getPartitionMydata 和 getSchema 等恳求,但不署理包括数据流的恳求。数据流恳求经过 CLB 或 VIP 直接连到集群来收发音讯,并不经过 Lookup Service。

其实 Lookup Service 不是为了跨集群搬迁而诞生,它的首要目的是在多种网络接入访问场景下,为云上集群供给会集处理不同网络服务路由的才能。在公有云上不只存在经过简单的 Broker IP 就能衔接的内网用户,还需求经过公网 CLB、VPC 或 VIP 服务进行转发,Lookup Service 首要应用于这方面。咱们跨集群搬迁时利用了 Lookup Service 才能来确保集群切换简单顺利地完成,一起借助于跨地域仿制的同步功用把数据从原有集群搬迁到方针集群上。搬迁完成后,经过 Lookup Service 的切入才能最终完成租户跨集群搬迁。

租户跨集群搬迁的首要流程

接下来介绍跨集群搬迁的具体流程。

腾讯云基于 Apache Pulsar 跨地域复制功能实现租户跨集群迁移

  1. 同步元数据。在方针集群上按照原集群的租户、命名空间、主题和订阅角色等资源,完成元数据同步。

  2. 敞开跨地域仿制功用,搬迁租户下的主题数据。

  3. 在集群切换前敞开订阅进展同步功用,把每个订阅的 individuallyDeletedMessages 和 Mark Delete Messages 同步到方针集群上。

  4. 修改 Lookup Service 中租户与物理集群的对应联系,主动调用 Unload 触发客户端从头寻址。Lookup Service 根据新租户到物理集群的对应联系回来新物理集群的地址。

  5. 在搬迁完成后,整理原集群上的资源。

总结

完成租户跨集群搬迁的方法有许多,本文只分享一种在公有云上完成改造本钱较低、复杂程度较小而且可靠性较高的计划。这种计划不需求对现有 Pulsar 客户端和服务端协议做任何改动就能够完成滑润搬迁。