2.40 dble中线程处理(print、kill、recover)

目前dble内部维护的主要以下几个线程:

mysql> select * from dble_thread_pool;
+----------------------+-----------+----------------+--------------+--------------------+
| name                 | pool_size | core_pool_size | active_count | waiting_task_count |
+----------------------+-----------+----------------+--------------+--------------------+
| Timer                |         1 |              1 |            0 |                  0 |
| TimerScheduler       |         2 |              2 |            0 |                 15 |
| frontWorker          |         8 |              8 |            1 |                  0 |
| managerFrontWorker   |         4 |              4 |            4 |                  0 |
| backendWorker        |         8 |              8 |            0 |                  0 |
| complexQueryWorker   |         8 |              8 |            1 |                  0 |
| writeToBackendWorker |         8 |              8 |            8 |                  0 |
| NIOFrontRW           |         8 |              8 |            8 |                  0 |
| NIOBackendRW         |         8 |              8 |            8 |                  0 |
+----------------------+-----------+----------------+--------------+--------------------+

mysql> select * from dble_thread_pool_task;
+----------------------+-----------+-------------------+-----------------+----------------+------------+
| name                 | pool_size | active_task_count | task_queue_size | completed_task | total_task |
+----------------------+-----------+-------------------+-----------------+----------------+------------+
| Timer                |         1 |                 0 |               0 |          89208 |      89208 |
| TimerScheduler       |         2 |                 0 |              15 |        1158830 |    1158845 |
| frontWorker          |         8 |                 0 |               0 |              0 |          0 |
| managerFrontWorker   |         4 |                 0 |               0 |             60 |         60 |
| backendWorker        |         8 |                 0 |               0 |          11339 |      11339 |
| complexQueryWorker   |         8 |                 1 |               0 |           2189 |       2190 |
| writeToBackendWorker |         8 |                 0 |               0 |              0 |          0 |
+----------------------+-----------+-------------------+-----------------+----------------+------------+
7 rows in set (0.42 sec)

补充(在非性能模式下):

  • TimerScheduler,作为dble内部定时任务的调度器;
    • 线程数固定(core_pool_size)2个,搭配无界队列;活动时机由定时任务触发周期而定,active_count有时为0;
    • 定时任务个数见task_queue_size;有时task_queue_size会减少,说明部分任务正在执行中;
    • 负责几个重要的定时任务包括心跳检测、主从延迟检测、疑似残留xaid检测。
    • 如果此连接池中2个线程都hang了,completed_task不变,task_queue_size表示任务个数会持续增长
  • Timer, 异步参与执行TimerScheduler线程中做一些较为复杂任务;
    • 核心线程为1个,预备线程数1个,搭配有界队列(固定大小65535);pool_size初始时为1,当队列满时,pool_size会增大为2;
    • 如果此连接池中2个线程都hang了,则pool_size、active_count均为2,completed_task、total_task不再变,task_queue_size值为65535。
  • frontWorker,负责8066前端连接处理请求的线程池;
    • 线程数固定,且为常驻线程(active_count等于pool_size),线程长期均处于RUNNING状态
    • 如果active_count小于pool_size,可以尝试使用thread @@recover name='0-frontWorker';
  • managerFrontWorker,负责9066前端连接处理请求的线程池;
    • 同frontWorker
  • writeToBackendWorker,广播下发SQL时候批量处理的线程池
    • 同 frontWorker
  • NIOFrontRW,进行前端网络IO吞吐的线程数
    • 同frontWorker
  • NIOBackendRW,进行后端网络IO吞吐的线程数
    • 同frontWorker
  • backendWorker,后端业务处理线程
    • 线程数固定,但非常驻线程;业务需要处理时,active_count会+1,但不超过pool_size
  • complexQueryWorker,负责处理一些复杂逻辑或者;
    • 线程数不固定,且非常驻线程;业务需要处理时,active_count会+1,pool_size会出现超过core_pool_size
  • 其他线程
    • 只能通过thread @@print或者jstack等方式观测

2.40.1 dble中观察疑似hang的线程

2.40.1.1 内部检测

局限:仅对Timer、TimerScheduler线程&线程池的检测
dble单独起一个内部观测的"ThreadChecker"线程,固定间隔2min检测一次。
检测机制:

  1. 若某个任务执行的时间长达10s -- thread.log中会有提示Thread[{}] suspected hang, execute time:[{}ms] more than 10s, currentState:[{}]
  2. 若本次线程池距离上一次检测周期所保留的快照对比active_task_count、completed_task没有发生变化,则thread.log中会有提示The thread pool where the thread[{}] is located is in the hang state and cannot work. Trigger alarm,且会有DBLE_THREAD_SUSPECTED_HANG告警
  3. 若不满足第2点了,则DBLE_THREAD_SUSPECTED_HANG告警会自动解决

2.40.1.2 通过print线程堆客栈的方式,人为判断

thread @@print 打印所有堆栈信息
thread @@print name=? 指定单个线程打印堆栈信息

强调注意:这两个命令类似于jstack工具,都会有STW的风险;因此建议不要轻易执行print命令

2.40.2 当确定某个线程执行任务的过长或者hang了,dble还可以哪些手段可以补救?

thread @@kill name=?,用于中断某个线程正在执行任务
thread @@kill poolname=?,仅支持TimerScheduler/Timer线程池中断
thread @@recover name=?,一般对常驻线程的恢复操作
thread @@recover poolname=?,仅支持TimerScheduler/Timer线程池恢复

强调注意:不要随意执行以上命令

具体场景&尝试补救

  • TimerScheduler
    • 场景1:当发现存在单个线程hang了(多个时间点这个线程的堆栈没有变化)
    • 尝试补救:
      1. 执行thread @@kill name=? 尝试将执行中的任务中断;
      2. 继续观察这个线程后续的堆栈是否有发生变化,若发生变化了,则视为解决hang问题;若没有发生变化,则表示此线程大概率陷入死循环,则只能暂时接受剩余正常线程继续工作。
    • 场景2:当发现池中所有线程都hang了(多个时间点的所有堆栈不再变化)且completed_task不再继续增长
    • 尝试补救:
      1. 执行thread @@kill poolname=?将整个线程池内部进行shutdown操作(一些重要的心跳检测、主从延迟检测等任务也会停掉,在恢复之前可以通过查看心跳信息发现所有的实例中的STOP均为true,所有实例均不可用);
      2. 若pool_size为0,表示连接池shutdown成功;继续执行thread @@recover poolname=?命令,以及观察pool_size恢复原来的初始值,completed_task、total_task均在重新增长(重要的心跳检测、主从延迟检测等任务也会恢复)。
      3. 若pool_size为2保持不变,则表示此线程池可能陷入死循环,只能通过重启解决此现象。
    • 注意:thread @@kill name='0-TimerScheduler' + thread @@kill name='1-TimerScheduler'不等于thread @@kill poolname='TimerScheduler'
  • Timer
    • 与TimerScheduler类似处理
  • frontWorker
    • 场景1:当发现存在单个线程hang了(多个时间点这个线程的堆栈没有变化)
    • 尝试补救:
      1. 执行thread @@kill name=? 尝试将执行中的任务中断;
      2. 若active_count值不变,后续单独观察此线程后续堆栈是否有变化,若堆栈有变化表示已解决此线程hang问题,若堆栈无变化,则表示此线程可能陷入死循环了,在影响面较大的情况下只能通过重启解决,影响面较小的情况,可暂时接受。
      3. 若active_count值减少,则继续执行thread @@recover name=?, 观察active_count值+1 (注意,这里如果name为'0-frontWorker',实际上恢复的可能并不是'0-frontWorker',具体原因与实现机制有关,这里不做阐述)。
    • 强烈建议:不要将所有的常驻线程,都被kill,否则会引起dble不可正常使用。
  • managerFrontWorker
    • 与frontWorker类似
  • writeToBackendWorker
    • 与frontWorker类似
  • NIOFrontRW,进行前端网络IO吞吐的线程数
    • 不支持kill/recover命令(因为kill掉NIOFrontRW会影响已经建立的前侧连接的业务执行)
  • NIOBackendRW,进行后端网络IO吞吐的线程数
    • 1.与frontWorker类似
    • 2.在做recover之后,dble中的旧连接池中的连接不再由此RW维护了;因此需要做些对后端连接的刷新操作,比如:fresh conn forced where dbGroup ='groupName'用来刷新连接池 或者执行reload @@config_all -r重置连接池。
    • 注意,当kill掉这个线程时,dble中内部与后端连接会收到影响:比如心跳不正常、执行sql有时hang有时can't reach等 凡事与后端实例交互的都会收到牵连,因此,不要随意使用kill命令。
  • backendWorker
    • 场景1:当发现存在单个线程hang了(多个时间点这个线程的堆栈没有变化),
    • 尝试补救:
      1. 执行thread @@kill name=? 尝试将执行中的任务中断;
      2. 继续单独观察此线程后续堆栈是否有变化,若堆栈有变化表示已解决此线程hang问题,若堆栈无变化,则表示此线程可能陷入死循环了,在影响面较大的情况下只能通过重启解决,影响面较小的情况,可暂时接受。
      3. 此线程无需执行thread @@recover命令。
  • complexQueryWorker
    • 与backendWorker类似
  • 其他线程,可通过jstack等工具观测
    • 与backendWorker类似,但建议不要轻易thread @@kill name=?命令

以上线程检测、print、kill、recover操作均会记录到logs/therad.log中,可自行演练观察日志。

results matching ""

    No results matching ""