本文由 StreamNative 整理自 Pulsar Summit Asia 2022,来自网易有道基础架构工程师沈家琦的分享《Apache Pulsar 在⽹易有道智慧教育场景下的实践》。本文主要介绍 Apache Pulsar 在网易有道的建设实践经验,以及在智慧教育领域的业务落地经验。

关于 StreamNative

StreamNative(北京原流数据科技发展有限公司)由 Apache Pulsar 与 Apache BookKeeper 创始团队成员组建,致力于打造云原生批流融合数据平台,助力企业挖掘实时数据价值。

关于网易有道

网易有道是一家以帮助用户实现“高效学习”为使命,依托强大的 AI 技术,围绕学习场景持续发力的公司。目前网易有道全线产品月活跃用户超 1.2 亿,业务涉及智能学习硬件、学习工具 App 和智能学习平台等。

背景介绍

业务特点

  • • 网易有道公司整体的业务应用都部署在云上,需要考虑的问题比较多,比如如何保持性能,怎样部署来同时方便运维和扩容等。
  • • 有道在智慧教育的业务场景中,有大量的独立业务研发,比如 OCR 翻译、实时录入和自动打分等。这些业务数量众多、种类繁杂、需求各异,因而需要一个消息队列系统进行解耦。
  • • 在实际业务中,大部分业务对于吞吐和延时并不敏感,但是对可用性、兼容性有着较高的需求。
  • • 在以往的业务实践中,各个业务线会根据实际情况维护自己的消息系统,具体选型包括 Kafka、RabbitMQ 和 RocketMQ 等常⻅的消息系统。但对业务线同学来说,除了具体业务,亲自运维基础组件是一件非常耗费精力且人效不高的工作。综上所述,有道需要一套较高兼容性的系统,同时支持多租户来为大量种类各异的业务提供服务,既要便于维护,又要方便扩展。在有道的实际业务场景中,对消息系统的极限性能和对超大规模集群支持的需求优先级并不是很高。

针对上述业务特点与需求,网易有道调研了部分消息系统,并最终选择了 Apache Pulsar。

为什么选择 Apache Pulsar ?

首先是对云原生的支持。有道的整体业务应用都部署在云上,选择在设计上本身就具备云原生特性的 Apache Pulsar 来为各个业务线提供消息队列服务,符合公司既定技术发展路线。Apache Pulsar 计算存储分离的架构设计⾮常适合云原⽣部署。如下图所示,存算分离、节点对等的设计便于用户快速在 K8s 之上进行横向扩展。Broker 层无状态,而 Bookie 层有状态,可以通过对 Broker 层、Bookie 层分别进行扩展来获取不同的资源。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_有道

基于 Apache Pulsar 云原生的特性进行容器化部署,在保持性能的同时,也有便于运维、易于观测、快速扩展等容器化部署的优势。

其次是 Apache Pulsar 对 Topic 概念的设计和实现。Topic 仅相当于逻辑上的分区概念,它的数据由存储层自动分片单一 Topic 分区的存储可以平均分散到 Bookie 节点中,存储不受限于单个节点的存储容量。如下图漫画所示,在 Kafka 视角下,单一 Topic 的分区就是存储分区,分区的存储容量受限于单个节点存储容量。而 Pulsar 存储层与计算层互相分离,不存在存储受限的问题。即使是无分区或者单一分区的 Topic 需要存储大量数据,数据也可以很平均地分配到每个节点上。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_apache_02

https://jack-vanlightly.com/sketches/2018/10/2/kafka-vs-pulsar-rebalancing-sketch

有道业务类型多样,各个业务线对消息队列系统的性能要求各不相同。基于自身业务特点,大部分业务在使用 Apache Pulsar 时都使用无分区的 Topic,这样可以让业务线更专注于具体的业务,同时无需规划分区。

另外,Pulsar 提供多租户与隔离性。Apache Pulsar 支持多租户机制,且可以提供 Broker / Bookie 节点级别的硬件资源隔离。以下图为例:



Apache Pulsar 在⽹易有道智慧教育场景下的实践_数据_03

题库和智慧课堂两条业务线对于吞吐和延迟有不同的需求。假定题库的业务特点是持续、大量写入,对于实时性的要求不高,可以容忍较高的延时;而智慧课堂的业务特点是消息量比较少,但对可用性、实时性的要求很高。如果不进行硬件资源隔离,大流量的题库业务就很容易影响到智慧课堂的服务质量。

如果 Pulsar 不支持资源隔离,就没有办法将不同业务放在同一集群。借助 Apache Pulsar 亲和组的功能,我们给智慧课堂单独划分了 Broker 亲和组和 Bookie 亲和组,让智慧课堂的 Broker 节点和 Bookie 节点形成单独的子网,实现硬件资源级别隔离,继而实现了将不同类型业务放在统一、单一集群实例下的性能需求——既保证了题库业务的大量写入,又保证了智慧课堂业务的服务质量。在有道智慧教育的业务实践中,各业务线可能会在相同时段产生大量流量,通过划分亲和组实现资源隔离,保障业务服务质量。

最后,Apache Pulsar 提供了丰富的业务功能,如延时消息、消息 Schema 和跨地域复制等。我们的一些课程系统会利用延时消息功能,实现课程的自动结算;在录题系统中,会利用消息 Schema 进行各处理环节的消息校验;而跨地域复制对异地多活也是一个很重要的特性。

Apache Pulsar 在有道的部署

Apache Pulsar 在网易有道的部署方式与策略如下:

  • • 基于有道的网络基础设施,有道的网络互相打通,因此我们没有采用 Pulsar Proxy 而是直接向用户提供 K8s Service IP,以规避 Proxy 可能出现的瓶颈。
  • • 基于有道的业务需求,以及 Apache Pulsar 云原生和多租户的特性,针对用户高可用的需求,我们选择在 K8s 上部署一套各业务线共用的 Pulsar 集群单一实例。
  • • 为了向业务线提供统一的多租户、开箱即用的 Pulsar 服务,我们把 Pulsar 的租户(Tenant)作为划分项目的依据,把租户下的每个 Namespace 作为服务实例提供给用户。当用户在内部云平台申请一个 Pulsar 服务实例时,相当于在所在项目对应的租户下创建一个新的 Namespace,同时用户也会获得相应的访问权限。监控、报警、限流、统计等操作也基于服务实例进行。
  • • 使用单一 Pulsar 集群实例兼容其他消息队列:我们使用 StreamNative 提供的 KoP(Kafka-on-Pulsar) 插件来兼容 Kafka 业务。

Apache Pulsar 在有道的最佳实践

多消息队列协议支持的单一集群实例

由于一些历史原因,有道的各个业务线各自运维自己的消息系统,从旧有的 Kafka、RabbitMQ 和 RocketMQ 等消息系统直接切换到 Pulsar 非常困难。原有的代码难以迁移,对 Kafka 生态依赖较强,即使迁移也会面临着比较高的迁移成本等问题。

对不同业务线来说,应采用稳定性以及尽量小的代码修改的迁移方案。各业务线希望用一种无感的迁移方式,即在不修改已有代码的前提下,就可以获取到 Pulsar 多租户和分层存储等优势。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_有道_04

有道使用了 StreamNative 提供的 KoP(Kafka-on-Pulsar)/AoP(AMQP-on-Pulsar) 插件作为解决方案。以上图 KoP 架构图为例,通过加入 Pulsar 插件来兼容其他类型的消息队列。这个方案的实现逻辑是在 Broker 端采用插件的方式做协议的转换,通过单一的集群实例可以实现对多种队列协议的支持,而且客户端无感知——只需要切换服务地址。

有道的方案充分利用了 Pulsar 的各种优势来减轻运维压力,并且业务的客户端也无需修改代码,真正实现无感迁移。

高可用、高性能、弹性扩展的容器化部署方案

下面我将简单介绍有道的容器化部署方案,这对 Pulsar 在有道的服务化比较关键。有道对消息队列系统比较重要的需求是随着业务的增长进行方便快速地横向扩容。基于此,我们将 Pulsar 在 K8s 上进行了容器化部署。

首先,Pulsar 支持读写分离,即 Journal 盘(写盘)和 Ledger 盘(读盘)可以配置在不同磁盘之上。有道将 Journal 盘配置为速度较高的 SSD,将 Ledger 盘配置为容量大、成本低的 HDD,既减少了成本,也在一定程度上提高了发布效率,同时避免了读写互相干扰的问题。

其次,根据 Broker 无状态、Bookie 节点对等的特点,可以对容器化部署的 Broker 节点和 Bookie 节点进行快速的横向扩容。下图为如何快速扩展 Bookie 的示例。假设我们需要在某一业务线的单一 Topic 下快速地写入数据,而 Bookie 节点处于将近被打满的状态,需要快速扩容。在 Pulsar 体系下,可以快速而简单地增加 Bookie 节点实现容量的横向扩展。Topic 可以自动进行物理切片,通过打开新的分片、写入新的节点来快速进行流量切换。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_数据_05

在可用性方面,有道通过 K8s 健康检查和重启策略来保证 Broker 节点和 Bookie 节点的高可用性。

最后,有道通过配置 Prometheus/Grafana 来保障节点的可观测性,同时也通过一些其他的高层机制保证节点的可用性。

Rest Pub/Sub

在实际业务中,经常会出现一些不方便使用 SDK 生产消费的场景,比如智能学习终端和测试平台。由于设备技能和网络隔离性等原因,需要一种更加简单、轻量化和通用的方式来投递消息。虽然 Pulsar 支持丰富的 SDK,但是使用 SDK 还是一种很繁重的选择。所以,通过 HTTP 请求来进行生产/消费是很好的方案。

Pulsar 支持 Broker 端的 HTTP 生产消费接口。社区采取的方案是在 Broker 内部实现消息的投递,这种方案有一定的性能优势,但是需要解决的问题也比较多。目前该方案仅支持消息生产,不支持消息消费,接口的设计较为复杂。在调研社区已有方案后,结合平台实际建设情况及实际的业务场景需求后,有道开发了一套基于 Client 的 HTTP 投递/消费方案,逻辑如下图所示。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_数据_06

在将 Apache Pulsar 集群接入到百川(网易有道内部私有云平台)的过程中,需要一层 API 来做接入工作——在这一层中封装了一个 Go Client 做消息投递请求的解析和生产/消费转发。在实际业务应用中,只要直接访问 API 层提供的 HTTP 生产/消费接口,就可以方便地进行消息的投递和消费。这个方案实现起来更简单灵活,虽然在性能上可能有一些损失,但是对有道实际的业务场景来说已足够。该方案已经应用于实际业务。

Apache Pulsar 在有道实际业务中的应用场景

Apache Pulsar 在网易有道的建设情况

网易有道内部的私有云平台——百川将 Apache Pulsar 作为消息队列服务的技术底座。在有道的教育场景中,业务种类繁多,如何保障各业务线开发人员方便地获取 Pulsar 服务是一项非常重要的工作。

有道在 K8s 上对 Pulsar 进行了容器化部署,因为是单一实例,所以还需要把服务暴露给用户。在实践当中,用户以 Namespace 为单位在所属项目(项目对应的是 Pulsar 中租户的概念)下获取服务。用户在申请服务的同时,相应的权限控制等附加功能也会被一并建立起来。用户只需要将获取到的服务地址、Token 等信息填入到程序中就可以开始使用。

实践一:多任务异步解耦与衔接



Apache Pulsar 在⽹易有道智慧教育场景下的实践_有道_07

上图是一个传统的消息队列场景,左边是有道的实时业务,即学生端和老师端,右边是一些准实施业务,比如实时 OCR、 实时转译和实时阅卷打分等,这些都需要借助 Pulsar 来进行解耦。

以一个实际的业务场景为例。假设教师端需要将文本题目、教辅页面等录入到系统中,但是录入素材的类型不一,有图片、文本等各种类型,因此就需要在后台进行一些准实时的操作,比如实时 OCR 和实时转译等。但这些操作涉及人工智能服务,结果和处理时间不确定,需要借助 Pulsar 来保证入库的顺序性和数据的一致性。将人工智能处理的结果放到消息队列中,由消费端进行消费,对消息对应的业务进行前后依赖检查,检查无误后统一入库。这样即使有部分人工智能任务出现问题,主要的业务逻辑和业务链路也不会被影响,各个业务方只需要关注最终的处理结果即可。

实践二:Apache Pulsar 充当消息总线

在智慧教育的试卷排版场景中,有道将 Pulsar 作为一条可靠的数据总线来使用。对于学校用户来讲,HTML 的显示精度不足以满足需求。为了使题目的显示表现更加接近印刷标准,有道将 HTML 标签处理为 LaTex 标签。由于各种标签的处理规则不一样,所以即使对于同一份试卷,也是由多个独立的处理进程来分步处理。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_有道_08

在具体实践中,有道会维护一个掌握整个转换流程所有规则的 Task Coordinator, 由它向各 Processor 发布任务。各 Processor 收到消息后会根据 Task 中的上下文来判断如何处理业务或丢弃任务;当处理结束后,改变 Task 的上下文向 Topic 回发 Task,由 Task Coordinator 重新调度任务。

在整个处理链路中, Pulsar 作为任务的消息总线使用。Pulsar 的持久化使得各 Processor 一定可以收到 Task Coordinator 发布的任务。通过 Pulsar 灵活的发布订阅机制,各个 Processor 之间可以进行完全独立的开发和上线。各 Processor 的开发者无需关心其他 Processor 的处理结果和处理逻辑。即使 Processor 独立下线调整也不会影响到整体转换的流程。整体转换完成之后,系统会输出最终的转换结果给用户,用户就可以获得印刷标准的 LaTex 排版试卷。

实践三:延迟消息赋能业务场景

前面有提到, Apache Pulsar 提供延迟消息功能,用户可以通过客户端设置便捷地发送延迟消息。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_有道_09

在智慧课堂的实际业务场景中,在老师上课过程中,系统会不断地同步上课进度到服务端。如果老师正常结束上课,系统就会发送一条结束指令到服务端。但有时老师不会正常结束上课,可能直接关闭软件或者直接拔掉电源,在这种情况下,课程无法自动结束。

所以有道内部以收到最后一次老师上课进度的时间为课程的结束时间。老师的客户端每 5 分钟会发送一条延迟消息到服务端。服务端收到消息后会再检查这条消息之后是否还有新的上报记录。如果没有,这条消息就是客户端的最后一条消息,而此条消息的时间就是课程的结束时间。课程结束之后,系统会进行相应结算。延迟消息的好处是即使老师非正常关闭软件,服务端也可以很方便地得知并进行相应处理。

实践四:使用 Apache Pulsar 进行数据同步

在实际业务中,一条业务数据会被多个子系统处理或者备份,而系统间又需要通过一种相对轻量级的方式来保持数据一致性。



Apache Pulsar 在⽹易有道智慧教育场景下的实践_Apache_10

在优客业务中,优客授课系统会接收到各种各样的用户端请求。产生的数据如操作日志需要同步到优客的教务系统或者其他子系统做相应的处理与备份。这就要求优客授课系统所接收到的所有数据要与其他子系统中的数据保持一致性和顺序性。

在过往的实践中,有道的业务同学一般通过 RPC 的方式来实现上面的逻辑,但是通过 RPC 实现需要额外考虑数据一致性的问题,比如因为网络故障导致 RPC 调用失败。

在使用 Pulsar 后,Pulsar 的顺序性和持久化可以保证逻辑的实现。业务同学可以放心地将数据放入到消息队列中,由其他子系统进行消费,进而大大降低了开发过程中数据同步所消耗的精力。

总结

网易有道部署并使用 Pulsar 服务智慧教育的多个业务线。本文介绍了 Apache Pulsar 在有道的最佳实践,包含兼容多协议、容器化部署方案和 Rest Pub/Sub,并分享了 Apache Pulsar 在具体业务中的应用与实践经验,如多任务异步解耦与衔接、如何 Apache Pulsar 作为消息总线、延迟消息和使用 Apache Pulsar 进行数据同步等。