消息队列前文目录

消息队列初见:一起聊聊引入系统mq 之后的问题 https://www.cnblogs.com/yizhiamumu/p/16573472.html

分布式事务实战方案汇总 https://www.cnblogs.com/yizhiamumu/p/16625677.html

分布式事务原理及解决方案案例 https://www.cnblogs.com/yizhiamumu/p/16662412.html

消息队列为什么选用redis?聊聊如何做技术方案选型 https://www.cnblogs.com/yizhiamumu/p/16690033.html

消息队列的对比测试与RocketMQ使用扩展 https://www.cnblogs.com/yizhiamumu/p/16677881.html

消息队列的一些场景及源码分析,RocketMQ使用相关问题及性能优化 https://www.cnblogs.com/yizhiamumu/p/16694126.html

一:为什么使用MQ

中小公司系统一开始体量较小,后来随着用户量逐渐扩大,需要把很多业务进行拆分,因此引入消息队列来优化问题。

其通用的使用场景可以简单地描述为:

当不需要立即获得结果,但是并发量又需要进行控制的时候,就是需要消息队列的时候。

二:消息队列应用的几大场景:

解耦

多应用间通过消息队列对同一消息进行处理,避免调用接口失败导致整个过程失败。

具体场景:用户注册,系统发送邮件并验证短信。

一般情况下,串行方式,并行方式均可。

或使用消息队列,注册信息写入到消息队列。

或电商交易系统,交易服务发送消息,要生成订单,要扣减库存,要物流发货。

异步

多应用对消息队列中同一消息进行处理,应用间并发处理消息,相比串行处理,减少处理时间。

具体场景:人脸识别系统。用户上传图片,调用人脸识别,调用完成后再返回信息。该方法的缺点是:1 人脸识别失败导致图片上传失败;2 延迟高,需要系统处理完成后再返回客户端,即使用户不需要立即知道结果;3 图片上传系统和人脸识别系统互相调用,耦合度高。

客户端上传图片后,图片上传系统将图片信息如uid, 批次写入mq, 直接返回成功。人脸识别系统定时从mq 中取数据,完成对新增图片的识别。

此时,图片上传系统不需要关心人脸识别系统是否对这些图片信息的处理,以及何时对这些图片的处理。事实上,由于用户并不需要立即知道人脸识别的结果,人脸识别系统可以选择不同的调度策略,按忙时、闲时、正常时间对队列中的图片信息进行处理。

消峰

广泛应用于秒杀或抢购活动,避免流量过大导致系统挂掉。

具体场景:秒杀活动一般瞬时访问量过大,服务器接收过大,会导致流量暴增,相关系统无法处理请求甚至崩溃。而加入mq 后,系统可以从mq 中取数据,相当于mq 做了一次缓冲。

优点:

  • 1 请求先入mq, 而不是由业务系统直接处理,做了一次缓冲,极大减少业务处理系统的压力。
  • 2 队列长度可以做限制,事实上,秒杀时,后入队列的用户无法秒杀到商品,这些请求可以直接被抛弃,返回活动已结束或商品已售完。

消息驱动的系统

系统分为消息队列、消息生产者、消息消费者,生产者负责产生消息,多个消费者负责对消息进行处理。

具体场景:用户新上传一批照片,人脸识别系统需要对这个用户的所有照片进行聚类,聚类完成后由对帐系统重新生成用户的人脸索引加快查询。这三个子系统间由mq 连接起来,前一个阶段处理结果放入队列中,后一个阶段从队列中获取消息继续处理。

优点:

  • 避免了直接调用下一个系统导致当前系统失效
  • 每个子系统对于消息的处理方式可以更灵活,可以选择接收到消息 时就处理,可以选择定时处理,也可以划分时间段按不同处理速度处理。

三:MQ 存在问题及场景优化

3.1 重复消费问题

问题出现的场景:

  • 消息生产者产生了重复的消息
  • kafka 和 RocketMQ 的 offset 被回调了
  • 消息消费者确认失败
  • 消息消费者确认超时
  • 业务系统主动发起重试
解决方案

不管是生产者产生的重复消息,还是消费者导致的重复消息,我们都可以在消费者中解决这个问题。这就需要我们做幂等设计。

增加一张消费消息表,使用messageId 做唯一索引。在处理逻辑前,先根据messageId 查询一下该消息有没有处理过,如果已经处理过则直接返回,如果没有处理过,则继续做业务处理

3.2 数据一致性问题(异步分布式事务问题)

问题出现的场景:

当服务是同步调用的时候,我们可以使用本地事务来控制数据一致性。但异步调用会存在数据不一致的问题。如商品订单下单成功,但是扣减库存失败,就是造成超卖问题。

解决方案

数据一致性分为:强一致性,弱一致性,最终一致性。

mq 为了性能使用的是最终一致性,那么必定会出现数据不一致的问题。这类问题大概率是因为消费者读取消息后,业务逻辑处理失败导致的。这个时候可以增加重试机制。

重试可以分为同步重试和异步重试。消息量比较小的业务场景,可以采用同步重试,如果消息处理失败立即重试3-5次,如果还失败则写入记录表中。如果消息量比较大,则采用异步方式。在处理失败后立即写入重试表,有个job 专门重定时重试。

还有一种做法,如果消费失败,自己给同一个topic 发一条消息,在后面的某个时间点自己又会消费到那一条消息,起到了重试的效果。如果对消息顺序要求不高的场景。这种做法适合对消费顺序要求不高的场景。

需要事务强一致的,不用消息异步,如下单、减库存要放在一个事务时在,加积分等业务放在mq 中异步处理。

3.3 消息丢失问题

问题出现的场景:

  • 生产者产生消息时,由于网络原因发送到mq 失败
  • mq 服务器持久化,存储磁盘时出现异常
  • kafka 和 rocketMQ 的offset 被回调时,略过了很多消息
  • 消费者刚读取消息,已经ack 确认,但是业务还没处理完,服务被重启了。

生产者、消费者、服务器都可能产生问题,最终的结果会导致消费者无法正确的处理消息而导致数据不一致的情况。

解决方案

增加一张消息发送表。

  • 当生产者发完消息后,会往该表中写入一条数据,状态status 标记为待确认
  • 如果消费者读取消息后,调用生产者api 更新该消息status 为已确认
  • 有个job 每隔一段时间检查一次消息发送表,如果执行后还有状态是待确认的消息,则认为该消息丢失,重发该消息。

3.4 消息顺序问题

问题出现的场景:

如商品订单-支付-完成-退货等状态,如果订单数据作为 消息体,就会涉及顺序问题。如果先支付后下单,是不可以的。

这样的问题场景有很多,比如:

  • kafka 同一个partition 中能保证顺序,但是不同的partition 无法保证顺序
  • rabbitMQ 的同一个queue 能够保证顺序,但是如果多个消费者同一个queue 也会有顺序问题
  • 如果消费者使用多线程消费消息,无法保证顺序
  • 如果生产者发送到mq 中的路由规则跟消费者不一样,也无法保证顺序
解决方案

首先我们需要确认,消费者是否真的需要知道中间状态,只知道最终状态行不行。

其实很多时候我们真的需要知道的最终状态,这样我们可以把流程优化一下:

这种流程可以解决大部分的消息顺序问题。但是如果真的有需要保证顺序的需求,可以将订单号路由到不同的partition,同一个订单号的消息,每次发送到同一个partition

3.5 消息堆积问题

问题出现的场景:

很多时候,由于某些批处理或其他原因,导致消费速度小于生产速度,这样会直接导致消息堆积问题,从而影响业务功能。

比如开通会员,如果消息出现堆积会导致用户下单后,很久才变会员。这种情况肯定会引起大量用户投诉。

解决方案

看消息是否需要保证顺序。如果不需要保证顺序,可以读取消息之后用多线程处理业务逻辑。

这样就能增加业务逻辑处理速度,解决消息堆积问题。但是线程池的核心线程数和最大线程数需要合理配置,不然可能会浪费系统资源。

如果需要保证顺序,可以读取消息后将消息按照一定的规则分发到多个队列中,然后在队列中用单线程处理。

rabbitmq ,activemq , rocketmq, kafka 对比

引入mq 之后的问题

本来我们需要保证系统服务可用就可以了,现在引入新的服务,我们要保证mq 的可用,系统的可用性和复杂性都会有新的要求。

文::一只阿木木

消息队列初见:一起聊聊引入系统mq 之后的问题的更多相关文章

  1. 为什么要用消息队列 及 自己如何设计一个mq架构

    1. 解耦:如左图, 系统a因为业务需求需要调用系统b,后续因为业务需求可能需要改代码调用系统c,甚至还要考虑被调用的系统挂了访问超时的问题.耦合性太高! 如右图, 系统a产生一条数据发送到消息队列里 ...

  2. 消息队列的一些场景及源码分析,RocketMQ使用相关问题及性能优化

    前文目录链接参考: 消息队列的一些场景及源码分析,RocketMQ使用相关问题及性能优化 https://www.cnblogs.com/yizhiamumu/p/16694126.html 消息队列 ...

  3. 一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬

    消息队列 为什么写这篇文章? 博主有两位朋友分别是小A和小B: 小A,工作于传统软件行业(某社保局的软件外包公司),每天工作内容就是和产品聊聊需求,改改业务逻辑.再不然就是和运营聊聊天,写几个SQL, ...

  4. 转载:消息队列MQ

    本文大概围绕如下几点进行阐述: 为什么使用消息队列? 使用消息队列有什么缺点? 消息队列如何选型? 如何保证消息队列是高可用的? 如何保证消息不被重复消费? 如何保证消费的可靠性传输? 如何保证消息的 ...

  5. IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

    1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...

  6. 天天都用消息队列,却不知道为啥要用MQ,这就有点尴尬了

    1.为什么要使用消息队列? 分析:一个用消息队列的人,不知道为啥用,有点尴尬.没有复习这点,很容易被问蒙,然后就开始胡扯了. 回答:这个问题,咱只答三个最主要的应用场景(不可否认还有其他的,但是只答三 ...

  7. rabbit MQ 消息队列

    为什么会需要消息队列(MQ)? 一.消息队列概述消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ...

  8. 深入消息队列MQ,看这篇就够了!

    大厂面试爱问消息队列 MQ. 因为消息队列MQ,既是大型分布式系统不可缺少的中间件,也是高并发系统的基石中间件. 如果你想要快速掌握消息队列 MQ 最内核的知识,以及消息队列MQ的主流应用场景.主流产 ...

  9. 消费端如何保证消息队列MQ的有序消费

    消息无序产生的原因 消息队列,既然是队列就能保证消息在进入队列,以及出队列的时候保证消息的有序性,显然这是在消息的生产端(Producer),但是往往在生产环境中有多个消息的消费端(Consumer) ...

  10. (转)Linux环境进程间通信----系统 V 消息队列列

    转:http://www.ibm.com/developerworks/cn/linux/l-ipc/part3/ 消息队列(也叫做报文队列)能够克服早期unix通信机制的一些缺点.作为早期unix通 ...

随机推荐

  1. Python数据分析代码示例

    数据清洗 在进行数据分析之前,通常需要对原始数据进行清洗,即处理缺失值.异常值.重复值等问题. 下面是一个数据清洗的示例代码: import pandas as pd # 读取原始数据 data = ...

  2. [oeasy]python0083_[趣味拓展]字体样式_正常_加亮_变暗_控制序列

    字体样式 回忆上次内容 上次了解了 一个新的转义模式 \033 逃逸控制字符 esc   esc 让输出 退出 标准输出流 进行 控制信息的设置 可以 清屏 也可以 设置光标输出的位置     还能做 ...

  3. [oeasy]python0117 文字的演化_埃及圣书体_象形文字_楔形文字

    埃及圣书体 回忆上次内容 两河流域 苏美尔文明 所使用的 楔形文字 不是象形文字     ​   添加图片注释,不超过 140 字(可选)   楔形文字的字型 究竟是怎么来的呢?   巴别塔 苏美尔的 ...

  4. [oeasy]python0040_换行与回车的不同_通用换行符_universal_newlines

    换行回车 回忆上次内容 区分概念 terminal终端 主机网络中 最终的 端点 TeleTYpewriter 电传打印机 终端硬件 shell 终端硬件基础上的 软件壳子 Console 控制台 主 ...

  5. [oeasy]python0015_十六进制_hexadecimal_字节形态_hex函数

    ​ 十六进制(hexadecimal) 回忆上次内容 上次数制可以转化 bin(n)可以把数字转化为 ​​2进制​ binary 接收一个整数(int) 得到一个二进制数形式的字符串 ​ 编辑 数字在 ...

  6. 基础-数组_C语言

    C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合.数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量. 数组的声明并不是声明一个个单独的变量,比如 runoob0. ...

  7. 最新SEO自动外链蜘蛛池工具促进百度快速收录使用方法介绍

    此工具集成市面上所有自动外链网站的资源链接,经过合并.去重.筛选.验证 总结出最终的外链资源 ,软件实时更新 本软件将您繁杂的外链推广转为自动化进行,并且加入站群的支持,您只需要将你的站群域名粘贴到软 ...

  8. 【Java】逻辑错误BUG

    开局一张图来解释就够了 查询 COUNT() 结果数,有且仅有一条记录 好死不死判断查询的结果数量等等于0, 这不永远都是取TRUE返回 花了一个下午的时间就为了解决这个BUG

  9. 【Vue】Re19 Promise

    一.概述 Promise是异步编程的解决方案 异步事件的处理: 封装的异步请求函数不能立即获取结果, 通常会传入另外一个函数,在请求成功的时候将数据通过传入的函数回调出去 如果只是一个简单的请求,那么 ...

  10. 常回家看看之fastbin_attack

    常回家看看之fastbin_attack 原理分析 fastbin属于小堆块的管理,这里说的fastbin_attack大多指glibc2.26之前的手法,因为自glibc2.26以后,glibc迎来 ...