MQ消息队列

MQ有什么作用/为什么使用MQ

应用解耦

  • A通过接口调用的形式发送数据给BCD, 此时如果E也需要这个数 据呢? 如果C不要这个数据呢? 这时候A和其他系统严重耦合
  • 如果A直接发送数据给MQ, 新系统需要数据, 直接监听MQ即可, 旧系统不需要数据了, 就不需要监听MQ了.
  • 这样就是谁需要谁去拿, A只用和MQ交互. A不需要考虑给谁发送 数据, 也不需要考虑别人调用失败, 或者超时了怎么办.

异步提速

  • A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三 个系统写库
  • 自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、 450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s
  • 如果使用 MQ,那么 A 系统自己本地写库要 3ms, 连续发送 3 条 消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一 个请求到 返回响应给用户,总时长是 3 + 5 = 8ms; 就非常快

削峰填谷

  • 假设我们的系统每秒只能承载1000请求,如果请求瞬间增多到每秒 5000,则会造成系统崩溃。此时引入mq即可解决该问题
  • 使用了MQ之后,限制消费消息的速度为1000,这样一来,高峰期产生的数据势必会被积压在MQ中,高峰就被"削"掉了,但是因为消息积压,在高峰期过后的一段时间内,消费消息的速度还是会维持在1000,直到消费完积压的消息,这就叫做"填谷"。

MQ优缺点

优点就是: 异步 削峰 解耦

缺点就是:

  • 系统的可用性降低了: 新引入了MQ, 那么如果MQ挂了, 和MQ相 关的服务就崩溃了
  • 系统复杂度提高了: 硬生生加个 MQ 进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况? 怎么保证消息传递的顺序性?问题一大堆
  • 数据一致性问题: A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致 了

延时队列

延迟队列指的是消息发送后到mq不会立即被消费,mq会存储对应的延迟消息,而是等待特定时间后,消费者才能拿到这个消息进行消费

比如订单的超时取消, 订单信息被放到mq中, 30分钟未支付订单就取 消. 如果使用延时队列, 那监听mq的消费者从mq中直接拿到的就是 30分钟未支付订单的信息, 然后直接取消订单. 避免轮询数据库查找超时订单


什么是死信队列? 如何导致死信

死信, 就是无法被正常消费的消息. 当一个队列中的消息满足下列情 况之一时,可以成为死信(dead letter):

  • 消息被消费者拒绝且不重新入队
  • 消息TTL到期,超时无人消费
  • 要投递的队列消息堆积满了

死信队列是放置死信的队列, 即把无法被消费的消息放到一个队列中

  • 死信队列可以作为消息消费失败的兜底方案
    • 在死信队列里面可以对我们的异常消息进行MySQL/Redis持 久化,然后人工处理等操作
  • 另一方面可以处理消息超时无人消费以及队列满了的问题

如何保证消息可靠性

所谓保证消息可靠性就是要保证消息不丢失

你要保证消息不丢,是不是得先知道消息啥时候会丢?那消息啥时候会丢呢?

  • 第1,从生产者发送消息给mq这个过程会丢。
  • 第2,mq自己也可能会把消息弄丢,比如mq宕机重启了。
  • 第3,mq把消息发送给消费者也可能会丢,或者消费者拿到消息 还没来得及消费就出现了异常或者消费者重启了或者线程崩溃了 等等

那应该怎么解决呢?

  • 首先从生产者发送到mq这里,可以使用ack机制。当mq收到消 息,给生产者回复一个ack即可。
  • 其次, mq自己把消息弄丢了怎么办?开启mq的持久化机制,把 消息持久化到磁盘中,这样即便mq宕机重启,也还是能从磁盘 中恢复消息。然后就是做mq集群,保证高可用,避免mq宕机呀
  • 最后,消费者还没消费,消息就丢了。那就使用消费者的ack机 制,当消费者消费完消息再给mq发送ack。mq收到ack后再删除 消息。否则mq就重发消息。

消息的幂等性

消息幂等性是指:无论消息被重复消费多少次,业务效果与只消费一次完全相同

什么情况下会产生重复消息

  • 消息生产者
    • 生产者发完消息, mq由于网络抖动, 网络延迟, 没有及时返回 ack确认.
    • 那生产者为了确保消息发送成功, 就会重发消息, 就导致mq会 收到了重复消息
    • 或者在业务层, 也会有一些重试操作, 也有可能重发消息
  • 消息消费者
    • 如果消费者处理完消息之后, 发送ack之前就宕机重启了, 或者 说因为网络问题, ack延迟了
    • 那mq一段时间没收到ack就认为消息没有被成功处理, 然后重 发消息. 这就会导致消息的重复消费问题

解决方案:唯一id

  • 最通用的方案就是给发消息时给消息分配一个唯一id
  • 消费者消费时, 把消息id存到redis, 使用setnx去存, 如果能保存说明是第一次消费, 如果失败, 就说明是重复消息
  • 当然了还要给这个key设置一个过期时间, 避免一直占内存

消息积压如何处理

当生产者发送消息的速度超过了消费者处理消息的速度, 或者如果消费者因为某些原因持续阻塞,就会导致队列中的消息堆积,直到队列存储消息达到上限。最早接收到的消息,可能就会成为死信,会被丢弃,这就是消息堆积问题

解决消息堆积

  • 增加更多消费者,提高消费速度
  • 提高单个消息者的处理能力, 在消费者内开启线程池加快消息处理速度
    • 缺点: 消息太多就会开启太多新线程, cpu压力大

相关推荐
开开心心_Every2 小时前
PDF转图片工具推荐:免费支持批量转换
linux·运维·服务器·spring boot·edge·pdf·powerpoint
小白电脑技术2 小时前
SMB挂载与iSCSI挂载飞牛存储:你该选择哪一种连接方式?
服务器·电脑
郝学胜-神的一滴2 小时前
Python中的with语句与try语句:资源管理的两种哲学
linux·服务器·开发语言·python·程序人生·算法
SmartRadio3 小时前
基于RK3568实现多电脑KVM共享方案(HDMI采集+虚拟USB键鼠+无缝切换+剪贴板/文件共享)
运维·服务器·网络·电脑·kvm·rk3568
未来之窗软件服务3 小时前
服务器运维(二十五)终端安全证书管控与Nginx HTTPS 部署—东方仙盟练气期
运维·服务器·安全·仙盟创梦ide·东方仙盟
qq_229058013 小时前
Docker常用命令
linux·服务器·docker
是个西兰花3 小时前
进程间通信:匿名管道
linux·运维·服务器
爱吃泡芙的小白白3 小时前
使用Cursor来进行连接SSH远程主机中出现的问题(自用)
服务器·学习·ssh·cursor
Lenyiin4 小时前
Linux 进程控制
linux·运维·服务器