当前位置: 首页 > news >正文

十二、消息队列-MQ

文章目录

  • 前言
  • 一、MQ介绍
    • 1. 背景
    • 2. 解决思路
    • 3. 解决方案
  • 二、应用场景
  • 三、常见的MQ产品
  • 四、MQ选型总结
  • 五、相关知识
    • 1. AMQP
    • 2. JMS
  • 五、如何设计实现一个消息队列
    • 1. 设计消息队列的思路
    • 2. 实现队列基本功能
    • 3. 队列高级特性设计


前言

消息队列

  传统应用系统出现同步耗时、系统耦合、高并发等痛点问题,支撑业务逐渐吃力。

  通过引入MQ(Message Queue)消息队列机制,实现异步调用,系统解耦,流量削峰的方式,解决传统应用系统的痛点问题。

  作为分布式系统中重要的组件,MQ本质是创建和维护应用程序间消息传输的通道。实现高性能,高可用,可伸缩和最终一致性架构。


一、MQ介绍

1. 背景

  传统应用系统出现以下痛点问题,支撑业务逐渐吃力。

  1. 痛点1-同步耗时

有些复杂的业务系统,一次用户请求可能会同步调用N个系统的接口,需要等待所有的接口都返回了,才能真正的获取执行结果。

同步耗时
这种同步接口调用的方式总耗时比较长,非常影响用户的体验,特别是在网络不稳定的情况下,极容易出现接口超时问题。

  1. 痛点2-系统耦合

很多复杂的业务系统,一般都会拆分成多个子系统。以用户下单为例,请求会先通过订单系统,然后分别调用:支付系统、库存系统、积分系统 和 物流系统。

系统耦合
系统之间耦合性太高,如果调用的任何一个子系统出现异常,整个请求都会异常,对系统的稳定性非常不利。

  1. 痛点3-高并发

有时候为了吸引用户,会搞一些促销活动,比如秒杀。
如果用户操作突增,一时间所有的请求都到数据库,可能会导致数据库无法承受这么大的压力,响应变慢或者直接挂掉。

高并发
对于这种突然出现的请求峰值,无法保证系统的稳定性。

2. 解决思路

  通过引入MQ(Message Queue)消息队列机制,实现异步调用,系统解耦,流量削峰的方式,解决传统应用系统的痛点问题。

  1. 方法1-异步调用

主业务执行结束后从属业务通过MQ,异步执行,减低业务的响应时间,提高用户体验。

异步
2. 方法2-系统解耦

主业务完成以后,发送一条MQ,其余模块异步消费MQ消息,既可实现业务,又降低模块之间的耦合。

系统解耦
3. 方法3-流量削峰

高并发情况下,业务异步处理,提供高峰期业务处理能力,避免系统瘫痪。

流量削峰

3. 解决方案

  MQ(Message Queue)是一种跨进程的通信机制,用于上下游传递消息。作为分布式系统中重要的组件,MQ本质是创建和维护应用程序间消息传输的通道,实现高性能,高可用,可伸缩和最终一致性架构。

  MQ早已成为企业IT系统内部通信的核心手段。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能,成为异步RPC的主要手段之一。

  当今市面上有很多主流的MQ,如老牌的ActiveMQ、RabbitMQ,炙手可热的Kafka,阿里巴巴自主开发RocketMQ等。

MQ概念

二、应用场景

  1. 异步处理

  不用MQ,那么我们的代码必然耦合在一起,下单成功后,依次要通过RPC远程调用这几个系统,然后同步等到他们的响应才能返回给用户是否成功的结果。假设每个系统耗时200ms,那么就得花费600ms。

异步处理
2. 应用解耦

  我购买车票成功后,会收到信息提醒,但是如果短信系统故障了,客户就有可能收到不短信了,这就是各个系统之间的耦合太高了,我们应该解耦。传统的做法如下:

应用解耦
我们在订单系统产生数据后,将订单这条数据发送给MQ,就返回成功,然后让短信、邮件等系统都订阅MQ,一旦发现MQ有消息,他们主动拉取消息,然后解析,进行业务处理。
这样一来,就算你短信系统挂了,丝毫不会影响其他系统,而且如果后来想加一个新的系统,你也不用改订单系统的代码了,你只要订阅我们的MQ提供的消息就行了。

应用解耦是消息队列 MQ 的主要特点,主要目的是减少请求响应时间和解耦。主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时,由于使用了消息队列MQ,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦合

  1. 流量削峰

  流量削峰也是消息队列 MQ 的常用场景,一般在秒杀或团队抢购(高并发)活动中使用广泛。

流量削峰以12306为例,假设平时可能买票的人不多,所以订单系统的QPS( 每秒查询率 )也不是很高,每秒也就处理1000个请求,但是一到节假日、春运期间可能抢票的人就非常多,并发量远远大于平时,这个时候,订单系统明显扛不住了。

为解决这些问题,可以设计高可用的MQ,让所有的请求都到MQ,缓存起来。这样一来高峰期的流量和数据都将积压在MQ中,流量高峰就被削弱了(削峰),然后我们的订单系统就避免了高并发的请求,它可以慢慢的从MQ中拉取自己能力范围内的消息就行处理。这样一来,高峰期积压的消息也终将被消费完,可以叫做填谷

三、常见的MQ产品

目前业界有很多MQ产品,比较出名的有下面这些:

  • ActiveMQ
    历史悠久的Apache开源项目。已经在很多产品中得到应用,实现了JMS1.1规范,可以和springjms轻松融合,实现了多种协议,支持持久化到数据库,对队列数较多的情况支持不好。

  • RabbitMQ
    使用erlang语言开发,性能较好,适合于企业级的开发。但是不利于做二次开发和维护。

  • RocketMQ
    阿里巴巴的MQ中间件,由java语言开发,性能非常好,能够撑住双十一的大流量,而且使用起来很简单。

  • Kafka
    Kafka是Apache下的一个子项目,是一个高性能跨语言分布式Publish/Subscribe消息队列系统,相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

  • ZeroMQ
    号称最快的消息队列系统,尤其针对大吞吐量的需求场景。扩展性好,开发比较灵活,采用C语言实现,实际上只是一个socket库的重新封装,如果做为消息队列使用,需要开发大量的代码。
    ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。

四、MQ选型总结

需要根据具体的应用场景和需求的多维度来决定:
性能:吞吐量、并发时效性
可靠性:可用性、集群支持、持久化、性能稳定性、安全性
可维护性:管理界面等运维能力
易用性:平台熟悉度
兼容可扩展性:易于扩展
服务支持:社区活跃度

  • ActiveMQ
    作为老牌的消息队列,吞吐量比较低,也缺少大规模吞吐量场景的验证、社区活跃度也很低,数据持久化的支持一般,目前渐渐被淘汰,已经不是主流了,不太建议选择了。

  • RabbitMQ和RocketMQ
    社区比较活跃,吞吐量比较高,支持AMQP,稳定性也比较好,如果你的场景是应用需要可靠性消息传递和较高的并发,那么这两者是比较好的选择。
    要注意,rabbitMQ是使用Erlang语言开发的,而RocketMQ则使用Java语言开发,所以如果是需要深度研究掌握的话,要考虑团队中是否有Erlang工程师,如果不具备相关的人才储备的话,更建议选择RocketMQ。当然,如果只是小团队简单使用,则rabbitMQ是一个挺好的选择。

  • Kafka和Pulsar
    如果是大数据领域的实时计算、日志采集等场景,那么这两者是比较好的选择。
    Kafka经历了超大规模应用的验证,社区活跃度很高,性能也非常高,几乎是全世界这个领域的事实性的标准。
    Pulsar作为新兴的分布式消息传递系统,可扩展性强、性能高、社区活跃度也很高,最重要的是支持存储和计算分离,这在云原生下是非常出色的一项能力,并且天然支持跨数据中心的容灾,目前的应用也越来越广泛,如果集群对于持久化要求高,数据级别是超大规模,对于机器成本敏感,且支持多数据中心容灾,则建议选择Pulsar。

  • RabbitMQ:当需要性能稳定、低延时、功能强大且易于管理的方案,建议使用 RabbitMQ。

  • RocketMQ:当需要低延迟和金融级别的稳定性,且吞吐量需求较大的消息队列,系统主要场景是处理在线业务,比如在交易系统中传递订单,那 RocketMQ 是最适合的方案。

  • Kafka:对消息吞吐量需求很大,且不在乎消息偶尔丢失的情况,像收集日志、监控信息或是前端埋点这类海量数据,或是应用场景大量使用了大数据、流计算相关的开源产品,那 Kafka 是最适合的消息队列。

比较项ActiveMQRabbitMQRocketMQKafkaPulsar
单机吞吐量较低(万级)一般(万级)高(十万级)高(十万级)高(十万级)
时效性ms级us级ms级ms级以内-
可用性高(主从架构)高(主从架构)非常高(分布式架构)非常高(分布式架构)-
持久化支持(小)支持(小)支持(大)支持(大)支持(大)
顺序消息不支持不支持支持支持支持
性能稳定性一般较差一般
集群支持主备模式镜像模式(复制)主备模式Leader-Slave每台既是master也是slave,集群可扩展性强集群模式,broker无状态,易迁移,支持跨数据中心
消费模式P2P、Pub-Subdirect、fanout、topic、Headers基于Topic和MessageTag的的Pub-Sub基于Topic的Pub-Sub基于Topic的Pub-Sub
管理界面一般较好一般
计算和存储分离不支持不支持不支持不支持支持
AMQP支持支持支持支持不完全支持不完全支持
开发语言JavaErlangJavaJava/ScalaJava
维护者ApacheSpringApache(Alibaba)Apache(Confluent)Apache(StreamNative)
Star数量2.1K10.4K18.8K24.3K12.4K
Contributor126246438991600
社区活跃度较高
功能特性成熟的产品,有较多的文档;各种协议支持较好并发能力很强,性能很好,延时很低;管理界面丰富MQ功能比较完毕,扩展性佳支持主要的MQ功能,在大数据领域应用广泛可扩展性强、性能高、云原生下非常出色,支持存储和计算分离,跨数据中心的容灾

五、相关知识

1. AMQP

**高级消息队列协议(Advanced Message Queuing Protocol)**是一个网络协议。它支持符合要求的客户端应用(application)和消息中间件代理(messaging middleware broker)之间进行通信。主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP是协议,类比HTTP。

2. JMS

Java消息服务(JavaMessage Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的 API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。JMS是API接口规范,类比JDBC。

五、如何设计实现一个消息队列

MQ设计思路

1. 设计消息队列的思路

  1. 一次RPC做成两次RPC

基于消息的系统模型,不一定需要broker(消息队列服务端)。
而之所以要设计一个消息队列,并且配备broker,无外乎要做两件事情:

  • 消息的转储,在更合适的时间点投递,或者通过一系列手段辅助消息最终能送达消费机。

  • 规范一种范式和通用的模式,以满足解耦、最终一致性、错峰等需求。

掰开了揉碎了看,最简单的消息队列可以做成一个消息转发器,把一次RPC做成两次RPC。发送者把消息投递到服务端(简称broker),服务端再将消息转发一手到接收端,就是这么简单。

  1. 整体设计思路如下

两次RPC加一次转储,外加消费确认的第三次RPC

  • 数据流
    build一个整体的数据流,例如producer发送给broker,broker发送给consumer,consumer回复消费确认,broker删除/备份消息等。

  • RPC
    利用RPC将数据流串起来。考虑RPC的高可用性,尽量做到无状态,方便水平扩展。

  • 内容转储
    考虑如何承载消息堆积,在合适的时机投递消息。而处理堆积的最佳方式,就是存储,存储的选型需要综合考虑性能/可靠性和开发维护成本等诸多因素。

  • 消费关系
    而为了实现广播等功能,必须要维护消费关系,可以利用zk/config server等保存消费关系。

  1. 在完成了上述几个功能后,消息队列基本就实现了。然后我们可以考虑一些高级特性,如可靠投递,事务特性,性能优化等。

2. 实现队列基本功能

下面以设计消息队列时重点考虑的模块为主线,穿插灌输一些消息队列的特性实现方法,来具体分析设计实现一个消息队列时的方方面面。

  1. RPC通信协议

所谓消息队列,无外乎两次RPC加一次转储,当然需要消费端最终做消费确认的情况是三次RPC。既然是RPC,需要考虑,负载均衡、服务发现、通信协议、序列化协议等等。

因为消息队列的RPC,和普通的RPC没有本质区别。利用公司现有的RPC框架:Thrift也好,Dubbo也好,或者是其他自定义的框架也好。

简单来讲,服务端提供两个RPC服务,一个用来接收消息,一个用来确认消息收到。并且做到不管哪个server收到消息和确认消息,结果一致即可。

  1. 高可用

依赖于RPC和存储的高可用来做的。

  1. 服务端承载消息堆积的能力

为了满足我们错峰/流控/最终可达等一系列需求,把消息存储下来,然后选择时机投递就显得是顺理成章的了。

存储可以做成很多方式。比如存储在内存里,存储在分布式KV里,存储在磁盘里,存储在数据库里等等。但归结起来,主要有持久化和非持久化两种。

持久化的形式能更大程度地保证消息的可靠性(如断电等不可抗外力),并且理论上能承载更大限度的消息堆积(外存的空间远大于内存)。

但并不是每种消息都需要持久化存储。很多消息对于投递性能的要求大于可靠性的要求,且数量极大(如日志)。这时候,消息不落地直接暂存内存,尝试几次failover,最终投递出去。

  1. 存储子系统的选择

理论上,从速度来看,文件系统 > 分布式KV(持久化) > 分布式文件系统 > 数据库,而可靠性却截然相反。

还是要从支持的业务场景出发作出最合理的选择,如果你们的消息队列是用来支持支付/交易等对可靠性要求非常高,但对性能和量的要求没有这么高,而且没有时间精力专门做文件存储系统的研究,DB是最好的选择。

分布式KV(如MongoDB,HBase)等,或者持久化的Redis,由于其编程接口较友好,性能也比较可观,如果在可靠性要求不是那么高的场景,也不失为一个不错的选择。

  1. 消费关系解析

消息队列定义了一堆名词,如JMS 规范中的Topic/Queue,Kafka里面的Topic/Partition/ConsumerGroup,RabbitMQ里面的Exchange等等。

抛开现象看本质,无外乎是单播与广播的区别。所谓单播,就是点到点;而广播,是一点对多点。当然,对于互联网的大部分应用来说,组间广播、组内单播是最常见的情形。

至于广播关系的维护,一般由于消息队列本身都是集群,所以都维护在公共存储上,如config server、zookeeper等。维护广播关系所要做的事情基本是一致的:

  • 发送关系的维护。

  • 发送关系变更时的通知。

3. 队列高级特性设计

  1. 可靠投递(最终一致性)
  • 消费确认

  • 重复消息和顺序消息

  • 版本号

  • 状态机

  • 中间件对于重复消息的处理

  1. 事务

  2. 性能相关

  • 异步/同步

  • 批量

  1. push 还是 pull,模型简要分析
  • 慢消费

  • 消息延迟与忙等

  • 顺序消息


http://www.mrgr.cn/news/78999.html

相关文章:

  • 【开源】A059-基于SpringBoot的社区养老服务系统的设计与实现
  • 蓝桥杯准备训练(lesson1,c++方向)
  • C++:特殊类设计及类型转换
  • 一文解析Kettle开源ETL工具!
  • 数据结构基础之《(9)—归并排序》
  • Solidity开发智能合约
  • 国产CPU 安装Windows可行性操作
  • Redis 之持久化
  • 将空白背景透明化
  • 【C++笔记】map和set的使用
  • 【ETCD】ETCD用户密码认证
  • Mac安装MINIO服务器实现本地上传和下载服务
  • 使用Tomcat搭建简易文件服务器
  • Ansible 运维工具
  • 零基础快速掌握——【c语言基础】数组的操作,冒泡排序,选择排序
  • 我们来学mysql -- 事务并发之脏写(原理篇)
  • HDFS 操作命令
  • Spring Boot Actuator未授权访问漏洞处理
  • 【机器学习】机器学习的基本分类-监督学习-决策树-ID3 算法
  • Unity 模拟百度地图,使用鼠标控制图片在固定区域内放大、缩小、鼠标左键拖拽移动图片
  • Seatunnel解决ftp读取json文件无法读取数组以及格式化之后的json无法解析的问题
  • AllegroHand 四指灵巧手:机器人领域的创新力量
  • 十,[极客大挑战 2019]Secret File1
  • SciPy Optimize和 CVXPY对比
  • Selenium常见问题
  • 生态环境影像评价、遥感解译与GIS技术生态环境影像评价制作