消息队列常见问题总结

news/2025/2/22 16:49:32

消息队列常见问题总结

作者:Grey

原文地址:

博客园:消息队列常见问题总结

CSDN: 消息队列常见问题总结

说明

本文是极客时间消息队列高手课的学习笔记

消息队列的主要作用

解耦

如果采用推送的方式,A 系统通过接口调用发送数据到 B、C、D 三个系统,A 系统的维护成本就非常的高,而且 A 系统要时时刻刻考虑B、C、D 四个系统如果出现故障该怎么办?使用消息队列就可以解决这个问题。A 系统只负责生产数据,不需要考虑消息被哪个系统来消费。

异步

A 系统需要发送个请求给 B 系统处理,由于 B 系统需要查询数据库花费时间较长,以至于 A 系统要等待 B 系统处理完毕后再发送下个请求,造成 A 系统资源浪费。使用消息队列后,A 系统生产完消息后直接丢进消息队列,不用等待 B 系统的结果,直接继续去干自己的事情了。

削峰

A 系统调用 B 系统处理数据,每天 0 点到 12 点,A 系统风平浪静,每秒并发请求数量就 100 个。结果每次一到 12 点 ~ 13 点,每秒并发请求数量突然会暴增到 1 万条。但是 B 系统最大的处理能力就只能是每秒钟处理 1000 个请求,这样系统很容易就会崩掉。这种情况可以引入消息队列,把请求数据先存入消息队列中,消费系统再根据自己的消费能力拉取消费。

消息队列的有什么局限性?

首先,消息队列会降低系统的可用性,因为引入消息队列,就等于引入多一种外部依赖,多一种外部依赖,挂掉的可能性就多一点;

其次,消息队列会使得系统复杂度提高,比如:需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题;

最后,使用消息队列,要考虑一致性问题:A 系统处理完了直接返回成功了,但问题是:要是 B、C、D 三个系统那里,B 和 D 两个系统写库成功了,结果 C 系统写库失败了,就造成数据不一致了。

如何保证消息队列的高可用?

RabbitMQ 使用的是 镜像集群模式。
Kafka 使用的是 partition和 replica 模式来保证高可用。

如何保证消息不被重复消费?或者说,如何保证消息消费的幂等性?

可以在写数据时,先根据主键查一下这条数据是否存在,如果已经存在则 update;

数据库的唯一键约束也可以保证不会重复插入多条,因为重复插入多条只会报错,不会导致数据库中出现脏数据;

如果是写 Redis,就没有问题,因为 set 操作是天然幂等性的。

如何保证消息不丢失?

在生产阶段,你需要捕获消息发送的错误,并重发消息。
在存储阶段,你可以通过配置刷盘和复制相关的参数,让消息写入到多个副本的磁盘上,来确保消息不会因为某个 Broker 宕机或者磁盘损坏而丢失。
在消费阶段,你需要在处理完全部消费业务逻辑之后,再发送消费确认。
在 Producer 端,我们给每个发出的消息附加一个连续递增的序号,然后在 Consumer 端来检查这个序号的连续性。如果没有消息丢失,Consumer 收到消息的序号必然是连续递增的,或者说收到的消息,其中的序号必然是上一条消息的序号 +1。如果检测到序号不连续,那就是丢消息了。还可以通过缺失的序号来确定丢失的是哪条消息,方便进一步排查原因。大多数消息队列的客户端都支持拦截器机制,你可以利用这个拦截器机制,在 Producer 发送消息之前的拦截器中将序号注入到消息中,在 Consumer 收到消息的拦截器中检测序号的连续性,这样实现的好处是消息检测的代码不会侵入到你的业务代码中,待你的系统稳定后,也方便将这部分检测的逻辑关闭或者删除。

消息积压如何处理?

能导致积压突然增加,最粗粒度的原因,只有两种:要么是发送变快了,要么是消费变慢了。大部分消息队列都内置了监控的功能,只要通过监控数据,很容易确定是哪种原因。如果是单位时间发送的消息增多,比如说是赶上大促或者抢购,短时间内不太可能优化消费端的代码来提升消费性能,唯一的方法是通过扩容消费端的实例数来提升总体的消费能力。如果短时间内没有足够的服务器资源进行扩容,没办法的办法是,将系统降级,通过关闭一些不重要的业务,减少发送方发送的数据量,最低限度让系统还能正常运转,服务一些重要业务。还有一种不太常见的情况,你通过监控发现,无论是发送消息的速度还是消费消息的速度和原来都没什么变化,这时候你需要检查一下你的消费端,是不是消费失败导致的一条消息反复消费这种情况比较多,这种情况也会拖慢整个系统的消费速度。如果监控到消费变慢了,你需要检查你的消费实例,分析一下是什么原因导致消费变慢。优先检查一下日志是否有大量的消费错误,如果没有错误的话,可以通过打印堆栈信息,看一下你的消费线程是不是卡在什么地方不动了,比如触发了死锁或者卡在等待某些资源上了。

消息过期了怎么办?

我们可以采取一个方案,就是批量重导。就是大量积压的时候,直接丢弃数据了,然后等过了高峰期以后开始写程序,将丢失的那批数据一点一点的查出来,然后重新灌入 MQ 里面去,把丢的数据给补回来。


http://www.niftyadmin.cn/n/1647616.html

相关文章

Transformer for image quality assessment阅读笔记

Transformer for image quality assessment阅读笔记 Abstract 提出一种在由CNN提取的特征图上使用浅层Transformer编码器的机构。Transformer采用自适应位置编码来处理任意分辨率的图像。 1 Introduction Transformer完全基于注意力机制,包括self-attention and…

和链表相关的一些问题

和链表相关的一些问题 作者:Grey 原文地址: 博客园:和链表相关的一些问题 CSDN:和链表相关的一些问题 反转单链表 题目描述见:LeetCode 206. Reverse Linked List 思路如下 对于任何一个节点 cur 来说&#xf…

Incorporating Convolution Designs into Visual Transformers阅读笔记

Incorporating Convolution Designs into Visual Transformers阅读笔记 Abstract 纯Transformer架构需要大量的训练数据或者额外的监督,才能获得与CNN相当的性能。为克服限制,提出一种新的Convolution-enhanced image Transformer(CeiT&…

华杉讲透孙子兵法

相信很多人和我一样,对《论语》、《大学》、《孙子兵法》等等这类传统文化是挺感兴趣的,问题在于这类古文,往往自己读的一知半解,昏昏欲睡,读完之后呢,似有似无,好像学到了,又好像啥…

栈和队列相关的一些问题

栈和队列相关的一些问题 作者:Grey 原文地址: 博客园:栈和队列相关的一些问题 CSDN:栈和队列相关的一些问题 最小栈 题目链接见:LeetCode 155. Min Stack 主要思路 准备两个栈,一个栈叫 stack, 用于…

(转)多个单列索引和联合索引的区别详解

转自https://blog.csdn.net/Abysscarry/article/details/80792876 背景:为了提高数据库效率,建索引是家常便饭;那么当查询条件为2个及以上时,我们是创建多个单列索引还是创建一个联合索引好呢?他们之间的区别是什么&am…

Pre-Trained Image Processing Transformer阅读笔记

Pre-Trained Image Processing Transformer阅读笔记 Abstract 我们研究了底层计算机视觉任务(如去噪,超分辨率和去雨),开发了IPT。只通过一个预训练好的模型,IPT在各种低水平的benchmark上达到state-of-the-art的水平…

位图的使用与实现

位图的使用与实现 作者:Grey 原文地址: 博客园:位图的使用与实现 CSDN:位图的使用与实现 说明 本文内容使用的编程语言是 Java。其他语言有类似的数据结构。 位图的使用 在 Java 中,使用HashSet可以实现如下操…