一、为什么需要Kafka这样的消息队列
在没有消息队列之前,两个系统之间最直接的通信方式通常就是:
系统A
↓
直接调用
↓
系统B
例如一个电商系统中,用户提交订单以后,需要执行:
创建订单
↓
扣减库存
↓
发送短信
↓
发送邮件
↓
记录日志
最直接的写法可能类似:
createOrder(); // 创建订单
reduceStock(); // 扣减库存
sendMessage(); // 发送短信
sendEmail(); // 发送邮件
writeLog(); // 写入日志
这样写功能当然可以实现,但会出现一个比较明显的问题:
这些操作全部串在一起了
假设:
sendMessage();
执行比较慢,那么整个下单流程也会被拖慢。
甚至如果短信服务出现故障:
订单系统
↓
调用短信系统
↓
短信系统异常
↓
订单流程可能受到影响
也就是说,两个系统之间:
耦合得比较紧
如果中间增加一个消息队列:
订单系统
↓
发送消息
↓
消息队列
↙ ↓ ↘
库存 短信 日志
系统 系统 系统
订单系统只需要完成:
我产生了一条"订单创建成功"的消息
然后把消息交给消息队列。
至于谁去处理:
库存系统
短信系统
日志系统
订单系统并不需要关心。
这就是消息队列非常重要的一个作用:
系统解耦
除了系统解耦之外,消息队列还有另外两个非常常见的作用:
异步处理
+
流量削峰
例如某一秒突然出现:
100000个请求
如果后面的业务系统每秒只能处理:
10000个请求
直接把这 10 万个请求全部打过去:
10万请求
↓
业务服务器
↓
瞬间压力过大
就可能导致系统崩溃。
加入消息队列之后:
10万请求
↓
消息队列
↓
暂时保存
↓
消费者按照自己的速度处理
这样消息队列就像一个:
缓冲区
把突然出现的大量流量先接住,然后慢慢处理。
所以从应用角度来说,Kafka 首先可以理解成:
一个负责在不同系统之间暂存和传递消息的平台。
二、Kafka到底是什么
Kafka 最开始可能很容易被理解成:
一个队列
但实际上 Kafka 并不只是一个简单的队列。
更准确地说,Kafka 是一个:
分布式事件流平台
不过对于刚开始学习来说,不需要先纠结这个定义。
先把 Kafka 理解成:
生产者
↓
Kafka
↓
消费者
就够了。
这里有三个最重要的角色:
Producer
Kafka Broker
Consumer
分别对应:
Producer:生产消息
Broker:保存和管理消息
Consumer:消费消息
例如:
订单系统
产生一条订单信息:
{
"orderId": 10001,
"userId": 9527,
"price": 299
}
订单系统就是:
Producer
它把消息发送给 Kafka:
Producer
↓
Kafka
Kafka 负责把消息保存下来。
库存系统再从 Kafka 中读取:
Kafka
↓
Consumer
那么库存系统就是:
Consumer
整个过程就是:
Producer
↓
发送消息
↓
Kafka
↓
保存消息
↓
Consumer
↓
消费消息
所以第一阶段学习 Kafka 时,可以先牢牢记住:
Kafka并不是主动帮我们处理业务
Kafka 做的主要事情是:
接收消息
保存消息
提供消息
真正处理业务的还是:
Producer
和
Consumer
三、Producer、Broker、Topic和Consumer是什么
Kafka 中有几个最基础的概念:
Producer
Broker
Topic
Consumer
先来看 Producer。
1. Producer
Producer 就是:
消息生产者
例如:
订单系统
日志系统
支付系统
设备采集系统
都可能成为 Producer。
Producer 的工作非常简单:
创建消息
↓
发送给Kafka
例如:
Producer
↓
"订单10001创建成功"
↓
Kafka
2. Broker
Kafka 真正运行起来以后,本质上也是一个:
服务程序
运行 Kafka 服务的服务器节点通常叫:
Broker
例如:
服务器1 → Broker 1
服务器2 → Broker 2
服务器3 → Broker 3
多台 Broker 可以组成:
Kafka Cluster
Kafka集群
结构可以简单理解成:
Kafka Cluster
┌────────┬────────┐
↓ ↓ ↓
Broker1 Broker2 Broker3
为什么需要多个 Broker?
因为一台机器会存在:
性能上限
磁盘上限
故障风险
多台机器以后,可以共同:
存储数据
处理请求
提供容错
这也是 Kafka 被称为:
分布式系统
的重要原因之一。
3. Topic
Producer 把消息发送给 Kafka 时,不能随便乱放。
需要告诉 Kafka:
这是什么类型的消息
于是就有了:
Topic
Topic 可以理解成:
消息的分类
例如:
order_topic → 订单消息
payment_topic → 支付消息
log_topic → 日志消息
订单系统发送消息:
订单系统
↓
order_topic
支付系统发送消息:
支付系统
↓
payment_topic
所以 Topic 可以先简单理解成:
Kafka 中用于对不同类型消息进行分类的逻辑容器。
4. Consumer
Consumer 就是:
消息消费者
负责从 Kafka 中取出消息。
例如:
Kafka
↓
订单消息
↓
库存系统
库存系统读取订单消息并完成扣库存,它就是一个 Consumer。
因此 Kafka 最基础的整体结构就是:
Producer
↓
发送消息
↓
Topic
↓
Kafka
↓
保存消息
↓
Consumer
↓
处理消息
理解这几个角色以后,Kafka 的整体框架基本就已经出来了。
四、一条Kafka消息到底是怎么流转的
现在把整个过程真正串起来。
假设有一个订单系统:
Order Service
用户成功创建订单以后产生一条消息:
{
"orderId": 10001,
"price": 299
}
Producer 将消息发送给:
order_topic
流程:
订单系统
↓
Producer
↓
order_topic
↓
Kafka Broker
Kafka 收到以后负责保存。
然后库存系统:
Stock Service
作为 Consumer:
Kafka
↓
读取order_topic
↓
Stock Consumer
↓
扣减库存
整个完整流程就是:
用户创建订单
↓
订单系统
↓
Producer
↓
发送订单消息
↓
order_topic
↓
Kafka Broker
↓
保存消息
↓
Consumer
↓
库存系统
↓
扣减库存
这样订单系统就不用直接写:
reduceStock();
而是:
只发送一个订单创建消息
库存系统自己去消费。
假设以后还要增加:
短信系统
积分系统
日志系统
原来的订单系统也不需要不断增加:
sendMessage();
addPoints();
writeLog();
而是可以变成:
Kafka
↓
┌─────────────────┼─────────────────┐
↓ ↓ ↓
库存系统 短信系统 积分系统
这就是前面提到的:
解耦
Producer 不需要知道:
到底有几个Consumer
Consumer具体怎么处理
它只负责:
把消息送到Kafka
五、先跑一个最简单的Kafka消息流程
Kafka 环境搭建后,可以直接通过 Kafka 自带的命令测试 Producer 和 Consumer。
假设已经存在一个:
test
Topic。
可以先启动一个消费者:
kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test
其中:
--bootstrap-server localhost:9092
表示连接:
localhost:9092
这个 Kafka Broker。
而:
--topic test
表示消费:
test
这个 Topic 中的消息。
然后再启动一个 Producer:
kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test
启动以后输入:
hello kafka
Producer 会把:
hello kafka
发送给 Kafka。
整个流程:
Producer终端
↓
hello kafka
↓
test Topic
↓
Kafka Broker
↓
Consumer终端
↓
hello kafka
于是 Consumer 就能够读取到:
hello kafka
这里看起来只是:
发送一句话
但实际上已经把 Kafka 最基本的工作模型完整跑了一遍:
Producer
↓
Topic
↓
Broker
↓
Consumer
因此第一阶段学习 Kafka,并不需要一开始就记:
ISR
Replica
KRaft
Leader
Follower
Controller
Rebalance
这些概念。
先把最基础的一层搞清楚:
Kafka
Producer → Broker → Consumer
↑
Topic
其中:
Producer
负责生产消息
Topic
负责对消息分类
Broker
负责接收和保存消息
Consumer
负责读取和处理消息
而 Kafka 最常见的三个价值可以先记成:
系统解耦
+
异步处理
+
流量削峰
不过这里还留下了一个非常重要的问题。
前面一直说:
消息保存在Topic里面
但实际上:
Topic 本身只是一个逻辑概念,Kafka 中真正负责存储消息的是 Partition。
也就是说,一个 Topic 内部实际上可能是:
Topic:order_topic
├── Partition 0
├── Partition 1
└── Partition 2
Producer 发送过来的消息最终会进入某一个:
Partition
而 Kafka 为什么一定要设计 Partition、一个 Topic 为什么要拆成多个 Partition、Offset 又是什么,这些就是理解 Kafka 真正存储模型的关键。
下一篇继续从:
Topic
↓
Partition
↓
Offset
这一条线开始分析 Kafka 中一条消息到底保存在哪里。