接口性能排查之线程池

目录

一、背景

二、排查及解决


一、背景

        某天开心的上班,突然产品找到我,说咱们有个查询接口,最长需要分钟级才有响应,已经被业务方骂惨了,需要优化,赶紧的。

二、排查及解决

        于是我吭哧吭哧的开始排查,记录下我得排查过程:

  1. 梳理代码,把怀疑对象定在了一个rpc接口调用上,页面实操,接着拿到traceId去全链路追踪平台去看调用链路,发现罪魁祸首好像并不是rpc接口调用,而是在接口内部;

        2. 理出可能耗时的关键步骤,借用StopWatch和日志打点记录其耗时;

        3. 定位到耗时最长的代码逻辑

     //方法1:线程池定义
	private final static ExecutorService executorService = new ThreadPoolExecutor(8, 200, 0L, TimeUnit.MILLISECONDS,
         new LinkedBlockingQueue<>(1024), new ThreadFactoryBuilder().setNameFormat
        ("PromoDisplayScheduleController-pool-%d").build(),
        new ThreadPoolExecutor.AbortPolicy());
	//关键耗时代码
    shopCode2SkuSet.forEach((shopCode, skuSet) -> {
        executorService.submit(() -> {
            //省略其它逻辑......
            Map<String, StoreSkuDTO> storeSkuDTOMap = skuReadManager.mGetStoreSku(merchantCode, shopCode,skuSet);
        });
    });
    //方法2:线程池定义
	private final static ExecutorService executorService = new ThreadPoolExecutor(8, 200, 0L, TimeUnit.MILLISECONDS,
         new LinkedBlockingQueue<>(1024), new ThreadFactoryBuilder().setNameFormat
        ("PromoDisplayScheduleController-pool-%d").build(),
        new ThreadPoolExecutor.AbortPolicy());
	//关键耗时代码
    List<List<String>> partition = Lists.partition(skuList, 50);
    for (List<String> skuCodeList : partition) {
        executorService.execute(() -> {
            //rpc远程调用
            Result<List<StoreSkuDTO>> mGetRes = shopSkuServiceClient.getStroeSku(skuCodeList, shopCode, merchantCode);
        });
    }

分析代码:

        发现是方法1中利用一个线程池去并发调用方法2,方法2内部使用线程池去多线程调用外部rpc接口,这个写法比较奇怪,之前也没有见过,于是仔细研究了一下代码,最终问题定位:

        分析数据情况,发现外层线程池平均会处理40个任务,内层线程池平均处理15个任务,内层方法中rpc接口调用平均耗时5s(没办法,忍着吧,其它团队开发),外层和内层线程池参数均为:核心线程数8,最大线程数200,任务队列1024。当一次接口调用来临时,首先走到外层线程池调用,由8个核心线程执行8个任务,其余任务放入任务队列,外层核心线程调用的任务中会调用内层方法,然后走到内层线程池调用,同样是8个核心线程执行8个任务,其余任务放入任务队列,理想情况下,内层线程池只需要每个核心线程执行2个任务,所以外层核心线程执行的每个任务时长应该在10s,而外层线程池只需要每个核心线程执行5个任务,所以整个多线程执行完毕耗时在50s左右,这也是导致接口过慢的罪魁祸首。

解决:

        分析到原因之后,解决方法就比较简单粗暴了,将任务队列调小或者将核心线程数调大(视具体业务情况来定,一般是将任务队列调小,毕竟核心线程是不会被销毁的,耗资源,但也要注意是否会造成线程池超负荷,从而丢弃任务),不让任务有进入到任务队列的机会,这样整个多线程执行完毕耗时在5s左右,也就是rpc接口调用耗时的时长。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dubbo连接超时问题通常是由于网络延迟、服务提供者负载过高或者配置错误等多种原因引起的。下面是排查Dubbo连接超时问题的一些常见方法和建议: 1. 检查网络延迟:首先,可以尝试通过ping命令来检查与服务提供者之间的网络延迟情况。如果延迟较高,可能需要优化网络环境或者切换到更稳定的网络连接。 2. 服务提供者负载过高:可以查看服务提供者的系统资源使用情况,例如 CPU、内存、磁盘等是否过载。如果负载过高,可以优化代码、增加服务器资源或者增加服务实例数等来提高性能。 3. 超时配置错误:可以检查Dubbo的超时配置是否正确。例如,可以确认是否设置了正确的连接超时时间、读写超时时间等,以及是否合理地设置了重试次数等参数。 4. 服务提供者响应时间过长:可以对服务提供者进行性能分析,找出响应时间较长的接口或者方法,并优化其实现。如果有必要,可以采用异步调用方式来提高吞吐量和响应速度。 5. 检查服务调用链路:可以通过监控工具或者日志来查看服务调用链路,找出是否存在调用关系错乱、环路或者循环依赖等问题。这些问题可能导致连接超时或者请求被阻塞。 6. 调整Dubbo配置参数:可以尝试调整Dubbo的相关配置参数,如线程池大小、队列大小、IO线程数等,以适应当前的应用场景。 总之,解决Dubbo连接超时问题的关键是要深入分析问题背后的原因,并针对性地采取相应的优化措施。在排查问题过程中,可以结合相关的监控工具、日志和性能测试工具来帮助定位和解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值