????️ 阅读本文需 7 分钟
作者:张永红,开放平台组研发工程师(涂鸦智能)
>>> 关于涂鸦
涂鸦智能是一个全球化智能平台和“AI+IoT”开发者平台,也是世界排名前列的语音 AI 交互平台。连接消费者、制作品牌、OEM 厂商和零售连锁的智能化需求,为客户提供一站式人工智能物联网的解决方案,并且涵盖了硬件介入、云服务以及 APP 软件开发三方面,形成人工智能+制造业的服务闭环,为消费类 IoT 智能设备提供 B 端技术及商业模式升级服务,从而满足消费者对硬件产品更高的诉求。
上图体现了涂鸦目前的生态模式,包含涂鸦云、涂鸦 OS、涂鸦 APP,形成一个生态闭环。右半部分则为涂鸦涉及到的一些应用场景,例如,智能酒店、智能安防、全屋智能等。
>>> 涂鸦的消息系统架构
上图是涂鸦智能之前的消息架构图。上层是一些 IoT 的独立设备,包括智能开关、投影仪等。通过 MQTT 协议,将消息上报给消息系统。还有一部分设备是传感器等,通过 zigbee 网关和 MQTT 协议的传输,最后上报至消息系统。
上图是涂鸦消息系统具体的链路,从 MQTT 网关开始,接入服务连接到 Kafka,通过 Kafka 进行消息的分发。用户在接收到消息后,可以采取不同的处理方式。
以上的架构模式存在一些业务痛点。
1. HTTP 投递方式不灵活,这个是最明显的一个痛点。假如用户的服务挂掉,想在重启后重新进行消费。如果我们想要满足这个需求,就需要对消息的持久化进行额外的处理。
2. Kafka topic 数量与日俱增,运维成本高。用户使用 Kafka 订阅模式下,可以解决前文提到的持久化问题,但是随着用户和消息量的增加,Kafka 的运维层面压力会比较大,人力和时间等耗费比较高。
3. 租户之间会相互影响。通过架构图可以看出,从 Kafka 模式进行分发后,租户之间会受到很大影响。
>>> Pulsar 自身的优势
Apache Pulsar 是灵活的发布-订阅消息系统,采用分层分片架构。
1. 丰富的投递/订阅策略
Pulsar 做了队列模型和流模型的统一,在 Topic 级别只需保存一份数据,同一份数据可多次消费。以流式、队列等方式计算不同的订阅模型大大提升了灵活度。
2. 运维难度小(相比 Kafka),偏向自动化
主要体现在跨地域复制方面。Pulsar 使用计算与存储分离的云原生架构,数据从 Broker 搬离,存在共享存储内部。上层是无状态 Broker,复制消息分发和服务;下层是持久化的存储层 Bookie 集群。
Pulsar 存储是分片的,这种架构可以避免扩容时受限制,实现数据的独立扩展和快速恢复。
3. 多租户隔离优势
租户和命名空间(namespace)是 Pulsar 支持多租户的两个核心概念。
在租户级别,Pulsar 为特定的租户预留合适的存储空间、应用授权与认证机制。
在命名空间级别,Pulsar 有一系列的配置策略(policy),包括存储配额、流控、消息过期策略和命名空间之间的隔离策略。
在社区方面,Pulsar 的线上社区里,用户们都很活跃,不管是技术问题还是文档问题,响应都非常迅速。
>>> 与竞品相比,性能更出色
当然,在决定使用 Apache Pulsar 前,涂鸦也做足了充分的调研,并从性能、缩扩容、运维等角度对比了多个消息队列。
LeviMQ 是涂鸦自己研发的基于 MQTT 协议的消息队列。
NSQ 是 Go 语言里比较流行的开源消息中间件产品。
首先在扩容上 Kafka 稍显不足,尤其是在缩容时。从运维角度看,Kafka 也如上文提到的,运维过程对人力和时间的消耗较多。最后在生态方面,因为 LeviMQ 是涂鸦自研的系统并且没有开源,所以生态上具有一定的局限性。
在各性能对比后,也从单个产品角度分析了各个消息队列的优缺点,如下图所示。
从上图可以看出,Pulsar 在扩容和应用场景方面会更出色一些,相比较而言也比 Kafka 更灵活一点。
当然,关于参考资料少的情况,Pulsar 社区也在一直努力在填补这些缺失,最近新增了不少文档。
>>> 测试结果
使用 Apache Pulsar 后,涂鸦的消息系统架构发生了变化,如下图所示:
架构有以下变化:
1. 从 Kafka 到消息分发中,加了一层 Pulsar 结构。在这个架构下,最明显的提升就是解决了租户隔离的问题。在进行 Pulsar 部署时,为每个用户在 Pulsar 里新建了一个租户。
2. 投递给用户的方式中新加了 Pulsar 的传递方式,可以直接使用涂鸦的 SDK 去订阅 Pulsar 的消息。
在尝试使用 Pulsar 的这段时间里,涂鸦的消息系统运作效率比之前有了很大的提升。但是在使用过程中,也出现了一些 bug,比如消息堆积、消费重复等现象。当然涂鸦也对此采取了一些措施。以下为实践案例:
>>> 消息堆积
问题描述
使用过程中的一个消费者,服务运行一段时间后,出现消息堆积。但是查看日志发现没有报错情况,选择重启后,恢复正常。一段时间后,消息堆积情况再次出现。
原因描述
导致该问题的原因是 flow 计数机制。
Kafka 是推拉模型结合,Client 去 flow 了多少条数据,Pulsar 会在消息到了的时候,往里推多少数据。如果这个时候,不去 flow 数据,Pulsar 不会再去 Client 推送数据。
Go client 的代码中有计数机制(红框)。计数机制会循环使用,并执行红框里的内容。
但是在使用时,不知是网络问题还是 Apache Pulsar 的 broker 问题,比如拉取了 10 条,却只反馈了 8 条。这会导致下一次的 flow 永远不会触发。这时生产者一直往上推送消息,消息就会一直堆在 Pulsar 里。
解决措施
解决措施是:定时发送 flow 指令,即每隔 30s,flow 一些数据过来。这样做的额外成本是会增加一些定时器。如果 topic 数量少,这个定时器成本还在承受范围内。但如果 topic 数量过多,大量的定时器会导致 CPU 的压力很大。
>>> 解析紊乱
问题描述
上图所示,上部分是 Java 发的,下部分是 Go 接收的。通过对比可以看出:下方多了一个回车、一些空格,以及制表符。
上图中 Java 发送了四遍 "hello pulsar",下方在 "hello pulsar" 前边多了个 `3`。
最后我们发送 "hello",输出正常。但仍然发现有部分字节码是有点问题的。
原因描述
Java Client 在默认发送时,有一个 batch 参数默认为 `true`。解析 batch message 时,发现其 payload 里有一个复合结构,是个数组。
P1 是 metadataSize,表示后边字节有几个。
P2 里的 24 和 5 是它的 meta 信息。
P3 中 5 表示后边的 5 位才是真实的 payload。
>>> 消息重复消费
问题描述
消费者服务是通过 failover 模式去订阅 Pulsar。在此订阅模式下,某个 topic 下新加入的消费者有几率成为 active 状态。此时旧的消费者可能还有一部分消息还未消费完。如果没做相应处理,部分消息就会被新旧消费者同时消费。
如图所示,从 M3 到 M6,左边的在消费,右边的也在消费。
解决措施
Pulsar 有一个接口,初始化 Consumer 时,有个 Consumer list,在消费者变化时,从活跃变成不活跃、不活跃变成活跃,都能收到消息。对这些消息做监听然后进行处理,虽然这种情况下也会出现消费重复的 bug,但是概率很小。
Apache Pulsar 现已应用在涂鸦智能的各应用层,总体表现不错。涂鸦也对 Pulsar 的使用有一些规划和期望。
>>> 规划
持续引导客户使用 Pulsar 的消息推送模式,取代之前的 HTTP 和 Kafka。
结合 Pulsar 实现一套规则引擎,满足日益丰富的消息订阅需求。
>>> 期望
除了上文提到的实践效果外,涂鸦也希望在未来的业务支撑中,Apache Pulsar 能有更多扩展的功能,提供更加丰富的使用场景,所以也对 Pulsar 提出了一些的期望。
在技术层面,希望添加更多运维 API,比如查看某个 topic 所属的 broker 和 bookie。
在文档层面,希望官方多发布一些 Pulsar 设计文档,帮助更多用户充分了解 Pulsar。
伴随着 5G 的到来,IoT 行业迎来了一系列挑战和机遇。涂鸦智能作为一个全球化智能平台,除了在链接各个销售平台厂商外,也与用户之间有着千丝万缕的联系功能。在主打「万物智能」主题的背后,涂鸦也在寻找极高的性能与稳定性的消息系统。
在经过对比诸多消息系统(例如 Kafka 和 LeviMQ)后,涂鸦选择了性能出色的 Apache Pulsar,也通过 Pulsar 的跨地域复制、多租户隔离等特性,解决了之前消息系统中的诸多痛点问题,例如,投递不灵活、topic 数量增加和租户互相影响等,进一步证明了 Apache Pulsar 在 IoT 行业的应用前景十分可观。
????查看更多 Pulsar 用户案例:
甜橙金融如何利用 Apache Pulsar 在日均上亿的交易中抵御金融诈骗
Narvar 为何迁移到 Apache Pulsar
雅虎日本如何用 Pulsar 构建日均千亿的消息平台
Apache Pulsar 在腾讯计费场景下的应用