基础起步
为什么使用mq
- 削峰
- 异步
- 解耦
- 分布式事物
- 订单的状态修改
- 数据分发
核心概念
virtual host 多用户来使用

- broker服务节点
- queue队列
- exchange交换机
- bindings 交换机和队列之间的虚拟连接
- routing key 路由规则
MQ技术选型对比
1️⃣**ActiveMQ**
维护少了
2️⃣****Kafka
大数据的杀手锏
优点
:性能卓越,吞吐量高,单机写入TPS约在百万条/秒。分布式的,一个数据多个副本。- 消费者使用pull方式获取信息,消息有序,通过控制能够保证所有信息被消费且仅被消费一次。
缺点
:Kafka单机超过64个队列/分区,Load会发生明显的飙高现象,队列越多,load越高,发送消息响应时间变长- 使用短轮训方式,实时性取决于轮训间隔时间,消息失败不支持重试
- 支持消息顺序,但是一台代理宕机后,就会产生消息乱序
3️⃣ RocketMQ
消息可以做到 0 丢失,支持 10 亿级别的消息堆积
消息发送
- 发布订阅
- 轮训分发
- 公平分发
- 重发
- 消息拉取
总体流程:生产者发送给交换机,交换机路由到队列。
消息模型
HelloWorld

红色区域就是MQ中的Queue,可以把它理解成一个邮箱
- 首先信件来了不强求必须马上马去拿
- 其次,它是有最大容量的(受主机和磁盘的限制,是一个缓存区)
- 允许多个消费者监听同一个队列,争抢消息
Wokder模型

Worker模型中也只有一个工作队列。但它是一种竞争消费模式。可以看到同一个队列我们绑定上了多个消费者,消费者争抢着消费消息,这可以有效的避免消息堆积。
比如对于短信微服务集群来说就可以使用这种消息模型,来了请求大家抢着消费掉。
如何实现这种架构:对于上面的HelloWorld这其实就是相同的服务我们启动了多次罢了,自然就是这种架构。
订阅模型
订阅模型借助一个新的概念:Exchange(交换机)实现,不同的订阅模型本质上是根据交换机(Exchange)的类型划分的。
订阅模型有三种
- Fanout(广播模型): 将消息发送给绑定给交换机的所有队列(因为他们使用的是同一个RoutingKey)。
- Direct(定向): 把消息发送给拥有指定Routing Key (路由键)的队列。
- Topic(通配符): 把消息传递给拥有 符合Routing Patten(路由模式)的队列。
订阅之Fanout模型

这个模型的特点就是它在发送消息的时候,并没有指明Rounting Key , 或者说他指定了Routing Key,但是所有的消费者都知道,大家都能接收到消息,就像听广播。
订阅之Direct模型

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。
X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列
C1:消费者,其所在队列指定了需要routing key 为 error 的消息
C2:消费者,其所在队列指定了需要routing key 为 info、error、warning 的消息
拥有不同的RoutingKey的消费者,会收到来自交换机的不同信息,而不是大家都使用同一个Routing Key 和广播模型区分开来。
订阅之Topic模型

类似于Direct模型。区别是Topic的Routing Key支持通配符。
防止消息丢失
1.连接重试 在yaml中配置
2.发送确认
RabbitMQ 懒队列 (Lazy Queue)
消息尽可能快的放入到磁盘中,在需要的时候拿出来放在内存中,主要用于解决大量的消息。
3.消费者ack机制
java
// 肯定确认
void basicAck(long deliveryTag, boolean multiple)
// 否定确认
void basicNack(long deliveryTag, boolean multiple, boolean requeue)
void basicReject(long deliveryTag, boolean requeue)
deliveryTag
表示消息的标志,multiple表示是不是批量应答

如果批量应答是true 而且回复的是6 那么1-6的消息都会别确认
实际应用到项目中的注意点
不公平分发
RabbitMQ默认分发消息使用轮训分发模式,如果消费者的速率不一样,那么就会导致消息消费的低下
为了避免这种情况,我们可以设置参数 <font style="color:rgb(25, 27, 31);background-color:rgb(248, 248, 250);">channel.basicQos(1)</font>
,意思就是每个消费者只能处理完当前消息才能接受新的消息。
幂等性
消息唯一id 存到mysql
延迟消息
只适用于时长较短的情况
队头阻塞问题:因为rabbitmq默认只检查死信队列的第一条信息,如果第一条信息的ttl时间很大,所以就算第二个ttl很短,那也会被卡住

优先级队列
电商系统中常常会遇到订单催付的场景,比如用户在淘宝下单后,往往会及时将订单信息推送给用户,如果用户在设定的时间内未付款那么就会给用户推送一条短信提醒,这个功能看似很简单,但是当订单量十分大的情况下,商家往往要进行优先级排序,大客户先推送,小客户后推送的。
todo:
联邦交换机