抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

消息队列

消息队列是分布式系统的一个重要组件,从五个问题来初步认识一下消息队列,基本原理是什么样的,如何正确的使用消息队列。

  • Q1: 为什么需要消息队列?
  • Q2: 如何保证消息不丢失?
  • Q3: 如何处理重复消息?
  • Q4: 如何保证消息有序性?
  • Q5: 如何处理消息堆积?

为什么需要

异步处理

  • 随着业务的增长,业务逻辑会不断加重,为了保持较快速的响应,可以在核心逻辑处理完后就返回,其他逻辑放到消息队列之后异步处理

应用解耦

  • 业务模块增加,可以通过订阅核心服务的消息主题,不影响核心服务

流量控制

  • 后端服务无法支撑大量的并发请求,请求先放到队列,后端服务尽最大的能力消费队列

日志处理

基本概念

模型

  • 点对点(队列)模型

    • 同一个消息只能由一个消费者消费一次

      • Rabbit MQ
  • 发布/订阅模型

    • 订阅了某个主题的所有消费者都可以消费该主题的消息

      • Rocket MQ、Kafka

各个组件术语(Kafka)

  • 生产者(Producer)

  • 消息队列服务器(Broker)

    • 主服务器(Leader)

    • 从服务器(Follower)

    • 主题(Topic)

      • 分区(Partition)
  • 消费者组(Consumer Group)

    • 消费者(Consumer)

工作流程

  • 生产消息(发送数据)

      1. 从Kafka Cluster获取分区的Leader,Producer将消息发送给Leader
      1. Leader将消息写入本地文件(此时可以直接到步骤3)
      • 2.1. Followers从Leader pull消息并写入本地后向Leader发送ACK确认
      1. Leader向Producer响应ACK
  • 存储数据

    • 单独开辟一块磁盘,顺序写入

    • 每个分区相当于一个文件目录

      • Partition/Segment

        • .index
        • .log
        • .timeindex
  • 消费消息(接收数据)

      1. Consumer也是从Leader中拉取数据
      1. 一个消费者组内的某个消费者可以消费一个Topic的不同分区,单同一个组内的不同消费者不能同时消费某个Topic的同一个分区,一个组的消费者数量最好和分区数相同

分区的好处

  • 方便扩展
  • 提高并发

实际问题

如何保证消息队列不丢失?

    1. 生产消息阶段
    • 正确处理Broker的响应,做重试机制
    1. 数据存储阶段
    • 数据落盘再响应成功,有多个副本时可以等多副本都落盘再响应成功
    1. 消费消息阶段
    • 业务逻辑处理完再确认消息
  • 确保了可靠性的同时会影响性能,根据业务选择合适的方式

如何处理重复消息?

  • 为了保证消息不丢失,消息重复是不可避免的

  • 业务逻辑幂等性

    • 增加version版本号做控制
    • 数据库唯一索引

如何保证消息有序?

  • 全局有序

    • 一个生产者、一个分区、一个消费者
  • 部分有序

    • 消息按特定规则分配到不同的分区,分区本身是有序的,每个分区由一个消费者消费

如何处理消息堆积?

    1. 定位问题,如果是bug引起,修改bug(实际生产场景如果由于发版导致,先回滚再定位原因)
    1. 如果不是bug,看能不能优化消费逻辑
    1. 如果不能优化,就要横向扩容,同时增加分区数和消费者数量

参考文章1 微信公众号文章
参考文章2 知乎

评论