三尺非寒 发表于 2024-12-21 09:04:13

黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(RabbitMQ

2024最新版的SpringCloud黑马商城项目
笔记对应讲授视频讲解序号,并附上每小节所在的视频分p位置
笔记包含了视频讲解的焦点内容及实战功能实现的具体过程
课程地点: 2024最新SpringCloud微服务开辟与实战,java黑马商城项目微服务实战开辟(涵盖MybatisPlus、Docker、MQ、ES、Redis高级等)
项目代码:课程地点简介中领取
系列文章目次
本笔记包含Docker、微服务、RabbitMQ、Elasticsearch等(持续更新)
黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(Docker篇)
黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(微服务篇)
黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(RabbitMQ篇)
黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(Elasticsearch篇)


RabbitMQ

p85 MQ入门-01 MQ课程先容

https://i-blog.csdnimg.cn/direct/f20d136b69294e02800c9efe8c4508c1.png
https://i-blog.csdnimg.cn/direct/9307c951606749978514c4764df36a94.png
它是应用广泛的高性能异步通讯组件
https://i-blog.csdnimg.cn/direct/ac61222763c141ac825d334b74cbabf4.png
利用MQ前,顺序实行操作
https://i-blog.csdnimg.cn/direct/6eeab37ea536405b86fe8e7ed7855fd6.png
利用MQ后,异步实行操作,效率进步
https://i-blog.csdnimg.cn/direct/5b9f5989b8a046ad8d8ac7c853d4be19.png
基础篇和高级篇的学习内容
p86 MQ入门-02 初识MQ-同步调用优缺点

https://i-blog.csdnimg.cn/direct/2da6f167a71f4d59a224fdbfbe6d183c.png
https://i-blog.csdnimg.cn/direct/3210ae25236b487eae35d5df8354a3d0.png
以余额支付为例,它起首扣减用户余额,然后更新支付状态,末了更新订单状态等,
其中扣减余额和更新支付状态为整个支付的焦点业务,别的的是非焦点业务,
这些非焦点业务应该异步实行
同步调用的缺点:
1,拓展性差:如果后续有新的需求,那么调用会去调用很多服务,代码会变得很多,
2,性能降落:当依次调用的其中某个服务响应慢,会影响整个业务的响应时间,
3,级联失败:除了性能降落外,调用者会等候被调用者,会无效地占用调用者的资源,导致调用者雪崩,
如果调用的其中某个服务宕机了,还会导致数据差别等的环境
https://i-blog.csdnimg.cn/direct/836983b5da4f4fee94eb1031d8b5b8d0.png
同步调用的优点是时效性强,等候结果后返回
p87 MQ入门-03 异步调用优缺点

https://i-blog.csdnimg.cn/direct/edbb2b6f770449038dfc66ece16fb2f5.png
https://i-blog.csdnimg.cn/direct/ca943f3e52da42f9ae7feaec44ec8a27.png
https://i-blog.csdnimg.cn/direct/37009fe31d564b66973721dae9502d9a.png
支付服务发送消息通知后,服务会去监听消息代理的消息:
有新的需求增加时,支付服务无需增加代码,解除了服务之间的耦合,拓展性也进步了,
无需等候非焦点业务实行后返回,性能提升了,
对于宕机的服务,当服务重新上线后,消息代理继承通知未完成的消息,实现了故障隔离,
消息代理可以缓存突然激增的消息之后再慢慢处理,流量削峰
https://i-blog.csdnimg.cn/direct/df4733ee3c254c898941bc529108d68a.png
p88 MQ入门-04 初识MQ-技术选型

https://i-blog.csdnimg.cn/direct/b7d677be272c4feb9ff3e72804929937.png
MQ常见的技术
RabbitMQ采用Erlang语言开辟(这是一种面向并发的语言)
RabbitMQ支持集群,因此可用性高
RabbitMQ的单机吞吐量每秒10万,而Kafka的吞吐量每秒100万
目前市面上很少(小于10%)有公司的并发超过10万,而大多数的并发在几百
RabbitMQ的底层是基于内存的处理,它的消息延迟很低
如果消息能满意至少被消耗1次,那么它的可靠性就高,RabbitMQ的可靠性比Kafka好,Kafka轻易消息丢失
https://i-blog.csdnimg.cn/direct/23a9d73f8d0a40638dfb82f24b75e953.png
比力突出的技术是RabbitMQ和RoketMQ由于可靠性好,而Kafka实用于大数据对吞吐量有要求的
p89 MQ入门-05 RabbitMQ-安装摆设

https://i-blog.csdnimg.cn/direct/c1115736241d45889e9dfd47570a7dab.png
https://i-blog.csdnimg.cn/direct/7d9d24538cf64dd9bbb3b5ca751783b2.png
rabbitmq的官方文档
讲授视频以rabbitmq版本3.8为例
https://i-blog.csdnimg.cn/direct/c582461d29bc4d1e88f830da5de09fcc.png
采用docker来安装rabbitmq
它会提供一个控制台,然后需要设置用户名暗码,挂载数据卷,创建网络(到场黑马商城项目的网络)
控制台端口为15672,收发消息的端口为5672
https://i-blog.csdnimg.cn/direct/09a9706e0e544a36bf9bec3ab1d69bc4.png
下载大概从tar包加载好镜像
https://i-blog.csdnimg.cn/direct/5fec6bb88c414bae9d72a60e916091ca.png
Docker run创建容器
https://i-blog.csdnimg.cn/direct/0aabf78dbaf94141b546c426896b5f94.png
Docker logs -f mq检察日记,两个端口都打开了
https://i-blog.csdnimg.cn/direct/888fc41f9998447ea341cef55fcc390b.png
访问rabbitmq的网页控制台,输入设置的用户名和暗码
https://i-blog.csdnimg.cn/direct/cfbd0ef9fb554f49a8eaa4d3112bc009.png
可以在首页看到总览信息,它的版本,消息队列当前状态,节点等
https://i-blog.csdnimg.cn/direct/5ba9e79cb196402b93b12308d0e0d20b.png
可以在首页看到总览信息,它的版本,消息队列当前状态,节点等
https://i-blog.csdnimg.cn/direct/19299ba9f10a4bdd8754bb7c469c90c3.png
connections可以看到连接的消息发送者和吸收者
channels表示收发消息的通道,用通道举行消息传输
https://i-blog.csdnimg.cn/direct/046d4dddfeb04be09276c7e0aa442a9a.png
这是一些默认的互换机,
exchanges互换机和queues队列用于管理消息
https://i-blog.csdnimg.cn/direct/23af067674974c3bb68295d6bacdd3e1.png
在企业中,摆设的一个rabbitmq可能会由多个项目利用,
为了防止差别的项目创建的exchange冲突,需要做隔离,用virtual-host假造主机来完成(一个项目一个假造主机)
https://i-blog.csdnimg.cn/direct/a67fc260a73145ac95904ebe597879ad.png
在控制台右上角可以看到此时是利用默认的假造主机
p90 MQ入门-06 RabbitMQ-快速入门

https://i-blog.csdnimg.cn/direct/d88479fb4cbe46959b312fa3c66f7cd9.png
https://i-blog.csdnimg.cn/direct/541c986eabe2435ea206359b624bf030.png
在控制台中举行rabbitmq测试
https://i-blog.csdnimg.cn/direct/1c6d37178d674911adc6950d15e6a5f0.png
添加一个队列
测试向互换机发消息看队列是否能收到
https://i-blog.csdnimg.cn/direct/9ae8636c655449c4b18a0106a3a5c953.png
进入默认的fanout互换机,发送一条消息
https://i-blog.csdnimg.cn/direct/c67aefba61a348209538662186f8962a.png
点击发送消息后,提示not routed,然后队列内里也没有收到,
说明消息丢失了(互换机没有存储消息的能力,互换机只负责转发消息)
队列没有收到消息的原因是互换机和队列没有建立一种关系
https://i-blog.csdnimg.cn/direct/af2354cfd4d948c7842438ea99de4bf6.png
进入到互换机内里,点击bindings绑定,设置与它绑定的队列
https://i-blog.csdnimg.cn/direct/bbe853ea2bf142ada4158a47ed118bfa.png
进入到队列内里也能看到与它绑定的互换机
https://i-blog.csdnimg.cn/direct/bf90f4eae8614fa49110f07d90bdce8d.png
再次发送一条消息,没有刚才谁人提示了
https://i-blog.csdnimg.cn/direct/12dd51eb0237401996937b6faae3d6c7.png
去队列内里检察,这2个队列都收到了消息
https://i-blog.csdnimg.cn/direct/c1cf0dff70aa401da130444b31c2537f.png
检察队列内里的消息,内容就是刚刚发送的内容
https://i-blog.csdnimg.cn/direct/90440f6ae702427a976400aa50d0b4b1.png
p91 MQ入门-07 RabbitMQ-数据隔离

https://i-blog.csdnimg.cn/direct/b4ed20b396104d718d5a814d00783fd5.png
https://i-blog.csdnimg.cn/direct/37b41cbcaa134d3781776083dcb61682.png
希望差别的项目是隔离开的,通常的做法是一个项目对应一个用户,再为这个用户创建一个假造主机
https://i-blog.csdnimg.cn/direct/f14c0629743f46b38188b6fd2295d2f3.png
Users是用户管理,可以看到创建的用户
https://i-blog.csdnimg.cn/direct/9330017abca142a4befa3482245767c6.png
Virtual Hosts可以看到创建的假造主机,斜杠是目前默认的假造主机
https://i-blog.csdnimg.cn/direct/162a96ad4f634f0389361226bd45a1eb.png
创建一个用户,tags设为管理员
https://i-blog.csdnimg.cn/direct/4352958d7cbb42de9f007f18f986415e.png
可以看到刚刚创建的用户没有可以访问的假造主机
https://i-blog.csdnimg.cn/direct/87dda5473cf54d8bb162bd866c14ebb3.png
因此,利用这个用户登录后无法检察别的假造主机内里消息队列的内容
https://i-blog.csdnimg.cn/direct/b6866713a38249dcbc68414b6223cf8d.png
用hmall的身份登录后创建一个名为/hmall的假造主机,
https://i-blog.csdnimg.cn/direct/fbc2db218d5b47a49ba93d43c21a6276.png
创建完成后它默认当前用户可以利用,在Users中也可以看到
https://i-blog.csdnimg.cn/direct/da880f5999084925a881f942db384c45.png
在互换机内里也出现了一堆默认的互换机,名称与之前的一样,但是它们属于新的假造主机/hmall
p92 MQ入门-08 Java客户端-快速入门

https://i-blog.csdnimg.cn/direct/bd56bc57256a4481b19c291d2807a576.png
AMQP是rabbitmq采用的协议,该协议与语言平台无关
https://i-blog.csdnimg.cn/direct/2ca71695f92a4375997320271ab8c0b4.png
这里java客户端的演示不用官方的AMQP客户端,而是Spring AMQP客户端(在Spring官网内里可以找到)
https://i-blog.csdnimg.cn/direct/fa8233a55dc44603ad6d0285595e55df.png
打开课程资料的项目工程
https://i-blog.csdnimg.cn/direct/7506410ad2014183a0e1340e4e16ce48.png
可以看到有消息的发送者和吸收者
https://i-blog.csdnimg.cn/direct/c2303def58ff47ada4e976ccffcfd0df.png
这里的演示省略发送消息发到互换机,再发到队列的过程
https://i-blog.csdnimg.cn/direct/48433910b75e49bd835a22209c34a0ed.png
在RabbitMQ控制台中创建队列
https://i-blog.csdnimg.cn/direct/e69b7b7c3ba34013b617a1961db148d9.png
父工程内里引入amqp依赖,包含了rabbitmq
https://i-blog.csdnimg.cn/direct/2cf87c1e9b6b4fe6b996fca5a57c1602.png
配置rabbitmq服务端信息
https://i-blog.csdnimg.cn/direct/1a160f0604ce4d2bb7d904c7bc87ec1d.png
alt加enter快捷键创建一个单位测试 (单位测试要在启动类的包下或子包下)
https://i-blog.csdnimg.cn/direct/6dc34473edcf47dab0a988f25ce70f9b.png
https://i-blog.csdnimg.cn/direct/409e8350efbc47d9a9d4cc662028752d.png
发送一条消息,可以看到连接消息队列成功
https://i-blog.csdnimg.cn/direct/5b04b531cfc84e3d8685d01a90ce1037.png
队列内里出现了一条消息
https://i-blog.csdnimg.cn/direct/6e6e9519eed14fbe8889d16dcca974cd.png
然后在控制台内里可以看到了发送的消息内容
https://i-blog.csdnimg.cn/direct/3bdcc572de54432cbade59c344ca4f42.png
https://i-blog.csdnimg.cn/direct/9316d23ff6614f8aa0d8ca503eaa5bf9.png
在消耗者主类下创建一个类用于监听队列中的消息,这里吸收的参数范例是String由于发送的消息范例也是String
https://i-blog.csdnimg.cn/direct/f18385a57147407f8f209fdabe76ce81.png
启动消耗者的主类,控制台输出一条日记,监听到了队列的消息
https://i-blog.csdnimg.cn/direct/584715ca66f04ee8b45b1906040d14ef.png
p93 MQ入门-09 Java客户端-WorkQueue

https://i-blog.csdnimg.cn/direct/835cc8d34be047a6886689063f97f45b.png
WorkQueue是消息发送模型,它让多个消耗者共同消耗队列中的消息
https://i-blog.csdnimg.cn/direct/8dd394ac9d94432f91734aaacef1f12a.png
https://i-blog.csdnimg.cn/direct/165186835f6f400886e46f25dc5df173.png
在吸收者中定义2个消息监听者
(在现实生产中一般不会写成这样的2个方法,由于这2个消耗者运行时斲丧的是相同的呆板资源,这样做没故意义,
因此,通常是写一个消耗者方法,然后再摆设多个实例分别在差别的呆板上,它们代码相同,这些实例就是多个消耗者)
https://i-blog.csdnimg.cn/direct/a1a5f8fb53634bb4bbdc87a5403156b3.png
在发送者中定义一个测试方法,发送50条消息,每条消息带上一个序号便于之后观察
https://i-blog.csdnimg.cn/direct/d352e64576674ba59fe7a9ac6b519a50.png
启动消息吸收者主程序,启动消息发送者的测试类,
控制台的部分打印输出,发现消耗者2吸收了奇数序号的消息,消耗者1吸收了偶数序号的消息,消息被交替消耗了
可以发现:
消息只会被1个消耗者处理(被处理了就不能被别的消耗者处理)
消息会被消耗者匀称分配(轮询)
多个消耗者去消耗一个队列可以加速消息的处理速率,因此,消息堆积的问题可以添加更多的消耗者来解决
由于消耗者实例运行的呆板性能可能存在差异,需要设置消耗者的处理速率来适配对应的呆板性能
https://i-blog.csdnimg.cn/direct/6e5383dc9e5f4c58a1e01d15f5d4764a.png
比如,设置消耗者的处理速率为以上速率
https://i-blog.csdnimg.cn/direct/cc1b4f6937fb40c7b247f1c71442143d.png
设置的方式是让这个线程休眠
https://i-blog.csdnimg.cn/direct/ca069f68e9ad47cabf924929df74324b.png
再次发送消息举行测试,发现处理了5秒才完成,预计是1秒多(消耗者1的40与消耗者2的5,那么每秒就是45条),
这里消耗者1处理速率很快,只处理本身的那一半消息,处理完后就没有消息了,
消耗者2的处理速率很慢,但依然要处理本身的那一半消息,造成了时间浪费(应该消耗者1要多处理一些才行)
造成的原因是,rabbitmq默认是将消息轮询投递给消耗者,不思量消耗者的处理速率
解决方法是修改rabbitmq的配置,将prefetch设为1,表示每次只能获取1条消息,处理完成才会获取下一个消息
https://i-blog.csdnimg.cn/direct/40d08e39b1d44040b3f32562dfa1d6c4.png
将消耗者的配置prefetch设为1
https://i-blog.csdnimg.cn/direct/c78c064d849743a1aa3c98f47b9acb39.png
再次发送消息举行测试,发现消耗者1不但处理奇数序号的消息还处理了偶数序号的消息(消耗者1处理了比一半更多的消息),
整个消息也在大约1秒内处理完毕,与预期相符(能者多劳)
https://i-blog.csdnimg.cn/direct/6e7283c27e29485eb2c56e9117a4e36a.png
p94 MQ入门-10 Java客户端-Fanout互换机

https://i-blog.csdnimg.cn/direct/493be536f866496cae0eca62419c4026.png
消息队列的完整模型包括:发送者、互换机、队列、消耗者
https://i-blog.csdnimg.cn/direct/8540a98fdd7b4ebfab659f8b79768690.png
互换机的范例有:fanout(广播)、direct(定向)、topic(话题)
https://i-blog.csdnimg.cn/direct/52db4a336c45435882f4eca1a382739c.png
fanout互换机会复制消息给多个绑定的队列,那么一个消息会被多个消耗者消耗
(这种互换机就可以在需要发送消息给多个微服务的环境下利用)
https://i-blog.csdnimg.cn/direct/604eca0579d94253b11d17d1a786bab9.png
https://i-blog.csdnimg.cn/direct/d187c207166d4ed898d359ffd5b0637e.png
声明一个fanout互换机
https://i-blog.csdnimg.cn/direct/3edb2ff889f5490e8b8a73a44f0ad72d.png
将互换机与队列绑定
https://i-blog.csdnimg.cn/direct/8b5abd3d143647c99128387fabc2fe40.png
这里依然用convertAndSend方法,但是填入3个参数,
两个参数的方法会将第1个参数当成队列名,三个参数的方法会将第1个参数当成互换机名,
这里选三个参数的方法,由于现在是发送者只发到互换机因此第二个参数不填,routingKey参数是别的互换机会用到的
https://i-blog.csdnimg.cn/direct/c4e7f849cb77458482c74e20453100f2.png
从控制台可以看到2个消耗者都收到了消息
p95 MQ入门-11 Java客户端-Direct互换机

https://i-blog.csdnimg.cn/direct/f43b4e0a7a3a452e8ec45cecef32e0e4.png希望消息被部分消耗者收到,而不是所有的消耗者
https://i-blog.csdnimg.cn/direct/18476fbd117345a08ab6cef5e1523574.png
通过队列与互换机设置BingdingKey和发送者设置的RoutingKey,来决定哪些消耗者能收到消息,
Direct互换机也能实现Fanout互换机的功能
(应用场景举例,比如用户取消了订单,只需要给生意业务服务发送消息,不用给用户发短信以及加积分了,即不用发送给所有的消耗者)
https://i-blog.csdnimg.cn/direct/7d308ff7fbdb49e89601d6dfa3ad99c7.png
设置互换机的绑定队列的RoutingKey
https://i-blog.csdnimg.cn/direct/f282065b41fe40d9aab61b2142c99aa5.png
设置消耗者监听消息
https://i-blog.csdnimg.cn/direct/028bdf01b54548a28c3fe539ca12670e.png
设置消息发送者的routingKey
https://i-blog.csdnimg.cn/direct/48324b866792464fa3f66ca6756b930a.png
两个消耗者都监听到了消息
https://i-blog.csdnimg.cn/direct/74495c8c604e44b59a60511f252ec7a9.png
将routingKey设为blue
https://i-blog.csdnimg.cn/direct/dce7e6758a5b48689f0e96bedd058150.png
只有消耗者1收到了消息
https://i-blog.csdnimg.cn/direct/18abe449a5b94d03b04bd85c14c083f5.png
p96 MQ入门-12 Java客户端-Topic互换机

https://i-blog.csdnimg.cn/direct/847241cad00244cb85618eaff260201e.png
https://i-blog.csdnimg.cn/direct/4983ca593aa646549647cdc92bb679a5.png
RoutingKey由多个单词构成,之间以点分割,允许利用通配符(井号和星号),
因此,具有共同前缀的routingKey可视为一个Topic,这种方式的拓展性更强
https://i-blog.csdnimg.cn/direct/8c30befc2e684299947dbcde3c9fdf57.png
https://i-blog.csdnimg.cn/direct/9d64bc3798a24b63a0f7f3c385b3afcc.png
创建topic互换机
https://i-blog.csdnimg.cn/direct/6dfa2b6a19844e488ed79c71ba2e020e.png
设置互换机绑定的队列并指定RoutingKey
https://i-blog.csdnimg.cn/direct/6a524b2451e9424da5a85affcefe9968.png
2个消耗者都监听到了
https://i-blog.csdnimg.cn/direct/c6bad0f6267e4b2295db0e2f0269bd0c.png
修改发送的RoutingKey,这次只有消耗者1能收到
https://i-blog.csdnimg.cn/direct/9e280269c5db454091d9fda4a7f022b5.png
p97 MQ入门-13 Java客户端-基于Bean声明队列和互换机

https://i-blog.csdnimg.cn/direct/380f39420bfe461eb9a800a4b7113618.png
基于Bean声明队列和互换机
https://i-blog.csdnimg.cn/direct/2cb6942943164c7896d4b38e34d51b19.png
https://i-blog.csdnimg.cn/direct/bb6e9c0b7fd94ef894ed883bbca063e6.png
这里声明互换机和队列有两种方式:new的方式、利用Buider的方式。这两种方式没有区别
其中,durable意味持久化
https://i-blog.csdnimg.cn/direct/61fb3084b27d49559499309608b438e7.png
声明以及绑定的代码通常是在消耗者内里写(而不是发送者),
这里声明1个互换机和2个队列,并将它们绑定,运行消耗者主程序
https://i-blog.csdnimg.cn/direct/966775dc45044963923dc0f139542173.png
进入RabbitMQ的控制台可以看到声明成功,并且完成了绑定
p98 MQ入门-14 Java客户端-基于注解声明队列和互换机

https://i-blog.csdnimg.cn/direct/fbb07e2d31f449528dae22fc8abfe046.png
基于注解声明队列和互换机
https://i-blog.csdnimg.cn/direct/b60f7da4031f464289ffb292bedff600.png
之前的案例,这次在Java中声明(而不是控制台)
https://i-blog.csdnimg.cn/direct/1539d869daa540f7a85d180a81d21b5b.png
基于Bean的方式的缺点,如果要指定routingKey,但是一个Bean只能传一个参数,
有多个参数就要写多个Bean来实现绑定,这会造成Bean的数目很多,这个问题可以用注解解决
https://i-blog.csdnimg.cn/direct/4f39ba73d8fe4696b43cf899f0e2b94d.png
用一个注解完成队列声明、互换机声明、绑定关系
https://i-blog.csdnimg.cn/direct/fb324494e8214ce89e4d192125991d1b.png
在监听者的注解中声明互换机和队列并且完成绑定
@RabbitListener注解的一个属性是bindings,而这个属性的值也是一个@QueueBinding注解
https://i-blog.csdnimg.cn/direct/012132cd9ca14dde9342172d3fb77f61.png
进入控制台,声明和绑定都正常配置了
p99 MQ入门-15 Java客户端-消息转换器

https://i-blog.csdnimg.cn/direct/5eea7065fa5a4be290064bcd91f446ce.png
rabbitmq支持发送恣意范例的对象,因此在发送消息时需要将java对象转换为字节,这个转换由消息转换器来完成
https://i-blog.csdnimg.cn/direct/1856abf4bd77424385ee6e1531639c6c.png
https://i-blog.csdnimg.cn/direct/0f52f6458baa4c2e805c89ead061fc76.png
发送一条Map范例的消息,但不设置消耗者,然后去队列内里检察这条消息
https://i-blog.csdnimg.cn/direct/def3ccb4d3bb4fbfa7ee2259f123121c.png
可以看到这条消息的内容是字符串
https://i-blog.csdnimg.cn/direct/a1b1ef3c62c2497e8294d0e2b1b46e2f.png
Spring rabbitmq的底层采用了jdk提供的序列化方式(ObjectOutputstream)将java对象转换成字节
https://i-blog.csdnimg.cn/direct/4ca13a5dc50f45a8aa0880d4ca97fbe1.png
jdk的序列化存在一些问题:反序列化时存在毛病轻易被注入代码、消息太大(比如刚刚很小的对象存储了170多个字节)、可读性差
https://i-blog.csdnimg.cn/direct/428824814b684ad884874be6bf5b19db.png
发起采用JSON序列化
由于publisher和consumer都需要依赖,可以在父工程引入依赖
https://i-blog.csdnimg.cn/direct/06a8a142c5b74386adabf49b71dcbfc3.png
子工程引入了依赖
https://i-blog.csdnimg.cn/direct/096ac92bc2b04421b9e0e640103df74c.png
定义一个MessageConverter的Bean(在publisher和consumer都要写),可以利用快捷键ctrl + H快速找到所在的类
https://i-blog.csdnimg.cn/direct/48424ad719af4a5d92de22d246363100.png
配置好Bean后再次运行单位测试发送一条消息
https://i-blog.csdnimg.cn/direct/55d42796c11d4846be4c3473253a34fe.png
在mq控制台get两条消息,可以看到修改后的消息范例为json,占用的空间变小了,内容可读性好
https://i-blog.csdnimg.cn/direct/995297081e72472fbe87237f8f569a96.png
在comsumer中定义一个监听器,参数范例与发送的消息范例保持同等
https://i-blog.csdnimg.cn/direct/d96176cdc284467e96d7e90cd94d86d8.png
启动消耗者程序,可以看到输出的消息,
投递消息时范例是Map然后mq会把消息转换为字节(json方式),取出消息时会把字节又转回Map范例
p100 MQ入门-16 业务改造

https://i-blog.csdnimg.cn/direct/98c3603359b241cb95d3227edb1efcc7.png
将黑马商城中的一个业务从同步调用改为异步调用
https://i-blog.csdnimg.cn/direct/3897ba54e6c24912b83d1fba337faef6.png
由于不是通知所有的服务,因此不能用fanout互换机,这里采用direct互换机
起首声明队列和互换机(在消耗者内里去写),发送者是pay服务,消耗者是trade生意业务服务
第一步引入依赖,第二步配置mq的地点,第三步配置消息转换器,第四步配置监听器指定队列互换机
https://i-blog.csdnimg.cn/direct/84d1e9e325534b348bbfbfa5ea6b921a.png
在发送者和消耗者中引入依赖
https://i-blog.csdnimg.cn/direct/5ab8a01783c940fabfc7c74a0d3c4eab.png
配置mq的地点,在发送者和消耗者中都要配置,可以放到nacos的共享配置中
https://i-blog.csdnimg.cn/direct/30b3f802a8cc4fc88e65893450b44a5e.png
配置消息转换器,由于发送者和消耗者中都要配置,这里就写在common中,但是现在这个包路径下无法被扫描到因此无法生效
https://i-blog.csdnimg.cn/direct/8f914c65184341608115a6a18ebc5dc5.png
因此在spring.factories文件中加上一句话,让它能被扫描到,让配置生效
https://i-blog.csdnimg.cn/direct/3c69b62ade8e4cbdb3f89367f4afc326.png
注意这里由于在common中配置了mq消息转换器,因此所有的服务都需要配置amqp的依赖,那么可以在父工程中到场这个依赖,否则无法运行
https://i-blog.csdnimg.cn/direct/3e8cd229b95b4372b08748641ad6149e.png
在发送者中修改原有的业务逻辑,将利用同步调用的FeignClient方式改为利用MQ的方式,指定发送的互换机、routingkey、消息等,
为了防止队列的利用影响到原有的代码(比如队列出错导致这里发送者的代码报错),这里加上try-catch来捕捉异常
https://i-blog.csdnimg.cn/direct/48084c8bd5ed42ef99d254d6d4d6cb01.png
在消耗者(trade生意业务服务)中配置监听器,创建队列互换机配置绑定关系,然后在监听方法中写原有的controller调用的代码
https://i-blog.csdnimg.cn/direct/d64c9c9d851849dcacaf78ccfe38477b.png
运行发送者和消耗者服务,在mq控制台中可以看到创建好的互换机并完成了队列绑定
https://i-blog.csdnimg.cn/direct/dcbf204a0f2f41738e7f084268f71644.png
订单创建成功,可以看到订单号
https://i-blog.csdnimg.cn/direct/54b1ccea9e964fc393471139a92d50c7.png
去数据库内里查这个订单,可以看到状态为1,未支付
https://i-blog.csdnimg.cn/direct/7f5a44bb77e14977a40e07fa5a4e16cc.png
通过用户余额的方式支付成功
https://i-blog.csdnimg.cn/direct/f753c6bda0c141649a4abdb4e5bfbd3e.png
用户的金额扣减成功
https://i-blog.csdnimg.cn/direct/df3b1091e28d422f95e23d418ff6f426.png
可以看到订单状态为2,已支付
p101 MQ高级-01 课程先容

https://i-blog.csdnimg.cn/direct/f88014b2b897442385a18d068d7b1c49.png
保证消息收发的高可靠性
https://i-blog.csdnimg.cn/direct/a09b9e412501488c9cc50a8f27d94561.png
消息可靠性对业务很重要,
比如支付成功后但是订单更新状态没有完成,就会造成严重问题
https://i-blog.csdnimg.cn/direct/709fb66cc8374733892888219c5c80ea.png
这可能由于一些问题导致的:
1,发送消息时的网络出现问题(发送者的可靠性)。2,消息代理出现问题。3,消耗者服务出现问题。
而在做好前3种可靠性后,延迟消息作为一种兜底的方案来利用
p102 MQ高级-02 发送者可靠性-发送者重连

https://i-blog.csdnimg.cn/direct/82405fd5a7294836a5fa2d9a31a34370.png
发送者重连机制默认是关闭的,需要通过配置打开
https://i-blog.csdnimg.cn/direct/3b90ceb83b9541ce9e462818988e2687.png
最大重试次数默认为3
https://i-blog.csdnimg.cn/direct/863033b8bfec430ea1aa90c1e8ecec8b.png
通过配置打开重试机制,然后将mq服务关闭,然后启动发送者去往队列内里发消息,会出现连接失败,
可以看到它会尝试连接3次,隔断时间与预期设置的相符
https://i-blog.csdnimg.cn/direct/f91c8130289f4c59816bf55597927936.png
这里的重试机制是阻塞式的,如果发送者的连接真的出现问题,它实行重试时会造成后续的代码被阻塞,影响性能
p103 MQ高级-03 发送者可靠性-发送者确认机制

https://i-blog.csdnimg.cn/direct/5024c3cef7a94b629fd42dfc9df8fec4.png
通过发送者确认来确保发送消息到MQ的可靠性
https://i-blog.csdnimg.cn/direct/f6ea29c3a48d4a80a0d53f985643dc4a.png
未路由成功的消息也算成功,MQ返回ACK给发送者。由于这是发送者造成的错误,而不是MQ造成的,
临时消息指不需要持久化的消息(普通的消息会举行持久化)
持久消息必须要写入完成以下才算成功,返回ACK:1,到达互换机;2,进入队列;3,完成持久化
而临时消息由于不需要持久化,因此进入队列就算成功,返回ACK
https://i-blog.csdnimg.cn/direct/d07135727edc4329a854dce820a5a4df.png
在配置种开启2个确认机制
correlated机制与simple差别,它避免了同步等候,
https://i-blog.csdnimg.cn/direct/186f6b030cd74dbbad68b3fe59d51642.png
这是publisher return(发送者返回)机制,发送失败时会记录日记
https://i-blog.csdnimg.cn/direct/31655ab3318c4b70842aec840f08ed62.png
这是publisher confirm(发送者确认)机制,在发送消息的时候会多传一个参数cd(CorrelationData),
它起首用getFuture方法得到一个空的对象,而addCallback方法用于未来MQ实行完成后会把确认结果通过回调函数通知给cd的空对象
p104 MQ高级-04 发送者可靠性-发送者确认的代码实现

https://i-blog.csdnimg.cn/direct/bae75de83de44b7e96059bbbfbb3d3fe.png
发送者确认的代码实现
https://i-blog.csdnimg.cn/direct/7ce95889cb0048038cf711001b859d81.png
在发送者的yaml中配置
https://i-blog.csdnimg.cn/direct/7e22862094c74303b16d809ad55ca0a6.png
Return callback定义在发送者的一个配置类中
https://i-blog.csdnimg.cn/direct/fabaf5594c294113a03f40d39a2cc343.png
Confirm callback定义在消息发送者中,测试消息正常发送环境下日记的输出结果
https://i-blog.csdnimg.cn/direct/832fc99b197e453080e249b09c3cac84.png
将消息的routingKey改为一个不存在的字符,会导致互换机路由失败,
在日记中可以看到return callback和confirm callback都收到了,并显示错误范例为路由失败
https://i-blog.csdnimg.cn/direct/91726e766ce844ac812ba265f77a6d4f.png
如果指定了一个并不存在的互换机名称,会返回nack消息发送失败
p105 MQ高级-05 MQ可靠性-数据持久化

https://i-blog.csdnimg.cn/direct/f6206c23dded438d9536eccfc06588db.png
MQ的数据持久化可以保证MQ的可靠性
https://i-blog.csdnimg.cn/direct/75ca233c14184374a4dd7a64dab8c6b5.png
解决方法是持久化和lazyMQ,这里先讲持久化
https://i-blog.csdnimg.cn/direct/5cc8972555ed4ff8a3f193d56bcc0e7c.png
互换机、队列创建默认是持久化的(Durable),而Transient表示临时的不持久化
消息在发送时有投递模式,Non-persistent非持久化(默认)和Persistent持久化
https://i-blog.csdnimg.cn/direct/197a72e1aaee49be82354af0f5e69bb2.png
往队列内里发送非持久化的消息和持久化的消息,然后将MQ重启,末了发现只有持久化的消息还在,别的消息不见了
现在,往队列内里发送一百万条消息举行测试
https://i-blog.csdnimg.cn/direct/a868272fd27741519f89a71a4903c337.png
为了方便观察结果,关闭发送者确认(由于这会造成一定的性能代价)
https://i-blog.csdnimg.cn/direct/9e3ffca7714b4b95b055023e91773bb7.png
由于消息默认是持久的,如果要发送非持久消息,要先定义一个消息体
https://i-blog.csdnimg.cn/direct/d7c7f7262a56431f8a00612d73e7fc0f.png
非持久化的消息是基于纯内存模式,如果内存满了,它也会写入磁盘(由于内存装不下了只能先放在磁盘里),
而此时写入会造成阻塞(消息处理速率降至0),然后随着写入完成逐渐提升处理速率
https://i-blog.csdnimg.cn/direct/ffa1f132378e450cb1e0aba7d32247ea.png
如上图,通常环境是,内存满了之后写入磁盘引起性能降落(黄线降落),多出的消息写入完成后逐渐规复性能(黄线上升)
接下来再看持久化的消息
https://i-blog.csdnimg.cn/direct/9b8db8692ca0496b8f60e6bd6a516827.png
将消息改为持久化模式,再举行一次测试
https://i-blog.csdnimg.cn/direct/f0d81b2a02d246e18c862092b019f6c8.png
可以看到,消息进入内存和持久化的数目是同等的(而不是内存满了再举行持久化),它会同时举行这2个操作,
因此,这种持久化消息的优点不但是保证消息丢失,而且不会造成阻塞
p106 MQ高级-06 MQ可靠性-LazyQueue

https://i-blog.csdnimg.cn/direct/401362c60d434594851d49ae346caf7c.png
这节讲队列持久化,惰性队列,它直接将消息写入磁盘,
它对写磁盘做了优化,性能较好,保举利用LazyQueue
https://i-blog.csdnimg.cn/direct/9932f2f330974525ae818ac74b5d55b7.png
为了淘汰从磁盘加载到内存所需时间的影响,它会监测消耗者的处理速率,提前加载部分消息到内存
LazyQueue的优点:1,持久化消息(直接存入磁盘);2,不写入内存也就不会内存满了pageOut导致阻塞
https://i-blog.csdnimg.cn/direct/07ee8b13bd5247ff8fc7128b8f5b533f.png
在控制台中创建一个lazyQueue时需要指定参数
https://i-blog.csdnimg.cn/direct/38e7f9e92b514a40b2dfb7a8fd7e0f31.png
lazyQueue两种代码声明方式
https://i-blog.csdnimg.cn/direct/ea4d72361c0e47e7b6734bf450bf165a.png
同样地,也往lazyQueue内里发一百万的消息举行测试,可以看到一开始就出现在paged out中,而不是内存和持久化
https://i-blog.csdnimg.cn/direct/8db7353d9f9f4dcb95abc0e594ce6dcf.png
p107 MQ高级-07 消耗者可靠性-消耗者确认机制

https://i-blog.csdnimg.cn/direct/7b5eb640c498431bb0920259b09aa085.png
消耗者返回给MQ的确认
https://i-blog.csdnimg.cn/direct/a7336960d22a49008f767deafff35b00.png
有三种消息处理状态,ack、nack、reject
返回消息状态不是在消耗者拿到消息后立即返回,而是处理消息后根据处理结果来返回
如果返回reject通常是消息的内容有问题,消息没有重试的必要(因此不能用nack)
https://i-blog.csdnimg.cn/direct/2cda53a17dc64f41af7e1c275b8de614.png
接下来举行测试
https://i-blog.csdnimg.cn/direct/958105d4a5f74cf2827bb598fddddc6c.png
将消耗者的yaml配置文件的消耗者确认模式设为none
https://i-blog.csdnimg.cn/direct/8491015b9e274549972dfd79b8041c1b.png
然后用发送者Test测试类往队列内里发一条消息,进入控制台可以看到存在一条消息
https://i-blog.csdnimg.cn/direct/857dbaf584414e35a24f1d6082081bfe.png
然后在消耗者打一个断点,debug启动
https://i-blog.csdnimg.cn/direct/a06edd9dea4344c497d912bb451bbdca.png
此时进入控制台检察,发现消息不见了,说明立即返回了一个ack,队列把消息删除了,
但此时消耗者并没有实行完毕,说明是拿到消息后立即返回的
接下来将消耗者确认模式改为auto来测试
同样地,进入上面的断点
https://i-blog.csdnimg.cn/direct/7ca652f92cca4963b37db1a3c9bdc312.png
进入控制台看到有一个未确认的消息
https://i-blog.csdnimg.cn/direct/2c0f68ad411146ac8a05ff993c24cd28.png
将这个断点放行,发现它又进入断点了(控制台输出内里再次监听到了消息),
说明消耗者返回的是nack,那么队列会将消息再次投递给消耗者(直至消耗者宕机)
https://i-blog.csdnimg.cn/direct/0647f23324264bbc9b2de10bfd3af2ca.png
将消耗者关闭后,进入控制台看到消息变回了ready
再测试一下抛出一个消息转换异常
https://i-blog.csdnimg.cn/direct/12e7794f758146eb96f188e4bf308137.png
同样地,进入到断点后,点击放行,发现它不会再次进入断点了,
说明队列没有再次重复发消息了,消息被拒绝了
p108 MQ高级-08 消耗者可靠性-消耗者失败重试机制

https://i-blog.csdnimg.cn/direct/f8e7a9a249394393bf494f5bfa8d6e20.png
消耗者失败重试机制
https://i-blog.csdnimg.cn/direct/c8b561dcca164c81a126d26d8976bf37.png
失败重试机制是消耗者异常时本地重试,而不是重新入队再取出消息(消息在消耗者和MQ之间踢皮球)
它默认是关闭的,需要在配置文件中打开
先测试一下现在的环境
https://i-blog.csdnimg.cn/direct/07bce5d832134fd6a786113f5abdba97.png
在消耗者中设定抛一个异常,然后往这个队列内里发一条消息,
启动消耗者后它会不断地报错,说明这条消息不绝在重复的发送(队列发给消耗者,而不是消耗者本身重试)
https://i-blog.csdnimg.cn/direct/95ce4ca9c8874fc9878d22d3fe78f19c.png
打开控制台可以看到每秒发了很多条消息(此时消耗者和MQ都会有很大的性能斲丧)
https://i-blog.csdnimg.cn/direct/718f087c310441ee8b337d850d4379b4.png
在消耗者中打开失败重试,再用上面发消息的例子
https://i-blog.csdnimg.cn/direct/3a6323baac20474bbab63606ae72ffae.png
失败重试3次后(默认3次),重试次数耗尽,消息就会被拒绝,此时消息既不在MQ也不在消耗者中(可靠性低落了)
https://i-blog.csdnimg.cn/direct/cfe368911337485489511725f60d15d8.png
第一种方式是默认的,
第二种方式是重试耗尽后,重新入队
第三种方式是重试耗尽后,投入到指定互换机,Republish重发消息
https://i-blog.csdnimg.cn/direct/67265afabe6149c286947d110f4bc12c.png
接下来举行第三种方式的测试
https://i-blog.csdnimg.cn/direct/68b8fdce3771468d90468e76811d1458.png
在消耗者内里创建一个配置类
https://i-blog.csdnimg.cn/direct/28d4b0be38924f0a8e392ed1c5fb2671.png
重新用之前的例子举行测试,可以看到重试3次后,它会将消息发送到刚刚配置的互换机
https://i-blog.csdnimg.cn/direct/8d1bce1ee2e54c2a8a5a22e40cdc666d.png
进入控制台可以看到创建了error队列,并且内里有一条消息
https://i-blog.csdnimg.cn/direct/5bbcc48b869e4360bd74a6f13586f387.png
检察这条消息,可以看到它带上了完整的异常栈信息(便于举行故障排查)
https://i-blog.csdnimg.cn/direct/a19bf8f1b7a7445db55a2ffe2fb229c6.png
p109 MQ高级-09 消耗者可靠性-业务幂等处理

https://i-blog.csdnimg.cn/direct/5ce1581542ef40cfba52fca58da940cf.png
以上的小节,保证了消息各方面的可靠性,但是可能出现消息被重复处理的可能性,
https://i-blog.csdnimg.cn/direct/f4314dbeffe2448181cda22659b3f0cc.png
比如由于网络出现故障,网络规复后再次投递一次消息,但是这条消息之前已经被处理过了,在某些业务中可能导致问题
解决消息重复消耗问题就是要举行业务幂等处理,即业务实行一次或多次的业务状态影响是一样的
https://i-blog.csdnimg.cn/direct/0b9284e927ab4d0da9f6c394dd160f97.png
方案一
https://i-blog.csdnimg.cn/direct/471c6e6943af46aaa051bf84f7c5e979.png
在发送者的消息转换器内里将消息id的设置打开,
然后往队列内里发送一条消息,之后观察结果
https://i-blog.csdnimg.cn/direct/cd5b76182c044e9282100f9bcb587aac.png
在控制台中可以看到这条消息的属性有一个id,那么消耗者就可以将这个id存入数据库来判断消息是否被消耗过,
接下来在消耗者中检察这个id
https://i-blog.csdnimg.cn/direct/432d10f023624db58f809f14a4418cab.png
将消耗者的方法参数范例修改为Message(而不是之前的String),就可以获取到属性,从而拿到消息id
这种方案不保举利用,业务内里会去判断与业务无关的消息这部分的逻辑,会造成业务侵入,而且也对业务性能有影响
https://i-blog.csdnimg.cn/direct/3be5cd403f0b4c23a50fef8fe690309b.png
第二种方案是在业务本身上增加健壮性,思量到这种消息重发的场景,
上图的场景:
比如用户付款后通过MQ通知生意业务服务将订单标志为已支付,生意业务服务然后返回ack给MQ表示处理成功,
此时网络出现故障,MQ没有收到这个ack以为生意业务服务宕机了(接下来,消息会重新入队并发消息给生意业务服务)
此时,用户再点击申请退款(由生意业务服务完成),生意业务服务将订单改状态为退款中,
此时,MQ到生意业务服务的网络规复,之前的MQ中的消息再次发送给生意业务服务,结果是造成订单状态从退款中被覆盖为已支付。
如果思量到业务幂等就可以加上图红圈部分的逻辑,
在举行标志前先判断是否是未支付,可以得出是否是一条重复消息,如果为重复消息则不作标志直接结束
https://i-blog.csdnimg.cn/direct/32700b9c8f374a0e934e2cc8c73f005e.png
在生意业务服务的Listener中标志订单为已支付前加上这段逻辑,实现业务的幂等性
https://i-blog.csdnimg.cn/direct/8e17c9c777d9430a8ece5fd7ad333ee8.png
起首,支付服务和生意业务服务之间的订单状态同等性由MQ异步通知实现的,
然后,多种可靠性保证消息至少被消耗一次,
末了,多次消耗引起的幂等问题,是业务中的幂等判断避免的
服务消息处理失败的兜底方案见下节
p110 MQ高级-10 延迟消息-什么是延迟消息

https://i-blog.csdnimg.cn/direct/f96492d93ff04b828cfbe8156a69338a.png
延迟消息是在指定时间之后消耗者才会收到的消息
https://i-blog.csdnimg.cn/direct/8e01e848dbca4016b8f89e6df6796637.png
比如说,用户下单后扣减了商品库存,
用户是否支付是由支付服务完成的,如果支付了支付服务需要通知生意业务服务修改订单状态为已支付,
但网络故障,支付服务给生意业务服务发送的消息没有收到,
这种环境下,生意业务服务就可以设置一个延迟使命,30分钟后去问一下支付服务是否用户支付了,
这样可以起到一个订单超时未支付主动取消的效果,
具体的做法是,在下单的时刻就往MQ内里发一个30分钟的延迟消息,
时间到了之后生意业务服务就会收到消息,从而去实行延迟使命
p111 MQ高级-11 延迟消息-死信互换机

https://i-blog.csdnimg.cn/direct/7e440e4bef3e4f65b08d1518fdf1f9a4.png
利用死信互换机可以实现延迟消息
https://i-blog.csdnimg.cn/direct/3696bf53e0e14ac59a965219c7ffc776.png
比如说,将normal.queue指定一个死信互换机dlx.direct,再往队列内里发送一条过期时间为30秒的消息,
由于这个队列是没有消耗者监听的,那么30秒后它就会被发送到死信互换机,再投递到绑定的队列,
因此,消耗者去监听这个队列就可以到达延迟消息的效果,
别的,这两个地方的互换机和队列的bindingKey需要设为同等(normal.direct到normal.queue、dlx.direct到dlx.queue)
https://i-blog.csdnimg.cn/direct/2db189c2ab934a9bac8353506f5b1d4e.png
在消耗者中定义一个死信互换机并绑定队列
https://i-blog.csdnimg.cn/direct/f9c40dab37424b5aabf242e2c67f883a.png
在消耗者中定义一个normal互换机和队列并绑定它们,并指定队列的死信互换机,
这里创建互换机和队列用的是传统Bean的方式,而不是上面的@RabbitListener注解的方式,由于这个队列没有消耗者
https://i-blog.csdnimg.cn/direct/55a16ce119244d5dacf7f683c5c5d193.png
启动消耗者后,进入MQ控制台可以看到互换机和队列都创建成功了,在队列中可以看到DLX标志,表示它指定了一个死信互换机
https://i-blog.csdnimg.cn/direct/43da905e254143de9cd559428d411d49.png
发送者发送一条消息,设置消息过期时间为10秒,
message是MessagePostProcessor是消息的后处理器,可以获取消息属性,来设置消息的过期时间
https://i-blog.csdnimg.cn/direct/8f8d3ac637d640a0b816754b01d8c928.png
在消耗者中可以看到10秒后收到了这条消息
p112 MQ高级-12 延迟消息-延迟消息插件

https://i-blog.csdnimg.cn/direct/878ecbee7e704e899dffbf893b0c8ed5.png
上一节的延迟消息是用死信互换机来实现的,这种方式配置比力复杂,可以用延迟消息插件来将互换机加上延迟功能
https://i-blog.csdnimg.cn/direct/6fc129976d544d70b6d8137442409814.png
消息到达互换机后不会立即举行路由,而是等候一段时间再路由到队列
插件可以在RabbitMQ社区下载也可以在GitHub下载,插件的版本要与MQ的版本同等
https://i-blog.csdnimg.cn/direct/51c69bd6a130454c96b31ced08a98449.png
将插件复制到mq容器的/plugins目次下
https://i-blog.csdnimg.cn/direct/2786e9b338b44a2b84e2a4c46f266603.png
然后先用下令docker exec -it mq进入容器,再用rabbitmq的插件下令启用这个插件,可以看到插件已启用
https://i-blog.csdnimg.cn/direct/2abb030e70d84b12a95103a1896dc3d8.png
在代码中声明队列为延迟的队列的2种方式(注解方式和Bean方式),加上delayed表示这是一个延迟消息
https://i-blog.csdnimg.cn/direct/87ec2d8c461b472aaaf654e4b74653af.png
在发送消息时需要设置消息的延迟时间,这里与上一节相同(都是通过MessagePostProcessor消息后处理器来完成),
差别的是,这里是setDelay(上一节是setExpiration)
https://i-blog.csdnimg.cn/direct/21b90e68f84648648c29ce4db2a67d0e.png
在消耗者中定义互换机和队列,并给互换机加上延迟属性
https://i-blog.csdnimg.cn/direct/ce96fd24007b4ef6beae7af911008c8d.png
启动消耗者,然后在控制台可以看到这个互换机的范例为延迟消息的互换机
https://i-blog.csdnimg.cn/direct/9f72e7e5d5b24b1ebf6fe1b27c744c27.png
启动发送者,发送一条延迟消息,时间设置为10秒
https://i-blog.csdnimg.cn/direct/d730f6932d1345499173b67c284582eb.png
10秒后,消耗者监听到了消息
这种延迟消息的实现是由cpu来完成计时的,是cpu密集型的使命,
如果有大量的消息需要计时,会给cpu带来很大的压力,
因此,只管不要设置过长的延迟时间,否则会造成很多延迟消息需要计时,影响性能
p113 MQ高级-13 延迟消息-取消超时订单

https://i-blog.csdnimg.cn/direct/df43a272a9f14e6eab4e65f90f652f3b.png
在黑马商城中用延时消息解决用户未支付超时订单的问题
https://i-blog.csdnimg.cn/direct/4607d93ceef844b0b125a0a949be360d.png
这里照旧之前谁人例子,假设支付服务向MQ发送消息的过程出现问题,支付服务和生意业务服务的同等性就会有问题,
那么无论支付服务是否可以或许成功通知生意业务服务,生意业务服务都应该有一个兜底方案(没有支付成功就取消订单规复库存),
https://i-blog.csdnimg.cn/direct/af0635b002e24023950feb38b163dd5f.png
在下单逻辑结束前发送一个15分钟的延迟消息到队列,在15分钟后生意业务服务本身收到这条消息,然后去做背面的业务,
然后查询订单是否支付,如果已为支付就不作操作,
如果为未支付,有可能是支付服务的支付成功的消息还没有发到生意业务服务的环境,那么就去查支付服务的生意业务流水,
如果有支付的流水就改为已支付,没有就不作操作
https://i-blog.csdnimg.cn/direct/b98d3f695b80480a8ee56f4fdd38fea6.png
由于生意业务服务要通过OpenFeign向支付服务发送请求,先定义好FeignClient需要的类
https://i-blog.csdnimg.cn/direct/fc9b8ca1dbbb4c3195812bd07f205481.png
在订单创建业务的末了发送一条延迟消息到MQ,消息内容为订单id,延迟时间设为10秒
https://i-blog.csdnimg.cn/direct/17a085f5018d41289244117e64044c71.png
在生意业务服务的中定义一个消耗者去监听这条延迟消息,收到消息后去做延迟的业务逻辑
接下来举行测试
https://i-blog.csdnimg.cn/direct/df5bb538b91a42309afd771bdb212c6a.png
起首将支付服务支付成功后发送MQ给生意业务服务的代码注释掉(用于通知生意业务服务修改订单为已支付),
为了模拟支付服务发送消息给MQ的故障环境
https://i-blog.csdnimg.cn/direct/dbb5c83afec5402baa8911175cecade0.png
在商城内里下单并支付,显示支付成功
https://i-blog.csdnimg.cn/direct/ba5fd61fb95f4af9804dd81e15491b6c.png
在生意业务服务的订单表内里可以看到这个订单的状态为2(已支付),支付时间是订单创建时间的10秒后,说明10秒后更新订单状态为已支付
https://i-blog.csdnimg.cn/direct/46f64077964d4eaca1331d02b41af7ca.png
在生意业务服务的日记中看到在10秒后,生意业务服务用PayClient向支付服务发了一个查询,发现订单已经支付了,就更新订单为已支付,
因此,实现了一种延迟查询的效果,作为生意业务服务订单业务的兜底方案

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 黑马商城项目—最新SpringCloud开辟实战—功能实现具体学习笔记(RabbitMQ