首页 > 其他分享 >小小逻辑判断符的错误使用,资损几万块

小小逻辑判断符的错误使用,资损几万块

时间:2024-04-14 10:44:57浏览次数:28  
标签:小小 几万块 老猫 系统 对账 资损 支付 我们

分享是最有效的学习方式。

博客:https://blog.ktdaddy.com/

故事

这是一个真实事件,三年前老猫负责公司的支付资产业务。为了响应上级号召,加强国央企之间的合作,公司新谈了一个支付对接的渠道(当然这个支付渠道其实很冷门的,也是为了对接而对接,具体哪个渠道也不方便透露),由于原始支付系统的第三方支付可拓展性设计得还不错的,所以老猫对接的也是比较快的,熟悉对方的对接文档之后对着编码就好了,差不多花了三天的时间就完成联调了。一切看似很顺利地上线了。

时隔几天,收到了一个快递包裹,是一袋价值53块钱的“原皮腰果”,当时诧异,翻看了各大消费平台,都没有之前的下单记录,后来和媳妇确认了一下,她也没有下单。“难道是某个崇拜哥的小姑娘送的?不能吧”当时心里美滋滋地yy着。

不过之后的一个客诉问题,引起了老猫的重视,老猫排查下来发现一个很重大的问题,钱款的扣除和实际的订单状态对不上。说白了就是订单完结了,但是账户资产并没有完成扣除。我瞬间明白了之前那个“原皮腰果”是怎么回事儿了,当时在生产测试渠道的时候,在公司内部商城提交了订单,但是并没有付款,然而订单却成功了。

再三确认之后,确实存在这一问题。一瞬间整个人心态崩了,头皮发麻,口干舌燥,心脏“突突突”。怎么办?怎么办?生产还不知道涉及多少单子,没办法,兜不住了,先把这件事情往上抛吧(向上级领导汇报)。

具体原因是什么呢?我们来看一下对接第三方支付的大概时序流程。

时序

我们一般在对接第三方支付渠道的时候会有上面一些基本流程。

1、当我们内部生成待支付单之后会请求外部第三方支付渠道,此时第三方支付渠道内部会生成待支付单。

2、我们第三方支付单创建成功返回之后,一般内部系统会唤起收银台,然后用户确认支付。

3、第三方支付成功返回消息之后,整个支付就算已经完结了。

但是问题就出在了第三方支付渠道还有一个定时异步通知的任务,并且我们也对接了这个接口。这个异步通知的功能主要是会定时告知我们支付系统第三方支付单的状态。而且无论成功与否,都会轮询告知,例如,如果是待支付,对方会告知状态是0,如果已完成支付,对方会告知状态是1。我们拿到支付结果之后就会执行后续的订单完成流程。

收到异步通知之后的代码处理判断如下:

事故代码

    //校验交易状态
    if (!Objects.equals(notifyModel.getTradeStatus(), TradeStatus.SUCCESS.getCode())
            && amtConvertY(notifyModel.getTradeAmt()).compareTo(thirdPartyCharge.getAmount()) != 0) {
        LOGGER.error("交易状态不正确:{}", notifyModel.getOutTradeNo());
        throw new BusinessRuntimeException(Errors.PAY_NOTIFY_IS_FAIL);
    }

正确代码

    //校验交易状态
    if (!Objects.equals(notifyModel.getTradeStatus(), TradeStatus.SUCCESS.getCode())
            || amtConvertY(notifyModel.getTradeAmt()).compareTo(thirdPartyCharge.getAmount()) != 0) {
        LOGGER.error("交易状态不正确:{}", notifyModel.getOutTradeNo());
        throw new BusinessRuntimeException(Errors.PAY_NOTIFY_IS_FAIL);
    }

相信眼尖的小伙伴已经发现了,其实就是“||”和“&”的区别。第一种情况当对方告知状态为0的时候,其实并不会被拦截掉,而是直接走了往后的流程,于是悲剧就发生了。

直接说一下最终的处理,最终其实还是比较幸运的。由于,我们本身已经对接了微信以及支付宝的支付渠道,再加上这个渠道的支付使用的频率还是非常少的,很多用户不太会使用这个渠道进行支付,所以最终盘算下来整个的资损金额差不多是3w左右,另外的是其中有个不幸中的万幸。是因为老猫在这之前做了一套资金追讨系统,该系统可以定位出那些用户“空手套白狼”了。并且能给这些用户生成对应的待支付订单,用户可以通过这些待支付订单最终完成资金的补偿付款,最终完成了资金了追讨。所以事后,完全盘点之后发现一共的资损是1600左右。

最终,也算是有惊无险。但是这次的经历给了老猫上了一课。

下面总结一下我们在做支付账务系统的过程中应该如何进行资金安全相关的设计,最终做到防患于未然。

概览

资金安全设计

针对资金安全的问题,不限于通过技术手段避免资损,其实很多时候我们还需要结合数据核对、监控等措施,做到快速发现资损并且止损。下面我们来一一盘点一下资金安全设计的一些点,希望能给大家一些帮助。

资损风险分析

风险要素

在我们做支付资产系统的时候,我们其实需要好好盘点一下资损风险,这些风险可能来自于各个方面。下面涉及,

资金流:我们实际的产品业务中,尤其是支付资产的时候,其实往往会有很多类型的资产形态,可能是积分,可能是现金,当然还有可能是优惠券等等。看到这些金额的时候,我们需要确保上下游系统的一致性、金额计算的正确性、逆向金额不能大于正向金额等等。

交互:我们需要考虑客户端展示内容是否正确。尤其是小数点展示的精确位上,很容易出现客户端展现信息不全的问题,实际其实为99.99元,但是展示的时候却为99.9或者9.99。

资金规则:资金规则是为资产本身的产品形态规则,举个例子,发放优惠券这个行为,每个人发多少,发的时间点,发放的人数,发放的门槛等等。再比如某个积分资产的限额,其中又涵盖着日限额以及月限额。

异常:存在资损风险很多时候其实由于异常导致的,抛开系统本身异常之外,我们还要考虑网络抖动异常,其他服务异常。如果系统本身的事务处理不好,或者最终一致性没有做好,就很有可能造成资损。

技术风险

系统发生资损么,很大一部分就是系统没有设计好或者是编码过程中的粗心,例如上面老猫的真实案例。那么且抛开粗心这个人为因素,我们盘点一下本身技术风险,这些技术风险场景主要来源于多并发、幂等、分布式事务、上下游服务超时、数据计算精度、接口协议、校验逻辑的不严谨等等。

上面罗列的这些很多都为一致性的问题。我们一个个来看。

1、并发:多线程、同时对数据进行读写处理的时候,就有可能造成一致性的问题,例如用户资产重复支付,积分超发等等,如果在系统层面还用了缓存的话,还有可能存在缓存未刷新,导致数据库和缓存不一致的情况。

2、幂等:在支付资产系统中,接口幂等性是十分必要的,接口的幂等能够很大程度上避免(1)中提到的资产重复支付问题、下单重复问题以及网络重发问题。关于幂等详细设计,其实老猫在以前的文章中也有梳理,大家有兴趣的可以看这里【前任开发在代码里下毒,支付下单居然没加幂等

3、服务超时:系统所依赖的服务执行结果返回慢,造成上下游数据状态不一致,例如核心的支付服务调用底层的资产服务进行扣款,结果由于资产扣款逻辑返回超时,导致两边数据不一致。

4、接口规范:尤其是对接第三方接口的时候,文档上的必填字段和非必填字段如果本身文档就有出入,可能就是致命的。

5、事务:其中包含本地事务以及分布式事务,研发在开发过程中对事务理解不够透彻,使用不严谨,最终导致数据不一致。

6、数据精度:主要在金额四舍五入的场景,最终导致精度丢失。或者上下游系统精度不一致。

防止资损

如果说想要彻底的避免资损,并不是一件容易的事情,系统链路复杂,任何一个环节出现问题都有可能导致最终的资损。我们虽然是技术,但是我们的眼光其实不能够仅仅局限在技术的眼光去看待资损这个事情,除了技术侧尽量规避资损发生之外,其实还有其他方案,例如下图。

步骤

上图准确来说其实是一个防止资损,或者说尽量保证企业损失最小的一系列的手段以及方案。这些步骤,其实从时间上来看是不同的时间线。以下咱们来一一看一下。

1、技术规避:

技术侧我们当然要保证我们自身代码的严谨性。这里主要提及的还是上述所说的一致性的问题。我们在系统开发的过程中要挖掘系统可能出现问题的点,其中可能包含事务的使用、接口需要做好幂等设计,系统和系统交互过程中需要考虑接口的重试机制等等。当然这些都是咱们研发在实际开发的过程中需要注意的点。

2、对账发现:

很多时候,资产支付系统上线出问题,并不是直接的日志异常。这种异常可能还好,容易被发现,因为已经卡流程了。怕就是怕在不知不觉的情况下,看似风平浪静,其实内部数据已经一团乱麻。资损已经产生了,就像老猫上面遇到的这种情况。这种情况的发生其实主要还是由于没有做好相关的对账措施。从而导致了悲剧的发生。其实如果我们能够做到每日对账,可能问题就能及时被发现。

对账方式:我们可以从上层系统一路往下游系统进行对账。例如,我们有这样几个系统,例如,上层电商业务系统,订单系统,支付核心系统,第三方支付系统。那么我们对账的方式就如下。

对账

咱进行对账的过程中,我们一般是系统之间进行两两单据对账,对账维护有两个方面,第一个是总数量,第一个是总金额。如果我们发现所有的系统能够两两账目对齐,那么系统就没有太大问题。

清洗对账

当然很多时候单据数量可能由于业务的原因是不对等的,所以这个时候可能还需要进行一定的数据清洗,然后才能进行对账处理。做得好点的话,可以将对不齐的单子能够自动告警,告警方式可以是短信或者邮件方式,当然也可以支持相关人员能够看到每日的对账看板。

这种对账的方式可以协助我们及时发现系统上的问题。老猫之前对接的那个渠道,其实还没有来得及做对账。因为那时候我也疏忽了,认为当前第三方渠道比较冷门,所以就偷个懒没有做对账。然而最终还是逃不过“墨菲定律”。所以咱们研发在做系统上的事儿的时候还是不要抱有任何的侥幸心理。

3、应急止损:

如果真的到了这一步,其实悲剧已经发生了,这个时候其实是比较考验心态的。因为系统漏洞已经造成了资损,并且资损还在持续。这时候内心就会燥热,像老猫那样口干舌燥,着急得像热锅上的蚂蚁。这个时候如果越想早点修复问题,可能越容易出错。很多时候人在着急得时候往往会病急乱投医。为了快速解决问题,修一下bug就直接上线。这种很容易导致错上加错。

所以当我们意识到问题已经发生了,就要向上汇报了,让上级知道这个事情,然后一起看一下问题的处理。这样的话多个人一起把控修复问题肯定比当事人一个人默默修复问题来得好。所谓“当局者迷旁观者清”是有道理的,这样也至少可以降低二次错误的概率。所以出现问题后,一定不能慌了手脚。唯一要做的就是冷静,然后一步步梳理处理的步骤。

当然如果有条件的话,可以根据当前的业务模式开发一个资金追讨系统来防范未然,当然这个系统真的希望是一辈子都用不上,然而这个系统可能是最后的一道屏障了。

总结

以上就是老猫的一段经历,大家可以当做乐子看个热闹。如果真的对你有所帮助,也希望能够得到你的点赞和收藏。当然,如果你也恰好维护同样的系统,对于这样的系统维护有其他新的认知,也欢迎大家能够在评论区留言。

标签:小小,几万块,老猫,系统,对账,资损,支付,我们
From: https://www.cnblogs.com/kdaddy/p/18133847

相关文章

  • python 小小入门2
    紧跟上章使用FinalShell1)mkdiraaa创建文件夹mkdir-p/aaa/bbb/ccc创建文件夹以及后续2)touch 例如touch1.txt也可touch1.txt2.txt3.txt以及touchfsd.sdad也可以创建如果已经有了touch1.txt再创建一个touch1.txt那么他不会覆盖以及删除原来的文件只......
  • 三载岁月的小小归纳与2024计划
    原本打算每年写一篇年终总结,但是由于22年和23年比较忙,导致这两年的年终总结一直拖延没有写。现在已经到了2024年3月份,再补应该是补不完了。正好发现自己毕业快3年了,于是决定对过去3年做一个简单的总结,也算是平了过去2年没写年终总结的烂账......
  • Python 小小入门分享
    介绍1)linux  开发平台2)mysql 数据库--数据存储和查询的工具3)kettle 数据采集工具4)FineB 数据可视化工具1.大数据属于新处理模式----传统的工具无法处理(太大无法捕捉等)解决1)海量数据存储 2)海量数据运算特点 大(数据体量大)     多(种类的......
  • lua小小实战的资料
    Lua实现JSON解析器http://www.manongjc.com/detail/25-ozepzazdsivhrxe.htmlhttps://blog.51cto.com/u_15072927/3936779游戏中的排行榜Lua设计(简单实现,线段树,跳表)https://codeleading.com/article/15992061562/LuaJSON解析与序列化https://blog.csdn.net/wx771720/art......
  • 写给郑小小的话
    半夜的列车哒哒地开,回家的路上睡不着,我知道,你又得出现在我脑海里了。其实,一直都想整理好思绪,将我的所思所感说给你听。出发前的几个晚上,配着音乐录了视频,但是你不在眼前,说出的话也不知道是在说给谁听。我预想,今晚会是一个思恋的高峰期;果不其然,我又想你了,珍着这股思恋涌上心头,给你......
  • 一个小小的乐观锁、悲观锁也能扯这么多
    前言:我们一个普通的下单接口通常都包含如下三步操作,如果下单不成功的话将会返回给用户一个提示下单失败。查询库存(selectstockfromxxwhereid=xx)扣减更新库存(updatexxsetstock=stock-1whereid=xx)生成订单如果是只有一个用户来请求下单接口,那么上述的操作毫无疑问......
  • 拓展了个新业务枚举类型,资损了
    翻车了,为了cover线上一个业务场景,小猫新增了一个新的枚举类型,盲目自信就没有测试发生产了,由于是底层服务,上层调用导致计算逻辑有误,造成资损。老板很生气,后果很严重。分享是最有效的学习方式。案例背景翻车了,为了cover线上一个业务场景,小猫新增了一个新的枚......
  • Self-attention小小实践
    目录公式1不带权重的自注意力机制公式2带权重的自注意力机制公式1不带权重的自注意力机制\[Attention(X)=softmax(\frac{X\cdot{X^T}}{\sqrt{dim_X}})\cdotX\]示例程序:importnumpyasnpemb_dim=3qkv_dim=4seq_len=5X=np.array([[1501,502,503],......
  • 拓展了个新业务枚举类型,资损了
    分享是最有效的学习方式。案例背景翻车了,为了cover线上一个业务场景,小猫新增了一个新的枚举类型,盲目自信就没有测试发生产了,由于是底层服务,上层调用导致计算逻辑有误,造成资损。老板很生气,后果很严重。产品提出了一个新的业务场景,新增一种套餐费用的计算方式,由于业务比较着急,......
  • 小小的日志,大大的坑
    1.背景压测过程中优化线程池以后单机qps存在性能瓶颈,优化过程中发现默认线程池及日志对性能存在严重的影响所以引发了一系列对日志优化的整理2.哪些场景可能导致性能问题在任何系统中,日志都是非常重要的组成部分,它是反映系统运行情况的重要依据,也是排查问题时的必要线索。绝大......