MySQL 原有线程调度方式有每个连接一个线程(one-thread-per-connection)和所有连接一个线程(no-threads)。
no-threads一般用于调试,生产环境一般用one-thread-per-connection方式。one-thread-per-connection 适合于低并发长连接的环境,而在高并发或大量短连接环境下,大量创建和销毁线程,以及线程上下文切换,会严重影响性能。另外 one-thread-per-connection 对于大量连接数扩展也会影响性能。
为了解决上述问题,MariaDB、Percona、Oracle MySQL 都推出了线程池方案,它们的实现方式大体相似,这里以 Percona 为例来简略介绍实现原理,同时会介绍我们在其基础上的一些改进。
线程池方案下,用户的每个连接不再对应一个线程。线程池由一系列 worker 线程组成,这些worker线程被分为
个group。用户的连接按 round-robin 的方式映射到相应的group 中,一个连接可以由一个group中的一个或多个worker线程来处理。
- thread_pool_size
次被放到优先队列中后,会移到普通队列中。worker线程先从高优先队列取event处理,只有当高优先队列为空时才从普通队列取event处理。 通过优先级队列,可以让已经开启的事务或短事务得到优先处理,及时提交释放锁等资源。
- thread_pool_high_prio_tickets
worker线程会退出。
- thread_pool_idle_timeout
时间检查一次。
- thread_pool_stall_limit
,重新创建listener;
- wake_or_create_thread
是否超时,如果超时退出连接,而不是退出worker线程。
- net_wait_timeout
一个group中活跃线程和等待中的线程超过
- thread_pool_oversubscribe
时,不会创建新的线程。 此参数可以控制系统的并发数,同时可以防止调度上的死锁,考虑如下情况,A、B、C三个事务,A、B 需等待C提交。A、B先得到调度,同时活跃线程数达到了
- thread_pool_oversubscribe
上限,随后C继续执行提交,此时已经没有线程来处理C提交,从而导致A、B一直等待。
- thread_pool_max_threads
控制group中活跃线程和等待中的线程总数,从而防止了上述情况。
- thread_pool_oversubscribe
- thread_pool_stall_limit
设置为10ms
- thread_pool_stall_limit
限制,从而导致性能下降。 优化方法是修改binlog dump线程不受
- thread_pool_oversubscribe
限制。
- thread_pool_oversubscribe
- information_schema.thread_group_status
- show create table THREAD_GROUP_STATUS\G
- *************************** 1. row ***************************
- Table: THREAD_GROUP_STATUS
- Create Table: CREATE TEMPORARY TABLE `THREAD_GROUP_STATUS` (
- `ID` int(21) unsigned NOT NULL DEFAULT '0',
- `THREAD_COUNT` int(21) unsigned NOT NULL DEFAULT '0',
- `ACTIVE_THREAD_COUNT` int(21) unsigned NOT NULL DEFAULT '0',
- `CONNECTION_COUNT` int(21) unsigned NOT NULL DEFAULT '0',
- `WAITING_THREAD_COUNT` int(21) unsigned NOT NULL DEFAULT '0',
- `DUMP_COUNT` bigint(21) unsigned NOT NULL DEFAULT '0',
- `LOW_QUEUE_COUNT` bigint(21) unsigned NOT NULL DEFAULT '0',
- `HIGH_QUEUE_COUNT` bigint(21) unsigned NOT NULL DEFAULT '0'
- ) ENGINE=MEMORY DEFAULT CHARSET=utf8
逻辑,从而解决无法连接的情况。
- one_thread_per_connection
最后说一点连接池和线程池的区别。连接池和线程池是两个独立的概念,连接池是在客户端的优化,缓存客户的连接,避免重复创建和销毁连接。而线程池是服务器端的优化。两者的优化角度不同,不相关,因此两种优化可以同时使用。
来源: http://mysql.taobao.org/monthly/2016/02/09/