• 自动还款业务事故案例,与金融场景幂等性思考


    一、自动还款业务 事故 案例

    事故名称:

    自动还款业务事故

    事故描述:

    事故发生时间:201x-0x-18 0x:15:00
    事故响应时间:201x-0x-20 0x:18:00
    事故解决时间:201x-0x-20 0x:28:00

    事故现象:

    自动扣款,出现扣款重复,同一用户在当天扣款多次.

    事故造成影响:

    重复给n个用户扣款,重复扣款的多支付金额部分已退款给用户。

    事故发生原因:

    1.自动还款的防重有问题,当出现并发进行消费MQ时,通过读库的防重是不起作用的。

    事故解决过程描述:

    1、0x:15左右:收到运营人员的反馈,自动扣款有几笔在x.18号进行重复扣款.
    2、0x:18左右:进行线上排查,在数据库里发现同一笔用户在当天有多笔的扣款数据信息,并且时间上都是同一时间内。
    3、0x:20左右:调取线上的相关日志,分析 MQ在同一秒内推送了3~5条一样的消息进来,走查代码发现防重是通过uuid来查询数据库,如果查询没有数据信息,则insert一条新数据。
    4、0x:25左右:排查线上数据库对uuid的唯一性约束,发现线上没有做uuid的唯一性约束.
    5、0x:28左右 : 提工单将uuid做成唯一性约束.
    6、201x-0x-21 8:00 左右,验证线上数据,没有重复扣款的记录信息,扣款正常。

    事故总结教训:

    1、 强化对于防重技术的实现,防重通过读是解决不了的(并发情况也需要考虑),通过写防重是更好的解决办法
    2、 针对于数据库表字段的唯一性的字段的处理,检查是否增加唯一性的约束条件。
    3、 消费MQ消息必做防重处理。
    4、加强业务逻辑上的监控,针对于同一用户在当天执行多次扣款进行监控告警处理。

    二、金融场景幂等性思考

      重复出款特指代付或者转账场景下,服务消费者A重复向服务提供者B发起的重复交易,导致资金损失;后续特指各类重复金融性交易导致的资金损失。出错的原因如下:
    1、程序逻辑错误:

    1)状态控制出错:由于程序、网络和系统异常等原因,A未得到B答复,A发起了新交易。2)未做幂等性设计:由于A未收到B明确响应,A发起重试交易,B未做幂等性处理,重复交易。

    2、跨会计日场景

    1)由于A发起交易为T日,而B处理交易为T+1日,所以A未收到T日的结果,可能再次发起交易。
    2)有些系统没有会计日,是按照机器时间为准,A和B的交易时间不一致,导致重复出款

    3、多任务并发:通常是指定时任务中,同一个定时任务并发处理的资源导致;
    4、提交并发:也就是防重复提交指引提到的;
    5、服务器异常:由于服务异常崩溃,消息或者缓存信息丢失,等服务器重启后,可能导致;

    设计原则:

    1. 先扣款,再生成处理订单,宁可长款也不能短款,宽进严出。
    2. 数据校验:设置校验规则,同一时间段,同一客户,相同金额的交易发起记录;如果是客户发起,提示客户确认;如系统发起(例如代付),建议转人工处理。
    3. 状态控制:交易状态为,成功、失败、未知(或处理中),对于未知状态,不能再重复自动发起。
    4. 时间控制:对于未实现24小时服务的应用,尽可能避免在23点30后做出款处理。
    5. 提交并发控制:审核提交等做防重复提交控制。
    6. 定时并发控制:禁止提交同一个文件给多个定时任务。
    7. 对账及差错处理:要对交易进行对账,并对差错交易进行差错处理

    相关阅读:
    支付系统的防重设计 (qq.com)

    三、服务间超时处理

    在一个很普遍的场景中,涉及到双端通信的情况下,不论是传统的单机服务,还是现在的微服务,甚至事异步通信技术(进程内,进程与进程),一直都存在着三态的问题,即成功,失败,超时。

    如下图两个服务间:
    在这里插入图片描述
    成功失败具有明确的业务语义和边界,正常处理即可。最复杂的就是超时,因为网络通信原因,双端都不总是确定,到底哪个环节超时。

    3.1 同步调用超时

    在这里插入图片描述
    超时点:

    1. -请求超时;
    2. -服务端内部处理超时:比如操作耗时的资源,调用第三方系统等造成客户端请求整体超时而主动断开连接;
    3. -服务端处理正常,但响应结果阶段超时;

    3.1.1 处理

    客户端:
    无论那个阶段,客户端都不确定请求是否被应答,即服务端处理的结果,客户端不知道是否成
    功。客户端此时能做的,有两种方法:

    1、 -重试,客户端需要主动做好重试方案,比如类似mq的重试队列(1s 5s 10s 30s 1m 2m 3m 4m 5m6m 7m 8m 9m 10m 20m 30m 1h 2h),主要的技术,spring-retry框组件,将请求扔到自产自销的mq,依靠mq的重试队列主动重试,或者建立定时任务表重试;

    2、-主动查询结果:超时后客户端主动查询,查询的时机类似重试机制,因为快速的查询,并不总是有效,当发生网络抖动的时候,很大概率就地查询,也是网络抖动阶段;

    不管哪种方式,需要服务端接口具备幂等性。

    服务端:
    服务端不存在请求超时和响应超时,但存在自身超时的情况,解决方案:

    1. 自身rt值需要优化,比如慢sql等;
    2. 以来三方接口的时候,跟第三方接口又形成了一个客户端-服务端模式,根据具体场景或者快速失败,或者做好容错措施,必要的时候,还会有比如金融领域的冲正操作;

    3.2 异步调用超时

    异步调用,类似ajax,客户端同步请求,服务端异步响应
    在这里插入图片描述
    超时点:

    1. 请求超时;
    2. 服务端内部处理超时:比如操作耗时的资源,调用第三方系统等造成客户端请求整体超时而主动断开连接;
    3. 服务端处理正常,但响应结果阶段超时;
    4. 异步响应超时;

    客户端:
    参考同步-客户端

    服务端:
    服务端不存在请求超时和同步响应超时,对于内部处理超时,同同步情况一样。那么就只剩下异步响应超时了。
    比较有代表性的就是支付结果通知,可参考: 支付结果通知文档

    存在此问题就是服务端通知客户端的时候(客户端需要同步提供响应服务端结果通知的接口),未接受
    到客户端的响应。

    MQ超时:
    在这里插入图片描述
    在此处讨论的超时,其实相当于另外一个话题,如何保证mq不丢消息,无论是kafka和RocketMQ,都支持ack的机制,用以确认消息的发送和接受的成功.

  • 相关阅读:
    iPhone设备中查看应用程序崩溃日志的最佳实践与经验分享
    ASP.NET按钮OnClick事件无法用JS触发
    nc反弹以及中 &>、0>&1是什么意思
    netty自定义channel id
    Spring Batch输出文本数据 XML数据 JSON数据 数据库
    Redis持久化(RDB AOF)
    链路状态路由协议OSPF的LSA头部讲解
    CMU 10-414/714: Deep Learning Systems --hw1
    嵌入式学习笔记(30)S5PV210的中断体系介绍
    C# WPF入门学习主线篇(二十三)—— 控件模板(ControlTemplate)和数据模板(DataTemplate)
  • 原文地址:https://blog.csdn.net/moneywenxue/article/details/134172912