本文最后更新于 320 天前,其中的信息可能已经过时,如有错误请发送邮件到wuxianglongblog@163.com
MessageQueue概述
一.什么是MQ
MQ的全称为"Message Queue",即消息队列。
消息队列是在消息传输过程中保存消息的容器,多用于分布式系统之间进行通信。
二.使用MQ的优势
1.应用解耦
如下图左侧所示:
系统的耦合性越高,容错性就越低,可维护性就越低。
(1)订单模块存在单点故障,需要从架构上解决;
(2)订单模块需要大量的代码连接后端的库存模块,支付模块,物流模块等;
(3)当某个后端模块出现故障后,尤其是从源码级上出现问题,我们可能需要修改订单模块的代码进行修复(比如后端的接口命名变更,我们在订单模块中也需要做相应的修改),但这也意味着其它的模块在此期间均会处于不可用的状态;
如下图右侧所示:
使用MQ使得应用间解耦,提升容错性和可维护性。
(1)订单模块只需将订单信息(订单信息可能包括但不限于订单ID,商品名称,物流公司,电话号码,发货地址,商品成交价格等)提交给MQ系统即可,无需其它冗余代码;
(2)后端的模块模块出现故障后,其它模块并不会收到影响,因为只要MQ不挂掉,后端的其它模块均可以正常拿到数据;
我们以"火影忍者"为例:
作为一个中国人,如果没有刻意去学习日语的话,我们很难看懂日本的动画片。而伴随我们90后多年的"火影忍者"想必大家都有印象。
但"火影忍者"原版用的是日语说的,我们可以通过"翻译社"将"火隐忍者"翻译为"普通话版火隐忍者","英文版火影忍者"等。
温馨提示:
所谓解耦就是允许你独立的扩展或修改两边的处理过程,只要确保它们遵守同样的接口约束。
2.异步提速
如下图左侧所示:
一个下单操作耗时:300 + 200 + 200 + 200 + 950 = 1850ms
用户点击完下单按钮后,需等待1850ms(接近2秒)才能得到下单响应,是在太慢了!
如下图右侧所示:
一个下单操作耗时:300 + 20 = 320ms
用户点击完下单按钮后,需等待320ms即可完成下单,速度提升了接近6倍!
可以很明显的提升用户体验和系统吞吐量(单位时间内处理请求的数量)
我们以生活中取快递为例:
(1)早期的快递是需要送货上门的,但当客户不在家时快递员需要多次投递,当快递件较多时,快递公司会积累很多快递件未送出去。
(2)但随着"蜂巢","菜鸟驿站"的推出,快递公司再也不需要积累过多的快递件了,而是将快递放到快递柜或者菜鸟驿站等,而后由客户自行去取快递,从而大大提升了快递的工作效率。
其它案例:
(1)比如我们下了一个订单,间隔30分钟未支付则自动取消订单以便于其它人购买;
(2)在比如我们发送的QQ,微信等消息,均是异步发送的,尽管对方不在线,我们照样是可以发送消息的。
温馨提示:
很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少就放多少,然后在需要的时候再去处理它们。
3.削峰填谷(灵活性 & 峰值处理能力)
如下图左侧所示:
假设订单模块现有的配置仅允许最高并发10w的QPS,当某电商公司在做秒杀活动时很可能超出平常的QPS或TPS,从而导致服务集群的崩溃。
如下图右侧所示:
我们在服务前添加一个MQ,这个MQ可以接受远超过当前订单模块的并发量数据,而后订单模块仅需根据自己的能力去MQ拿去相应的数据即可。
我们以三峡大坝(拥有强大的蓄水能力,主要作用是防洪)为例:
(1)早期在没有修筑大坝时,随着连续十多天的大雨倾盆,在新闻联播中不止一次发现很多地区的房子,汽车等都被淹没了,洪水这种自然灾害我们在一开始我们是没法控制的;
(2)但在修了三峡大坝后,它使得广袤富庶的汉江平原不受洪水威胁,对生态秩序走向良性循环和可秩序发展具有重要意义。当然,防洪是三峡大坝的首要功能,不仅如此,它也可以带来全国人民带来旅游景点哟~
有关三峡大坝的那些事:
三峡大坝,位于中国湖北省宜昌市三斗坪镇境内,距下游葛洲坝水利枢纽工程38公里,是当今世界最大的水利发电工程——三峡水电站的主体工程、三峡大坝旅游区的核心景观、三峡水库的东端。
三峡水电站大坝高181米,正常蓄水位175米,大坝长2335米,静态投资1352.66亿人民币 ,2012年7月4日已成为全世界最大的水力发电站和清洁能源生产基地。2015年12月,三峡大坝入选长江三峡30个最佳旅游新景观之一。
2020年8月20日,三峡枢纽入库流量达7.50万立方米/秒,开启11个泄洪深孔泄洪,是三峡水库建库以来遭遇的最大洪峰。截至2020年10月22日14时,三峡水库已蓄水至高程173.55米。
温馨提示:
在访问量剧增的情况下,应用仍然需要继续发挥作用,但是这样的突发流量并不常见。
如果为以能处理这类峰值访问为标准来投入资源随时待命无疑是巨大的浪费。使用消息队列能够使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
4.可恢复性
系统的一部分组件失效时,不会影响整个系统。消息队列降低了进程间的耦合度,所以即使一个处理消息的进程挂掉,加入队列中的消息仍然可以在系统恢复后被处理。
5.缓冲
有助于控制和优化数据流经过系统的速度,解决生产消息和消费消息的处理速度不一致的情况。
二.使用MQ的劣势
系统可用性降低:
系统引入的外部依赖越多,系统稳定性越差,一旦MQ宕机,就会对业务造成影响。那么问题自然就是如何保证MQ的高可用呢?也就是说如果MQ自身能实现服务的高可用则该问题自然就迎刃而解了。
系统复杂度提高:
MQ的加入大大增加了系统的复杂度,以前是同步的远程调用,现在是通过MQ进行异步调用,如何保证消息不会被丢失等情况。
GB ---> TB ---> PB ---> EB
三.常见的MQ产品
1.RabbitMQ
所属公司/社区:
Rabbit
开发语言:
Erlang
协议支持:
AMQP,XMPP,SMTP,STOMP等。
客户端支持语言:
Erlango,Java,Ruby等,社区产出多种API,几乎支持所有语言。
单机吞吐量:
万级别(其次)。
消息延迟:
微妙级。
功能特性:
并发能力强,性能及其好,延时较低,社区活跃,管理界面丰富等。
2.ActiveMQ
所属公司/社区:
Apache
开发语言:
Java
协议支持:
OpenWire,STOMP,REST,XMPP,AMQP等。
客户端支持语言:
Java,C,C++,Python,PHP,Perl,.net等。
单机吞吐量:
万级别(最差)。
消息延迟:
毫秒级。
功能特性:
老牌产品,熟度高,文档较多。
3.RocketMQ
所属公司/社区:
阿里巴巴
开发语言:
Java
协议支持:
自定义
客户端支持语言:
Java,C++(相对来说不成熟)。
单机吞吐量:
十万级别(最好)。
消息延迟:
毫秒级。
功能特性:
MQ功能比较完备,扩展性能佳。
4.Kafka
所属公司/社区:
Apache
开发语言:
Scala和Java
协议支持:
自定义协议,社区封装了http协议支持
客户端支持语言:
官方支持Java,社区产出多种API,包括但不限于Python,Lua,Php,C++等。
单机吞吐量:
十万级别(次之)。
消息延迟:
毫秒以内。
功能特性:
不仅支持主要的MQ功能,还支持流处理功能,毕竟是为大数据领域准备的。
5.MQ的选择
RabbitMQ:
优点:
消息可靠性高,功能全面。
缺点:
吞吐量比较低,消息积累会影响性能,erlang语言不好定制,国内相关的开发人员相对较少。
使用场景:
小规模场景。
Kafka:
优点:
吞吐量非常大,性能非常好,集群高可用。
缺点:
(1)维护起来比较复杂,比如数据均衡,数据迁移相对来说比较麻烦。
(2)当leader节点数据写入成功后(只是写入了OS cache,而后由OS异步写入磁盘),follow节点还来不及同步数据时,leader节点挂掉的情况可能会导致部分数据丢失。解决方案就是多节点写入成功后在回应客户端ACK,但这意味着会增大延迟,从而降低集群性能。
使用场景:
日志分析,大数据实时流的采集等。
RocketMQ:
优点:
高吞吐,高性能,高可用,功能全面。
缺点:
开源版功能不如云上版,官方文档比较简单,客户端只支持Java。
使用场景:
几乎全场景。
温馨提示:
(1)目前生产环境中使用ActiveMQ的公司越来越少了,但RabbitMQ,RocketMQ,Kafka目前很多公司还在使用。
(2)尽管RabbitMQ相比RocketMQ,Kafka性能较差,但RabbitMQ可以保证100%数据不丢失,因此由于其数据的安全性,目前该产品也赢得很多金融公司的喜爱;
(3)kafka诞生的背景就是为大数据生态而生的,因此在大数据量的情况下,使用kafka的相对较多;
(4)在阿里公司内部,肯定是主推RocketMQ较多,因为其将RabbitMQ和Kafka的优点基于一身,但RocketMQ开源社区的活跃度相比kafka较弱,如果想要用性能可以直接购买阿里云的SAAS产品即可;
四.MQ的两种模式
1.点对点模式(一对一,消费者主动拉取数据,消息收到后消息清除)
消息生产者生产消息发送到Queue中,然后消息消费者从Queue中取出并且消费消息。
消息被消费以后,queue中不在有存储,也就说说,该消息被删除,所以消息消费者不可能消费到已经被消费的消息。
queue支持存在多个消费者,但是对一条消息(message)而言,只会有一个消费者可以消费。
2.发布/订阅模式(一对多,消费者消费数据之后不会清除消息)
消息生产者(发布)将消息发布到topic中,同时有多个消息消费者(订阅)消费该消息。
和点对点方式不同,发布到topic的消息会被所有订阅者消费。
温馨提示:
如下图所示,消费者可以主动去MQ服务器去拉取数据,我们习惯称之为"pull(拉取)";当然,MQ服务器也可以主动发送数据给消费者,我们习惯称之为"push(推)"。而我们的kafka broker仅支持pull(拉取)的方式。
基于push(推)的优缺点:
优点:
无需客户端主动来拉取数据,而是由服务端主动发送数据,典型应用场景就是我们订阅的"公众号"等业务。
缺点:
(1)当消费者消费能力不足时,很可能消费者端的程序会有大量的数据延迟,更严重的情况是使得客户端程序崩溃掉。
(2)broker内部需要维护一个订阅者的列表(当订阅者较多时,可能会占用很大的内存),否则broker也不知道将数据推送给谁;
基于pull(拉取)的优缺点:
优点:
消费者程序可以根据自身的硬件配置(这里指的是CPU,内存,网卡,磁盘等)来消费broker端的数据。
缺点:
消费者端需要长期执行一个进程来询问broker是否有数据,如果有数据就主动拉取,如果没有数据则过一会再来询问,很可能会在很长的一段时间内始终没有数据,白白的浪费掉性能。
五.互联网大厂秒杀系统
1.秒杀前,页面访问压力大
解决方案:
页面静态化,可以使用CDN,Redis,Nginx等多级缓存技术。
2.秒杀时,下单过于集中,而且可能会存在作弊软件刷单的情况
解决方案:
前端页面增加答题环节,目的是可以防止作弊软件恶意刷单,而且还能有效的在短时间内错开高并发。
3.秒杀时,下单请求对系统冲击力过大,影响其它正常功能
解决方案:
为秒杀独立出一套订单系统。
4.秒杀时,快速精确扣减库存
解决方案:
基于缓存(例如Redis)实现快速精确扣减库存。
5.秒杀后,快速过滤未抢到的下单请求
解决方案:
库存扣减完后,快速通知nginx,过滤下单请求。
6.秒杀后,下单模块压力大
解决方案:
下单请求写入RocketMQ集群,后端下单模块慢慢下单。下单后,也通过RocketMQ通知下游服务,完成下单。
7.问题放大镜
要如何选择MQ产品?
参考上面"MQ的选择"内容。
如何快速处理未支付订单?
可以使用Rocket延迟消息快速回收未支付的订单。
如果不用RocketMQ也可以实现,思路如下:
(1)我们需要使用一个专门的延迟队列来存储原始数据;
(2)而后使用延迟消息服务(这通常由开发团队来设计)消费该队列数据,目的是用于过滤掉未支付的订单;
(3)将上一步处理后的消息重新写入一个新的队列中,该队列数据交由下游的消费者进行处理;
如何保证下单操作与消息发送的事务一致性?
使用RocketMQ事务消息保证事务的一致性。其实现思路如下:
(1)生产者开启事物发送half数据给RocketMQ,值得注意的是,此时未接收到回滚或提交对于消费者而言是看不到这部分half数据的,但这些数据已经发送到RocketMQ服务端了;
(2)当RocketMQ接收到消息后,会响应生产者已接收到half数据以确保数据接收成功;
(3)生产者继续执行本地事务;
(4)生产者在执行本地事务时可以进行回滚或者提交本次事务;
(5)如果RocketMQ长时间未能确定该事物是否提交,会定期访问生产者进行回查;
(6)生产者会访问本地的事务管理,用于回查消息状态(此处我们只讨论提交会回滚两种状态);
(7)根据上一步查询的消息状态提交进行回滚;
(8)一旦数据被提交,则提交到目标topic数据是可以被消费者正常消费的;如果数据未能提交,即回滚的事物数据将直接丢弃,而这些被回滚的数据消费者永远都无法拿到,因为消费者始终只能拿到已提交的事物哟;
如何保证集群高可用?
普通的多主多从集群,在RocketMQ的conf目录下提供了现成的配置Demo。而我们的课程会主要讲解kafka高可用集群搭建。
Kafka使用zookeeper实现高可用,而zookeeper的Zab协议是借鉴于Paxos协议。
RocketMQ使用Dledger技术实现高可用,而Dledger底层使用Raft协议来进行leader选举。
如何平衡MQ消息的高吞吐和高可靠?
我们可以从生产者的发送消息;broker的主从数据同步,消息刷盘;消费者的消费消息这三种角色的四个环节来优化高吞吐和高可用的区别。
如何保证高性能文件读写?
RocketMQ文件读写高性能的三大利器:磁盘顺序写,异步刷盘,零拷贝等技术。
如下图所示,DMA的英文拼写是"Direct Memory Access",汉语的意思就是直接内存访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。
温馨提示:
JDK NIO零拷贝实现分为两种方案,即mmap和sendFile。
(1)mmap比较适合小文件读写,对文件大小有限制,一般在1.5GB~2.0GB之间;
(2)sendFile比较适合大文件传输,可以利用DMA方式,减少CPU拷贝;
分布式服务消息等幂三大语义分类是什么?
"At Least Once","At Most Once","Exactly One"。