1. Kafka 前世今生:消息队列发展史、Kafka 诞生背景、核心概念与应用场景

大家好,我是你们这门课的老朋友。今天咱们正式开篇,聊聊 Kafka 的“前世今生”。

说实话,我接触 Kafka 快十年了。从最初在日志采集场景里用它,到后来支撑公司核心交易链路,这中间踩过不少坑,也积累了一些心得。今天这一讲,我不打算一上来就扔概念,而是想先带大家看看:消息队列这东西到底是怎么来的?Kafka 为什么会在 2011 年诞生?它那些核心概念——Topic、Partition、Offset——到底在说什么?

嗯,咱们慢慢聊。

消息队列发展史:从“点对点”到“发布订阅”

消息队列不是什么新鲜事物。早在上世纪 80 年代,IBM 的 MQSeries 就已经在金融系统里跑了。那时候的消息队列,说白了就是两个系统之间“传纸条”——一个发,一个收,中间有个缓冲区。

我最早接触的是 ActiveMQ。那时候做电商订单系统,订单服务要把数据同步给仓储和物流。如果直接调接口,仓储挂了订单就丢了。用 ActiveMQ 做异步解耦,确实解决了问题。但后来流量大了,ActiveMQ 的瓶颈就出来了——单机吞吐上不去,集群方案也不成熟。

消息队列的发展大致经历了三个阶段:

  • 第一阶段:点对点模型(P2P)。消息从生产者发出,被一个消费者消费。典型代表:IBM MQ、早期的 RabbitMQ。
  • 第二阶段:发布订阅模型(Pub/Sub)。一个消息可以被多个消费者订阅。典型代表:ActiveMQ、RabbitMQ 的 Topic 模式。
  • 第三阶段:分布式消息流平台。不仅支持发布订阅,还具备高吞吐、持久化、流式处理能力。典型代表:Kafka、Pulsar。

你想想看,为什么会有这个演进?说白了,业务在变。以前一个订单消息只给一个系统用,现在一个用户行为日志要给推荐、广告、风控、BI 四个系统同时消费。点对点模型根本扛不住。

核心观点:消息队列的本质是“解耦”和“缓冲”。但不同阶段,对“解耦”的深度和“缓冲”的容量要求完全不同。

Kafka 诞生背景:LinkedIn 的“日志危机”

Kafka 的故事要从 LinkedIn 说起。2010 年左右,LinkedIn 遇到了一个很现实的问题:他们需要收集海量的用户行为数据——页面浏览、搜索、点击、职位申请……这些数据要同时喂给多个下游系统。

当时 LinkedIn 用的是 ActiveMQ 和自定义的“管道”方案。结果呢?

  • ActiveMQ 吞吐上不去,单机也就几千 TPS。
  • 数据可靠性差,经常丢消息。
  • 消费者多了,生产者性能急剧下降。

我记得 Jay Kreps(Kafka 的创始人之一)在一次分享里说过:他们当时需要一个能处理“网站所有活动数据”的管道,但市面上的消息队列没有一个能满足。于是他们决定自己写一个。

Kafka 的设计灵感其实来自日志文件。你想想看,日志文件有什么特点?

  • 顺序写入,速度极快。
  • 可以反复读取,不会因为读了一次就消失。
  • 天然支持“回溯”——你可以从任意位置开始读。

Kafka 把消息存储设计成类似日志的结构,这就是它高性能的根源。2011 年,Kafka 被开源,很快在业界引起轰动。2012 年,LinkedIn 把它捐给了 Apache 基金会。

个人经验:我曾在项目中用 Kafka 替换了原有的 RabbitMQ 集群。替换前,单机吞吐不到 5000 TPS,CPU 经常飙到 90%。替换后,同样的硬件,Kafka 跑到了 10 万 TPS,CPU 只有 30%。这个差距,说白了就是设计理念的不同。

核心概念:Topic / Partition / Offset

好,咱们来聊聊 Kafka 最核心的三个概念。理解了它们,你就理解了 Kafka 的一半。

Topic(主题)

Topic 是 Kafka 中消息的逻辑分类。你可以把它理解成一个“消息的类别”或“消息的文件夹”。比如,订单消息发到 order_topic,用户行为消息发到 user_behavior_topic。

一个 Topic 可以有多个生产者往里面写,也可以有多个消费者从里面读。生产者不需要关心谁在读,消费者也不需要关心谁在写——这就是解耦。

Partition(分区)

Partition 是 Kafka 实现高吞吐的关键。一个 Topic 会被分成多个 Partition,每个 Partition 是一个有序的、不可变的日志文件。

为什么要分区?

  • 并行处理:多个 Partition 可以分布在不同的 Broker 上,读写可以并行进行。
  • 水平扩展:如果 Topic 的吞吐不够,增加 Partition 数量就能提升性能。
  • 数据冗余:每个 Partition 可以有多个副本,保证数据不丢。

我曾经遇到过一个案例:某个业务 Topic 只有一个 Partition,生产者的写入速度远大于消费者的处理速度,导致消息积压严重。后来我们把 Partition 增加到 8 个,消费者也扩展到 8 个实例,问题立刻解决了。

Offset(偏移量)

Offset 是 Partition 中每条消息的唯一编号。它从 0 开始,每条新消息的 Offset 递增 1。

Offset 的作用是什么?

  • 定位消息:消费者通过 Offset 知道自己该从哪条消息开始读。
  • 回溯消费:消费者可以重置 Offset,重新消费历史消息。
  • 断点续传:消费者崩溃后重启,可以从上次提交的 Offset 继续消费,不会重复也不会遗漏。

避坑指南:我曾经在项目中遇到过消费者 Offset 提交失败导致重复消费的问题。原因是消费者处理消息的时间太长,超过了 session.timeout.ms 的配置,被 Kafka 判定为“死亡”,然后触发了 rebalance。解决方案是:要么缩短处理时间,要么增大超时时间,要么使用异步提交 + 手动管理 Offset。

下面这张图展示了 Topic、Partition、Offset 之间的关系:

Kafka 核心概念关系图 Topic: order_topic Partition 0 Partition 1 Partition 2 Offset 列表 Offset 0: 订单创建 Offset 1: 订单支付 Offset 2: 订单发货 Offset 3: 订单完成 消费者组 A 消费者组 B 说明 • 一个 Topic 包含多个 Partition • 每个 Partition 有独立的 Offset • 不同消费者组独立消费 • 同一组内消费者负载均衡

应用场景剖析:Kafka 到底能干什么?

Kafka 的应用场景非常广泛。我根据自己的项目经验,把它归纳为四大类:

场景类别 典型应用 为什么用 Kafka
日志采集 用户行为日志、服务器日志、应用日志 高吞吐、持久化、支持回溯
消息系统 订单通知、短信发送、邮件推送 解耦、削峰填谷、异步处理
流式处理 实时计算、实时推荐、实时风控 Kafka Streams / Flink 集成
事件溯源 订单状态变更、账户流水 不可变日志、顺序保证

我重点说说第一个场景——日志采集。这是 Kafka 的“发家之地”。

在 LinkedIn,Kafka 最初就是用来收集用户行为日志的。每天几十亿条日志,要实时写入 HDFS 做离线分析,同时还要给实时推荐系统用。Kafka 的 Partition 机制让它可以水平扩展,Broker 不够了就加机器,吞吐不够了就加 Partition。

第二个场景——消息系统,其实是最常见的。很多公司用 Kafka 做订单消息的异步处理。用户下单后,订单服务把消息发到 Kafka,然后库存、物流、积分、通知各自消费。这样即使某个下游系统挂了,也不会影响主流程。

第三个场景——流式处理,是 Kafka 近几年的重点发展方向。Kafka Streams 和 KSQL 让开发者可以用 Kafka 直接做流式计算,不需要额外部署 Flink 或 Spark。我最近的一个项目就是用 Kafka Streams 做实时风控,延迟控制在 100 毫秒以内。

个人建议:如果你是第一次接触 Kafka,我建议先从“消息系统”这个场景入手。搭建一个简单的生产者-消费者 Demo,理解 Topic、Partition、Offset 是怎么工作的。等熟悉了基础概念,再尝试日志采集和流式处理。

小结

好了,这一章的内容就到这里。我们回顾一下:

  • 消息队列从点对点发展到发布订阅,再到分布式流平台,Kafka 是第三阶段的代表。
  • Kafka 诞生于 LinkedIn 的日志采集需求,设计灵感来自日志文件。
  • Topic 是逻辑分类,Partition 是物理分片,Offset 是消息的唯一编号。
  • Kafka 的应用场景包括日志采集、消息系统、流式处理和事件溯源。