可靠消息+最终一致性

# 可靠消息+最终一致性 ## 绪论 > 以为之气那说过了, 高并发场景下不适合用seata分布式事务, 因此, 我们最终采取该方法(**可靠消息+最终一致性**) ## 延迟队列的使用场景 > 在当前项目中, 就有两个, 第一, 订单的自动取消, 第二, 库存的自动解锁 > 即过一段时间, 没有确认的订单自动取消, 过一段时间, 取消的订单自动解锁库存等..... ![image.png](https://cos.easydoc.net/13568421/files/lmdgxjzl.png) > 这里有一个细节, 就是解锁库存必须在取消订单后面, 否则, 一个要被取消的清单在解锁库存的时刻, 因为没有改变订单状态而错失取消订单的机会, 这非常的危险 ## 最终一致性为什么使用延迟队列, 而不是定时任务? 1. 定时任务需要定期对数据库的大量数据进行扫描, 存在非常大的磁盘IO, 极度消耗系统资源 2. 定时任务存在一个致命的缺陷, 若30min一次扫描, 在29min的时候下订单, 实际上, 只有1min的下单时间, 凭空损失了29min, 这被称为时效性问题 ![image.png](https://cos.easydoc.net/13568421/files/lmdh27pj.png) ## 复习 ### 什么是TTL? > TTL是消息的过期时间, TTL可以设置在发送消息的时候, 也可以作为队列的一个属性 > 如果在发送消息的时候设置TTL, 那么只有当前消息的过期时间是TTL, 其他都不是 > 如果在队列设置TTL, 那么这个队列所有的消息的过期时间都是TTL > **我们不建议在发送消息的时候设置TTL, 因为, RabbitMQ采取的是惰性监测机制, 即只会监测第一个消息的过期时间, 如果第一个消息的过期时间远大于后面的消息, 后面的消息就会错误的被延长, 本来延迟10s 变成 延迟10min, 这个问题非常严重, 因此不建议发送消息的时候设置TTL** ### 什么是死信?(称为死信消息的三大场景) 1. 消息过期, 消息自动成为死信 2. 消息被NACK, 消息被拒绝确认应答, 消息成为死信 3. 队列溢出, 最老的消息成为死信 > 而死信交换机就是专门来接受死信消息的普通交换机 ### 延迟队列的实现思路 > 延迟队列利用的是消息的TTL和死信交换机来实现的, 我们可以设置消息的过期时间, 让一个消息在延迟队列中放着, 没有任何人去消费他, 等到他过期之后, 转发到私信交换机进而到死信队列, 此刻, 由消费者去消费, 等待过期就是实验了延迟 #### 第一种 ![image.png](https://cos.easydoc.net/13568421/files/lmdhjek3.png) #### 第二种(惰性机制, 不推荐) ![image.png](https://cos.easydoc.net/13568421/files/lmdhjnps) ## 整体架构 ![image.png](https://cos.easydoc.net/13568421/files/lmdhosg8.png) ![image.png](https://cos.easydoc.net/13568421/files/lmdhoy2o.png) ## 搭建环境 1. 创建bitmall-mq模块, 并引入对应的依赖, 配置对应的yaml, 可以将之前的配置CV过来 2. 搭建整个消息体系 > 注意, 在搭建交换机, 队列等时, 一旦在RabbitMQ建立成功, 里面的属性不可变, 除非把RabbitMQ对应的东西给删掉, 因此, 一定要好好配置 > 如果将队列, 交换机等注入组件, 会自动在RabbitMQ创建 ### 搭建误区 #### 为什么连接不上RabbitMQ > 我这里的错误是队列参数的时候出现了错误, 主要是过期时间不可以设置为字符串, 必须是整形 #### 为什么成功连接, 但是没有队列或交换机 > 我们必须发一次请求, RabbitMQ才会创建, 否则就不创建