【Kafka源码解读和使用指南】第01篇:Kafka是什么——从LinkedIn的救火队到全球消息中间件之王
下一篇【第02篇】手把手搭建Kafka开发环境——Win/Mac/Linux三平台全攻略摘要2010年LinkedIn的数据管道快撑不住了数十个数据系统两两之间直连形成了令人头秃的蜘蛛网工程师们每天都在救火。然后一群工程师搓出了Kafka——一个分布式提交日志把这团乱麻一刀斩断。如今Kafka已经成为互联网数据基础设施的标配超过80%的财富100强企业都在用它。本文从Kafka的起源故事讲起图解其核心架构概念与RabbitMQ、RocketMQ进行全面对比带你快速建立对Kafka的完整认知。读完这篇你不仅能说清楚Kafka是什么还能自信地回答为什么要用Kafka。一、一场数据管道危机——Kafka的诞生故事时间拨回2010年那年LinkedIn的工程师们正处于崩溃边缘。LinkedIn的数据规模在快速膨胀用户、连接、职位、消息……每天产生海量数据需要喂给各种系统——推荐系统、数据分析、监控告警、搜索引擎……这些系统之间的数据流动是这样的【混乱的数据传输架构Kafka诞生前】 前端日志 ──► 推荐系统 │ ╲ │ ──► 数据仓库 │ ╱ ▼ ╱ 用户行为 ──► 监控告警 │ ╲ │ ──► 搜索系统 ▼ ╲ 业务事件 ──► 离线分析 │ ▼ 消息系统 ──► ...更多系统 痛点N个数据源 × M个数据目的地 N×M 个自定义管道 这种架构有个专业名词叫意大利面条式架构Spaghetti Architecture——每加一个新系统就要重新写一堆对接代码维护地狱随之而来。Jay Kreps现在Confluent的CEO带领团队在2010年搓出了Kafka的原型2011年开源。Kafka的核心思想只有一句话让所有数据通过统一的管道流动而不是点对点乱串。【引入Kafka后的架构Hub-and-Spoke】 前端日志 ──┐ 用户行为 ──┤ ┌──► 推荐系统 业务事件 ──┤ │ 消息数据 ──┼──► Kafka ├──► 数据仓库 服务日志 ──┤ │ 指标数据 ──┘ ├──► 监控告警 │ ├──► 搜索系统 │ └──► 实时分析 优点N M 个连接每端只关心与Kafka对接 ✅LinkedIn用Kafka之后数据管道的复杂度从 O(N×M) 降到了 O(NM)工程师们终于可以睡个好觉了。Kafka的发展里程碑年份事件2010Jay Kreps等人在LinkedIn内部开发Kafka原型2011Kafka贡献给Apache正式开源2012Apache Kafka 0.7发布开始在LinkedIn生产使用2014Jay Kreps等LinkedIn核心开发者创立Confluent公司2016Kafka 0.10引入Kafka Streams2017Kafka 0.11引入幂等Producer和事务支持2019Kafka 2.3引入KRaft模式预研摆脱ZooKeeper2021Kafka 3.0发布KRaft模式进入Early Access2024Kafka 3.9KRaft模式全面稳定ZooKeeper模式正式废弃二、Kafka到底是什么——用一个比喻搞定用快递中转站来比喻Kafka就像一个超级快递分拣中心。快递员Producer把包裹消息送到分拣中心分拣中心Broker按照货架标签Topic存放包裹每个货架Partition上的包裹从左到右排好队每个包裹有编号Offset收货人Consumer随时来取自己要的包裹告诉中心我上次取到第N号了多个中转站Broker集群相互备份一个站点着火了其他站还能继续运营官方定义更严肃一些——Kafka是一个分布式流数据平台Distributed Streaming Platform具备三个核心能力发布与订阅类似消息队列但更强大容错的持久化存储以分布式、复制的方式持久化消息流实时流式处理可以对流数据进行实时处理与转换三、Kafka架构图解——核心概念一次看懂完整架构图┌─────────────────────────────────────────────────────┐ │ Kafka Cluster │ │ │ ┌──────────┐ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ Producer │───────►│ │ Broker 1 │ │ Broker 2 │ │ Broker 3 │ │ │ (生产者) │ │ │ │ │ │ │ │ │ └──────────┘ │ │ Topic: order│ │ Topic: order│ │ Topic: order│ │ │ │ Partition 0│ │ Partition 1│ │ Partition 2│ │ ┌──────────┐ │ │ [L] [F] │ │ [F] [L] │ │ [F] [F][L] │ │ │ Producer │───────►│ └─────────────┘ └─────────────┘ └─────────────┘ │ │ (生产者) │ │ │ └──────────┘ └──────────────────────────┬──────────────────────────┘ │ ┌──────────────────────────▼──────────────────────────┐ │ Consumer Group A │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │Consumer 1│ │Consumer 2│ │Consumer 3│ │ │ │(P0负责) │ │(P1负责) │ │(P2负责) │ │ │ └──────────┘ └──────────┘ └──────────┘ │ └─────────────────────────────────────────────────────┘ [L] Leader副本主副本负责读写 [F] Follower副本从副本同步Leader不参与读写六大核心概念详解① Topic主题——消息的分类标签Topic: order_events ┌──────────────────────────────────────────────────────┐ │ Partition 0: [msg1] [msg2] [msg3] [msg4] ... │ │ Partition 1: [msg1] [msg2] [msg3] ... │ │ Partition 2: [msg1] [msg2] [msg3] [msg4] [msg5] ... │ └──────────────────────────────────────────────────────┘Topic是消息的逻辑分类就像数据库里的表名。生产者向某个Topic发消息消费者从某个Topic拉消息。一个Topic可以有多个Partition这是Kafka实现水平扩展的关键。② Partition分区——并行处理的单元每个Partition是一个有序的、不可变的消息序列消息只追加到末尾append-only。不同Partition之间不保证顺序但同一Partition内的消息严格有序。分区数量决定了最大消费并发数——10个分区意味着最多10个Consumer并行消费。③ Offset偏移量——消息的身份证号Partition 0 的消息队列 ┌────┬────┬────┬────┬────┬────┬────┐ │msg │msg │msg │msg │msg │msg │msg │ │ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ ◄── LEOLog End Offset └────┴────┴────┴────┴────┴────┴────┘ ▲ ▲ │ │ ConsumerA读到这里 ConsumerB读到这里 (committed2) (committed4)Offset是每条消息在Partition中的唯一编号从0开始单调递增。Consumer通过提交Offset来记录消费进度重启后可以从上次的位置继续消费。④ Broker代理节点——Kafka服务器Broker就是Kafka集群中的一台服务器实例。一个Kafka集群由多个Broker组成生产环境最少3个每个Broker负责存储部分Partition的数据并处理来自Producer和Consumer的请求。⑤ Producer生产者——消息发送方Producer将消息发送到指定的Topic。可以指定发往哪个Partition通过Key的Hash或自定义分区器也可以让Kafka自动分配。⑥ Consumer Group消费者组——团队作战单元Topic: order_events (3个分区) ┌────────────┐ ┌────────────┐ ┌────────────┐ │Partition 0 │ │Partition 1 │ │Partition 2 │ └─────┬──────┘ └─────┬──────┘ └─────┬──────┘ │ │ │ ▼ ▼ ▼ ┌──────────────────────────────────────────────┐ │ Consumer Group order-service │ │ ┌────────────┐ ┌────────────┐ │ │ │ Consumer A │ │ Consumer B │ │ │ │ (P0P1) │ │ (P2) │ │ │ └────────────┘ └────────────┘ │ └──────────────────────────────────────────────┘ ┌──────────────────────────────────────────────┐ │ Consumer Group analytics │ │ ┌────────────┐ ┌────────────┐ ┌──────────┐│ │ │ Consumer X │ │ Consumer Y │ │Consumer Z││ │ │ (P0) │ │ (P1) │ │ (P2) ││ │ └────────────┘ └────────────┘ └──────────┘│ └──────────────────────────────────────────────┘Consumer Group的关键特性同一个Group内一个Partition只能被一个Consumer消费不同Group之间互相独立可以各自消费同一个Topic的全量消息Group内Consumer数量 Partition数量时多余的Consumer闲置这个设计让Kafka同时支持消息队列同一Group内互斥消费和发布订阅不同Group独立消费两种模式——一个Kafka玩出两种姿势。四、Kafka vs RabbitMQ vs RocketMQ——三雄对决搞中间件选型的最怕被问到这个问题今天一次性讲清楚对比维度KafkaRabbitMQRocketMQ诞生背景LinkedIn日志系统企业级消息传递阿里巴巴电商开发语言Scala/JavaErlangJava设计理念分布式日志/流平台通用消息代理金融级消息队列消息顺序分区内有序队列内有序分区内有序消息协议自研二进制协议AMQP 0-9-1自研协议吞吐量极高百万/秒级中等万~十万/秒高十万/秒级延迟毫秒级可调微秒级最低延迟毫秒级消息持久化磁盘顺序写默认持久化支持持久化支持持久化消息重放✅ 支持保留期内可回溯❌ 消费后删除✅ 支持死信队列需自行实现✅ 内置DLQ✅ 内置DLQ延迟消息需自行实现插件支持✅ 内置精确延迟事务消息✅ 支持✅ 支持✅ 支持流处理✅ Kafka Streams❌ 无❌ 无集群模式天然分布式水平扩展主从/镜像队列主从/Dledger管理工具kafka-ui/Confluent Control CenterRabbitMQ ManagementRocketMQ Dashboard社区生态极其活跃Confluent商业版活跃VMware维护活跃阿里维护选型建议一句话总结选Kafka日志收集、实时流处理、大吞吐数据管道、需要消息回放选RabbitMQ复杂路由规则、低延迟优先、需要AMQP协议兼容选RocketMQ电商场景延迟消息/死信队列是刚需、金融场景事务消息、国内企业首选五、Kafka的六大典型应用场景场景一日志收集与聚合【日志收集架构】 App Server 1 ──► Filebeat/Logstash ──┐ App Server 2 ──► Filebeat/Logstash ──┤ App Server 3 ──► Filebeat/Logstash ──┼──► Kafka ──► Elasticsearch App Server N ──► Filebeat/Logstash ──┘ └──► Kibana展示 └──► HDFS离线分析这是Kafka最经典的用法。统一收集所有服务的日志解耦日志产生方和日志消费方防止日志洪峰打垮后端存储。场景二实时流处理Kafka Flink/Kafka Streams 构建实时数仓实时UV/PV统计实时风控异常行为检测实时推荐用户行为实时分析场景三微服务异步解耦【订单系统的事件驱动架构】 订单服务 ──publish──► order.created ──► 库存服务扣减库存 │ ├──► 支付服务发起支付 │ ├──► 通知服务发送短信/邮件 │ └──► 积分服务发放积分订单服务只需发一条消息其他服务自行订阅处理互不干扰易于扩展。场景四CDC数据库变更捕获通过Debezium监听MySQL的Binlog将数据库的增删改以事件形式发到Kafka再同步到其他系统ES、Redis、数据仓库——这是数据同步的王炸方案。场景五事件总线Event Bus在大型分布式系统中Kafka作为事件总线串联起所有服务的事件流实现事件溯源Event Sourcing和CQRS命令查询职责分离。场景六监控指标收集Prometheus的Pushgateway不够用让各服务把指标数据推到Kafka再由消费者写入时序数据库InfluxDB/TDengine实现高吞吐的监控指标收集。六、Kafka为什么这么快——高性能的5个秘密很多人听说Kafka每秒能处理百万级消息就好奇它是怎么做到的。其实Kafka的高性能来自5个关键设计秘密一顺序写磁盘【随机写 vs 顺序写】 随机写传统数据库 磁头 ──► 跳到位置A写 ──► 跳到位置X写 ──► 跳到位置C写 ──► ... 寻道耗时!! 寻道耗时!! 顺序写Kafka的做法 磁头 ──► 追加到末尾 ──► 继续追加 ──► 继续追加 ──► ... 极速!! 极速!! 磁盘顺序写速度~600MB/s 磁盘随机写速度~100KB/s慢约6000倍秘密二零拷贝Zero-Copy传统方式消费消息需要4次数据拷贝磁盘 → 内核缓冲区 → 用户空间 → Socket缓冲区 → 网卡Kafka使用Linux的sendfile()系统调用只需2次拷贝磁盘 → 内核缓冲区 → 网卡省去了两次用户态/内核态切换CPU开销大幅减少。秘密三批量处理Producer端将多条消息打成一批RecordBatch统一发送Broker端批量写入Consumer端批量拉取——三端都批量减少了大量网络往返次数RTT。秘密四页缓存Page CacheKafka几乎不自己管内存全程依赖操作系统的Page Cache。写入时只写到内存Page Cache由OS异步刷盘读取时如果命中Page Cache直接从内存返回完全不碰磁盘。秘密五分区并行一个Topic多个Partition可以分散到多个Broker多个磁盘天然实现并行读写——水平扩展吞吐量只需加机器加分区。【5大性能密码汇总】 ┌─────────────────────────────────────────────────────────┐ │ Kafka 高性能设计 │ │ │ │ ① 顺序写磁盘 → 吞吐量提升 6000x vs 随机写 │ │ ② 零拷贝 → CPU开销减半网络传输更快 │ │ ③ 批量处理 → 网络往返次数 ↓吞吐量 ↑ │ │ ④ 页面缓存 → 热数据命中内存延迟极低 │ │ ⑤ 分区并行 → 横向扩展加节点即加吞吐 │ │ │ └─────────────────────────────────────────────────────────┘七、Kafka的局限性——什么场景不适合用它Kafka很强但不是万能的场景适合Kafka原因海量消息高吞吐✅ 最适合设计初衷日志流式处理✅ 最适合设计初衷微服务异步解耦✅ 适合天然支持多消费者消息回放/回溯✅ 适合消息可按Offset重复消费精确延迟消息如30分钟后提醒❌ 不适合原生不支持延迟投递复杂消息路由按Header路由❌ 不如RabbitMQ路由能力弱死信队列/重试队列❌ 需自行实现无内置DLQ超低延迟微秒级❌ 不如RabbitMQ批量等待有延迟消息量级很小 1000条/s⚠️ 杀鸡用牛刀运维成本高八、5分钟快速体验Kafka用Docker一键启动Kafka 4.xKRaft模式无需ZooKeeper# 启动 KafkaKRaft 模式Kafka 4.xdockerrun-d\--namekafka\-p9092:9092\-eKAFKA_CFG_NODE_ID1\-eKAFKA_CFG_PROCESS_ROLESbroker,controller\-eKAFKA_CFG_LISTENERSPLAINTEXT://:9092,CONTROLLER://:9093\-eKAFKA_CFG_ADVERTISED_LISTENERSPLAINTEXT://localhost:9092\-eKAFKA_CFG_CONTROLLER_QUORUM_VOTERS1kafka:9093\-eKAFKA_CFG_CONTROLLER_LISTENER_NAMESCONTROLLER\bitnami/kafka:latest# 进入容器dockerexec-itkafkabash# 创建 Topic3个分区1个副本kafka-topics.sh--create\--topichello-kafka\--partitions3\--replication-factor1\--bootstrap-server localhost:9092# 查看 Topic 详情kafka-topics.sh--describe\--topichello-kafka\--bootstrap-server localhost:9092# 发送消息生产者kafka-console-producer.sh\--topichello-kafka\--bootstrap-server localhost:9092# 输入Hello Kafka! 然后回车# 消费消息另开一个终端kafka-console-consumer.sh\--topichello-kafka\--from-beginning\--bootstrap-server localhost:9092看到自己发的消息被消费出来恭喜你——Kafka之旅正式开始本篇小结本文带你了解了Kafka的来龙去脉起源LinkedIn 2010年为解决数据管道蜘蛛网问题而生核心理念以分布式提交日志为核心用统一的消息管道解耦数据流六大概念Topic主题/ Partition分区/ Offset偏移量/ Broker节点/ Producer生产者/ Consumer Group消费者组——这六个概念是整个系列的基础务必记牢三雄对比Kafka适合高吞吐流处理RabbitMQ适合复杂路由低延迟RocketMQ适合电商金融场景性能密码顺序写 零拷贝 批量处理 页缓存 分区并行五剑合一从下一篇开始我们就要撸起袖子搭环境了——Win/Mac/Linux三平台全攻略一篇搞定所有环境问题下一篇【第02篇】手把手搭建Kafka开发环境——Win/Mac/Linux三平台全攻略