背景
在了解背景之前,我们先来了解"同步调用"和"异步调用"之间的区别吧
同步调用
同步调用就像我们同步通讯---打视频通话 一样,我们可以实时的获取对方的信息,对方也可以实时知道我们在干什么,双方对于信息的获取都是实时的
如果你在和某一个人打电话的额同时,其他电话打进来,你无法处理其他电话
回想我们之前微服务学习的OpenFeign远程调用,它就是经典的同步调用,我们的一条调用链中,同一条链路中需要拿到上一个被调用服务的信息下一次调用才能开始,正因为这种"实时"的特性它同时也会带来一系列的缺点,我们看接下来的介绍
同步调用问题
我们之前学习的微服务通过OpenFeign同步调用 远程调用来分布式的完成业务的需求,但是着同时也会伴随着一些问题
如上图所示,假设我们要完成一个支付服务,我们最核心的业务其实就是上图的1和2:扣减余额和更新支付状态。
如果我们使用同步调用的方式,此时又要给我们的支付服务新增几个新功能,比如说"交易服务"、"通知服务"、"积分服务",那么我们又要使用Feign来一步步远程调用,非常麻烦
同时,如果使用远程调用这种串联的调用方式,性能会很不好,假设每一个服务执行都需要50ms,那么这样一连串调用下来,整体的支付服务就需要300ms,这样子性能就非常差了
刚刚提到了"串联",我们还可以想到如果我们这一串调用链某一个服务出错,那么这整一串调用链就全部不可用了,如果我们使用分布式事务回滚的方式,第一步我们都扣减了余额,后面又回滚回去,体验也很不好
因此对于这些"拓展性""性能"的问题,我们推荐使用"异步调用"的方式
异步调用
不同于打电话的实时性,异步调用强调"异步",就像我们发消息一样,我们同样可以传递信息给对方,但是对方可能正在忙,此时此刻没有看到信息,忙完了打开微信就能看到我们发的信息,同时,我们发信息不需要像打电话一样只能"一对一聊天",发消息完全可以同时给很多人发不同的消息,我们也同时可以接收不同人的不同消息
对比于同步调用,异步调用我们发现发消息的一方和接收消息的一方没有什么很强的关联性**,**发消息的一方只需要把消息发出就好了,并不需要管对方到底看没看,接收消息的一方也不需要一致留意发消息的人,反正只要有时间就能看看消息就好了

回想我们的同步调用,调用链中角色就是"调用者"和"服务提供者",他们之间的"关联性"是非常强的,某一个服务完成了才能调用下一个服务

异步调用的"关联性"就没有特别的强,甚至可以说没有什么关联性,异步调用的角色我们可以看下图介绍
消息发送者(也就是调用的一方),只需要管把消息发到消息代理就好了, 接着消息接收者只需要在它空闲的时候从消息代理里面拿消息然后去执行发送者布置的任务就好了。完全不需要告诉消息发送者业务完成 
我们再回到刚刚出问题的同步调用场景,那么对于这些新增的服务,我们对于他们的调用方式完全可以该成使用消息代理来异步调用
因此我们就解决了之前同步调用所造成的问题,我们的支付服务只需要把这些调用服务的信息发送到消息代理里面即可,不用再和这些异步调用的服务有什么联系,不用管异步调用的服务是否忙碌,也不需要管异步调用的业务结果。异步调用的服务监听消息代理的消息,就选正在忙碌,忙完了就会从消息代理里面拿调用消息然后去执行相关业务,就算异步调用服务执行失败了,他也会继续从消息代理里面拿这个任务的消息,直到任务成功为止。
整一个过程中,异步调用服务完全不需要和发送消息方建立什么联系,异步调用失败了,不会像同步调用一样影响整一个调用链,会自己执行直到完成。

同时,对于并发量大的请求,异步调用也能很好的处理,归咎于消息代理的机制,大量请求打进来对于异步调用,一件件读调用者发的消息执行业务即可
我们上面一直在强调异步调用没有很强的关联性,因此我们设计微服务时,和我们主业务关联性不强的功能(就是少了这个功能其实也不咋受影响,因为对于"支付"我们最重要的就是"扣钱") 比如上图的"积分服务"、"通知服务"、"交易服务",我们就可以用异步调用的方式去调用他们。
但是那些必不可少的重要主要功能,我们就必须要使用同步调用来实现(支付如果不扣钱,或者扣钱了但是显示"未支付"那问题就非常严重了)
RabbitMQ基础
我们上面对于这个新的"异步调用"一直有一个重要的部分在强调,那就是"消息代理",用于存储以及转发消息
这个消息代理也叫broker或者"MQ",我们本次学习就以RabbitMQ为主
基本介绍
下载部署好rabbitMQ后我们来介绍一下,其实在下图所示已经非常清晰了,我们讲几个之前没有提及过的:
我们之前总是说消息发送者要发到MQ(消息代理)里面,那消息代理MQ到底长啥样呢
exchange:交换机,发送者首先把消息发送到交换机中,再由交换机发送到"队列"中
queue:队列,用于存储消息,当交换机把发送者的消息发送到队列时,队列会存储这些消息供消费者一步步监听
virtual-host:虚拟主机,用于数据隔离,由于RabbitMQ的性能非常强大,我们一个项目可能根本用不完你RabbitMQ的性能,因此大多数企业对于部署的一套RabbitMQ会让多个项目去用,多个项目的MQ需要隔离,因此virtualhost虚拟主机就是用于隔离不同项目的MQ的

来到3.8版本的RabbitMQ客户端
在客户端所示的选项卡可以看到我们上文所讲的部分内容,我们同时来简单介绍一下这些选项卡吧

connection:顾名思义就是连接,消息的发送者和接收者和RabbitMQ进行的连接
channel:通道,建立连接后需要通过"通道"进行数据传输
exchange与queue上文已经介绍过,这里不过多赘述
简单实践
交换机与队列简单实践
我们了解完上面的内容后,我们做一个简单的实践:
创建一个交换机,创建两个队列,并用这个交换机给者两个队列发送消息
下面我们一起来试一试吧:
先来创建一个交换机
找到exchange页面中的add exchange,填入交换机的名字即可创建交换机,我这里已经创建好了"exchange01"
创建队列也是同理
创建完后,交换机如果想要给队列发送消息,得和队列建立起"规则"进行绑定
给两个队列绑定完成后我们就可以模拟用交换机发送消息了
发送成功后来到queue队列里面可以查看刚刚发送的消息
数据隔离简单实践
我们前面介绍了虚拟主机用于数据隔离,接下来我们做一个简单实践吧:
创建一个新的用户,并且为该用户创建一个它自己的虚拟主机
首先我们先来到admin界面,创建一个新用户,注意tag输入框那里,用于输入该用户的用户权限,我们现阶段直接输入administrator超级管理员即可

创建完成后我们就可以看到用户列表以及虚拟主机列表,发现我们刚刚创建的用户还没有可用的虚拟主机,而我们一开始创建的用户itcast有默认的虚拟主机,这个虚拟主机就叫"/"
我们现在登录刚刚创建的用户Leaf,去到itcast所管理的虚拟主机"/",我们尝试去得到它队列中的信息,发现失败了
这正是虚拟主机数据隔离的作用,数据都是隔离的互不干扰,也没有权限去看或改别人的数据
接着我们来个刚刚创建的Leaf创建一个属于它自己的虚拟主机
创建成功后我们给该主机创建队列和交换机,并且发送信息
可以看到成功了
