如果你有看过任何一本消息队列的书籍,都会介绍到MQ的应用场景。一般来说,大体可以分为以下几类:异步处理,应用解耦,流量削峰,日志处理,远程调用,消息通信。
异步处理
帅旋在小程序上面点餐,下完单之后,给用户赠送积分,发送下单成功通知,按照串行的写法,是这样的:
可是发送通知是调用的第三方接口,这个时候第三方接口掉链子了,花费了100多毫秒时间,那么这个帅旋要等多100毫秒才能收到下单完成的响应了,等多了这么长时间,肚子都饿扁了。
为了避免饿肚子,那我们引入消息队列,异步去发送通知和赠送积分吧:
这样,不需要等到赠送积分和发送通知,帅旋立马就可以拿到下单结果了。而一般消息投递到消息中间件只需要几毫米的时间。
应用解耦
还是以上面点餐为例,下单是在订单服务完成的,赠送积分是在运营服务完成的,通知是在通知服务完成的。在没有引入消息队列前,在订单系统下完单后,需要通过接口调用去触发另外两个业务:
这样,订单服务就和运营服务、通知服务耦合在一起了,带来了以下问题:
- 如果要接入的下游系统越来越多,或者下游系统有调整,都有可能导致订单服务要做打量的改动。
聪明的小伙伴会说这种场景很适合用策略模式去实现,不同的下游系统封装到不同的策略实现类中,但似乎这并没有解决上面的问题,该修改的时候还是要修改。
这个时候,我们引入消息,队列,就可以对系统进行解耦了:
- 订单服务下单后,把消息入队消息队列,就返回成功了;
- 运营服务和通知服务订阅下单消息,当获取到下单消息之后,就进行各自的业务操作。
流量削峰
这是秒杀系统最常使用的一种场景。
一般秒杀场景中,在秒杀开始的时候会有大量流量涌入,更甚者有人写外挂抢购商品,为了避免这种大流量涌入都请求到秒杀系统,导致系统响应不过来最终崩溃,可以先把请求放入消息队列,秒杀业务再慢慢的从消息队列中获取消息进行处理,流程如下:
具体地,秒杀业务按照自己的处理能力,获取固定的消息数量到本地消费这样就避免秒杀业务过载了。如果想进一步的控制消费端的消费速度,可以在消费端里面通过Sentinel之类的限流工具限制每秒的消息处理数量。
那么问题来了,消费这么慢,消息不会出现积压吗?其实秒杀系统流量大的就是秒杀开启那一瞬间,把这些流量存入消息队列,很好的起到了一个流量缓冲,削峰的作用。如果消息队列真的过长,可以直接丢弃请求,响应秒杀失败之类的文案。
另外,秒杀系统使用令牌桶也是一种流量削峰的一种方式。
日志处理
在微服务架构中,产生日志的服务众多,就需要使用ELK这样的工具去汇总分析日志。使用ELK的时候,就可以使用消息队列去收集日志:
- 每个微服务的日志数据发送到Kafka;
- Logstash从Kafka中订阅主题,获取日志数据,对日志数据进行过滤、解析、转换、最终把处理后的数据发送到Elasticsearch;
- 通过Elasticsearch的查询DSL,就可以轻松的检索和分析日志了,如果这个用的不爽,那么可以直接到Kibana上面去做可视化的搜索分析。
远程调用
使用MQ来模拟实现远程调用也是可以的,具体的做法如下:
- 客户端发送请求:客户端服务将请求消息发送到MQ的请求队列中。每个请求消息应包含足够的信息,以便服务端识别请求类型并执行相应的操作。此外,请求通常会包含一个回调队列的名称或标识符,服务端将在这个队列中发布响应消息。
- 服务端处理请求:服务端服务监听请求队列。一旦接收到消息,它将解析消息内容,执行必要的操作,然后准备一个响应消息。这个响应应包括执行结果,如操作成功的确认、返回的数据或错误信息。处理完请求后,服务端将响应消息发送到客户端指定的回调队列。为了让客户端能将响应与原始请求关联起来,响应消息应包含一个能够唯一标识请求的ID或相似的关联数据。
- 客户端接收响应信息:客户端监听回调队列以接收来自服务端的响应。一旦接收到响应,客户端将处理结果,这可能包括更新用户界面、处理返回的数据或处理任何错误。
消息通信
消息系统的发布订阅机制,很是和用于实现点对点的聊天,或者是广播式的群聊。
点对点聊天:在点对点聊天中,每个用户都可以作为消息的发送者和接收者。你可以为每个用户创建一个唯一的队列来接收消息,这样,当一个用户想要发送消息给另一个用户时,他只需要将消息发送到对方的队列中;
群聊:消息被发送到一个Topic,订阅了该Topic的所有消费者都能接收到消息,这样就实现了群聊的功能。