消息队列 - 基础篇

消息队列 - 基础篇

前言

常见问题:

  • 技术选型
  • 高可靠、高可用、高性能
  • 不重复、不丢失
  • 水平扩展

底层技术:

  • 分布式系统
  • 海量数据
  • 海量并发

消息模型

消息模型:

  • 队列模型 生产者 - 队列 - 消费者
  • 发布订阅模型 发布者 - 主题 - 订阅者

RabbitMQ 消息模型:

                                             - Queue  - Consumer
Producer  -  Exchange
                                              - Queue - Consumer

RocketMQ / Kafka 消息模型:

                                                    - Queue/Partition   -
Producer Group - Topic                                              -  Consumer Groups 
                                                    - Queue/Partition  - 
  • 一个主题可以有多个分区,以支持多实例并行生产和消费
  • 一个主题可以被多个消费者组订阅,每个消费者组都会接收全量消息,同一个消息只能被组内的一个消费者消费
  • RocketMQ 只在队列上保证消息的有序性,无法在主题层面保证消息的严格顺序

kafka 叫分区,RocketMQ 叫队列

消息丢失

消息丢失检测

  • 分布式链路追踪系统
  • 给消息添加序号

序号检测方式:

  • 在生产者和消费者的拦截器注入和验证序号的连续性
  • 确保生产者、消费者、消息队列分区的数量一致

消息可靠传递

消息传递的三个阶段:

  • 生产阶段 (Producer)
  • 存储阶段 (Broker)
  • 消费阶段 (Consumer)

生产阶段:

  • 消息队列通过请求确认机制和失败重试机制确保消息不丢失
  • 生产者要确保处理消息发送失败的异常

存储阶段:

  • 写入磁盘并且刷盘后再发送确认
  • 集群环境要确保消息复制到两个副本后到发送确认

消费阶段:

  • 消息队列通过请求确认和失败重试确保消息不丢失
  • 消费者要在执行消费逻辑后再发送确认

消息重复

服务质量标准

MQTT 协议的三种服务质量标准:

  • at most once:至多一次,允许丢失消息。
  • at least once:至少一次,不允许消息丢失,但允许消息重复。
  • exactly once:精确一次,不允许消息丢失,也不允许消息重复。

大多数消息队列产品都提供至少一次的服务质量标准。

用幂等性解决消息重复

处理消息重复,需要保证消费者的消费逻辑具有幂等性。

at least once + 幂等消费 = exactly once

幂等性操作:一个操作执行任意多次和执行一次对系统的影响是相同的。

常用的幂等设计:

  • 利用数据库的唯一约束或 SETNX 实现幂等
  • 增加一个版本号字段
  • 使用 token 或 GUID (全局唯一ID),在操作前检查 token 是否有效,操作后销毁 token

检查、操作、销毁需要保证原子性和同步。
避免出现 A 检查后未销毁时 B 检查通过导致重复操作。

消息积压

Producer 性能

  • 批量发送:适合离线业务,比较在意吞吐量的场景
  • 提高并发:适合在线业务,比较在意时延的场景

Consumer 性能

  • 优化消费业务逻辑
  • 扩容 Consumer 实例数量(同时扩容分区数量)

要保证 Consumer 数量和分区数量一致,
因为每个分区实际上只支持单线程消费。

消息积压排查

排查方法:

  • 监控系统
  • 日志

常见原因:

  • 突发请求导致生产者发送大量消息(服务降低、扩容消费者)
  • 消费者消费失败导致重复消费
  • 消费者发生死锁

分布式事物

分布式事务:

  • 2PC:二阶段提交
  • TCC(Try-Confirm-Cancel)
  • 事务消息

事务消息

事务消息适合需要异步更新数据,对数据实时性要求不高的场景。

事务消息执行过程:

  1. 生产者在消息队列开启事务
  2. 生产者发送半消息(消息对消费者不可见)
  3. 生产者执行本地事务(数据库事务)
  4. 提交/回滚消息队列事务(提交后消息对消费者可见)

提交失败:

  • kafka 在事务提交失败时会抛出异常。
    • 重试:尝试再次提交事务
    • 补偿:删除插入数据
  • RocketMQ 使用事务反查机制来处理提交失败

参阅

  • 《消息队列高手》- 李玥
posted @ 2022-09-04 08:48  廖子博  阅读(52)  评论(0编辑  收藏  举报