消息中间件常用协议
-
AMQP协议
AMQP即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同开发语言等条件的限制。
优点:可靠、通用 -
MQTT协议
MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和致动器(比如通过Twitter让房屋联网)的通信协议。
优点:格式简洁、占用带宽小、移动端通信、PUSH、嵌入式系统 -
STOMP协议
STOMP(Streaming Text Orientated Message Protocol)是流文本定向消息协议,是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议。STOMP提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互。
优点:命令模式(非topic\queue模式) -
XMPP协议
XMPP(可扩展消息处理现场协议,Extensible Messaging and Presence Protocol)是基于可扩展标记语言(XML)的协议,多用于即时消息(IM)以及在线现场探测。适用于服务器之间的准即时操作。核心是基于XML流传输,这个协议可能最终允许因特网用户向因特网上的其他任何人发送即时消息,即使其操作系统和浏览器不同。
优点:通用公开、兼容性强、可扩展、安全性高,但XML编码格式占用带宽大 -
其他基于TCP/IP自定义的协议
有些特殊框架(如:redis、kafka、zeroMq等)根据自身需要未严格遵循MQ规范,而是基于TCP\IP自行封装了一套协议,通过网络socket接口进行传输,实现了MQ的功能。
总结思考
消息中间件面试题
关于消息队列的思考
17 个方面,综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列
MQ 快速入门
MQ(消息队列)常见的应用场景解析
MQ入门总结(一)消息队列概念和使用场景
MQ入门总结(二)JMS
应用场景
-
异步处理
场景说明:用户注册后,需要发注册邮件和注册短信。传统的做法有两种 1.串行的方式;2.并行方式,并发量,吞吐量,响应时间会有瓶颈,但3.消息队列更高效
1、串行:
2、并行:
3、消息队列:
-
应用解耦
场景说明:用户下单后,订单系统需要通知库存系统。传统的做法是,订单系统调用库存系统的接口。
1、传统模式:
缺点:假如库存系统无法访问,则订单减库存将失败,从而导致订单失败,订单系统与库存系统耦合
2、引入消息队列:

订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦
-
削锋填谷
应用场景:秒杀活动,一般会因为流量过大,导致流量暴增,应用挂掉。为解决这个问题,一般需要在应用前端加入消息队列。
a、可以控制活动的人数
b、可以缓解短时间内高流量压垮应用
用户的请求,服务器接收后,首先写入消息队列。假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
秒杀业务根据消息队列中的请求信息,再做后续处理 -
日志处理
-
消息通讯
1、点对点通讯:
2、聊天室通讯:
消息队列三角色
- 生产者:产生消息
- 消息代理:存储/转发消息
- 消费者:消费消息
消费语义
- 至多被消费一次
- 至少被消费一次
- 仅被消费一次
重复消费,幂等
现在消息队列一般都能保证at least once的,也就是消息至少一次投递。 在这种情况为什么会出现重复消费的问题呢? 通常都是由于网络原因造成的,原因如下: 通常消息被成功消费后消费者都会发送一个成功标志给MQ,MQ收到这个标志就表示消息已经成功消费了,就不会再发送给其他消费者了。 但是如果因为网络这个标志没有送到MQ就丢失了,MQ就认为这个消息没有被成功消费,就会再次发送给其他消费者消费,就造成了重复了。
保证消费端的幂等性
幂等性 是指一个操作其执行任意多次所产生的影响均与一次执行的影响相同 大白话就是你同样的参数调用我这个接口,调用多少次结果都相同
幂等性需要根据业务需求来具体看,但是主要的原理就是去重 一般可分为强校验、弱校验
- 强校验 一般与金融相关的操作都是强校验的 (人在996,锅从天上来 偷跑) 比如消费者是一个打款服务,在付款成功后都加一条流水记录。且两个操作放入一个事务中。 再次消费的时候就去流水表查一下有没有这条纪录,如果有表示已经消费过了,直接返回。流水表也能起到对账的作用! 一些简单的场景也可以依赖数据库唯一约束实现
- 弱校验 这个就没那么严格,重复一下也没那么重要的情况。 可以将ID保存在redis set中,过期时间看情况设置。 如果ID不能保证唯一可以选择生产方生成一个token存入redis,消费方在消费后将其删除(redis的操作能够保证其原子性,删除失败会返回0
消息丢失
一般来讲消息丢失的途径有三个:
- 生产者弄丢数据
主流的MQ都有确认机制或者事务机制,可以保证生产者将消息送达到MQ。 比如RabbitMQ就有事务模式和confirm模式。 - 消息队列弄丢数据
一般只要开启MQ的持久化磁盘配置就能解决这个问题,写入了磁盘就放心了。 - 消费者弄丢数据
消费者丢数据一般是因为采用了自动确认消息模式。MQ收到确认消息后会删除消息,如果这时消费者异常了,那消息就没了。改用手动确认就能解决这个问题了呢!
顺序消息
顺序消息的场景可能用的比较少,但是还是有的 比如一个电商的下单操作,下单后先减库存然后生成订单,这个操作就需要顺序执行的 那怎么保证顺序呢?
- 首先生产者需要保证入队的顺序,入队都是乱的那再厉害的MQ也招架不住啊
- 一般的MQ都能保证内部Queue是FIFO的(先进先出),但是只是针对一个Queue,所以在发送消息的时候可以使用Hash取模法将同一个操作的消息发送到同一个Queue里面,这样就能保证出队时是顺序的了。
- 消费者也需要注意,如果多个消费者同时消费一个队列。一样可能出现顺序错乱的情况。这就相当于是多线程消费了!
通过上面的连招基本就能解决顺序消息消费的问题了呢!
消息堆积
生产者能力大于消费者的能力时(系统的并发访问过高)
消费端阻塞,增加消费者
处理步骤:
1)先修复 consumer 的问题,确保其恢复消费速度,然后将现有的 consumer 都停掉
2)新建一个topic,partition是原来的 10 倍,临时建立好原先 10 倍或者 20 倍的 queue 数量
3)然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的 10 倍数量的 queue
4)接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据
5)这种做法相当 于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常 10 倍速度
6)等快速消费完积压数据之后,恢复原先部署架构 ,重新用原先的 consumer机器消费消息
消息组件对比图


-
Kafka是linkedin开源的MQ系统,主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,0.8开始支持复制,不支持事务,适合产生大量数据的互联网服务的数据收集业务。
-
RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。RocketMQ是阿里开源的消息中间件,它是纯Java开发,具有高吞吐量、高可用性、适合大规模分布式系统应用的特点。
-
RocketMQ思路起源于Kafka,但并不是Kafka的一个Copy,它对消息的可靠传输及事务性做了优化,目前在阿里集团被广泛应用于交易、充值、流计算、消息推送、日志流式处理、binglog分发等场景。
-
ZeroMQ只是一个网络编程的Pattern库,将常见的网络请求形式(分组管理,链接管理,发布订阅等)模式化、组件化,简而言之socket之上、MQ之下。对于MQ来说,网络传输只是它的一部分,更多需要处理的是消息存储、路由、Broker服务发现和查找、事务、消费模式(ack、重投等)、集群服务等。
网友评论