什么是消息队列
消息队列是一种异步的服务间通信的方式,是分布式系统中重要的组件,主要解决应用的耦合,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构的一种技术。
现有各消息队列性能对比
特性 | AcitveMQ | RabbitMQ | Kafka | RocketMq | NSQ |
---|---|---|---|---|---|
开发语言 | Java | erlang | scala | java | golang |
单机吞吐量 | 万级 | 万级 | 10万级 | 10万级 | 万级 |
时效性 | ms级 | us级 | ms级 | ms级 | - |
可用性 | 高(主从) | 高(主从) | 非常高(分布式) | 非常高(分布式) | 非常高(分布式) |
API完备性 | 高 | 高 | 高 | 高 | 低 |
多语言支持 | 支持,Java优先 | 语言无关 | 支持,Java优先 | 支持,Java优先 | 支持 |
提供快速入门 | 有 | 有 | 有 | 有 | 无 |
功能特性 | 成熟的产品,在很多公司得到应用;有较多的文档;各种协议支持较好 | 基于erlang开发,所以并发能力很强,性能及其好,延时很低;管理界面教丰富 | MQ功能比较完备,扩展性好 | 只支持主要的MQ功能,像一些消息查询,消息回溯等功能没有提供,毕竟是为大数据准备的,在大数据领域应用广 | 使用golang开发,基于分布式,性能很高,但目前文档不够完善,部署比较麻烦 |
关于消息队列的几个问题:
1.如何保证消息队列是高可用的?
- 大多数情况下,我们都是采用集群来保证高可用的,这一点和数据库其实是一样的;
- 以RabbitMQ为例,它通常用的两种集群模式,分别是默认模式,镜像模式,其中镜像模式最常用,其中镜像模式如下图所示;
- RcoketMQ的集群有多master模式、多master多slave异步复制模式、多master多slaver同步双写模式,其中多master多slaver模式部署架构如下
2.如何保证消息不被重复消费?
没有固定答案,需要根据业务场景来处理以RabbitMQ为例,RabbitMQ不保证消息不重复,如果业务需要保证严格的不重复消息,可通过一下方法实现:
- 保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现;
- 拿到这个消息做数据库的insert操作,给这个消息做一个唯一的主键,由于主键冲突即可避免重复消费的问题。
3.如何保证消息的可靠性传输?
对于消息队列的可靠性传输都应该从三个角度来分析:生产者弄丢数据、消息队列弄丢数据、消费者弄丢数据,下面以RabbitMQ为例进行说明:
- 生产者丢数据:RabbitMQ提供transaction和confirm模式来确保生产者不丢消息;transaction机制是说发送消息前开启事务(channel.txSelect()),然后发送消息,如果发送过程中出现什么异常,事务就会回滚(channel.txRollback()),如果发送成功则提交事务(channel.txCommit()),然而缺点是吞吐量下降了,因此在一般情况下,生产环境使用confirm模式的较多,一旦channel进入confirm模式,所有在该信道上发布的消息都将会被指派一个唯一的ID,一旦消息被投递到所有匹配的队列之后,RabbitMQ就会发送一个Avk给生产者,这就使得生产者知道消息已经正确到达目的队列了,如果RabbitMQ没能处理该消息,则会发送一个Nack消息,这时就可以进行重试操作。
- 消息队列丢失数据:处理消息队列丢失数据的情况,一般是开启持久化磁盘的配置,这个持久化配置可以和confirm机制配合使用,我们可以在消息持久化磁盘后,再给生产者发送一个Ack信号,这样如果消息持久化磁盘之前,RabbitMQ死了,那么生产者收不到Ack信号,生产者会重发,持久化主要分为两步:1.将queue的持久化表示durable设置为true,则代表是一个持久的队列;2.发送消息的时候将deliveryMode=2,这样设置后,RabbitMQ就算挂了,重启后也能恢复数据。
- 消费者丢数据:消费者丢数据一般是因为采用了自动确认消息模式,这种模式下消费者自动确认收到消息,这时RabbitMQ会立即将消息删除,解决方法时手动确认消息即可。
AMQP(Advanced Message Queuing Protocol;高级消息队列协议)
AMQP核心概念
- Broker:接收和分发消息的应用,RabbitMQ Server就是Message Broker;
- Virtual host:虚拟地址,用于进行逻辑隔离,最上层的消息路由。一个Virtual Host里面可以有若干个Exchange和Queue,同一个Virtual Host里面不能有相同名称的Exchange或Queue;
- Connection:Publisher / consumer和Broker之间的TCP连接,断开连接的操作只会在client端进行,Broker不对断开连接,除非出现网络故障或Broker服务出现问题;
- Channel:channel表示一个进行消息读写的通道,如果每一次访问RabbitMQ都建立一个Connection,在消息量大的时候建立TCP Connection的开销将是巨大的,效率也较低,Channel是在connection内部建立的逻辑连接,如果应用程序支持多线程,通常每个thread创建单独的channel进行通信,AMQP method包含了channel ID帮助客户端和message broker识别channel,所以channel之间是完全隔离的,Channel作为轻量级的Connection极大减少了操作系统建立TCP connection的开销;
- Exchange:message到达broker的第一站,根据分发规则,匹配查询表的routing key ,分发消息到queue中去,通常的类型有:direct(point-to-point), topic(publish-subscribe)
- Queue:消息队列、消息最终被送到这里等待consumer取走;
- Binding:exchange和queue之间的虚拟连接,binding中可以包含routing key,Binding信息被保存到exchange中的查询表中,用于message的分发依据。
- Routing key:一个路由规则,虚拟机可用它来确定如何路由一个特定消息;
- Message:消息,服务器和应用程序之间传送的数据,由Properties和body组成,Properties可以对消息进行修饰,比如消息的优先级、延迟等高级特性;Body则就是消息体内容。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。