Wiki LogoWiki - The Power of Many
DevOps

Kafka

Kafka

kafka

核心价值: 解耦 缓冲 异步通信 高吞吐

基本角色: 生产者 消费者 主题

生产者(Producer)

向Kafka里写数据的程序

消费者(Consumer)

从Kafka里读数据的程序

主题(Topic)

Kafka里组织数据的方式, 相当于一个"频道"或者"分类"

分区(Partition)

Kafka高性能的关键

一个主题可以被分成多个分区

为什么要分区?

  • 并行处理: 多个分区意味着可以同时写入, 同时读取.
  • 保证局部顺序: Kafka只保证同一个分区内的消息是按发送顺序存储的.

副本(Replica)

数据存在一台机器上是有风险的, 万一机器坏了, 数据就没了. Kafka通过"副本"机制解决这个问题.

每个分区都可以有多个副本, 其中一个叫 Leader, 其他叫 Follower. 生产者只往Leader写, 消费者只从Leader读. Follower在后台默默同步Leader的数据.

如果Leader所在的机器挂了, Kafka会自动从Follower中选一个新的Leader, 服务继续, 数据也不会丢(前提是配置得当). 这里有个关键概念叫 ISR(In-Sync Replicas), 意思是"跟得上节奏的副本". 只有那些和Leader数据同步的差不多的Follower, 才有资格被选为新的Leader. 这样能避免选出一个落后的副本导致数据丢失.

消费者组(Consumer Group)

多人协作读取数据. Kafka不是简单的一对一收发, 它支持"一对多"甚至"多对多"的消费模式, 靠的就是消费者组.

一个消费者组可以包含多个消费者实例. 它们共同消费一个主题, 但Kafka保证: 同一个分区在同一时间只能被组内的一个消费者读取.

如果消费者数量多于分区数, 比如有8个消费者但只有6个分区, 那多余的2个就只能"待业", 因为Kafka不允许一个分区被多个消费者同时消费(重复处理).

另外, 不同消费者组之间是完全独立的. 比如组A和组B都订阅了同一个主题, 那么组A的消费进度不影响组B, 两者都能完整拿到全部数据. 这非常适合多个业务系统各自处理同一份原始数据的场景.

偏移量(Offset)

消费者怎么知道自己上次读到哪儿啦? 靠的就是偏移量(Offset).

每个分区里的消息都有一个递增的编号, 从0开始.消费者每次读完一批消息, 就会记录下自己读到的最大偏移量. 下次重启时, 就从这个位置继续读,不会重复也不会遗漏.

Kafka默认会把消费者的偏移量自动存到一个特殊的内部主题(_consumer_offsets)里. 你也可以自己管理, 但一般没必要.

这里有一个常见误区: 偏移量是按分区记录的, 不是按整个主题.

持久化与日志结构

Kafka把消息持久化到磁盘, 而且性能还特别高.

秘密在于它的存储设计: Kafka把每个分区的数据写成一个"日志文件", 追加写入(append-only), 不修改已有内容.这种操作对磁盘非常友好. 再加上它利用操作系统的页缓存(page cache)和零拷贝技术, 读写效率极高. 而且, Kafka的消息默认会保留一段时间(比如7天), 即使消费者还没来得及处理, 数据也不会马上消失, 这让系统更有容错能力.

生产者如何保证可靠发送

虽然Kafka本身很稳, 但如果生产者发消息是网络抖动, 服务器挂了, 还是可能丢数据.

生产者有几种策略来提高可靠性:

  • 确认机制(acks): 生产者可以设置发完消息后要不要Kafka确认. (acks=0 acks=1 acks=all)
  • 重试机制: 如果发送失败, 生产者可以自动重试.
  • 幂等性: Kafka支持"幂等生产者", 开启后及时重试也不会产生重复消息. 这是通过给每条消息加唯一ID实现的.
  • 事物
    , Kafka还支持跨分区的事务, 确保多条消息要么全成功,要么全失败.

消费者如何避免重复或者遗漏

理想情况下, 消费者处理一条消息, 提交偏移量, 完美. 但现实中总有意外: 消费者处理到一半宕机了, 偏移量还没有提交, 重启后就会重新处理这条消息; 如果消费者先提交了偏移量, 再处理消息, 结果处理时崩溃了, 那这条消息就丢了. 建议: 先处理消息, 再提交偏移量. (这种情况可能导致重复消费, 但不会丢)

重复怎么办? 这就要求业务逻辑具备"幂等性". 另外, Kafka还提供了手动提交偏移量的选项, 让你更精细控制何时提交, 配合业务逻辑做到"恰好一次"(Exactly Once)语义, 但这需要额外设计.

Kafka适用场景和局限

虽然Kafka很强大, 但它不是所有场景都合适. 适合Kafka的场景:

  • 高吞吐, 低延迟的数据管道(日志搜集, 监控指标)
  • 需要解耦生产者和消费者的系统
  • 需要多个系统消费同一份数据
  • 需要回溯历史数据(比如重放最近24小时的日志)

不适合Kafka的场景:

  • 需要严格一对一, 点对点的消息传递(RabbitMQ更合适)
  • 消息非常大(Kafka设计是为大量小消息优化的)
  • 需要复杂的路由规则
  • 对消息延迟及其敏感

Kafka

运维和监控

Kafka集群一旦上线, 就得持续维护.

有几个关键点:

  • 集群规模: 几个Broker(kafak服务器) 分区怎么分布 副本因子设多少
  • 磁盘和网络: Kafka吃磁盘IO和带宽, 得监控资源使用
  • 消费者滞后(Lag): 如果消费者处理太慢, 积压的消息越来越多, 叫"lag太高", 可能拖垮系统
  • ZooKeeper 或 KRaft(新版): 老版本Kafka依赖ZooKeeper做协调, 新版本(2.8+)开始支持用内置的KRaft协议,简化架构 生产速率 消费速率 请求延迟 副本同步状态

Kafka生态

Kafka已经不只是一个消息中间件了, 而是一个流数据平台, 围绕它有一整套生态工具.

  • Kafka Connect: 用来和外部系统对接, 比如从 MySQL 同步数据到Kafka, 或者把 Kafka 数据写入 Elasticsearch
  • Kafka Steams: 轻量级流处理库, 让你直接在应用里做实时计算, 比如统计没分钟点击量
  • KsqlDB: 用SQL语法实时查询Kafka数据流

On this page