第二章:核心概念与协议——消息队列、发布-订阅与TCP/UDP

各位同学,欢迎来到第二章。上一章我们聊了实时数据通道的整体轮廓,今天咱们把地基打牢。说白了,这一章讲的就是「数据怎么在通道里流动」这件事。我做了这么多年实时系统,发现很多问题都出在基础概念没吃透上。嗯,咱们一个一个来。

2.1 消息队列:Kafka vs RabbitMQ

消息队列是什么?你可以把它想象成一个「邮局」。生产者把信投进去,消费者从信箱里取信。但不同的邮局,处理方式天差地别。

2.1.1 Kafka——为吞吐而生

Kafka 是我个人最常用的消息队列。它设计的初衷就是「快」。有多快?单机每秒能处理几十万条消息。我在做金融行情系统时,就用 Kafka 扛过每秒 50 万笔的订单流。

Kafka 的核心是「日志」——消息被追加到分区里,消费者自己维护读取位置。这种设计让 Kafka 特别适合做数据管道和日志收集。

关键特性:
  • 消息持久化到磁盘,不怕丢
  • 支持消息回溯重放
  • 天然支持分区和副本
  • 吞吐量极高,延迟中等(几毫秒到几十毫秒)

2.1.2 RabbitMQ——为可靠而生

RabbitMQ 走的是另一条路。它更强调「消息一定要送到」。我记得有一次做电商订单系统,要求每笔订单都不能丢,哪怕系统重启也要保证最终送达。这时候 RabbitMQ 的「确认机制」就派上用场了。

RabbitMQ 基于 AMQP 协议,消息路由非常灵活。你可以用交换机、队列、绑定键玩出各种花样。但代价是吞吐量不如 Kafka,单机大概每秒几万条。

我的选择建议:
  • 需要高吞吐、日志收集、数据管道 → 选 Kafka
  • 需要可靠投递、复杂路由、任务队列 → 选 RabbitMQ
  • 两者都想要?可以组合使用,我就在一个项目里用过 Kafka 做数据管道,RabbitMQ 做业务消息

2.2 发布-订阅模式

发布-订阅模式,简称 Pub/Sub。说白了就是「一对多」的消息分发。生产者发布一条消息,所有订阅者都能收到。

你想想看,这和传统的点对点模式有什么区别?点对点是一条消息只能被一个消费者消费,像排队打饭。而 Pub/Sub 就像广播电台——你播节目,所有收音机都能收到。

Kafka 的消费者组就是 Pub/Sub 的典型实现。同一个组内的消费者竞争消费(点对点),不同组的消费者各自消费(发布-订阅)。

我曾经踩过的坑: 在 Kafka 中,如果消费者组名写错了,会导致消息被重复消费。我调试了整整一个下午才发现是组名配置问题。所以,命名规范真的很重要。

2.3 生产者-消费者模型

这个模型是消息队列的基石。生产者只管发消息,消费者只管收消息,两者完全解耦。好处很明显:

  • 异步处理:生产者不用等消费者处理完
  • 削峰填谷:流量高峰时,消息先堆积在队列里,消费者慢慢消化
  • 系统解耦:生产者和消费者可以独立部署、独立升级

我在做实时风控系统时,就用这个模型处理过每秒 10 万次的请求。生产者把请求扔进 Kafka,多个消费者并行处理。如果不用消息队列,直接调接口,系统早就被冲垮了。

下面是一个简单的生产者代码示例(Kafka Java 客户端):

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");

Producer<String, String> producer = new KafkaProducer<>(props);
producer.send(new ProducerRecord<>("my-topic", "key", "hello world"));
producer.close();

消费者代码也很简单:

Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("group.id", "my-group");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("my-topic"));
while (true) {
    ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
    for (ConsumerRecord<String, String> record : records) {
        System.out.printf("offset = %d, key = %s, value = %s%n", record.offset(), record.key(), record.value());
    }
}

2.4 TCP vs UDP:协议选择

聊完消息队列,咱们得说说底层传输协议。TCP 和 UDP 的选择,直接影响实时通道的性能和可靠性。

特性 TCP UDP
连接方式 面向连接(三次握手) 无连接
可靠性 保证送达,自动重传 不保证送达,可能丢包
顺序性 保证数据顺序 不保证顺序
延迟 较高(重传、拥塞控制) 极低
适用场景 消息队列、HTTP、文件传输 实时音视频、游戏、监控

Kafka 和 RabbitMQ 都基于 TCP。为什么?因为消息队列必须保证消息不丢、不乱序。你想想看,如果订单消息丢了,那可就出大事了。

但有些场景必须用 UDP。比如实时音视频通话,丢几帧画面没关系,但延迟高了就卡顿。我做过一个低延迟行情推送系统,就是用 UDP 把延迟压到了 1 毫秒以内。TCP 在这种场景下根本做不到。

我的经验: 如果消息丢失可以接受,但延迟必须低 → 用 UDP。如果消息一条都不能丢 → 用 TCP。如果两者都要?那就用 TCP + 应用层优化,或者用 QUIC(基于 UDP 的可靠传输协议)。

2.5 知识体系总览

下面这张图,是我画的本章节知识结构。你可以把它当作一张地图,随时回来查阅。

实时数据传输通道 消息队列 发布-订阅模式 生产者-消费者 Kafka RabbitMQ 一对多消息分发 异步解耦 传输协议选择 TCP(可靠) UDP(低延迟) Kafka/RabbitMQ 音视频、游戏、监控 低延迟行情

这张图把本章的核心概念串起来了。从实时数据传输通道出发,往下分消息队列、发布-订阅、生产者-消费者,再到底层传输协议 TCP/UDP,最后落到具体应用场景。你可以在学习后续章节时,随时回来对照这张图。

本章小结:
  • 消息队列是实时通道的「血管」,Kafka 重吞吐,RabbitMQ 重可靠
  • 发布-订阅模式实现了一对多消息分发,是实时系统的核心模式
  • 生产者-消费者模型让系统解耦,能应对流量冲击
  • TCP 保证可靠但延迟高,UDP 延迟低但可能丢包——根据场景选

好了,这一章的内容就到这里。概念虽然多,但都是后面实战的基础。下一章我们会动手搭建第一个实时数据通道,到时候这些概念都会用上。


专注资料整理