记一次并发引起的问题及排查过程

简介: 聚合支付系统(第四方支付),协议支付模块一直有个小问题。商户调用协议支付接口,该模块会调用下层第三方支付渠道的协议支付服务,如果第三方支付渠道没有同步返回支付结果,则协议支付模块会通过定时任务向第三方支付渠道批量第查询支付结果(每查一笔订单就调一次第三方支付渠道,“批量”相当于并发调用第三方支付渠道)

问题背景


聚合支付系统(第四方支付),协议支付模块一直有个小问题。

商户调用协议支付接口,该模块会调用下层第三方支付渠道的协议支付服务,如果第三方支付渠道没有同步返回支付结果,则协议支付模块会通过定时任务向第三方支付渠道批量第查询支付结果(每查一笔订单就调一次第三方支付渠道,“批量”相当于并发调用第三方支付渠道),大致如下图:


109.png


在支付阶段,基本上没有问题,但是在定时任务批量查询支付结果时,如果查询的订单数量过多,就总会有几个查询请求报 “证书错误”(系统自定义异常,表示请求第三方支付的证书字符串有误)。


定时任务查询支付订单支付结果的逻辑大致是:每隔5秒钟查询当前支付结果是处理中(不是终态——成功或失败的状态)的订单列表,比如有100笔(这100笔订单中可能有一到多个商户发起的支付订单),然后开启100个线程分别调用第三方支付的查询接口进行查询。在调用第三方支付的时候,需要根据订单信息来获取证书字符串。


问题排查


在和第三方支付确认他们收到的证书字符串和对应请求中的证书字符串一致后,就回头看获取证书字符串的相关代码,大致代码如下:

生成证书字符串的工具类:

public class CertUtils {
    private static CertHandler certHandler;
    public CertUtils(String merchantInfo) {
        // 根据商户信息 merchantInfo 生成 certHandler
        // 略
    }
    public String getCertStr(){
        return certHandler.getCertStr();
    }
}

在项目中获取证书字符串(上面工具类的使用)

CertUtils certUtils=new CertUtils(merchantInfo); // ① 根据当前商户信息生成一个工具类的实例
String merchantCert=certUtils.getCertStr(); // ② 通过工具类的实例获得当前商户的证书字符串

不看不知道,一看吓一跳,这工具类用的有点奇葩啊~ 分析下奇葩的原因:


获得证书字符串是由certHandler的getCertStr()方法获得的,而certHandler是根据商户信息生成的,但这里却把certHandler定义为static的,所以即使用的时候new了100个CertUtils实例,CertUtils中引用的CertHandler实例却永远是一个,且指向的对象在不断变化,也就是说,CertUtils中引用的CertHandler实例是公共变量,在多线程环境下可能会出现线程安全的问题。


比如当线程1执行完上面的代码①,准备执行代码②之前,这时线程2也刚好执行完代码①,所以线程2就把线程1生成的certHandler给修改了,线程1执行代码②时获取到的证书字符串其实是线程2的。


分析完毕再具体看日志,正如所料,报“证书错误”的请求所携带的证书字符串,和与它并发发起的那些请求所携带的证书字符串一样:(两个线程发起的请求,红框是商户号不一样,黄色背景是证书字符串一样)


110.png

这就说明,报“证书错误”的请求跟上面分析的线程1情况一样,在执行完上面的代码①,准备执行代码②之前,被其他线程执行了代码①,把公共的CertHandler实例给改掉了,所以拿到的证书字符串也就是别人的。

解决方法:


1、使用上述工具类的时候,对代码①和代码②加锁,可以保证线程安全

2、直接把线程公有的变量certHandler变成线程私有变量,改成非静态的类型


相关文章
|
存储 Java
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(上)
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析
332 0
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(上)
|
6天前
|
缓存 JavaScript 前端开发
服务器反应慢如何解决?
通常来说,访问者会在最初的几秒钟内决定是留在您的网站还是离开。如果页面加载时间超过五秒,访问者离开的可能性就会增加 90%。所以,作为站长们,必须减少服务器响应时间,以确保其网站加载速度更快。以下是减少网站服务器响应时间的几种简单方式。
45 19
|
6天前
|
测试技术
如何避免测试同化现象?
如何避免测试同化现象?
|
8月前
|
Java 调度
CPU突然飙高系统反应慢,是怎么导致的?有什么办法排查?
面试过程中,场景类的问题更容易检测出一个开发人员的基本能力。这不,有一位小伙伴去阿里面试,第一面就遇到了关于“CPU 飙高系统反应慢怎么排查”的问题?当时这位小伙伴不知从何下手。 今天,我给大家分享一下我的解决思路。
114 0
|
10月前
|
缓存 监控 数据库连接
CPU飙高排查方案与思路
当CPU飙高时,可能是由于程序中存在一些性能问题或者死循环导致的。以下是一些排查CPU飙高的方案和思路
632 0
|
缓存 测试技术 数据库
软件测试面试题:假设在测试过程中某些事务的响应时间过长,但分析应用服务、数据库以及网络都属于正常现象,问题可能出现的原因有哪些?
软件测试面试题:假设在测试过程中某些事务的响应时间过长,但分析应用服务、数据库以及网络都属于正常现象,问题可能出现的原因有哪些?
320 0
|
测试技术
软件测试面试题:什么是并发?在lordrunner中,如何进行并发的测试?集合点失败了会怎么样?
软件测试面试题:什么是并发?在lordrunner中,如何进行并发的测试?集合点失败了会怎么样?
171 0
|
存储 安全 IDE
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(下)
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析
268 0
2021年了,生产环境的问题你怎么解决呢?快学习下线程Dump分析(下)
|
关系型数据库 Java 应用服务中间件
死锁的 4 种排查工具 !(5)
死锁的 4 种排查工具 !(5)
76 0
死锁的 4 种排查工具 !(5)