当前位置: 首页 > 科技观察

java中的awesome消息队列有什么用?

时间:2023-03-12 11:53:12 科技观察

最近小倩会听到很多同学说,面试大型互联网公司的时候,很可能会被问到消息队列的问题:消息中间件在什么场景下使用?为什么要将消息引入系统?中间件?如何做到幂等?链式调用是我们写程序的一般流程。为了完成一个整体的功能,会拆分成多个功能(或子模块)。比如模块A调用模块B,模块B调用模块C,模块C调用模块D。但是在大型分布式应用中,系统间的RPC交互复杂,调用上百个接口也不是没有可能一个功能的背后。这种架构有以下缺点:1.这些接口之间的耦合严重。下游功能必须修改上面的相关接口;例如:系统A要向系统B和系统C发送数据,发送到每个系统的数据可能不一样,所以系统A将向每个系统发送的数据将每个系统的数据组装起来,一个一个发送;代码上线后,增加了一个新的需求:把数据也发给D。这时候就需要修改A系统,让他感知到D的存在,同时把数据处理给D。在这个过程中,你会看到每连接一个下游系统,代码系统A必须修改,联合开发调试效率很低。其整体结构如下图所示:2.面对大流量并发,很容易不堪重负。每个接口模块的吞吐能力是有限的。如果上限容量是大坝,当大流量(洪水)来临时很容易被冲走。3.存在性能问题。RPC接口基本是同步调用,整体服务性能遵循“桶理论”,即链路中最慢的接口。比如A在50ms调用了B/C/D,但是此时B又调用了B1,耗时2000ms,直接拖累了整个服务性能。针对上述问题,在系统设计时可以明确要达到的目标:实现系统解耦,在接入新模块时,尽量减少代码改动;设置流量缓冲池可以让后端系统根据自己的吞吐量进行消费,不会被压垮;强弱依赖梳理,非关键调用环节操作异步,提高整体系统的吞吐量。比如上图中的A、B、C、D是用户发起支付,然后返回支付成功提示的几个关键流程,B1是支付完成后通知商家发货的模块被通知,那么本质上用户对B1的完成时间有比较大的容忍度(比如几秒后),可以异步。在目前的系统视野中,MQ消息队列是比较常用的,可以成为解决这些问题的完美工具。下图是使用MQ的简单架构图。可以看到MQ在前端存储流量,下游系统ABC只和MQ打交道,通过预定义的消息格式进行解析。MQ引入后的系统架构和交互方式与原来的链式调用架构有很大不同。虽然上面提到的问题都可以解决,但是还是要充分了解它的原理和特点,避免它的副作用。下面介绍如何使用消息队列。以保证“消息的可靠传递”为出发点,我们来看看MQ的实现。1、客户端如何可靠的将消息传递给MQ1。客户端将消息发送给MQ2。消息持久化后,MQ向客户端发送Ack消息,之后会重传消息;3、Client收到Ack报文后,认为报文投递成功。2、MQ如何可靠地将消息传递给Client1。MQ向Client推送消息(或者Client拉取消息)2.Client获取消息,完成业务逻辑3.Client向MQ发送Ack消息,通知MQ删除消息。有可能因为网络问题导致Ack失败,那么Client会重复消息,导致幂等消费的问题;4、MQ删除消费的消息