【现网】记一次并发冲突导致流量放大的生产问题
source link: https://www.cnblogs.com/Detector/p/17602502.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
阅读目录
欢迎转载,也请在明显位置注明出处 :https://www.cnblogs.com/Detector/p/17602502.html 谢谢!
生产环境,转账相关请求失败量暴增。
现网多个重试请求同时到达 svr,导致内存数据库大量返回时间戳冲突。业务方收到时间戳冲突,自动进行业务重试,服务内部也存在重试,导致流量放大。
首先我们一起了解一下转账。转账请求在支付场景中的应用频率非常高,它是现代金融系统中的一个核心功能。在日常生活中,个人和企业都需要进行各种不同类型的转账:
- 个人间转账:朋友、家人之间进行的转账,如还款、借款、生日礼物赠送等。
- 工资支付:企业向员工支付工资、奖金等。
- 税费缴纳:向政府缴纳所得税、增值税等税费、政府退回多征收的税费等。
- 跨境汇款:向国外的个人或企业进行的转账,如国际贸易、留学生汇款等。
- 投资与理财:向股票、基金、保险等金融产品进行的投资转账。
- 退款与赔付:商家或金融机构向客户退还购物款项、保险理赔等。
随着移动支付、网上银行等数字金融服务的普及,转账请求在支付场景中的应用频率越来越高。人们可以随时随地进行转账,这背后离不开金融科技的发展带来的更加便捷、安全、高效的转账过程。
业务背景介绍
背景一:转账流程
转账常见流程:
转账异常处理
当支付渠道系统内部出现异常,比如给转入方转钱时遇到被调系统返回超时时:
-
系统自动重试: 在大多数情况下,支付渠道系统会在短时间内自动重试转账操作,以确保交易成功。通常,系统会在一定时间内尝试多次,直到转账成功或达到重试次数上限。
-
转账暂停: 如果系统在多次重试后仍然无法完成转账,支付渠道可能会暂停该笔转账。在这种情况下,会通知转出方关于转账暂停的原因,并可能建议转出方稍后再次尝试转账。
-
** 资金退回:** 如果系统在尝试一定次数后仍无法完成转账,支付渠道可能会将资金退回到转出方的账户。转出方可以选择在支付渠道系统恢复正常后重新发起转账。
-
客户通知: 在上述情况下,银行会通过短信、电话或电子邮件等方式通知转出方关于转账失败的原因。客户可以根据银行的建议采取相应措施。
总之,渠道会尽力确保交易的顺利进行。
转账异常处理流程图
背景二:账户系统合并
因为公司账户系统存在多套,同一个服务商在不同的业务都存在商业合作时,账户归属不同的系统。降本增效大背景下,相关业务完成了业务账户的融合,将同一个商户在两个系统上的商户信息进行整合,融合到同一个账户,方便客户更好的维护,也方便客户账户资金共享,保证业务不中断。
改造后上层调用方会传递迁移前后两套uin
的参数来进行调用,账户系统通过查询 uin 的映射关系和关系中的迁移状态判断实际操作的账户。
即两个不同入口的请求都需要先查询一次迁移关系,如果账户已经迁移,则使用迁移后的账户进行操作,这个逻辑同时适用于转出方 和 转入方, 所以流程图上加上了查询关系的逻辑 蓝色部分。
如果操作过程中,账户状态发生了变化,则内部进行重试。
实际全流程:
背景三:扣内存数据库逻辑
为了支持高并发的需求,账户系统使用的是一个自研的缓存数据库,数据库内部有诸多逻辑,其中操作账户时,会先 get 数据,再 set 数据, get 的时候会拿到当前数据的的时间戳 和更新序列号,set 的时候,数据库会校验这个时间戳的合法性。
所以在请求出现并发时会出现这样的情况:
背景四:调用方重试逻辑
调用方除非遇到订单重复、余额不足等明确错误,不然会推送 MQ 进行重试。
相信大家看完上面的背景和前面的现象描述已经知道了问题的原因:业务的重试和系统内部的重试逻辑出现了重叠,导致了绝对并发(内存数据库的get\set逻辑极快),但是因为涉及到多个系统,每次请求的 uuid 又完全一致,导致了定位链路过长,定位难度增大。最后在测试环境复现了很多次才复现出来。
针对这个问题给我总结了以下几点:
-
测试环境和生产环境的差异:测试环境很难完全模拟生产环境的各种情况,特别是在并发、性能和压力测试方面。因此,我们需要更加关注这些方面的测试,并尽量使测试环境接近生产环境。
-
完善的测试用例:在设计测试用例时,需要考虑各种异常情况和边缘条件,包括系统之间的相互调用、失败重试等情况。这样可以提高测试的覆盖率,降低类似问题的发生概率。
-
强化并发和压力测试:在软件测试过程中,应该重点关注并发和压力测试,模拟大量用户同时访问和操作,以便发现潜在的性能瓶颈和冲突问题。(常态化性能测试是一个非常好的切入点。后续会专门写一篇博客介绍如何进行常态化性能压测。)
-
监控和日志分析:在生产环境中,应该加强对系统的监控和日志分析,以便及时发现并定位问题。同时,测试人员可以通过分析生产环境的监控和日志数据,了解系统在实际运行中的表现,从而改进测试策略。
以下是一些避免类似问题的发生的改进措施:
- 测试同学需要与开发团队紧密合作,了解系统架构和相互调用的关系,以便更好地设计测试用例。
- 在系统设计和开发阶段,可以引入容错和熔断机制,以应对失败重试和请求放大等问题。测试工程师需要关注这些机制的实现,并在测试中验证其有效性。
- 在测试计划中明确测试范围,包括并发测试、压力测试和性能测试,确保测试环境尽量接近生产环境,有条件的可以使用真实的数据和场景进行测试(现网引流)。
- 对于失败重试等可能会放大流量的逻辑,进行专项测试,模拟各种异常和故障情况(后续会专门写一篇博客介绍如何进行混沌注入),验证系统的稳定性和健壮性。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK