早上九点刚打开电脑,消息队列运维群的未读消息数量还在往上跳。不是告警,是有人发了一张截图,指向Kafka背后的商业化公司被收购的消息。群里沉默了几分钟,随后冒出一句话:“我们那二十多个Kafka集群,接下来怎么处理?”
这条新闻其实不算突然。过去一两年,圈子里一直在讨论Kafka生态的商业走向,只是没人想到会以这种方式落地。真正落到自己身上时,问题就变得具体了:手上几十个Topic、几百个消费组、几十个下游系统,都运行在Kafka之上,我们到底该不该换、能不能换、怎么换?
这篇文章就是我基于这件事做的一次完整复盘。我把它拆成四个部分:事件背后的风险到底在哪里、候选替代方案的真实能力如何、一次实际迁移会踩哪些坑、以及不是所有Kafka集群都该立刻动手。如果你也想给团队做一份类似的技术评估,这里的内容可以直接拿去当参考。
1. 收购案落地那天,技术群里的沉默比恐慌更值得回味
1.1 为什么官方公告出来之后,所有人的第一反应是“先别急”
相信很多同行和我一样,看到消息的第一反应不是恐慌,而是一种说不出来的疲惫感。过去一年里,群里关于“换不换Kafka”的讨论一直没有断过,但真正当收购消息尘埃落定,反而没有人再喊“马上全换”。原因很简单:存量系统太多,牵一发动全身。
Kafka虽然是一个开源项目,但它的生态主导权一直掌握在商业化公司手里。商标、核心维护团队、商业版服务、认证体系,这些东西都跟着收购案一起换了东家。对国内使用方来说,最直接的感受是:未来这个项目的路线图,不再由技术社区说了算,而是由收购方的商业战略说了算。
这里想给不太熟悉背景的朋友解释一下。Kafka本身是Apache基金会的顶级项目,使用它的代码、参与社区讨论,门槛并不高。但是开源只是项目的一部分,围绕Kafka建立的商业版、云托管服务、企业支持体系,才是真正容易被收购影响的部分。收购意味着这些商业能力全部换了主导权,而开源主项目虽然代码仍是开放的,但“谁说了算”这件事,已经彻底改变了。
我当时在群里回了一句:先别急着表态,我们需要的是评估,不是站队。这句话也是整篇文章的态度——替代不是目的,而是为了降低不确定性。
1.2 四个风险点:许可证、供应链、路线图、数据主导权
很多人以为开源项目被收购,最坏结果不过是“代码还是免费的”。但实际做过技术选型的人都知道,事情远没有这么简单。我梳理了四个真正值得关注的风险点。
许可证风险排在第一位。Kafka主项目用的是宽松型开源许可证,短期内不会出问题。但收购方整合之后,很可能把商业版组件和开源主项目打包成新的产品线。历史上类似的并购案,都出现过“商业产品里面的某个重要插件不再开源”的情况。某些企业正在使用的连接器、监控工具、多区域同步能力,如果恰好属于商业版范畴,未来就可能面临授权条款变动。
供应链风险同样不能忽视。这里的供应链指的不是买硬件,而是指技术支持与社区演化。过去团队遇到Kafka的疑难问题,还能指望官方社区甚至商业支持兜底。收购之后,支持团队的稳定性、响应速度、优先级分配,都会围绕新东家的客户体系重新排序,国内用户很可能被降级到“非重点客户”。
路线图风险则是中长期问题。Kafka的新特性会优先满足谁的需求,会向哪个方向发展,这完全取决于收购方的战略规划。比如某些对国内业务很重要的能力(更细粒度的配额控制、特定的安全认证方式、云原生部署形态)在原有路线图里排期靠前,在新东家手里就未必了。
数据主导权这一点容易被忽略,但对企业级用户来说往往最敏感。当消息中间件运行在别人的商业决策边界之内,集群配置、流量模型、峰值规律这些运维数据,也就一并进入了对方的商业视野。不是说一定会出问题,但它让“可控性”这件事失去了确定性。
四张风险牌摆到一起,“势在必行”这四个字就很好理解了——不是说明天就要换,而是每家认真在用Kafka的团队,都必须开始准备自己的Plan B。这个Plan B不是为了赌气,是为了让核心技术栈的命运不完全押在别人身上。
2. 替代方案摸底:协议兼容、性能数据、运维成本一次讲清
2.1 三条路:协议兼容代理、原生竞品、自研托管
确定要准备Plan B之后,第一步工作不是写代码,而是把所有可能的替代方向摸一遍。我梳理下来,目前能走的路大致有三条。
第一条路是选择兼容Kafka协议的消息队列。这类方案对客户端最友好,因为不用改生产端和消费端的代码,只需要替换地址配置,就可以把流量切过去。适合追求低成本快速迁移的团队。代价是协议兼容不等于行为完全一致,某些边界场景下还是会有差异,这需要在迁移阶段重点验证。
第二条路是选择原生协议的消息队列,比如在圈内讨论度很高的其他开源方案。这类方案不走兼容路线,客户端语言、连接方式、消费模型都需要重新适配。好处是能摆脱Kafka协议的限制,在一些高级特性上做得更顺手;坏处是迁移成本明显更高。适合本来就打算做深度改造的团队。
第三条路是购买云厂商或第三方提供的托管消息队列服务。这种方式把运维压力转移出去,团队不用关心集群扩缩容、副本同步、故障转移这些事。但托管服务通常有比较强的绑定关系,如果后续想迁走,可能比从Kafka迁过来还麻烦。适合运维人力紧张、业务又对稳定性要求极高的团队。
三条路各有取舍,不要问哪条路绝对更好,只能说哪条路更适合你现在的处境。我的建议是:如果业务形态明确、团队人力有限,第一条路是最务实的起点;如果公司技术实力强、愿意长期投入,第二条路是更可控的终局。
2.2 用真实流量压测:吞吐、延迟、堆积恢复的差异
摸底阶段最容易犯的错误是拿官方基准数据当结论。官方压测用的模型、消息体大小、分区配置,跟你的真实业务差得很远。我给团队定了一个原则:不跑业务流量回放的压测,一律不算数。
我组织了一次针对性的压测,规模不大但足够说明问题:用我们自己的订单消息回放,消息体平均2KB,峰值流量在10万条每秒左右,其中一个Topic是强顺序语义,另一个Topic用到了事务消息。测试环境是标准的3节点集群,磁盘用相同等级的SSD。
主要对比了三个指标:吞吐量、端到端延迟、堆积恢复速度。结果比我预想的更有参考价值。在吞吐量上,几个主流候选在同等规格节点下都能跑到10万条每秒以上,没有出现谁明显掉队的情况。在端到端延迟上,原生协议的候选方案在低峰期表现略好,但高峰期差距不大,基本在同一个数量级。堆积恢复速度是最让我意外的:某个候选方案在消费端滞后的情况下,把堆积清空的速度明显比Kafka原生方案更快,原因是它的消费模型更贴近多消费者并行拉取。
不过压测也暴露了兼容协议代理方案的问题:在不改客户端代码、纯靠协议翻译的条件下,吞吐量会下降约15%到20%,延迟增加几毫秒。这个代价对多数业务是能接受的,但不经过实测,你永远不会知道这个数字对你来说是“能接受”还是“不能接受”。
2.3 按业务场景选型的快速对照表
压测数据跑完,我让团队把结果整理成了一张选型对照表,方便后续各个业务线快速做出初步判断。这里把核心内容分享出来:
| 替代方向 | 迁移成本 | 运维复杂度 | 适合场景 | 需要注意的问题 |
|---|---|---|---|---|
| 兼容Kafka协议代理 | 低 | 中 | 客户端语言多、业务量大、希望快速切换 | 高级特性兼容性需逐项验证,吞吐有损耗 |
| 原生协议开源方案 | 中高 | 中高 | 愿意投入长期改造,需要更强事务、延迟消息能力 | 客户端要重写,消费模型要重新培训 |
| 云托管消息队列 | 低 | 低 | 运维人力少、业务快速迭代、对SLA要求极高 | 绑定风险高,跨云迁移难度大 |
| 自研消息内核 | 极高 | 极高 | 业务规模巨大、有专业中间件团队 | 投入周期长,非核心业务慎用 |
这张表不是让你照着选,而是提醒你:选型本质上是拿迁移成本、运维能力和业务需求三个因素做三角权衡。没有十全十美的方案,只有最不难受的取舍。
3. 从Kafka迁到替代MQ,一次真实迁移踩过的九个坑
3.1 迁移前先盘点Kafka家底:一张清单一次过
真正开始迁移之前,第一件事不是选工具,而是把现有Kafka集群的“家底”盘清楚。很多团队跳过这一步,直接开始改客户端配置,后面往往会被各种意想不到的问题拖垮。
我整理了一份盘点清单,建议你也按这个顺序走一遍。每个集群的Topic列表、分区数量、副本策略、消息保留时间这些基础配置要最先摸清;然后是消费组清单,必须知道每一个消费组的订阅关系、当前延迟积压情况、负责人是谁。接下来是消息体大小分布,花十分钟抽几个Topic看看消息加密格式和平均大小,这直接影响目标选型的规格设计。如果集群配置了安全认证,还要记录SASL、SSL的使用方式;如果依赖了拦截器或自定义序列化器,也要在盘点阶段就标注清楚。
有个容易漏掉的地方:消费组的偏移量标记方式。Kafka默认用内部Topic存储消费位点,但很多团队会自定义位点存储到外部数据库。迁移时如果只搬数据不搬位点信息,就会出现消费重复或者直接丢消息。我见过不止一次,因为忘了迁移位点信息,导致上线后消费侧重复消费了全量消息,业务侧差点炸锅。
盘点不一定要做到完美,但至少要形成一个动态更新的台账。这个台账不仅迁移时有用,迁移后做性能对比也是基准。没有基准数据,你后面根本说不清楚新的消息队列到底比Kafka好还是差。
3.2 客户端迁移最容易被忽略的三个细节
如果选择协议兼容方案,感觉上只是换个地址就能跑,但实际上有一些细节新人很容易踩坑,这里单独列出来。
第一个细节是客户端版本。Kafka官方客户端有多个大版本,不同版本对协议功能的支持等级不一样。有些老版本客户端,虽然能在Kafka里跑得好好的,但在协议兼容方案下可能因为某个字段不支持而直接报错。我们在迁移前做了一轮客户端版本普查,把低于某个版本的客户端全部列出来,优先升级到统一版本,再开始灰度。不做这步,问题会在流量切换之后才爆发,而且很难排查。
第二个细节是消息序列化方式。Kafka本身不关心消息体是JSON还是Avro还是Protobuf,它只负责搬运。但目标消息队列如果对消息元数据有额外要求,序列化器就可能成为瓶颈。我们在测试时发现某个序列化器在目标方案上性能骤降,最后定位到是序列化组件与消息队列的批处理机制不兼容。解决方案很朴素:在传输层关闭小消息自动批处理,或者升级序列化器版本。
第三个细节是请求超时与重试参数。Kafka客户端的不少默认参数,在原生集群里跑得很稳定,但换到协议兼容层之后,由于多了一层协议转换,单次请求耗时变长,超时重试阈值就需要重新调整。如果沿用原值,很可能出现大量超时与重复发送。这里我给个直观建议:迁移初期可以把request.timeout.ms调大到原来的1.5倍,等流畅运行后再逐步收紧。
这三个细节都不复杂,但都属于“看不懂文档踩不到、不踩一次不会记住”的坑。提前处理,能省掉后面很多折腾。
3.3 顺序消息、事务、死信:三个硬骨头逐个解决
迁移过程中最麻烦的其实是三类特殊消息:顺序消息、事务消息、死信消息。它们不像普通吞吐型消息那样换个地址就能跑,需要单独处理和验证。
顺序消息在Kafka里的实现方式是分区内有序,也就是说,只要把相同业务ID的消息发到同一个分区,消费端就能按顺序收到。换到其他消息队列时,这个语义可能不同。有的方案默认是全局顺序,有的方案把顺序保证放在队列级别而不是分区级别。迁移时如果直接照搬原有发送逻辑,没有显式指定MessageKey,顺序就会错乱。解决方案看起来很笨但非常有效:在所有需要保序的消息上,一律显式指定HashKey,不做任何隐式依赖。
事务消息是另一个大坑。Kafka的事务消息能力强调的是“原子写入多个分区”,和传统消息队列里的“本地消息表+事务回查”并不是同一个概念。我们在做迁移映射时,花了很长时间才理清楚目标方案的事务模型,确认它的回查机制、超时时间、事务状态存储方式都和Kafka不一样。强烈建议你把每种事务场景都写成测试用例,在迁移环境里单独跑一遍,而不是靠文档做判断。
死信队列这里其实没那么复杂,但很考验细节。不同消息队列对“重试到达上限之后怎么办”的处理逻辑差异很大。有的方案默认进入死信队列,有的方案直接丢弃,有的方案会回头调用业务回调。迁移前我们做了一个死信策略对照表,把每一个Topic的消费失败场景、重试次数、失败后处置方式都列出来逐一确认,比上线后靠人力盯日志靠谱得多。
这三个硬骨头的共同点是:不能只用“能跑通”作为验证标准,必须把失败场景全部模拟一遍,否则迁移上去的是一个看起来很稳、实际一碰就碎的隐形炸弹。
3.4 灰度切流和回滚预案,一个都不能少
迁移方案做得再细致,也不能把旧集群直接下掉,这是所有中间件迁移的底线。我们这次迁移采用了双写加灰度切流的组合拳,过程比预期顺利,但回滚预案依然救了命。
双写阶段,让生产端同时把消息发送到Kafka和替代消息队列,消费端暂时还是只消费Kafka的消息。这一步主要是验证替代方案的写入稳定性和数据一致性。双写跑了两周,确认两边数据能对上、消费延迟稳定,才开始进入切流阶段。
切流不是把流量一次性切过去,而是按消费组一步一步来。先把日志类、非核心链路的消费组切过去,观察一天;再切部分服务型消费组,观察三天;最后才处理核心交易的消费组。每次切流前都要记录基线指标,比如消息生产耗时、消费队列深度、端到端处理延迟,切流后与基线对比,有任何异常立即回滚。
回滚预案听起来简单,做起来需要准备充分。我们把Kafka集群的状态冻结在切流前的版本上,不做任何配置变更和客户端升级,保证随时可以一键切回。后来真有一类消费组在切换后出现了消息积压,运维直接把流量切回Kafka,整个回滚过程不到十分钟,业务几乎无感知。这就说明了预案存在的意义:不是为了预测一定会失败,而是为了在失败发生时让损失最小化。
4. 不是所有Kafka集群都该立刻动手,先做分级评估
4.1 三个问题决定你是“立刻迁”还是“先稳住”
消息发布后,后台收到不少留言,很多人的第一反应都是“那我们是不是下周就得开始迁?”我每次都会反问:你手里的Kafka集群,是不是全部都需要立刻迁?大多数人认真想一下就会发现,并不是。
我建议用三个问题来给集群做分级评估。第一,这个集群是否承载核心交易链路?如果Kafka停机十分钟就会导致订单失败、资金异常,毫无疑问是最高优先级,需要最短时间完成替代评估。如果只是一个日志中转集群,停机一小时也影响不大,那优先级就低得多。第二,现有业务是否重度使用了Kafka的专有特性?如果只是简单的发布订阅,迁移到任何替代方案都很快;如果深度依赖事务消息、精确一次语义、分层存储这些高级特性,迁移成本会成倍上涨。第三,团队是否有能力承接替代方案后续的日常运维?如果连当前Kafka集群的运维都已经捉襟见肘,那么引入一个需要全队重新学习的新系统,很可能不是减负而是加压。
真正合理的做法是:把集群分成A、B、C三级。A级是核心链路且依赖复杂,需要立刻投入资源去规划替代方案;B级是重要但非核心,可以先做兼容性预研,等工作流和工具链跑通之后顺势迁移;C级是边缘业务,不必赶时间,保持观察即可。
4.2 不迁移的Kafka集群,怎么用最小成本保住底线
对优先级较低的Kafka集群,短期内不迁移不等于什么都不做。用最小成本把风险控制到可接受范围,是更务实的选择。
第一步是锁版本。把Kafka服务端和客户端版本固定下来,禁止任何无计划的升级。理由很简单,Kafka被收购后,未来新版本的功能走向、兼容策略都存在不确定性,盲目跟随升级可能引入不可控的变化。锁版本本质上是在不确定性面前保留一个“已知状态”。第二步是备份核心配置。把每个集群的Topic配置、分区策略、安全配置、监控模板做快照,放到一个独立仓库里,保证即使原集群出问题,也能快速重建。第三步是建立健康基线。记录集群在正常情况下的关键指标:网络吞吐、磁盘IO延迟、消息积压水位、消费端Lag波动范围。这些数据平时不起眼,真到要判断集群是否出现异常时,价值就大了。
这个过程不复杂,但能让不迁移的集群也处于“可控”的状态,而不是“听天由命”的状态。对于资源有限的团队,这个投入比盲目迁移划算得多。
4.3 替代的真正目标,是把主导权拿回自己手里
复盘这次事件,我感受最深的一点是:替代Kafka本身不是目的,通过替代拿到对自己技术栈的掌控感,才是真正的目标。
我们最后交付给管理层的不是“要不要换Kafka”的结论,而是一份包含分级评估、候选测评、迁移预案、回滚机制的完整方案。这份方案的价值在于:无论未来收购方做出什么商业决策,我们都不会被它拖着走。
迁移期间团队还做了一件小事:把所有新项目选型评审要求里,加上了“是否依赖不可控的商业决策”这一条。以后不管是消息队列、数据库还是缓存组件,只要评估结果是“核心链路依赖了外部主导权的项目”,就必须额外准备替代路线。这一条写进评审规则之后,团队讨论技术栈的方式变得清晰了很多。
最后说一点我自己的体会。这次收购消息出来之后,外界讨论最多的是“换哪个”,真正经历过这次评估之后,我看到的问题却是“你敢不敢把命运攥在自己手里”。很多技术债不是不能还,而是一直没人认真掂量过还款的代价。Kafka是个好项目,但好项目不等于没有风险;替代一个好项目也不必带着情绪,只需要带着清单、数据、预案,然后一步步走过去。希望这篇文章,能让你面对类似选择题的时候,少一点慌张,多一点底气。