设计模式-异步调用(中介者+观察者+备忘录)库存中心
00 分钟
2022-4-26
2023-4-26
type
status
date
slug
summary
tags
category
icon
password
URL
  1. 订单中心对库存中心的库存操作调用,以及对调度中心的调度发货的调用,都通过内存队列做成异步的方式,来让订单中心跟库存中心以及调度中心来解耦,异步可以让订单中心的操作非常的快速。
    1. 中介者模式的本质,就是解耦。将一个组件对另外一个组件的调用解耦,不要让一个组件直接调用另外一个组件,而是让一个组件调动中介者,然后中介者去调用另外一个组件
      但是实际使用场景中,几乎我是从来没有严格按照中介者模式的代码去写,异步解耦,我们一个组件不要直接调用另外一个组件,而是将消息写入一个队列,然后另外一个组件去队列里面消费信息然后自行处理
      队列,又有两种大的场景:jvm内存队列;分布式队列(RabbitMQ、RocketMQ、Kafka)
      系统内部一般使用jvm队列;一个系统跟另外一个系统使用分布式队列
  1. 观察者模式,订单中心执行了异步的操作之后,他要去对其他的中心注册一个观察者,等到其他中心完成操作之后,将结果通知给订单中心
    1. 观察者模式非常经典在分布式系统里面的一个应用,就是做分布式协调,异步调用之后,系统A发送一个消息到了MQ里去,系统B从MQ里消费了数据来处理,系统A想要了解系统B是否成功处理完了这个数据,该怎么办?
      系统B处理完值后会过来去通知系统A,如果系统A专门为这个事开了个接口,开个接口,很麻烦,系统A发送完了异步消息之后,直接监听一个东西,系统B处理完之后,就出发一下系统A的监听器,通知系统A处理的结果
      如果是纯jvm内存里面的队列来结合,那就是用jdk监听器api来实现观察者模式即可;如果是跟外部的分布式队列来结合,那肯定是用zookeeper了
      用的是jvm内存队列,所以说我们这个管擦着模式的提现,就是用jdk观察者api来做就可以了
  1. 备忘录模式,一旦订单那中心发现说内存队列满了,写不进去了,那么此时就需要通过备忘录将数据离线存储到磁盘上去。等后面内存队列恢复了,就可以通过备忘录将数据给恢复回来
    1. 在用MQ的时候,备忘录模式,是一个非常经典的使用场景,为什么呢?你如果是写内存队列,那肯定是要用阻塞队列的,因为避免说你的数据量多大,把非阻塞的队列可能会写爆jvm oom;
      写分布式队列,rabbitmq如果挂了怎么办?一旦挂掉,公司业务瘫痪
      写内存队列的时候,如果内存队列满了,阻塞了,为了避免整个系统被内存队列卡住,此时你需要将数据暂存到比如磁盘上去,事后内存队列不再阻塞之后,再将数据从磁盘上读取出来再往队列里面去写;如果是写分布式队列,在队列挂掉之后,需要将数据离线储存起来,事后当分布式队列恢复之后,再次从离线存储中读取数据写入队列
      每次放队列里面写数据的时候先判断一下,如果队列的大小已经满了,就不要往里面去写了
      此时消息给写入一个MySQL的表中,MySQL的表是需要有一个字段保持顺序的,其实按照自增id就可以
      然后需要更新内存中的状态标识位,表明说现在已经触发了离线储存
      然后之后每次消息过来,都会在讲消息写入内存队列之前,先判断一下内存中的状态标志位,看看是否触发了离线存储,如果触发了离线存储,需要看一下,内存队列当前是否还阻塞,如果已经已不阻塞了
      此时一单触发了离线存储,之后所有的消息都会直接写入MySQL,此时就相当于是通过一个备忘录组件,往备忘录里去存储数据,备忘录地城是基于MySQL来实现的
      但是一旦某次消息发现说内存队列已经不阻塞了,没有积压了,此时就会启动一个后台线程,由那个后台线程去批量的从MySQL中查询数据
      那么可以将MySQL中的数据,按照顺序一批一批的查询出来,查询出来一批,就往内存队列里面去写入,写入成功之后,就将MySQL中的数据给批量的删除掉
      然后循环往复,循环执行上面的操作,直到这个后台线程将MySQL中的数据全部写入了内存队里额,都ok了,MySQL里一条数据都没有了
      此时就可以由后台线程更新内存里的标志位,说不需要再触发离线存储了
      在之后过来的请求,就不会写入MySQL了,而是正常写入内存队列中

评论