1. 到底什么时候该使用MQ?
1). 典型场景一:数据驱动的任务依赖
采用MQ的优点是:
a. 不需要预留buffer,上游任务执行完,下游任务总会在第一时间被执行
b. 依赖多个任务,被多个任务依赖都很好处理,只需要订阅相关消息即可
c. 有任务执行时间变化,下游任务都不需要调整执行时间
需要特别说明的是,MQ只用来传递上游任务执行完成的消息,并不用于传递真正的输入输出数据。
2). 典型场景二:上游不关心执行结果
采用MQ的优点是:
a. 上游执行时间短
b. 上下游逻辑+物理解耦,除了与MQ有物理连接,模块之间都不相互依赖
c. 新增一个下游消息关注方,上游不需要修改任何代码
3). 典型场景三:上游关注执行结果,但执行时间很长
有时候上游需要关注执行结果,但执行结果时间很长(典型的是调用离线处理,或者跨公网调用),也经常使用回调网关+MQ来解耦。
举个栗子,微信支付,跨公网调用微信的接口,执行时间会比较长,但调用方又非常关注执行结果,此时一般怎么玩呢
一般采用“回调网关+MQ”方案来解耦:
a. 调用方直接跨公网调用微信接口
b. 微信返回调用成功,此时并不代表返回成功
c. 微信执行完成后,回调统一网关
d. 网关将返回结果通知MQ
e. 请求方收到结果通知
这里需要注意的是,不应该由回调网关来调用上游来通知结果,如果是这样的话,每次新增调用方,回调网关都需要修改代码,仍然会反向依赖,使用回调网关+MQ的方案,新增任何对微信支付的调用,都不需要修改代码啦。
2. 消息总线能否实现消息必达?
消息总线为了尽量保证消息必达,架构设计方向为:
a. 消息收到先落地
b.消息超时、重传、确认保证消息必达
3. 消息总线真的能保证幂等?
1). 上半场的幂等性设计: 重发是MQ-client发起的,消息的处理是MQ-server,为了避免步骤2落地重复的消息,对每条消息,MQ系统内部必须生成一个inner-msg-id,作为去重和幂等的依据,
这个内部消息ID的特性是:
a. 全局唯一
b.MQ生成,具备业务无关性,对消息发送方和消息接收方屏蔽
有了这个inner-msg-id,就能保证上半场重发,也只有1条消息落到MQ-server的DB中,实现上半场幂等。
2). 下半场的幂等性设计
此时重发是MQ-server发起的,消息的处理是消息消费业务方,消息重发势必导致业务方重复消费(上例中的一次付款,重复发卡),为了保证业务幂等性,业务消息体中,必须有一个biz-id,作为去重和幂等的依据,这个业务ID的特性是:
a. 对于同一个业务场景,全局唯一
b.由业务消息发送方生成,业务相关,对MQ透明
c. 由业务消息消费方负责判重,以保证幂等
最常见的业务ID有:支付ID,订单ID,帖子ID等。
具体到支付购卡场景,发送方必须将支付ID放到消息体中,消费方必须对同一个支付ID进行判重,保证购卡的幂等。
有了这个业务ID,才能够保证下半场消息消费业务方即使收到重复消息,也只有1条消息被消费,保证了幂等。
4. 1分钟实现“延迟消息”功能
高效延时消息,包含两个重要的数据结构:
a. 环形队列,例如可以创建一个包含3600个slot的环形队列(本质是个数组)
b. 任务集合,环上每一个slot是一个Set<Task>
5. 58到家MQ如何快速实现流量削峰填谷
1). MQ-client提供拉模式,定时或者批量拉取,可以起到削平流量,下游自我保护的作用(MQ需要做的)
2). 要想提升整体吞吐量,需要下游优化,例如批量处理等方式(消息接收方需要做的)
如果上游发送流量过大,MQ提供拉模式确实可以起到下游自我保护的作用,会不会导致消息在MQ中堆积?
答:下游MQ-client拉取消息,消息接收方能够批量获取消息,需要下游消息接收方进行优化,方能够提升整体吞吐量,例如:批量写。