签到成功

知道了

CNDBA社区CNDBA社区

MySQL 线程池(Thread Pool) 体系结构 说明

2024-04-25 15:02 770 0 转载 MySQL
作者: dave

1 体系结构说明

https://docs.percona.com/percona-server/8.0/threadpool.html

http://www.cndba.cn/dave/article/131539


Percona Server for MySQL 的线程池架构旨在优化高并发环境下的性能,通过减少线程创建和销毁的开销,以及提高资源利用率,来保持系统性能的稳定。

Thread Pool由一个Timer线程和多个Thread Group组成,而每个Thread Group又由两个队列、一个listener线程和多个worker线程构成。

1.1 基本组件

  • 线程组 (Thread Group):线程池由多个线程组组成,每个线程组包含一组工作线程(worker threads)。线程组的数量通常配置为数据库实例的 CPU 核心数量,通过参数 thread_pool_size 设置。
  • Timer 线程:除了工作线程外,线程池还包含一个 Timer 线程,用于处理定时任务或超时事件。Timer线程周期性检查group是否处于处于阻塞状态,当出现阻塞的时候,会通过唤醒线程或者新建线程来解决。
    worker线程:worker线程是真正干活的线程。

1.2 监听与分配

  • Listener 线程:每个线程组都有一个 Listener 线程,负责监听来自现有连接的新请求。当监听到新请求时,Listener 线程会从线程组的工作线程中分配一个线程来提供服务。
  • 连接分配:新连接在到达时,会根据一定的策略(如线程ID对线程组数取模)被分配到某个线程组中。在线程组内,连接通过竞争方式获取工作线程来处理。

1.3 任务队列

高优先级队列和低优先级队列:线程池使用两个队列来存放待执行的 IO 任务。高优先级队列的任务会优先被处理,通常用于存放需要快速响应的任务。低优先级队列则用于存放其他任务。任务的优先级可以根据实际情况进行调整,例如非事务引擎或开启了 autocommit 的事务引擎的任务可能会被放入低优先级队列。http://www.cndba.cn/dave/article/131539

1.4 线程状态与管理

线程池会监控线程的状态,包括空闲、忙碌、死亡等。当线程空闲超过一定时间(由 thread_pool_stall_limit 参数控制)时,线程可能会被销毁以释放资源。同时,当新连接到达且没有空闲线程时,线程池会根据配置决定是否创建新线程。

2 运行机制

2.1 Thread Pool运作机制

  • Step1:请求连接到MySQL,根据threadid%thread_pool_size确定落在哪个group;

  • Step2:group中的listener线程监听到所在的group有新的请求以后,检查队列中是否有请求还未处理。如果没有,则自己转换为worker线程立即处理该请求,如果队列中还有未处理的请求,则将对应请求放到队列中,让其他的线程处理;http://www.cndba.cn/dave/article/131539

  • Step3:group中的thread线程检查队列的请求,如果队列中有请求,则进行处理,如果没有请求,则休眠,一直没有被唤醒,超过thread_pool_idle_timeout后就自动退出。线程结束。当然,获取请求之前会先检查group中的running线程数是否超过thread_pool_oversubscribe+1,如果超过也会休眠;http://www.cndba.cn/dave/article/131539

  • Step4:timer线程定期检查各个group是否有阻塞,如果有,就对wokrer线程进行唤醒或者创建一个新的worker线程。http://www.cndba.cn/dave/article/131539

2.2 Thread Pool的分配机制

线程池会根据参数thread_pool_size的大小分成若干的线程组(thread group),每个线程组(thread group)各自维护客户端发起的连接,当客户端发起连接到MySQL的时候,MySQL会跟进连接的线程id(thread_id)对thread_pool_size进行取模,从而落到对应的线程组(thread group)。

thread_pool_oversubscribe参数控制每个线程组(thread group)的最大并发线程数,每个线程组的最大并发线程数为thread_pool_oversubscribe+1个。若对应的线程组达到了最大的并发线程数,则对应的连接就需要等待。

3 参数说明

mysql> show variables like 'thread_%';
+-------------------------------+-----------------+
| Variable_name                 | Value           |
+-------------------------------+-----------------+
| thread_cache_size             | 58              |
| thread_handling               | pool-of-threads |
| thread_pool_high_prio_mode    | transactions    |
| thread_pool_high_prio_tickets | 4294967295      |
| thread_pool_idle_timeout      | 60              |
| thread_pool_max_threads       | 100000          |
| thread_pool_oversubscribe     | 32              |
| thread_pool_size              | 96              |
| thread_pool_stall_limit       | 10              |
| thread_stack                  | 262144          |
| thread_statistics             | OFF             |
+-------------------------------+-----------------+
11 rows in set (0.01 sec)
  • thread_handling:该参数是配置线程模型,默认情况是one-thread-per-connection,即不启用线程池;将该参数设置为pool-of-threads即启用了线程池。

  • thread_pool_size:该参数是设置线程池的线程组(thread group)的数量,默认为系统CPU的个数,充分利用CPU资源。http://www.cndba.cn/dave/article/131539

  • thread_pool_oversubscribe:该参数设置每个线程组(thread group)中的最大线程数,每个线程组(thread group)中的最大线程数为thread_pool_oversubscribe+1,注意listener线程不包含在内。

  • thread_pool_high_prio_mode:高优先级队列的控制参数,有三个值(transactions/statements/none),默认是transactions,三个值的含义如下:
    1) transactions:对于已经启动事务的语句放到高优先级队列中,不过还取决于后面的thread_pool_high_prio_tickets参数。
    2) statements:这个模式所有的语句都会放到高优先级队列中,不会使用到低优先级队列。
    3) none:这个模式不使用高优先级队列。http://www.cndba.cn/dave/article/131539

  • thread_pool_high_prio_tickets:该参数控制每个连接最多语序多少次被放入高优先级队列中,默认为4294967295,注意这个参数只有在thread_pool_high_prio_mode为transactions的时候才有效果。

  • thread_pool_idle_timeout:worker线程最大空闲时间,默认为60秒,超过限制后会退出。

  • thread_pool_max_threads:该参数用来限制线程池最大的线程数,超过该限制后将无法再创建更多的线程,默认为100000。 实际最多的线程数 = thread_pool_size * (thread_pool_oversubscribe+1)http://www.cndba.cn/dave/article/131539

  • thread_pool_stall_limit:该参数设置timer线程的检测线程组(thread group)是否异常的时间间隔,默认为500ms。

  • thread_cache_size:用于控制线程缓存的大小。当客户端连接关闭时,档设置了一个非零值,MySQL 会尝试缓存该线程而不是立即销毁它。对于后续的连接请求,MySQL 可以从缓存中快速获取一个已经存在的线程,而不是重新创建一个新的线程,从而减少线程创建和销毁的开销,这在高并发场景下尤为重要,可以显著提高性能。http://www.cndba.cn/dave/article/131539

    http://www.cndba.cn/dave/article/131539

用户评论
* 以下用户言论只代表其个人观点,不代表CNDBA社区的观点或立场
dave

dave

关注

人的一生应该是这样度过的:当他回首往事的时候,他不会因为虚度年华而悔恨,也不会因为碌碌无为而羞耻;这样,在临死的时候,他就能够说:“我的整个生命和全部精力,都已经献给世界上最壮丽的事业....."

  • 2261
    原创
  • 3
    翻译
  • 578
    转载
  • 191
    评论
  • 访问:7966108次
  • 积分:4346
  • 等级:核心会员
  • 排名:第1名
精华文章
    最新问题
    查看更多+
    热门文章
      热门用户
      推荐用户
        Copyright © 2016 All Rights Reserved. Powered by CNDBA · 皖ICP备2022006297号-1·

        QQ交流群

        注册联系QQ