一、消息队列的介绍
1.1 什么是消息队列
消息(Message)是指在应用间传送的数据。消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象。
消息队列(Message Queue)是一种应用间的通信方式,是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源传递到它的目标时充当中间人。消息队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
其通用的使用场景可以简单地描述为:当不需要立即获得结果,但是并发量又需要进行控制的时候,差不多就是需要使用消息队列的时候。
消息队列由 Broker(消息服务器,核心部分)、Producer(消息生产者)、Consumer(消息消费者)、Topic(主题)、Queue(队列)和Message(消息体)组成。
下图便是消息队列的基本模型,向消息队列中存放数据的叫做生产者,从消息队列中获取数据的叫做消费者。
1.2 消息队列的应用场景(它的优点)
异步通信
多应用对消息队列中同一消息进行并发处理,减少请求响应时间,实现非核心流程异步化,提高系统响应性能。
以电商系统之新用户注册业务为例,新的用户注册时,需要将用户的信息保存到数据库中,同时还需要额外发送注册的邮件通知、以及短信注册码给用户。
但因为发送邮件、发送注册短信需要连接外部的服务器,需要额外等待一段时间。如果用串行方式实现,耗时550ms(写入用户信息到数据库50ms+发送注册邮件250ms+发送注册短信250ms)
此时,就可以使用消息队列来进行异步处理。用异步通信实现,耗时60ms左右(写入用户信息到数据库50ms+写入注册信息到消息队列10ms),写入的消息可用来并行处理发送注册短信、发送注册邮件业务等等。相比之下,异步通信能有效提升系统的响应速度。
总结:异步的典型场景就是将比较耗时而且不需要即时(同步)返回结果的操作,通过消息队列来实现异步化。
应用解耦
使用消息队列之后,消息的生产和消费是分开的,即使某个业务系统突然崩溃了,不会影响另外一个业务系统的正常运转。换句话说就是避免调用接口失败导致整个消息处理的过程失败。
以用户秒杀(下订单)业务为例,由于涉及订单系统和库存系统,且二者存在依赖关系,由此产生如下问题:
- 如果库存系统出现问题,会导致订单系统生成订单信息失败;
- 如果库存系统接口修改了,也会导致订单系统无法工作;
- 由于需要库存系统处理完成才能返回结果给用户,导致延迟会比较高
使用消息队列可以实现系统与系统之间的解耦,订单系统不再调用库存系统接口,而是把订单消息写入到消息队列。库存系统从消息系统中拉取消息,然后再减库存,从而实现系统解耦。
流量削峰
一般在秒杀或团抢活动中使用广泛。
这种场景中系统的峰值流量往往集中于一小段时间内,所以为了防止系统被短时间内的峰值流量冲垮,往往采用消息队列来削弱峰值流量,相当于消息队列做了一次缓冲。
该方法有如下优点:
- 请求先入消息队列,而不是由业务处理系统直接处理,做了一次缓冲,极大地减少了业务处理系统的压力;
- 队列长度可以做限制,事实上,秒杀时,后入队列的用户无法秒杀到商品,这些请求可以直接被抛弃,返回活动已结束或商品已售完信息;
日志处理(大数据领域常见)
大型电商网站(淘宝、京东、国美、苏宁...)、App(抖音、美团、滴滴等)等需要分析用户行为,要根据用户的访问行为来发现用户的喜好以及活跃情况,需要在页面上收集大量的用户访问信息。
1.3 消息队列的缺点
可用性降低
系统引入的外部依赖越多,越容易挂掉。之前只需关注业务系统的稳定性即可,有了MQ,需要关注其高可用问题。如果MQ挂掉,会导致整套系统崩溃。
系统复杂性提高
需要考虑消息重复发布/消费、消息丢失、消息的顺序消费等问题。
一致性问题
若ABCD系统均处理完返回系统成功,用消息队列后,A系统处理完了直接返回成功了,人都以为你这个请求就成功了;问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,就导致数据不一致了。
1.4 消息队列的传输模式
点对点模式
用于消息生产者和消息消费者之间点到点的通信。
消息生产者将消息发送到Queue(队列)中,然后消息消费者从Queue(队列)找取出消息,当消息被消费之后就从Queue(队列)中删除,消息只能被一个消息消费者使用,不可重复消费。
比如,用户下单或登录这样的业务,只要有一个消费者(某业务系统)处理完即可。因为多个消费者处理会带来数据重复消费和处理的问题。
发布/订阅模式
消息生产者向一个特定的Topic(主题)生产消息。0或多个消费者订阅了该Topic(主题)的消息,接收Topic(主题)的消息。此时发布者和订阅者彼此无需感知对方的存在。
消息生产者和消息消费者只有建立了订阅关系才能收到消息。Topic(主题)实现了发布和订阅,当消息生产者发布一个消息,所有订阅这个Topic(主题)的服务都能得到这个消息。
有两种订阅类型:
- 持久订阅:订阅关系建立后,消息就不会消失,不管订阅者是否都在线;
- 非持久订阅:订阅者为了接受消息,必须一直在线。当只有一个订阅者时约等于点对点模式
1.5 队列的特性
- 消息基于先进先出的原则进行顺序消费
- 消息可以持久化到磁盘节点服务器
- 消息可以缓存到内存节点服务器以提高性能
二、主流消息队列中间件对比
特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafka |
单机吞吐量 | 万级,比 RocketMQ、Kafka 低一个数量级 | 万级,比 RocketMQ、Kafka 低一个数量级 | 10 万级,支撑高吞吐 | 10 万级,高吞吐,一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
topic 数量对吞吐量的影响 | topic 可以达到几百/几千的级别,吞吐量会有较小幅度的下降,这是 RocketMQ 的一大优势,在同等机器下,可以支撑大量的 topic | topic 从几十到几百个时候,吞吐量会大幅度下降,在同等机器下,Kafka 尽量保证 topic 数量不要过多,如果要支撑大规模的 topic,需要增加更多的机器资源 | ||
时效性 | ms 级 | 微秒级,这是 RabbitMQ 的一大特点,延迟最低 | ms 级 | 延迟在 ms 级以内 |
可用性 | 高,基于主从架构实现高可用 | 同 ActiveMQ | 非常高,分布式架构 | 非常高,分布式,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
消息可靠性 | 有较低的概率丢失数据 | 基本不丢 | 经过参数优化配置,可以做到 0 丢失 | 同 RocketMQ |
功能支持 | MQ 领域的功能极其完备 | 基于 erlang 开发,并发能力很强,性能极好,延时很低 | MQ 功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 |
负载均衡 | 支持 | 支持 | 支持 | 支持 |
三、主流MQ的应用场景和选择
3.1 ActiveMQ
ActiveMQ支持任何消息传递用例的能力和灵活性,比较适合小型吞吐量比较小的公司进行使用,或者MQ起步学习的首选。
3.2 Kafka
Kafka 主要特点是基于Pull 的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的互联网服务的数据收集业务。大型公司建议可以选用,大数据分析必备,如果有日志采集功能,肯定是首选 kafka 了。
3.3 RocketMQ
天生为金融互联网领域而生,对于可靠性要求很高的场景,尤其是电商里面的订单扣款,以及业务削峰,在大量交易涌入时,后端可能无法及时处理的情况。RoketMQ 在稳定性上可能更值得信赖,这些业务场景在阿里双 11 已经经历了多次考验,如果公司业务有上述并发场景,建议可以选择 RocketMQ。
3.4 RabbitMQ
结合 erlang 语言本身的并发优势,性能好时效性微秒级,社区活跃度也比较高,管理界面用起来十分方便,如果数据量没有那么大,中小型公司优先选择功能比较完备的 RabbitMQ。
标签:订阅,队列,系统,用户,介绍,MQ,消息,对比 From: https://blog.51cto.com/u_15796303/6204092