2022腾讯全球数字生态大会已圆满落幕,大会以“数实创新、产业共进”为主题,聚焦数实融合,探索以全真互联的数字技术助力实体经济高质量发展。大会设有29个产品技术主题专场、18个行业主题专场和6个生态主题专场,各业务负责人与客户、合作伙伴共同总结经验、凝结共识,推动数实融合新发展。
本次大会设立了微服务与中间件专场,本专场从产品研发、运维等最佳落地实践出发,详细阐述云原生时代,企业在开发微服务和构建云原生中间件过程中应该怎样少走弯路,聚焦业务需求,助力企业发展创新。
随着大数据时代的到来,企业在生产和经营活动中产生的各类数据正以前所未有的速度增长,通过对实时及历史数据的融合分析,及时挖掘业务洞察和辅助决策,已成为企业的普遍行动。在云原生的浪潮下,企业需要聚焦业务,迫切需要简单易行,零代码地配置搭建起自己的可以达到将本增效效果的数据链路系统。
本篇文章将从以下几个方面来跟大家一起分享 Pulsar 在腾讯的实践中遇到的问题和挑战以及对应的解决方案。
● 消息队列发展历史
● 开源方案可能面临的问题和挑战
● 我们的探索与解决方案
● Pulsar 在腾讯内部的案例实践
● TDMQ 未来规划
下图是开源社区整个消息中间件产品,从2003年诞生的 ActiveMQ 到2012年 诞生的 Pulsar 的整个发展过程。
在这个发展过程中,不同的产品解决了各种各样不同的问题。下图是各产品之间的对比,大家最关注的是在线消息和离线消息,现在业界比较通用的会把 Kafka 用在离线消息上,在线消息更多采用的是 RocketMQ。RabbitMQ可能在扩展性上存在一些差异,但是它简单易用,历史也更悠久。规模决定了这些消息产品的扩展性如何,能否支持十万或者百万的消息 Topic 的量级,下表中对最小规模也做了详细对比。
看了以上那么多消息产品的对比,大家肯定会有一个疑问,既然已经有这么多的消息产品了,为什么还要用 Pulsar?Pulsar 它存在的意义是什么呢?基于 Pulsar 研发人员自己的经验以及社区的背景,Pulsar 有三个值得关注的发展方向:云原生环境适配、多租户和海量 Topic、离在线流批一体。
● 计算与存储分离的架构,对于原生的 K8s 或者容器化的环境是更加友好的,天然适配云原生环境,不同的组件可以分开扩展。
● 基于对机器容灾的考虑,支持跨 Region/ 机架数据写入。
● 对于普通用户,可以方便的使用开源的 Operator 在云环境直接部署,真正的服务于业务。
● 天然支持多租户, Namespace 和 Topic 级别的权限管理,可以做共享大集群。
● 设计层面支持海量 Topic,对于有这类需求的用户有比较强的吸引力。
● 在系统维护层面,All in one 的吸引力。
● 对业务只需要维护一套中间件即可实现流批一体。
● Kafka 等 Connector 的存在,迁移方便。
普遍情况下离线会采用 Kafka,在线会采用 RocketMQ,但实际上,很多用户或者很多基础设施的同学团队,更希望有一款产品能够把离线和在线结合起来,具有 All in one 的能力。Pulsar 在设计之初就是有这样的考量,也参考了前者的一些优势。
上图左下角的部分可以看成一个整体,是 Pulsar 的一个 Broker 集群,也就是前面介绍到的计算节点,右侧 Bookeeper 是 Pulsar 的存储节点,也就是存算分离中的存,Zookeeper 是 Pulsar 元数据管理中心,这是整个分布式的部署环境。大家可以看到整体的架构包括三个部分:
● 2Broker+3Zookeeper+3Bookeeper,这是一个最小集群结构。
● 多语言 SDK,Java/Go/C++/Node,对应的是上图的上半部分,Pulsar 现在多语言 SDK 也是比较丰富的,用的最多的就是 Java/Go/C++/Node 等。
● 一些 Manager 的管控 UI,这部分在社区相对不是特别完善。
管控面:
1、元数据资源的权限管理,如何划分不同的用户和不同的权限。
2、当一个集群超过一定的规模,海量 Topic (3w 分区)的情况下,策略更新对管控稳定性产生影响。
3、用户对元数据( Topic 等)进行管理出现问题,比较难以定位,没有操作轨迹。
数据面:
1、在线消息生产限流之后,客户端无法明确感知,对生产稳定性有影响。
2、不少配置项缺少动态能力,进行更新时需要重启 Pulsar。
3、不同网络环境下面,ListenName 的网络方案扩容不友好。
4、出现消息空洞时,无法自动恢复。
5、如果集群容量不足,如何将用户从一个集群无缝迁移到另一个集群减轻集群压力
可观测性:
1、海量 Topic 的数据指标上报, Promethus 一次性产生几十MB数据,对 Broker 有较大性能影响。
2、服务端消息轨迹,服务提供方和用户侧无法对一条消息的轨迹进行追溯。
3、 针对复杂的生产问题,无法提前发现,如 Unack 导致 Backlog 堆积。
基于以上三个方面的问题,开源方案遇到的挑战也有三个方面:
● 百万级 Topic 支撑,如何保障性能和稳定性?
● 生产级运维要求,如何快速预警排查定位问题?
● 多业务场景共享,如何精细化安全管控和治理?
1、性能:对 Broker 能承受什么样的量级要有感知,感知来源不能是普通的压缩数据,比如说大家从开源社区里看到的一些指标在当前的场景下适不适用要存疑,频繁操作资源会导致Broker 不稳定。
2、稳定性:在部分场景下,当 Topic 数据很多,或者运行时间足够长,会存在一定的 Zookeeper 元数据泄漏,元数据会越积越多,因为目前 Pulsar 版本对 Zookeeper 有强依赖,所以如果 Znote 无限增长,那么最终对稳定性有极高的影响。
3、可运维性:当资源出现不符合预期的场景时,无法追踪每次请求的信息。
● 性能优化:Broker 操作资源性能优化+专享压测保障 + 生产大规模集群验证,保证可以支持操作元数据1000TPS长时间运行没有问题;
● 针对稳定性影响的问题,做了运维管理系统,可以观测 Znote 的增量,知道哪些增量是不符合预期的,能通过和 Broker 元数据做比对,校验元数据是否有逻辑问题,不该增长,便于自助订正与运维;
● 元数据存储标签,对事后数据分析提供支持;
● 资源管理轨迹,保证每笔资源操作信息可查。
当把管控面的问题解决之后,生产更多要关注数据面的稳定性问题,数据面的稳定性其实就包括两部分生产和消费。
1、生产消费问题:限流场景用户无法感知,空洞消息的问题,可能需要重启或者服务端去帮用户做 Unload 的操作。
2、网络方案:用户通过 ListenerName 的方式接入存在一定的感知,但需要扩容的时候运维不够灵活。
3、性能稳定性:Pulsar 里有缓存的概念,那么缓存的有效性命中率有多高,在共享的场景下
需要做判断或者压测,需要做缓存的集中式的管理,包括对整个 Pulsar 存储场面 BK 的一些稳定性的优化。
4、可运维性:不少配置项需要重启 Broker 机器生效,在运维场景下不够友好,对在线消息的场景影响较大,用户消息的轨迹无法确认,但对离线场景感知不明显。
● 支持空洞消息的主动推送,Pulsar 在服务端能感知到空洞消息,因为 Pulsar 有一个记录,是已经被确认的消息的集合,这样在服务端去判断空洞消息的时候就是看它在服务端是否超过了用户配置的时间,比如,用户认为拿到一条消息到消费完最多需要10秒,那么就可以10秒检测一次,如果发现这个消息在空洞消息列表里存在了10秒,Pulsar 就会主动推给用户,解决用户单机常见的问题。
● 生产限流的场景下,Pulsar 也支持 Failfast 的逻辑,如果你被限流了,可以把限流的异常直接返回给用户,这样的话用户也就可以很快的知道这个场景,他能去做对应的逻辑处理。
● 通过泛域名的分配与解析,解决用户需要指定 listenerName 的问题,提升后期的运维灵活性;
● 支持 OHC+LRU 的全局缓存策略,修复 BK 稳定性 Bug Fix,性能和稳定性会有较大提升。
● 对于可运维性上的配置项问题,其实社区目前的动态配置主要是基于 ZK 的,当你的代码层面上支持了动态配置,你可以通过去操作 Pulsar 的动态配置的命令将这个数据写入 ZK,然后 Broker 会监听到 ZK 的变化,然后去更新内存的这种配置,这样的话,首先需要去做一些代码层面的改动,动态运维的东西都要动态调整,这里面包括负载均衡的比例、策略等,社区后面也会对 ZK 做一些相应的替换,我们更希望与运维相关的动态配置有一个通用的地方去存储,代码级别支持Apollo动态配置,包括腾讯云内部的动态配置。这样对于运维管控就不依赖于 ZK 的稳定性。
● 在消息轨迹层面,在 Broker 的代码层面,做了一些 Feature。就是当用户发送消息的时候,我们会把用户发送消息的客户端的来源 IP、消息 ID 以及发送消息的耗时等这些信息,记录下来组成一笔轨迹;当这条消息被消费的时候,也会记录一条轨迹,包括哪一台客户端,哪一个 Consumer 去消费;当用户把这条消息真正去 Ack 的时候,也会做相应的轨迹,最终会呈现给用户一个产品化的东西,当用户发现某一笔消息没有被正常消费的时候,他可以拿消息ID来运维管控端查询,我们会告诉他这个消息有没有被推过,推了几次,目前这个消息在哪里。
1、海量topic:exporter 造成频繁的gc;
2、broker轨迹:生产消费,资源管理服务端无轨迹;
3、监控报警:需要用户配置一套报警系统和规则;
4、指标复杂:如何有效监控预警
● 信息主动上报:当 Topic 很多的时候,当 Brocker 上有3万分区的时候,每次 Promethus 去拉取用户的指标时,需要产生一个 String 的数据,这个数据需要一次性报给 Promethus,通过我们的判断,可能会出现几十兆,上百兆的数据,这样一分钟拉取一次,对服务端的GC压力非常大,服务端的性能就会下降的比较明显。如果把拉的方式改成推的方式,在代码层面,周期性的把内存中的这种数据做拆分,比如每5个 Topic 上报一次,我们在服务端做这样的聚合,好处在于,把一次性的这种数据变成了类似于流的处理,这样的话,性能和稳定性也会有较大的提升。
● 全链路跟踪,支持消息轨迹和资源管理轨迹。
● 精细化监控,对接云监控与报警系统,支持精细的监控与报警。
● 自动化巡检:社区的版本,指标是比较完善的,我们可以通过各种各样的指标来判断服务端目前的健康状态,包括用户的消费情况,真正用户使用的情况下会发现一些问题,主要原因是指标确实很多也很复杂,对用户来说,他要理解这个指标,并且通过这个指标来判断自己的问题,是比较困难的,腾讯云 TDMQ 做了自动化巡检,针对复杂的指标有效性问题,通过自动化巡检系统,主动触达用户。
王者营地App 对用户的登入登出状态,组队状态,房间状态,局内高光数据,击杀数据等用户的消费状态,生产到 Pulsar 集群,这些行为的消费方会在 Pulsar里面去消费,通过 TDMQ Pulsar 削峰填谷,以及 Shared 的订阅模式,进行消息的分发。如果不用消息的话,下图左侧的生产方,需要感知他所有的消费方,并且对所有的消费方做一次RPC的调用,成本较高。包括很多消息不是需要实时性的,通过削峰填谷可以减少业务的压力。下面是一些实践情况。
● 通过不同的 Topic 后缀来区分不同环境。
● 由于业务上过期数据可以不消费,因此设置了2小时的ttl过期时间。
● 客户端使用 Golang pulsar sdk。
● 吞吐量级:十万级生产,十万级消费。
基于以上场景,腾讯云在生产商推荐用户使用最多的是 Java 和 Go 的 SDK,同时也更推荐用户们使用 Shared 的订阅模式,包括 Namespace 的策略上,也更建议用户根据自己的场景来决定是不是需要消费过期,是不是需要设置一些消息保留的机制,方便用户后期的一些回溯。
前面介绍了很多,大家在自己的实际使用场景中,不管是自建还是做开源社区的开发,或者是自己公司内部使用 Pulsar,如果大家遇到以上类似的问题,都可以参考以上的优化方案或者去跟进社区的新版本,腾讯云开发的 Pulsar 也会尽量跟社区保持一致,并贡献给社区。后续也会在以下几个方面做更多的努力。
● 支持根据业务 ID 的消息轨迹查询
● 增强运营管控端业务可理解的指标丰富度
● 运维测支持消息生产消费问题诊断
● 优化大规模超长延迟消息
● Broker动态配置能力支持,支持灰度配置变更