这是我参与更文挑战的第3天,活动详情查看: 更文挑战
我们为什么要用消息队列?
消息队列即Message Queue。
说到为什么要使用MQ,我们就不得不说MQ的使用场景。其主要使用场景有:
- 解耦
- 削峰
- 异步
- 流量监控
- 分布式事务的可靠消费和可靠生产
- 索引、缓存、静态化处理数据同步
- 日志监控(ELK)
- 下单、订单分发、抢票
其最主要的作用便是将串行的操作并行化。为实现这一目的,我们当然可以自己写并行程序实现,但用异步线程池有几个缺点:
- 耦合度高
- 需要自己维护线程池
- 消息可能会丢失,要自己做消息补偿
- 要自己写保证消息的可靠性
- 如果服务器承载不了,要自己写高可用
这便为消息队列的产生提供了条件。
建议,如果你仅仅还只是一个初创公司建议还是使用单体架构,最多加个缓存中间件即可,不要盲目追求新或者所谓的高性能,而追求的背后一定是业务的驱动和项目的驱动,因为一旦追求就意味着你的学习成本,公司的人员结构以及服务器成本,维护和运维的成本都会增加,所以需要谨慎选择和考虑。
为什么选择RabbitMQ?(技术选型)
选择RabbitMQ可以归结一下原因:
- 支持事务
- spring开发的,对spring支持好
- 开源
对比市面上常用的几种MQ:
| ActiveMQ | RabbitMQ | Kafka | RocketMQ | |
|---|---|---|---|---|
| 发布订阅 | 支持 | 支持 | 支持 | 支持 |
| 轮询分发 | 支持 | 支持 | 支持 | / |
| 公平分发 | / | 支持 | 支持 | / |
| 重发 | 支持 | 支持 | / | 支持 |
| 消息拉取 | / | 支持 | 支持 | 支持 |
对比得出:
- 都支持持久化
- 都支持发布订阅
- 总之,RabbitMQ支持分发的策略最多。支持轮询、重发等
浅谈消息中间件协议
常见的消息中间件协议有:
- OpenWire
- AMQP(advanced message queuing protocol 高级消息队列协议)
- MQTT
- Kafka
- OpenMessage
各种协议一般都是基于TCP进行改进,通过协议进行规范,以满足自己的需要。
而消息中间件为什么不用http协议?
- 追求极致的性能,http请求报文头和响应报文头是比较复杂的。
- 大部分情况下http是短连接的,不可靠。
RabbitMQ则是采用AMQP,其特点有:
- 支持分布式事务
- 支持消息的持久化
- 高性能和高可靠的消息处理优势
Kafka协议是基于TCP/IP的二进制协议,特点是:
- 结构简单
- 解析速度快
- 无事务支持
- 有持久化设计
MQTT:物联网体系支持
消息队列的模式
官方定义的模式7种,主要使用的有5种
- 简单模式。一个生产者+一个队列+一个消费者(使用默认交换器,没指定交换器那么发消息时routingkey写的就是队列名)
- 工作模式 work。一个生产者+一个队列+多个消费者(使用默认交换器)
- work模式-轮询模式(Round-Robin):一个消费者消费一条消息,按均分配。应答方式为自动应答,即autoAck = true
- work模式-公平分发:处理的快的处理的多,按劳分配。一定要改成手动应答,即消费者的autoAck = false,并且手动去应答。qos指标:表示每次从队列取多少条
- 发布订阅模式,使用fanout交换器,发送时不用指定routekey,无意义
- 路由模式 routing,只是在发布订阅模式上加了个路由key,相当于where routekey = xxx。要使用direct交换器,使用fanout毫无意义。相当于发布订阅+分类。
- 主题模式 topic。#没有或一级或多级,*有且只有一级
- RPC
- 确认模式
rabbitMQ的几种角色
- none
- management:只能查看自己相关结点信息
- policymaker:可以创建自己的
- monitoring:可以看别人的
- administrator:都可看可改
Spring整合rabbitMQ
Springboot整合rabbitmq十分方便,因为本来就是同一家公司的,步骤如下:
- 引依赖spring-boot-starter-amqp
- 写配置类创建交换器、队列以及他们的绑定关系。
- org.springframework.amqp.core.Queue
- org.springframework.amqp.core.FanoutExchange
- BindingBuilder.bind(smsQueue()).to(fanoutExchange());
- 写生产者
- 写消费者。
- 用@RabbitListenner(queues = {xxxqueue})注解
- @RabbitHandler