记一次分布式事务问题的解决实践
问题背景
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
方案选择
方案实现复杂
效率会大幅下降
1) 客户将请求发送到A系统
2) A系统处理逻辑,并落库且提交数据库事务,将订单标注为处理中
3) A系统返回处理请求给界面程序,同时将请求发送到MQ
4) B系统从MQ上消费消息,并处理逻辑和完成写库操作
5) 处理完成之后,发送处理结果回MQ
6) A系统将MQ上的B系统的处理结果消费掉,更新一开始的订单的状态
1) C系统每隔一定时间(5秒钟)扫描过去一段时间(3分钟)内的订单,检查A系统中是否有未知和失败的订单,发起重试(不经过MQ,以RPC的形式直接调用)
A和C系统可能对未知订单同时发起状态更新,需要加锁
B系统通过对jetty线程的控制做限流处理,将无法完成的请求缓存在jetty队列,如果队列已经满了就直接返回:HTTP-Code=429,too many request的返回。这样子可以防止B系统被流量压垮
浏览器同步等待n秒(5秒),同时轮询订单结果。如果n秒内订单有明确结果,就同步呈现给客户;如果是n秒订单还是状态未知,就异步返回,同时页面显示“订单正在处理中,请稍后”
系统使用的是ActiveMQ。数据使用DB持久化,消息事务开启的情况下,生产者最大的QPS大概是1万多一点,消费者的QPS大概是生产者的1/20。MQ与DB、MQ与应用之间的网络带宽影响很大。满载的时候,CPU的负载大概是80%左右,消息体大小对ActiveMQ的影响不大…(具体的机器性能没有记录下来…-_-||)
通过MQ系统解耦,对订单流量进行削峰平谷
只有明确的业务错误才不会发起重试,对例如网络抖动,锁竞争发生的错误,C系统可以通过重试下单成功
增加了系统的复杂度
客户可能看到“订单正在处理中”的情况,无法及时获得订单信息