目前市面上比较常用的 MQ(Message Queue,消息队列)中间件有 RabbitMQ、Kafka、RocketMQ,如果是轻量级的消息队列可以使用 Redis 提供的消息队列,其中 Redis 属于轻量级的消息队列,而 RabbitMQ、Kafka 属于比较成熟且比较稳定和高效的 MQ 中间件。
RabbitMQ
RabbitMQ 是一个老牌开源的消息中间件,它实现了标准的 AMQP(Advanced Message Queuing Protocol,高级消息队列协议)消息中间件,使用 Erlang 语言开发,支持集群部署,和多种客户端语言混合调用,它支持的主流开发语言有以下这些:
Java and Spring、.NET、Ruby、Python、PHP、JavaScript and Node、Objective-C and Swift、Rust、Scala、Go......更多支持语言,请点击这里访问官网查看。
重要的概念
RabbitMQ 中有 3 个重要的概念:生产者、消费者和代理。
生产者:消息的创建者,负责创建和推送数据到消息服务器。
消费者:消息的接收方,用于处理数据和确认消息。
代理:也就是 RabbitMQ 服务本身,它用于扮演“快递”的角色,因为它本身并不生产消息,只是扮演了“快递”的角色,把消息进行暂存和传递。
运行流程
RabbitMQ 优点
• 支持持久化,RabbitMQ 支持磁盘持久化功能,保证了消息不会丢失;
• 高并发,RabbitMQ 使用了 Erlang 开发语言,Erlang 是为电话交换机开发的语言,天生自带高并发光环和高可用特性;
• 支持分布式集群,正是因为 Erlang 语言实现的,因此 RabbitMQ 集群部署也非常简单,只需要启动每个节点并使用 --link 把节点加入到集群中即可,并且 RabbitMQ 支持自动选主和自动容灾;
• 支持多种语言,比如 Java、.NET、PHP、Python、JavaScript、Ruby、Go 等;
• 支持消息确认,支持消息消费确认(ack)保证了每条消息可以被正常消费;
• 它支持很多插件,比如网页控制台消息管理插件、消息延迟插件等,RabbitMQ 的插件很多并且使用都很方便。
RabbitMQ 的消息类型
(1)direct(默认类型)模式,此模式为一对一的发送方式,也就是一条消息只会发送给一个消费者;
(2)headers 模式,允许你匹配消息的 header 而非路由键(RoutingKey),除此之外 headers 和 direct 的使用完全一致,但因为 headers 匹配的性能很差,几乎不会被用到;
(3)fanout 模式,为多播的方式,会把一个消息分发给所有的订阅者;
(4)topic 模式,为主题订阅模式,允许使用通配符(#、*)匹配一个或者多个消息,我可以使用“cn.mq.#”匹配到多个前缀是“cn.mq.xxx”的消息,比如可以匹配到“cn.mq.rabbit”、“cn.mq.kafka”等消息。
RabbitMQ 集群
RabbitMQ 集群是由多个节点组成,但默认情况下每个节点并不是存储所有队列的完整拷贝,这是出于存储空间和性能的考虑,因为如果存储了队列的完整拷贝,那么就会有很多冗余的重复数据,并且在新增节点的情况下,不但没有新增存储空间,反而需要更大的空间来存储旧的数据;同样的道理,如果每个节点都保存了所有队列的完整信息,那么非查询操作的性能就会很慢,就会需要更多的网络带宽和磁盘负载来存储这些数据。
为了能兼顾性能和稳定性,RabbitMQ 集群的节点分为两种类型,即磁盘节点和内存节点,对于磁盘节点来说显然它的优势就是稳定,可以把相关数据保存下来,若 RabbitMQ 因为意外情况宕机,重启之后保证了数据不丢失;而内存节点的优势是快,因为是在内存中进行数据交换和操作,因此性能比磁盘节点要高出很多倍。
如果是单个 RabbitMQ 那么就必须要求是磁盘节点,否则当 RabbitMQ 服务器重启之后所有的数据都会丢失,这样显然是不能接受的。在 RabbitMQ 的集群中,至少需要一个磁盘节点,这样至少能保证集群数据的相对可靠性。如果集群中的某一个磁盘节点崩溃了,此时整个 RabbitMQ 服务也不会处于崩溃的状态,不过部分操作会受影响,比如不能创建队列、交换器、也不能添加用户及修改用户权限,更不能添加和删除集群的节点等功能。
注意:对于 RabbitMQ 集群来说,我们启动集群节点的顺序应该是先启动磁盘节点再启动内存节点,而关闭的顺序正好和启动的顺序相反,不然可能会导致 RabbitMQ 集群启动失败或者是数据丢失等异常问题。
RocketMQ
消息队列RocketMQ是阿里巴巴集团中间件技术部自主研发的专业消息中间件。产品基于高可用分布式集群技术,提供消息发布订阅、消息轨迹查询、定时(延时)消息、资源统计、监控报警等一系列消息云服务,是企业级互联网架构的核心产品。
详细介绍请查看,常见消息队列--RocketMQ
Redis 轻量级的消息中间件
Redis 是一个高效的内存性数据库中间件,但使用 Redis 也可以实现消息队列的功能。
早期的 Redis(Redis 5.0 之前)是不支持消息确认的,那时候我们可以通过 List 数据类型的 lpush 和 rpop 方法来实现队列消息的存入和读取功能,或者使用 Redis 提供的发布订阅(pub/sub)功能来实现消息队列,但这种模式不支持持久化,List 虽然支持持久化但不能设置复杂的路由规则来匹配多个消息,并且他们二者都不支持消息消费确认。
于是在 Redis 5.0 之后提供了新的数据类型 Stream 解决了消息确认的问题,但它同样不能提供复杂的路由匹配规则,因此在业务不复杂的场景下可以尝试性的使用 Redis 提供的消息队列。
Apache Kafka
大名鼎鼎的 Kafka 是高性能消息队列的代表,Kafka 是 LinkedIn 开源的一个分布式消息系统,主要使用 Scala 语言开发,已经加入 Apache 顶级项目。
Kafka 集群部署时依赖 ZooKeeper 环境,相比其他的消息队列,运维成本要高很多,ZooKeeper 的引入,使得 Kafka 可以非常方便地进行水平扩展,支持海量数据的传输。
Kafka 的另外一个特点是高吞吐率,在消息持久化写入磁盘的过程中,使用了多种技术来实现读写的高性能,包括磁盘的顺序读写、零拷贝技术等。