• 2022/07/22:服务504超时响应告警 - 线程池的秘密


    如图:告警504服务的整体调用流程 

    2022/07/22 14:20:00 

    事情发生在一个明媚的下午,部门说来了一个大客户需要POC - XX测试,竞品给到他们1千QPS,咋们也需要支持到,我作为XX技术负责(已经骚不动),非常明确的说明,<瓶颈服务>二级子服务-目前最多支撑300QPS,而且是共享的,日常会使用100QPS,所以只有200富余。 一番沟通之后扩容加机器,根据压测报告最后扩容到总体500QPS的量,然后和客户协商后约定限制QPS到300

    2022/07/22 15:20:00 

    QPS限流工单审批通过,客户流量进入,整体QPS出现上升,带宽告警,立即通知运维同学扩带宽,500M->1000M,整理RT趋于稳定,监控30分钟,群内反馈QPS/RT情况,事情真的结束了吗?

    2022/07/22 17:05:00 

    gateway出现大量504告警,持续7s左右后恢复,排查监控

    1. 最下游一个<二级子服务>RT非常高,也出现了大量超时-通知子服务负责人排查原因-END
    2. <一级子服务>调用<二级子服务>应该是有降级处理,为何不生效

    先贴代码:

    1. for (AbstractModelTask task : tasks) {
    2. futures.add(MODEL_TASK_EXECUTOR_POOL.submit(task));
    3. }
    4. long timeout = modelLbUtil.getModelExecuteTimeout();
    5. long now = System.currentTimeMillis();
    6. for (Future future : futures) {
    7. if (future != null) {
    8. long remain = timeout - (System.currentTimeMillis() - now);
    9. try {
    10. if (remain < 0) {
    11. LOG.warn("futureGet remain out p={} s={}", partnerCode, seqId);
    12. break;
    13. }
    14. future.get(remain, TimeUnit.MILLISECONDS);
    15. } catch (XXXX e) {
    16. //XXXXXXXXXXXXXX
    17. } catch (Exception e) {
    18. LOG.warn("future get error, msg={} p={} s={}", e.getMessage(), partnerCode, seqId);
    19. } finally {
    20. future.cancel(true);
    21. }
    22. }

    然后在结合日志

    分析发现在 2022/07/22 17:08:06 时间点的时候,线程池future已经报错,但是直到 2022/07/22 17:08:12 时间点才进入到 futureGet remain out 超时判断逻辑中,这中间线程有哪些操作呢?

    1. 执行 future.cancel(true);
    2. 下一次foreach的get();
    3. long remain = timeout - (System.currentTimeMillis() - now);

    分析这三个动作

    • 第三个 : 系统时间算数, (本身不可能出现耗时久)
    • 第二个,foreach获取list数组内的值,线程无竞争, (本身不可能出现耗时久)
    • 第一个, cancel(true);future任务取消,中断内部线程,结束任务,(本身不可能出现耗时久)
      • 但从日志看它的执行时间是在 2022/07/22 17:08:12 342之后,2022/07/22 17:08:12 495之前,这就很诡异了,逻辑上它本应在2022/07/22 17:08:06 时间点就执行完成,想不通。

    继续分析cancel这个动作,

    1. //========================= 接口
    2. /**
    3. * Attempts to cancel execution of this task. This attempt will
    4. * fail if the task has already completed, has already been cancelled,
    5. * or could not be cancelled for some other reason. If successful,
    6. * and this task has not started when {@code cancel} is called,
    7. * this task should never run. If the task has already started,
    8. * then the {@code mayInterruptIfRunning} parameter determines
    9. * whether the thread executing this task should be interrupted in
    10. * an attempt to stop the task.
    11. *
    12. *

      After this method returns, subsequent calls to {@link #isDone} will

    13. * always return {@code true}. Subsequent calls to {@link #isCancelled}
    14. * will always return {@code true} if this method returned {@code true}.
    15. *
    16. * @param mayInterruptIfRunning {@code true} if the thread executing this
    17. * task should be interrupted; otherwise, in-progress tasks are allowed
    18. * to complete
    19. * @return {@code false} if the task could not be cancelled,
    20. * typically because it has already completed normally;
    21. * {@code true} otherwise
    22. */
    23. boolean cancel(boolean mayInterruptIfRunning);
    24. //========================= 抽象实现
    25. protected void cancel() {
    26. canceled = true;
    27. }
    28. //========================= 实现
    29. @Override
    30. protected void cancel() {
    31. super.cancel();
    32. if (completed)
    33. setLocalResult(getEmptyResult());
    34. }
    35. @Override
    36. protected final Node getEmptyResult() {
    37. return Nodes.emptyNode(op.getOutputShape());
    38. }
    39. @Override
    40. protected void setLocalResult(R localResult) {
    41. if (isRoot()) {
    42. if (localResult != null)
    43. sharedResult.compareAndSet(null, localResult);
    44. }
    45. else
    46. super.setLocalResult(localResult);
    47. }

    翻看官方API介绍不会阻塞,进入方法内部,唯一耗时的是compareAndSet() - CAS 但也不会阻塞6秒之久,真相究竟是啥啊!!!

    =========================分割线============================

    阶段性结论:这时候得到的结论是,线程平白无故阻塞了

    回顾职业生涯:之前也有过504的经历,那次是出现了tomcat初始化的连接数不够,在QPS起来之后,频繁创建连接导致资源消耗,部分线程出现阻塞,有没有可能也是这个原因呢??

    寻找资料

          发现了疑点,在504故障时间点线程池出现非常明显的波动,本身线程池coreThreadNum = 300, MaxThreadNum = 600

         很奇怪为啥会出现这种情况,会不会和线程销毁重建有关呢??

    此处本应执行 Jstack pid > stackLog.stack,但是机会错过就不再

    jstack脚本-记录工作线程:Model_Task_Executor_Pool的数量变化----观察监控出现波动是,工作线程是否发生变化

    但是结果不乐观:并没有关联关系

    1. #!/bin/bash
    2. if [ $# -eq 0 ];then
    3.   echo "please enter java pid"
    4.   exit -1
    5. fi
    6. pid=$1
    7. #修改成自己安装的JDK配置路径
    8. jstack_cmd="/usr/bin/jstack"
    9. #line=`top -H -o %CPU -b -n 1 -p $pid | sed '1,/^$/d' | grep -v $pid | awk 'NR==2'`
    10. #line=`top -H -b -n 1  -p $pid | sed '1,/^$/d' | sed '1d;/^$/d' | grep -v $pid | sort -nrk9 | head -1`
    11. #echo "$line" | awk '{print "tid: "$1," cpu: %"$9}'
    12. #tid_0x=`printf "%0x" $(echo "$line" | awk '{print $1}')`
    13. #$jstack_cmd $pid | grep $tid_0x -A20 | sed -n '1,/^$/p'
    14. for i in {1..2000};
    15. do
    16. $jstack_cmd $pid > stack_thread.log
    17. #Model_Task_Executor_Pool_
    18. echo "每5s统计一次,Model_Task_Executor_Pool_ 执行线程数量=========>"
    19. line=`grep 'Model_Task_Executor_Pool' stack_thread.log | awk '{print$8}'|uniq -c`
    20. echo "$line"
    21. line2=`grep 'Model_Task_Executor_Pool' stack_thread.log | awk '{print$4}'|uniq -c`
    22. echo " 总数: $line2"
    23. echo "=================>"
    24. sleep 5s
    25. done

    使用Future停止超时任务 - 小源求学 - 博客园今天学了下多线程中超时任务的处理,这里和大家分享下,遇到了点问题没能解决,留下来希望大家帮我解疑啊。在JAVA中停止线程的方法有多种,有一种是结合ExecutorService和Future的使用,停https://www.cnblogs.com/hanyuan/archive/2013/03/10/2952229.html

  • 相关阅读:
    论文解读(GGD)《Rethinking and Scaling Up Graph Contrastive Learning: An Extremely Efficient Approach with Group Discrimination》
    ES(Elasticsearch)概述及基本使用方法
    sqlalchemy模块介绍、单表操作、一对多表操作、多对多表操作、flask集成.
    SAP message-06 027 供应商 & 还未为采购组织 & 创建
    门阀-bitlocker
    x86 --- 任务隔离特权级保护
    [论文笔记]ESIM
    外包干了5天,技术退步明显。。。。。
    ahk系列——ahk_v2实现win10任意界面搜狗翻译
    leetcode 509. Fibonacci Number(斐波那契数字)
  • 原文地址:https://blog.csdn.net/qq_33199919/article/details/126051621