编辑|futeng
背景介绍
Flipkart 是印度领先的电子商务平台之一。我们基于 Kafka 打造的异步总线承接了公司海量的 HTTP 调用和消息传输。但随着业务的发展,Kafka 已经不能跟上公司快速变化的业务发展要求。随着调研和测试,我们最终决定使用 Pulsar 替换 Kafka。
我们选择Pulsar 的主要原因,包括:
从 Kafka 迁移到 Pulsar 给我们带来了诸多优势。Pulsar 内置的企业级功能,减少了我们自行开发和维护的成本,也降低了系统的总体复杂性。在 Kafka 中,这些高级功能都需要额外构建和维护。
本文中,我们将分三个部分详细讨论 Flipkart 的异步总线如何实现从 Kafka 到 Pulsar 的实时迁移:
在深入探讨之前,我们需要回顾一下同步和异步的区别,以及我们为什么选择异步操作。
在同步操作中,服务 A 通过 HTTP 连接到服务 B,并等待其响应,直到服务 B 完成请求的处理。然而,这种方式并不可扩展,因为存在阻塞,并且与服务 B 紧耦合。这就是为什么我们使用异步处理:在异步处理中,服务 A 将请求发往服务队列,然后继续执行自己的任务,不会等待服务 B 的响应。服务 B 可以自行决定处理时间,甚至可以延迟处理。这意味着两个服务在职责上是解耦的,它们可以独立地扩展,并且效率高,不会发生锁定。
我们通常使用可持久的消息队列(消息代理Broker)来实现这一点。消息代理位于服务 A 和服务 B 之间。服务 A 向消息代理生产消息,而服务 B 则从消息代理中消费消息。当有多个消费者或多个服务对同一消息感兴趣时,它们就也会消费相同的主题。
但问题是,这样就足够了吗?
现在的微服务都会围绕消息代理构建多种多样的服务,以满足其端到端的需求。而简单的消息队列,无法满足这类多样化的需求。复杂点的业务都需要考虑失败管理。
组内有序(Group Ordering),这是用户会在消息队列服务中寻找的一个重要特性。在许多消息队列系统中,为了保证同一个组的消息被顺序处理,系统会确保同一组的所有消息都进入到同一个分区。只不过,这时候在同个分区内,也可能有来自不同组的消息。在这种情况下,需要有一种机制来跟踪每个组内的消息处理状态,并确保按顺序处理消息。例如,如果一个组的第一条消息在时间点T0被成功消费,然后同一组的第二条消息在时间点T1失败了,那么在时间点T3来自同一组的第三条消息就不应该被处理,直到问题得到解决。因此你需要维护一个状态管理系统,来记录每个消息的处理结果,并基于这些信息来决定是否处理后续的消息。
同样,在一个订单系统中,会有多个服务在彼此协同。比如当用户下单时,首先需要确认支付成功,然后再更新库存,最后再由仓库发货。这三个服务虽然是独立的,但实际是相互依赖的:没有完成支付,你就不要更新你的库存;如果库存没有更新,你就不要发货。前一步骤失败了,下一步骤就要中止。这就是用户通常寻求的组内顺序性。同样,这表明需要维护组内消息的状态,需要根据前一个状态,来决定如何处理后一条消息。
此外,有相当一部分用户,他们想让微服务A 对微服务 B 进行一个简单的 HTTP 调用,并希望这个过程是异步的,不需要等待响应的。
通常,我们实际上仍然会引入消息代理来提供异步通信和服务解耦。
不过这会导致客户端过于复杂,同时引入新的问题:
因此,基于以上需求,Flipkart 需要的消息代理至少要满足以下特点:
为了解决以上问题,我们推出了 Varadhi,这是 Flipkart 自研的异步总线。
Varadhi 实现了我们上述需要的所有功能要求。Varadhi隐藏了内部的消息队列的实现细节,对外给用户提供完整的平台服务。
目前 HTTP 或者 HTTPS 都是支持的。用户集成也没有任何额外的负担。
目前Pulsar Varadhi平台支持了:
在 Varadhi平台,目前已经有180多个租户加入,3500多个Topic和9500多个订阅。每天最多约能产生10亿条消息,而且这些消息能在同一天被消费完。
这是Varadhi的组件架构图。其中ZooKeeper 维护元数据。我们有一个控制平面,允许用户配置他们的订阅主题和端点,以及设置他们要从哪里接收消息。我们还有个HTTP服务器,这些服务器处理来自用户的生产请求。这些生产请求随后被持久化在消息代理中。
以下是每个组件的详细说明:
这样的架构设计分离了消息的生产、管理和消费过程,增强了系统的扩展性和可维护性,允许我们灵活地处理大量的消息生产和消费请求。同时,通过ZooKeeper确保系统的配置和同步,控制平面也可以为用户提供易于管理和配置的界面。
我们之前还是使用 Kafka 作为消息代理。而现在,里面的 Kafka 系统已经被 Pulsar 取代了。因为我们想利用 Pulsar 原生自带的多租户模型、GEO特性还有存储和计算分离架构。使用这些功能使得我们的平台管理变得更加简单和有效。而在 Kafka 中,需要额外构建这些功能,增加了开发和维护的复杂性。
从 Kafka 迁移到 Pulsar 还是会面临很多挑战,我们有以下具体的迁移要求:
这些要求,体现了迁移的复杂性。对我们保持高可用和数据一致性方面提出了很大的挑战。
在介绍迁移方案之前,需要先说明下我们自定义了一个 Varadhi 版本的Topic。里面包含 Topic名称,是否分组还是有 Topic 的存储位置,是基于Kafka的或是基于Pulsar的存储。最后还有个 Topic 的配置版本。每次更新Topic时,版本号会递增。
方案 1:整体替换
第一个方案是更换存储 Topic,这是最简单的方案。但是要从 Kafka 替换为 Pulsar 的存储主题,我们得先暂停生产,等待消费者追上来。一旦完成同步,也就是说 Kafka 存储主题中的所有消息都被消费了,然后我们就可以用 Pulsar 替换它了。同时生产者和消费者的指针都是切换到 Pulsar。这样就可以从 Pulsar 主题上进行消费和生产了。
这个方案的优点是生产者和消费者可以同时进行,这意味着用户的顺序性得到保留。任何生产出的消息将会以产生的顺序被消费,因为迁移没有带来这方面的改变。而且方案很容易实现。然而,也有一些不利因素,由于这些原因,我们无法继续采用这种方法。其中之一是,我们可能会有多个消费者对应一个生产者,一旦其中有消费出现延迟的,就会使我们的生产停机时间变得很长,这是我们不希望让用户经历的。另外,偏移重置不可用,你不能将你的消费指针回退到 Kafka,即使用户已经为该主题设置了某种保留策略。那时候,我们将不得不丢失那些信息,这对我们来说可能是不可接受的。
方案 2:分组替换
为了克服这个问题,我们决定采用一个分段的Varadhi主题方案。
这会出现一个现象:消费的指针总是落后于生产的指针。尽管消费者的指针可能位于不同的存储主题中,但仍然落后于生产者所在的存储主题。
在这个例子中,我们可以看到存储主题1存在了一段时间,然后我们增加了存储主题2,消费仍然发生在存储主题2中。我们将继续生产并移动到存储主题3进行生产。
所以,从一个主题到另一个主题的迁移过程会是这样的:我们设立了一个目标主题,在某一特定时间点,我们尝试更改开关,请求进行迁移,并会告诉生产者现在可以切换到目标主题进行生产。此时,生产者继续前进,开始向目标主题生产,一旦消费者完成从前一个主题的消费,最终也会转移到目标主题上来。
这个方案有一些优势。
然而,这里也有一个挑战,因为生产者和消费者是异步切换的,生产者之间没有协调。记得我们有多个 HTTP 端口吧。这些异步切换,这会带来一个风险,可能会导致我们组内的顺序性出现问题。
为了克服这一点,我们决定采用一个基于协调的生产切换方案。这里面有两部分非常重要。第一个是控制平面,负责协调整个切换过程。第二个是ZooKeeper ,用来维护迁移过程中的程序状态。生产服务会监听这些状态,并根据获取到的状态做出对应的反应。
然而,如果在任何阶段出现问题,如生产者无法停止发送消息或控制平面无法成功更新Zookeeper,或丢失连接等,系统将回滚到之前的状态。在这些情况下,我们要做的是回滚到 Kafka 主题,限制生产的数量,并且停止迁移,并且将状态更新为失败。控制平面和生产者将根据当前迁移状态决定是恢复还是中止操作。
如果出现失败,例如在请求步骤中,生产者指向了 Pulsar 上,但无法生产消息。这时候将重置切换,生产指针将回到 Kafka 主题,并开始只向 Kafka 发送消息。整个操作将被标记为完成,但状态为失败。
消费的切换是相当直接的。消费者由控制平面指定从哪里消费消息。从指定的消费 ID 开始消费,或者消费主题里面滞后的消息。一旦完成,控制平面将更新消费者主题 ID 并移至下一段,这个时候,消费者就可以发送切换了。
就故障回滚方面我们采取的策略,假设从 Pulsar 发现问题想要回滚到 Kafka,我们的策略规定不能回到之前的主题,而是必须添加一个新的 Kafka 存储段,并且移动生产指针,或者从 Pulsar 重新迁移一次到 Kafka。这是必要的,我们不能重复使用同一主题。我们本可以将指针从 Pulsar 移回例子中的Kafka 主题一,但这意味着 Pulsar 主题中的消息将被错误错乱,从而导致我们的用户遭受顺序性方面的损失。
因此,即使是回滚也意味着另一次变相的迁移。
我们通过这种迁移策略获得了一些额外的好处。例如,我们现在可以更改主题的命名空间,这在 Pulsar 中本来是不可能的。我们甚至还可以利用这一特性,将主题从一个命名空间迁移到另一个命名空间。我们还可以在 Pulsar 中更新主题的分区数而不会失去消息的顺序性。这是目前任何消息队列都不能提供的。
我们还可以展示主题的使用情况,像一个时间轴一样,毕竟每个段都是被记录的。我们可以看到段1是在 Kafka 中,然后我们移动到 Pulsar,然后从 5 个分区扩容到 10 个分区等等。我们可以用它来看到主题在这段时间的自然演变。
最后,我们正在将 Varadhi 开源。我们现在正在重新审视 Varadhi,做一些彻底的改进。我们正在重写所有的模型,以解决我们在初版 Varadhi 中发现的一些架构漏洞,并希望将其贡献给开源社区。
我们会很高兴听到来自您的反馈。如果您有任何问题,可以联系 Pulsar 社区,或者直接联系我们。感谢大家的时间。
最新 Pulsar 岗位招聘,快来点击(公众号菜单-联系社区-名企直达)
结尾