对于作者
鲍明宇
腾讯高级软件工程师,目前就任于腾讯 TEG 数据平台部,负责 Apache Pulsar、Apache Inlong、DB 数据采集等我的项目的开发工作。目前专一于大数据畛域,消息中间件、大数据数据接入等方向,领有 10 年 Java 相干开发教训。
张大伟
腾讯高级软件工程师,Apache Pulsar Committer,目前就任于腾讯 TEG 数据平台部,次要负责 Apache Pulsar 我的项目相干工作。目前专一于 MQ 和数据实时处理等畛域,领有 6 年大数据平台相干开发教训。
对于 Apache Pulsar
云原生时代音讯队列和流交融零碎,提供对立的生产模型,反对音讯队列和流两种场景,既能为队列场景提供企业级读写服务质量和强一致性保障,又能为流场景提供高吞吐、低提早;采纳存储计算拆散架构,反对大集群、多租户、百万级 Topic、跨地区数据复制、长久化存储、分层存储、高可扩展性等企业级和金融级性能。
GitHub 地址:http://github.com/apache/pulsar/
导读
近期,腾讯 TEG 数据平部 MQ 团队开发部署了一套底层运维指标性能剖析零碎(本文简称 Data 我的项目),目前作为通用基础设施服务整个腾讯团体。该零碎旨在收集性能指标、上报数据以用于业务的运维监控,后续也将延用至前后端实时剖析场景。
腾讯 Data 我的项目选用 Apache Pulsar 作为音讯零碎,其服务端采纳 CVM 服务器(Cloud Virtual Machine,CVM)部署,并将生产者和消费者部署在 Kubernetes 上,该我的项目 Pulsar 集群是腾讯数据平台部 MQ 团队接入的音讯量最大的 Pulsar 集群。在整个我的项目中,咱们在 Apache Pulsar 大规模集群运维过程中遇到了一些问题和挑战。本文将对这些问题开展形容剖析,并分享对应解决计划,同时也会解析波及到的相干 Apache Pulsar 设计原理。
心愿本文可能对面临同类场景的用户与开发者提供参考。
业务音讯量大,对生产与生产耗时指标敏感
Data 我的项目的业务场景,具备非常明显的特点。首先,业务零碎运行过程中,音讯的生产、消费量都十分大,而且生产音讯的 QPS(每秒查问率)波动性不显著,即业务会在近乎固定的 QPS 生产和生产数据。
其次,业务方对系统的可靠性、生产耗时、生产耗时这几个指标项比拟敏感,须要在比拟低的提早根底上实现业务解决流程。像 Data 我的项目这样的业务场景和需要,对集群的部署、经营和零碎稳定性都提出了十分高的要求。
Data 我的项目集群最大的特点是音讯量大、节点多,一个订阅里可高达数千消费者。尽管 Data 我的项目以后 Topic 总量并不多,但单个 Topic 对应的客户端比拟多,每个分区要对应 100+ 个生产者和 10000+ 个消费者。在对音讯零碎选型时,团队将音讯零碎的低提早、高吞吐设为要害指标。通过综合比照市面上常见的音讯零碎,Apache Pulsar 凭借其性能和性能胜出。
Apache Pulsar 提供了诸多生产模型如独占、故障转移、共享(Shared)和键共享(Key_Shared),其中在 Key_Shared 和 Shared 订阅下能够撑持大量消费者节点。其余音讯流零碎如 Kafka,因为消费者节点受限于分区个数,导致其在多分区时性能绝对较低。(编者注:Pulsar 和 Kafka 的最新性能测评,敬请期待 StreamNative 行将公布的 2022 版报告)
超大 Pulsar 集群:单分区最大消费者数量超 8K
目前 Data 我的项目业务数据接入两套 Pulsar 集群,分为 T-1 和 T-2。其中,T-1 对接的业务的客户端 Pod(分为生产者和消费者,且不在同一个 Pod 上,部署在腾讯云容器化平台 (STKE),与 Pulsar 集群在雷同机房;T-2 对接业务的客户端 Pod 与 Pulsar 集群不在雷同的机房(注:机房之间的数据时延相比同机房外部略高)。
服务器侧相干参数
序号 | 参数 | 详情 | 备注 |
---|---|---|---|
1 | 集群 数 | 2 | T-1/ T-2 |
2 | 机器数量 | 100+ 台 / 集群 | CVM IT5(非物理机 /64 核 /256G 内存 / 4 SSD) |
3 | Broker 数量 | 100+ | 2.8.1.2(外部版本),部署三台 Discovery 服务 |
4 | Bookie 数量 | 100+ | |
5 | Discovery 服务 | 3/ 集群 | 与 Bookie 混合部署在同一台机器下面 |
6 | ZooKeeper 数量 | 5/ 每集群 | 3.6.3 版本,独自部署,应用 SA2.4XLARGE32 机型 |
7 | 部署形式 | Broker+Bookie 混合部署在同一台机器下面 | |
8 | Topic 数 | 3/ 集群 | |
9 | 分区数 | 100+/Topic | |
10 | 音讯正本数 | 2 | 正本写入策略:E=5, W=2, A=2 |
11 | 音讯保留时长 | 1 天 | Retention\TTL 均配置为 1 天 |
12 | namespace 数 | 3 | 每个 namespace 下一个 Topic |
13 | 以后音讯量 / 天(依照每条音讯大小 4k 均值评估) | 千亿 / 天 / 集群 | |
14 | 以后音讯量 / 分钟 | 千万 / 分钟 |
业务侧相干参数
Data 我的项目业务侧应用 Go 语言开发,接入 Pulsar 集群应用 Pulsar Go Client 社区 Master 分支的最新版本。应用云梯 STKE 容器形式部署。
序号 | 参数 | 形容 | 备注 |
---|---|---|---|
1 | 单分区最大生产者数量 | 150 左右 | |
2 | 单分区最大消费者数量 | 1w 个左右 | 单分区这个量,服务器端须要保护大量的元数据信息 |
3 | 客户端接入形式 | Go SDK | 目前应用 Master 分支最新代码 |
4 | 生产者 Pod 数量 | 150 左右 | |
5 | 消费者 Pod 数量 | 1w 个左右 | |
6 | 客户端部署平台 | STKE | 腾讯外部的腾讯云容器服务平台 |
本文接下来将介绍 Pulsar 客户端在多种场景下的性能调优,别离针对我的项目在应用 Pulsar 的过程中遇到的客户端生产超时、客户端频繁断开等状况进行起因解析,并提供咱们的解决方案,供大家参考。
客戶端性能调优:问题与计划
调优一:客户端生产超时,服务器端排查
在大集群下,导致客户端生产音讯耗时较长或生产超时的起因有很多,咱们先来看几个服务器端的起因,包含:
- 音讯确认信息过大(确认空洞)
- Pulsar-io 线程卡死
- Ledger 切换耗时过长
- BookKeeper-io 单线程耗时过长
- DEBUG 级别日志影响
- Topic 分区数据分布不均 \
接下来,针对每个可能的服务器端起因,咱们一一进行解析。
解析 1:生产确认信息过大(确认空洞)
与 Kafka、RocketMQ、TubeMQ 等不同,Apache Pulsar 不仅仅会针对每个订阅的生产进度保留一个最小的确认地位(即这个地位之前的音讯都曾经被确认已生产),也会针对这个地位之后且曾经收到确认响应的音讯,用 range 区间段的形式保留确认信息。
如下图所示:
另外,因为 Pulsar 的每个分区都会对应一个订阅组下的所有消费者。Broker 向客户端推送音讯的时候,通过轮询的形式(此处指 Shared 共享订阅;Key_Shared 订阅是通过 key 与一个消费者做关联来进行推送)给每个消费者推送一部分音讯。每个消费者别离确认一部分音讯后,Broker 端可能会保留很多这种确认区段信息。
如下图所示:
确认空洞是两个间断区间之间的点,用于示意确认信息的区间段的个数。确认空洞受雷同订阅组下消费者个数的多少、消费者生产进度的快慢等因素的影响。空洞较多或特地多即示意生产确认的信息十分大。
Pulsar 会周期性地将每个生产组的确认信息组成一个 Entry,写入到 Bookie 中进行存储,写入流程与一般音讯写入流程一样。因而当生产组的生产确认空洞比拟多、生产确认信息比拟大、写入比拟频繁的时候,会对系统的整体响应机制产生压力,在客户端体现为生产耗时增长、生产超时增多、耗时毛刺显著等景象。
在此状况下,能够通过缩小消费者个数、进步消费者生产速率、调整保留确认信息的频率和保留的 range 段的个数等形式解决确认空洞。
解析 2:Pulsar-io 线程卡死
Pulsar-io 线程池是 Pulsar Broker 端用于解决客户端申请的线程池。当这里的线程解决慢或卡住的时候,会导致客户端生产超时、连贯断连等。Pulsar-io 线程池的问题,能够通过 jstack 信息进行剖析,在 Broker 端体现为存在大量的 CLOSE_WAIT
状态的连贯,
如下图所示:
Pulsar-io 线程池卡住的景象,个别为服务器端代码 bug 导致,目前解决过的有:
- 局部并发场景产生的死锁;
- 异步编程 Future 异样分支未解决完结等。
除了程序本身的 bug 外,配置也可能引起线程池卡住。如果 Pulsar-io 线程池的线程长时间处于运行状态,在机器 CPU 资源足够的状况下,能够通过变更 broker.conf
中的 numioThreads
参数来调整 Pulsar-io 线程池中的工作线程个数,来进步程序的并行处理性能。
留神:Pulsar-io 线程池忙碌,自身并不会导致问题。 然而,Broker 端有一个后盾线程,会周期的判断每一个 Channel(连贯)有没有在阈值工夫内收到客户端的申请信息。如果没有收到,Broker 会被动的敞开这个连贯(相同,客户端 SDK 中也有相似的逻辑)。因而,当 Pulsar-io 线程池被卡住或者解决慢的时候,客户端会呈现频繁的断连 - 重联的景象。
解析 3:Ledger 切换耗时过长
Ledger 作为 Pulsar 单个分区音讯的一个逻辑组织单位,每个 Ledger 下蕴含肯定大小和数量的 Entry,而每个 Entry 下会保留至多一条音讯(batch 参数开启后,可能是多条)。每个 Ledger 在满足肯定的条件时,如蕴含的 Entry 数量、总的音讯大小、存活的工夫三个维度中的任何一个超过配置限度,都会触发 Ledger 的切换。
Ledger 切换工夫耗时比拟长的景象如下:
当 Ledger 产生切换时,Broker 端新接管到或还未解决完的音讯会放在 appendingQueue 队列中,当新的 Ledger 创立实现后,会持续解决这个队列中的数据,保障音讯不失落。
因而,当 Ledger 切换过程比较慢时会导致音讯生产的耗时比拟长甚至超时。这个场景下,个别须要关注下 ZooKeeper 的性能,排查下 ZooKeeper 所在机器的性能和 ZooKeeper 过程的 GC 情况。
解析 4:BookKeeper-io 单线程耗时过长
目前 Pulsar 集群中,BookKeeper 的版本要绝对比较稳定,个别通过调整相应的客户端线程个数、保留数据时的 E、QW、QA 等参数能够达到预期的性能。
如果通过 Broker 的 jstack 信息发现 BookKeeper 客户端的 Bookkeeper-io 线程池比拟忙碌时或线程池中的单个线程比拟忙碌时,首先要排查 ZooKeeper、Bookie 过程的 Full GC 状况。如果没有问题,能够思考调整 Bookkeeper-io 线程池的线程个数和 Topic 的分区数。
解析 5:Debug 级别日志影响
在日志级别下,影响生产耗时的场景个别呈现在 Java 客户端。如客户端业务引入的是 Log4j,应用的是 Log4j 的日志输入形式,同时开启了 Debug 级别的日志则会对 Pulsar Client SDK 的性能有肯定的影响。倡议应用 Pulsar Java 程序引入 Log4j 或 Log4j + SLF4J 的形式输入日志。同时,针对 Pulsar 包调整日志级别至多到 INFO 或 ERROR 级别。
在比拟夸大的状况下,Debug 日志影响生产耗时的线程能将生产耗时拉长到秒级别,调整后升高到失常程度(毫秒级)。具体景象如下:
在音讯量特地大的场景下,服务器端的 Pulsar 集群须要敞开 Broker、Bookie 端的 Debug 级别的日志打印(倡议线网环境),间接将日志调整至 INFO 或 ERROR 级别。
解析 6:Topic 分区散布不均
Pulsar 会在每个 Namespace 级别配置 bundles,默认 4 个,如下图所示。每个 bundle range 范畴会与一个 Broker 关联,而每个 Topic 的每个分区会通过 hash 运算,落到对应的 Broker 进行生产和生产。当过多的 Topic 分区落入到雷同的 Broker 下面,会导致这个 Broker 下面的负载过高,影响音讯的生产和生产效率。
中度可信度形容已主动生成]()Data 我的项目在开始部署的时候,每个 Topic 的分区数和每个 Namespace 的 bundle 数都比拟少。通过调整 Topic 的分区个数和 bundle 的宰割个数,使得 Topic 的分区在 Broker 下面达到逐渐平衡散布的目标。
在 bundle 的动静宰割和 Topic 的散布调整上,Pulsar 还是有很大的晋升空间,须要在 bundle 的宰割算法(目前反对 range_equally_divide
、topic_count_equally_divide
,默认目前反对 range_equally_divide
,倡议应用 topic_count_equally_divide
)、Topic 分区的散布层面,在保证系统稳固、负载平衡的状况下做进一步的晋升。
调优二:客户端频繁断开与重连
客户端断连 / 重连的起因有很多,联合腾讯 Data 我的项目场景,咱们总结出客户端 SDK 导致断连的次要有如下几个起因,次要包含:
- 客户端超时断连 - 重连机制
- Go SDK 的异样解决
- Go SDK 生产者 sequence id 解决
- 消费者大量、频繁的创立和销毁
上面顺次为大家解析这些问题的起因与解决方案。
解析 1:客户端超时断连 - 重连机制
Pulsar 客户端 SDK 中有与 Broker 端相似逻辑(可参考 #解析 2 局部内容),周期判断是否在阈值的工夫内收到服务器端的数据,如果没有收到则会断开连接。
这种景象,排除服务器端问题的前提下,个别问题呈现在客户端的机器资源比拟少,且使用率比拟高的状况,导致应用程序没有足够的 CPU 能力解决服务器端的数据。此种状况,能够调整客户端的业务逻辑或部署形式,进行躲避解决。
解析 2:Go SDK 的异样解决
Pulsar 社区提供多语言的客户端的接入能力,如反对 Java、Go、C++、Python 等。然而除了 Java 和 Go 语言客户端外,其余的语言实现绝对要弱一些。Go 语言的 SDK 绝对于 Java 语言 SDK 还有很多中央须要欠缺和细化,比方说在细节解决上与 Java 语言 SDK 相比还不够细腻。
如收到服务器端的异样时,Java SDK 可能辨别哪些异样须要销毁连贯重连、哪些异样不必销毁连贯(如 ServerError_TooManyRequests
),但 Go 客户端会间接销毁 Channel,从新创立。
解析 3:Go SDK 生产者 Sequence id 解决
发送音讯后,低版本的 Go SDK 生产者会收到 Broker 的响应。如果响应音讯中的 sequenceID
与本端保护的队列头部的 sequenceID
不相等时会间接断开连接——这在局部场景下,会导致误断,须要辨别小于和大于等于两种场景。
这里形容的场景和解析 1- 客户端超时中的局部异样场景,曾经在高版本 Go SDK 中做了细化和解决,倡议大家在选用 Go SDK 时尽量选用新的版本应用。目前,Pulsar Go SDK 也在疾速的迭代中,欢送感兴趣的同学一起参加和奉献。
解析 4:消费者大量且频繁地创立和销毁
集群运维过程中在更新 Topic 的分区数后,消费者会大量且频繁地创立和销毁。针对这个场景,咱们已排查到是 SDK bug 导致,该问题会在 Java 2.6.2 版本呈现。运维期间,消费者与 Broker 端曾经建设了稳固的连贯;运维过程中,因业务音讯量的增长需要,须要调整 Topic 的分区数。客户端在不须要重启的前提下,感知到了服务器端的调整,开始创立新增分区的消费者,这是因为解决逻辑的 bug,会导致客户端大量且频繁地重复创立消费者。如果你也遇到相似问题,倡议降级 Java 客户端的版本。
除了下面的断连 - 重连场景外,在咱们腾讯 Data 我的项目的客户端还遇到过 Pod 频繁重启的问题。通过排查和剖析,咱们确定是客户端出现异常时,抛出 Panic 谬误导致。倡议在业务实现时,要思考相干的容错场景,在实现逻辑层面进行肯定水平的躲避。
调优三:降级 ZooKeeper
因为咱们腾讯 Data 我的项目中应用的 Pulsar 集群音讯量比拟大,机器的负载也绝对较高。波及到 ZooKeeper,咱们开始应用的是 ZooKeeper 3.4.6 版本。在日常运维过程中,整个集群屡次触发 ZooKeeper 的一个 bug,景象如下截图所示:
以后,ZooKeeper 我的项目曾经修复该 Bug,感兴趣的小伙伴能够点击该连贯查看详情:https://issues.apache.org/jir…。因而,在 Pulsar 集群部署的时候倡议打上相应的补丁或降级 ZooKeeper 版本。在腾讯 Data 我的项目中,咱们则是抉择将 ZooKeeper 版本升级到 3.6.3 进行了对应解决。
小结:Pulsar 集群运维排查指南
不同的业务有不同的场景和要求,接入和运维 Apache Pulsar 集群时遇到的问题,可能也不太一样,但咱们还是能从问题排查角度方面做个梳理,以便找到相应法则晋升效率。
针对 Apache Pulsar 集群运维过程中遇到的问题,如生产耗时长、生产超时(timeout)、音讯推送慢、生产沉积等,如果日志中没有什么显著的或有价值的异样(Exception)、谬误(Error)之类的信息时,能够从如下几个方面进行排查:
- 集群资源配置及应用现状
- 客户端生产情况
- 音讯确认信息
- 线程状态
- 日志剖析 \
上面针对每个方面做个简要阐明。
1. 集群资源配置及应用现状
首先,须要排查过程的资源配置是否可能满足以后零碎负载情况。能够通过 Pulsar 集群监控仪表盘平台查看 Broker、Bookie、ZooKeeper 的 CPU、内存及磁盘 IO 的状态。
其次,查看 Java 过程的 GC 状况(特地是 Full GC 状况),解决 Full GC 频繁的过程。如果是资源配置方面的问题,须要集群管理人员或者运维人员调整集群的资源配置。
2. 客户端生产情况
能够排查生产能力有余引起的反压(背压)。呈现背压的景象个别是存在消费者过程,然而收不到音讯或迟缓收到音讯。
能够通过 Pulsar 治理命令,查看受影响 Topic 的统计信息(stats),可重点关注 未确认音讯数量数量(unackedMessages)
、backlog 数量
和生产订阅类型
,以及 解决未确认音讯(unackmessage)比拟大的订阅 / 消费者
。如果未确认音讯(unackmessage)数量过多,会影响 Broker 向客户端的音讯散发推送。这类问题个别是业务侧的代码解决有问题,须要业务侧排查是否有异样分支,没有进行音讯的 ack 解决。
3. 音讯确认信息
如果集群生产耗时比拟长或生产耗时毛刺比拟多,除了零碎资源配置方面排查外,还须要查看是否有过大的音讯确认信息。
查看是否有过大的确认空洞信息,能够通过治理命令针对单个 Topic 应用 stats-internal
信息,查看订阅组中的 individuallyDeletedMessages
字段保留的信息大小。
音讯确认信息的保留过程与音讯的保留过程是一样的,过大的确认信息如果频繁下发存储,则会对集群存储造成压力,进而影响音讯的生产耗时。
4. 线程状态
如果通过下面的步骤,问题还没有剖析分明,则须要再排查下 Broker 端的线程状态,次要关注 pulsar-io
、bookkeeper-io
、bookkeeper-ml-workers-OrderedExecutor
线程池的状态,查看是否有线程池资源不够或者线程池中某个线程被长期占用。
能够应用 top -p PID(具体 pid) H
命令,查看以后 CPU 占用比拟大的线程,联合 jstack 信息找到具体的线程。
5. 日志剖析
如果通过下面所述步骤依然没有确认问题起源,就须要进一步查看日志,找到含有有价值的信息,并联合客户端、Broker 和 Bookie 的日志及业务的应用特点、问题呈现时的场景、最近的操作等进行综合剖析。
回顾与打算
下面咱们花了很大篇幅来介绍客户端性能调优的内容,给到客户端生产超时、频繁断开与重连、ZooKeeper 等相应的排查思路与解决方案,并汇总了常见 Pulsar 集群问题排查指南 5 条倡议,为在大音讯量、多节点、一个订阅里高达数千消费者的 Pulsar 利用场景运维提供参考。
当然,咱们对 Pulsar 集群的调优不会进行,也会持续深刻并参加社区我的项目共建。
因为单个 Topic 对应的客户端比拟多,每个客户端所在的 Pod、Client 外部会针对每个 Topic 创立大量的生产者和消费者。由此就对 Pulsar SDK 在断连、重连、生产等细节的解决方面的要求比拟高,对各种细节解决流程都会十分的敏感。SDK 外部解决比拟毛糙的中央会导致大面积的重连,进而影响生产和生产。目前,Pulsar Go SDK 在很多细节方面解决不够细腻,与 Pulsar Java SDK 的解决有很多不一样的中央,须要继续优化和欠缺。腾讯 TEG 数据平台 MQ 团队也在积极参与到社区,与社区共建逐步完善 Go SDK 版本。
另外,针对腾讯 Data 我的项目的特大规模和业务特点,Broker 端须要解决大量的元数据信息,后续 Broker 本身的配置仍须要做局部的配置和继续调整。同时,咱们除了扩容机器资源外,还打算在 Apache Pulsar 的读 / 写线程数、Entry 缓存大小、Bookie 读 / 写 Cache 配置、Bookie 读写线程数等配置方面做进一步的调优解决。