@boothsun
2018-04-24T23:54:20.000000Z
字数 1989
阅读 1281
面试题
参考文章:消息队列使用的四种场景介绍
非重要业务场景异步处理,提高接口响应速度。一个订单流程是非常长的,下单过程中需要各种校验、扣减商品库存、扣减服务者排班等,此时类似于下单短信或者微信模板消息等推送,就可以异步处理,将要发的短信内容和接收人信息等以MQ形式发出去,然后接收到短信后,再给用户发送。
允许非强一致性出现,主要保证最终一致性即可。
一对多:
订单完成时,可能积分系统需要给用户发积分,用户画像系统可能会给用户打上近期有完成单标签,优惠券系统可能需要给用户发券诱导再次下单等。此时对订单系统来说,将会有多个下游。此时订单系统就可以不关注下游信息,而将必要的订单信息通过MQ形式通知出去,相应的业务系统自己接受信息即可。
多对一:
用户画像系统需要实时记录用户定位城市,作为一种用户标签,服务于精准用户营销。此时,对于用户画像系统,是多端上游,上游比如有小程序、微信公众号、微信钱包、集团APP定位、业务线APP定位、外接纯H5定位等。而且对于这些多端来说,同步用户定位城市并非是它们的主流程,此时就可以由用户画像系统定义统一数据接收格式,多端按照此格式在定位成功后通知用户画像系统。
日志处理是指将消息队列用在日志处理中,比如kafka的应用,解决大量日志传输的问题。架构图如下:
此类主要是针对于延迟消息应用场景。在业务上遇到的场景是:支付成功后,需要回调业务线告知订单支付成功,业务线需要完成自己的订单以及按照自己的各种策略给商家结算,但是由于业务线处理流程非常长或者其他原因,时有回调失败的情况,且业务上不允许出现回调失败的情况,因为回调失败会影响到商家结算、商家账户收入等。但是回调失败的场景并不多见,平均一个月两三次。为了解决这个问题,就可以使用延迟消息队列,当回调失败时,先计算回调次数和回调延迟时间(这个延迟时间可以根据回调次数增大而增大),指定时间后接收到延迟消息再次给业务线尝试通知支付成功重试。 好处:不用定时任务扫表,不用记录错误重试记录表
适用场景:
针对于只关注最终结果的用户场景。
业务场景:
营销部门需要接收用户打开APP的每次城市定位信息形成城市定位用户标签,此时对于营销部门只关心用户最后的城市定位消息。
解决思路:
强制发送方在消息体内加入一个时间戳,接收方接收到信息 处理成功后会落库。此时一条消息到达后,先验证是否有同一个用户但是时间戳更大的消息被消费成功了,如果有,则说明先发的消息延迟到达了,此时就可直接忽略时间戳更小的消息,因为我们只需要关注最新的消息即可。
以下单整个流程为例,下单消息、支付消息、退款消息是要求顺序到达的,不能退款消息在支付消息之前到达,此时业务无法处理。
还是以下单流程为例,支付消息是可能会在下单消息之前到达,也就是消息间是耦合的,顺序是不能被打断。但是对于异步消息队列来说,我们无法保证顺序。
所以,我们可以在发送一条信息时带上全部前置消息的必要信息,比如退款消息,消息体中就可以带上必要的订单信息和支付信息;如果觉得这样消息体很大时,也可以只带上相应主键,比如订单id、支付记录Id等,然后反查补全消息消息时必须的信息。
业务去重 幂等
比如订单支付消息,一个订单正常业务场景下,只能支付一次,同样也只能接收到一条支付消息。所以,如果实际确实收到了两条消息,对于第二条消息可以抛弃或者打Error日志。
人为全局唯一编号:
可以由发送方在消息体内加上消息的一个全局唯一编号,接收方在接收到信息后,先使用分布式锁,以这个全局唯一编号作为key去加锁,加锁成功后,再验证是否有这条消息的成功消费记录,如果有则代表消息已被消费,直接ACK消息。如果没有则进行消息消费,消费成功后消息落库,释放锁。
https://www.w3cschool.cn/architectroad/architectroad-message-queue.html