消息队列和可靠性

一.消息队列

消息队列(Message Queue,简称 MQ)是一种进程间通信(IPC)机制,用于在分布式系统或多线程/多进程程序中传递消息。通过提供 消息传递 和 消息排队 模型,它可以在 分布式环境 下提供 应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步 等等功能。常见的消息队列有 Kafka、RabbitMQ、RocketMQ、ActiveMQ 等。

1. 解耦: 模块之间不直接通信,减少耦合度。

2. 异步处理: 可以先把请求丢进队列里,慢慢处理,提高系统响应速度。

3. 削峰填谷: 高并发时排队处理,避免系统被压垮。

4. 失败恢复: 消息未消费前可以保留,实现容错。

二.防止消息丢失 

以kafka为例:

在 Kafka 中有一个重要的概念叫偏移量(Offset)它是消息在分区中的编号,用来唯一标识该分区里的一条消息的位置。 Kafka 中的消息是按“主题(Topic) → 分区(Partition)”来组织的,每条消息在分区中都有一个递增的数字编号,这就是偏移量。 消费者读取分区里的消息时,就是从某个 offset 开始往后读,然后手动或自动告诉 Kafka 读到哪里的数据了。

1.消费者丢失数据

在kafka中, offset 是默认提交的,但是如果消费者自动提交了offset,让 Kafka 以为已经消费好了这个消息,但其实才刚准备处理这个消息,客户端就挂了,此时这条消息就丢失了,我们只需要在消费者端改成在处理完业务后手动提交 offset 即可

但此时我们又会产生重复消费数据的可能下面说。

2.Kafka 丢失数据

首先,我们要知道,Kafka 为每个分区(Partition)支持多副本(replica)机制:每个分区有一个 Leader 和若干个 Follower。生产者写入数据时,只写入 Leader。Follower 会从 Leader 同步数据(副本)

如果 Kafka 某个分区的leader宕机,然后重新选举 leader。如果此时其他的 follower 刚好还有些数据没有同步,然后选举某个 follower 成 leader 之后,就会丢失一些数据。

我们要可以设置以下参数:

1.replication.factor : 给 topic 设置该参数,这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。

2.min.insync.replicas : 在 Kafka 服务端设置该参数,这个只必须大于1至少几个副本必须同步成功,才算“写入成功”。

3.acks=all : 在生产者设置改参数,生产者等待“所有同步副本”都写成功,才能认为是写成功了。

4.retries=3 : 在生产者设置改参数,如果一旦写入失败,则重试。

3.生产者丢失数据

开启生产确认机制(acks),设置 acks=all,要求所有副本写入成功才返回,并开启重试机制。但这也可能引写重复的问题下面说

三.消息的幂等性

幂等性:相同的操作执行一次或多次,效果都一样。

在整个数据流转过程中可能会发生以下情况:

1. 生产者层面的幂等性(防止写重复)

Kafka 生产者幂等性问题的本质原因在于:消息可能被“重复发送”到 Kafka Broker,而 Kafka 默认是允许重复写入的,如果没做“去重”或“确认机制”,在重试的时候就可能写了两条一模一样的消息。

Kafka 从 0.11 开始支持幂等生产者机制。

enable.idempotence=true

acks=all

retries > 0

Kafka 会为每个 producer 分配一个 producerId 和 sequence number;若发送同一条消息多次,Kafka 自动识别并去重;同一条消息在 broker 上 只会被写入一次。

注意:

1. 幂等性不是“去重”,而是防止“写重复”;

2. 幂等性保证的是同一个 producer 的“同一条消息”不会被 Kafka 多次写入;

3. 多个 producer(或重启时 ID 变了)就无效了。

2. 消费者重复消费

上面我们说在消费端我们手动提交 offset这样的话在处理完数据之后提交数据之前突然程序崩溃那么我们实际已经消费了这条消息但是kafka没有收到offset所以在重启消费者后会重复发生该数据就会导致重复消费了。

解决方案:

1. 使用唯一消息 ID + 幂等判断

每条消息携带唯一业务 ID(比如订单号、消息流水号)消费时先查数据库是否已处理过该 ID 没处理就执行业务 + 记录已处理状态如果已处理直接跳过。如支付、扣款、积分发放等业务。

2. 采用唯一约束

为数据库加上唯一约束字段。或者增加一张消费记录表表字段加上唯一约束条件(UNIQUE)消费完之后就往表里插入一条数据防止重复插入。

3.消费写入使用数据库的 UPSERT 或 ON DUPLICATE KEY

例如 mysql 中使用 ON DUPLICATE KEY UPDATE

INSERT INTO user_bonus (user_id, bonus) VALUES ('u123', 100) ON DUPLICATE KEY UPDATE bonus = bonus;

如果发现有唯一约束冲突则进行更新操作。

4.使用 redis 做幂等锁

幂等锁是一种防止同一请求/消息被重复处理的机制是构建高并发下可靠幂等机制的关键手段之一,尤其在分布式场景下。

4.1 SETNX 实现幂等锁
SETNX key value

如果 key 不存在,就设置它,返回 true;如果已存在,就啥也不做,返回 false。

4.2 使用 Lua 脚本

如果需要执行多条redis指令则可能发生线程安全的问题这时可以采用Lua脚本。

Redis 会把整个 Lua 脚本当作一条命令执行,执行过程不会被中断、不会被其他命令插入,具备原子性。

四.Kafka保证消息有序性

Kafka 在每个分区内部保证消息是按照写入顺序被追加到日志文件中的。消费者按 offset 顺序读取,自然就能获取有序的消息。但是跨分区的情况下是不能保证有序的。

1. 生产者端每条消息会带一个 key,比如订单号、用户 ID、会话 ID。Kafka 根据 key 的哈希值分配到特定 partition。每条具有相同的 key 的数据,会一直被发到同一个 partition,因此保持顺序。但要注意以单线程的方式写入。

2. Broker 端消息会被顺序地写入相应的 partition, 每条消息都有一个递增的 offset。

3. 消费者端按 offset 顺序读取消费。每个 partition 通常由一个消费者来处理,以保证顺序性。

跨分区的情况下,只能在业务层自己做排序了如利用时间戳放在有序队列中或者使用外部排序软件如 Flink、Spark 等。

五.消息传输协议和队列

WebSocket、MQTT、Kafka、RabbitMQ、RocketMQ、ActiveMQ 虽然它们都与消息传递、实时通信或异步处理有关,但实际上它们处在不同的技术层面和使用场景。

1.WebSocket一种通信协议,用于客户端和服务端之间的实时通信(比如网页聊天室)。

2.MQTT(Message Queuing Telemetry Transport)是一种轻量级、发布/订阅(Pub/Sub)模式的消息协议,专为低带宽、不稳定网络环境设计,广泛用于物联网(IoT)、移动设备、智能家居等场景。

3.Kafka/RabbitMQ/RocketMQ/ActiveMQ是消息中间件系统,用于分布式系统之间异步、可靠、高吞吐量的消息传递。

特性/工具WebSocketMQTTKafkaRabbitMQRocketMQActiveMQ
本质通信协议协议(轻量消息传输)分布式消息队列系统(日志系统)消息队列系统(面向可靠性)分布式消息队列系统(阿里)传统消息队列系统(JMS)
使用场景实时双向通信,低延迟单向推送为主(客户端订阅)日志采集、指标流、流处理、高吞吐任务调度、微服务解耦分布式事务、金融、电商下单场景企业应用集成、JMS兼容
消息模型非消息队列发布-订阅发布-订阅生产者-消费者(队列+主题)类似 Kafka,增强事务支持点对点、发布订阅
传输协议TCPTCP自定义协议(基于TCP)AMQP(支持多协议)自定义协议OpenWire(也支持MQTT/AMQP等)
持久化支持不持久化可选,依赖 QoS 配置高效持久化(磁盘+零拷贝)可配置持久化高性能持久化可配置
实时性极佳(毫秒级)非常好延迟可接受(批量处理优先)较好良好一般
吞吐量一般(每连接独立)中等偏低(低功耗、低延迟、小负载)超高(百万级 TPS)中等(万级)较高较低
事务支持不支持不支持弱事务(Exactly-once很难)支持事务强事务支持(分布式事务)支持
部署复杂度低(有QoS 2,但并不适用于复杂事务)低至中中等中高
适配网络需长连接非常好(2G/3G/卫星)要求网络质量高中等中等中等

典型使用场景:

技术选型场景原因

WebSocket

网页聊天室 / 实时推送 / 游戏服务

WebSocket 保持双向连接、低延迟

MQTT

智能家居 / 传感器网络 / 远程设备

网络差、设备资源少,用 MQTT 非常合适

Kafka

大数据日志收集 / 链路追踪 / 流处理平台

高吞吐、分区并行、顺序性好

RabbitMQ

微服务异步通信 / 任务队列 / 异步任务处理 / RPC解耦 / 分布式微服务轻量级,易用性强,支持多种协议

RocketMQ

高并发订单处理 / 分布式事务 / 金融场景支持消息顺序、事务、延迟等复杂功能

ActiveMQ

企业集成 / 兼容 JMS 老系统

JMS 支持好,适合传统业务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纯洁的小魔鬼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值