[MySQL5.6] Percona Server 5.6.14的线程池浅析

Percona的线程池 基本上是从Mariadb中引入,其实现思路也比较简单,就是在线程调度器那增加了一组新的回调函数。线程池可以有效改善在大并发下的性能;

Thread pool的原理在Percona的这篇博客描述的很生动;其实就是限制同时运行的线程数,让大家不要一起挤进来,有序运行负载。线程池的目的不是为了提高性能,而是为了保持性能的稳定。

在使用线程池的场景下,就不是通常的一个连接一个线程(one-thread-per-connection),你可以创建几千甚至上万个Socket连接,MySQL只会创建有限个线程来

以下从不同的点来介绍下相关的代码,这里没有太多的深入,也没有性能测试数据,只是阅读时带着疑问做的一些笔记;

 

Q:如何控制同时运行的并发线程数

 

参数thread_pool_size的命令可能会让大家产生误解,它不是指的线程池的大小,而是线程组的大小。类似所有创建的线程都在某一个group里,group的编号从1~thread_pool_size,每个group里的线程数可以通过参数thread_pool_oversubscribe来控制(默认为3),如果把thread_pool_oversubscribe设置为1,那么thread_pool_size就被严格限制为能够同时活跃的最大线程数。

thread_pool_size默认值为CPU核心数,最大为128(MAX_THREAD_GROUPS),在启动时,就会把128个Group对应的结构体(all_groups)初始化好。每个group(编号小于等于thread_pool_size)会创建一个epoll对象;

 

Q:如何处理新连接

 

当客户端发起一个连接请求时,会被main线程捕捉到(handle_connections_sockets),然后调用tp_add_connection将新的连接加入到某个线程池的group中(根据thread_id%thread_pool_size),每个连接创建一个connection_t结构体对象(这个connection结构体里包含了连接的相关信息,例如是否登录,thd,是否正在等待,tickets等等),

创建好的connection被加入到其所属group的队列中(thread_group->queue),如果当前该group没有active的线程(thread_group->active_thread_count == 0)尝试去唤醒一个工作线程或者新建一个线程(wake_or_create_thread):a.首先尝试唤醒当前空闲的线程(空闲的线程对象在thread_group->waiting_threads中),如果有的话,则将其从waiting_threads中移除,并发送信号 ; b.否则表示现在该group内还没有线程, 需要创建一个新的worker线程(create_worker);
在创建worker线程时,一个比较有趣的代码段:

if (tp_stats.num_worker_threads >= (int)threadpool_max_threads

&& thread_group->thread_count >= 2)

{

err= 1;

max_threads_reached= true;

goto end;

}

实际上thread_pool_max_threads不是完全严格的限制总共的线程数,只有当当前线程数大于该max值,且当前group已有2个及以上worker线程时才拒绝新建线程

从上一步可以保证有一个活跃线程被唤醒来处理新连接的登录请求,worker线程的回调函数为worker_main,也就是处理socket请求的真正函数逻辑。

 

Q:如何处理新请求

 

 

worker线程调用worker_main,在一个循环内干两件事儿:

#get_event

顾名思义,该函数的目的就是为了获取一个事件,大约有如下的流程:

a.如果当前活跃线程数大于thread_pool_oversubscribe,并且该group的stall状态为false(何时设置?),暗示这时候该group的活跃线程数太多了(oversubscribed)。

b.如果oversubscribed为false,则取从队列中取connection_t对象(queue_get),先从高优先级队列(thread_group->high_prio_queue)取,如果没有的话,再从普通队列(thread_group->queue)取。如果存在的话,取得该对象返回

c.如果当前group里没有正在监听的线程(这时候没有任何请求),则把当前worker线程设置为监听线程,进入epoll监听socket请求

对于监听到的新请求,如果当前group里的没有event,,则由监听线程自己来处理监听到的第一个任务,剩下的任务放到队列中,否则把任务加入到队列中,由其他worker线程来处理。

加入队列的规则:

1.当该连接的ticket没用完(初始值为thread_pool_high_prio_tickets, Percona引入) 并且事务是活跃时,将该请求加入到高优先级队列,将tickets—

2.否则,将ticket设为threadpool_high_prio_tickets,并加入到普通队列中;

这实际上和innodb的ticket类似,保证一个大事务不要占用worker线程太长时间。以免引起其他事务饿死。

然后会去唤醒别的worker线程

d.oversubscribed为false时,再次尝试一次通过epoll看看有没有新请求(io_poll_wait),有的话直接处理该请求,这里的等待时间为0

f.将该worker线程加入等待队列(thread_group->waiting_threads),进入condtion wait,等待被唤醒,等待时间为thread_pool_idle_timeout

超时线程将直接退出;如果是被唤醒的,则跳转到a

#handle_event

worker线程拿到一个新请求后,进入处理阶段,这里就比较简单了。

如果connection还没有认证(connection->logged_in为false),则调用threadpool_add_connection(connection->the) 进行账户认证

否则,调用threadpool_process_request处理新请求。

在处理完后,设置connection的超时时间,以决定是否在超时后断开链接(pool_timer.next_timeout_check会被设置成最小的值),具体则由timer线程来检查;

然后再次将该socket的fd加入到其group所属的epoll中。

 

Q:异常场景下的处理

 

后台有一个timer线程在初始化thread pool时(tp_init)被启动,线程回调函数为timer_thread,用于检查每个线程组是否被阻塞了(check_stall)。大体思路是,在一段时间内,如果任务队列不为空,且从上次检查到现在没有从队列中取出任务(即thread_group->queue_event_count为0),那么就回去尝试唤醒或新创建一个worker线程;

如果查询运行的时间都非常长,那么最终可能退化成thread-per-connection这种原始模式;

timer线程也负责检查connetion是否net timeout.

thread_pool_stall_limit在Percona版本里似乎暂时没用到,根据其语义应该是用来控制timer线程循环检查的间隔时间

wait_begin/wait_end在进入等待前调用(我们在写代码时要注意这一点),其中wait_begin会先确保要有活跃的线程来处理请求,然后才会去让当前线程进入等待;

 

BluePrint

 

(Percona开发中,当前是基于Percona 5.6.14, 你看到这篇博客时,下面的几点可能已经实现了):

#1.可配置的优先队列模式

提供三种控制模式:

当设置为transaction模式时,只有一个已经开启了事务的SQL才会进入到高优先级队列中;

当设置为statements模式时,单独的SQL总是进入高优先级队列;

当设置为none时,则总是不走优先队列

通过这种方式来让客户端自己选择;当然更进一步的,可以在grant 权限时为其设置一个模式

#2.timer-based priority escalation

基于计时器的优先调度? 语焉不详。猜测大概意思是在低优先级队列如果超过一定的时间,就自动转移到高优先队列。

#3.low priority queue throttling

描述了一种场景:大多数SQL在等待某个事务释放行锁,而该事务所对应的事件由于oversubscribe了,无法被调度的问题;

代码 (尚未正式发布)来看,定义了一种线程忙的状态(就是active的线程加上wait的线程大于thread_pool_oversubscribe)。这种状态下不允许低优先级队列中的任务执行;那么对于上述场景,已经开启的事务拥有ticket且处于活跃状态,能够被优先更快的执行掉。

 

时间: 2024-10-24 09:49:11

[MySQL5.6] Percona Server 5.6.14的线程池浅析的相关文章

Percona Server 5.7有哪些性能提升?

In this blog post, we'll be discussing Percona Server 5.7 performance improvements. 在这篇文章中,我们将讨论Percona Server 5.7有哪些性能提升. Starting from the Percona Server 5.6 release, we've introduced several significant changes that help address performance proble

[MySQL 5.6] Percona Server 5.6.15(及之前版本)的优化点

Percona版本的MySQL 5.6目前已经GA了几个版本,本文大概理一下Percona版本相比Oracle版本的主要不同之处. 本文基于Percona Server 5.6.15,不排除后续有更多的新特性. 总的来说,Percona版本的5.6最吸引我的地方在于,强化了后台线程的优先级(例如Page cleaner),让后台线程多干活,同时弱化用户线程对全局资源(buffer pool)的管理介入:这在大负载写入的场景下,可以有助于性能稳定(例如通常我们在redo log推进到74%左右的时

Percona Server 与 MySQL 5.5 的性能比较

Percona 为 MySQL 数据库服务器进行了改进,在功能和性能上较 MySQL 有着很显著的提升.该版本提升了在高负载情况下的 InnoDB 的性能.为 DBA 提供一些非常有用的性能诊断工具;另外有更多的参数和命令来控制服务器行为. Percona Server 只包含 MySQL 的服务器版,并没有提供相应对 MySQL 的 Connector 和 GUI 工具进行改进. Percona Server 使用了一些 google-mysql-tools, Proven Scaling,

MySQL服务器版Percona Server 5.1.49-rel11.3

Percona 为 MySQL 数据库服务器进行了改进,在功能和性能上较 MySQL 有着很显著的提升.该版本提升了在高负载情况下的 InnoDB 的性能.为 DBA 提供一些非常有用的性能诊断工具;另外有更多的参数和命令来控制服务器行为. Percona Server 只包含 MySQL 的服务器版,并没有提供相应对 MySQL 的 Connector 和 GUI 工具进行改进. Percona Server 使用了一些 google-mysql-tools, Proven Scaling,

Percona Server 5.7 并行doublewrite 特性

In this blog post, we'll discuss the ins and outs of Percona Server 5.7 parallel doublewrite. 在这篇文章中,我们将由里及外讨论Percona Server 5.7的并行doublewrite. After implementing parallel LRU flushing as described in the previous post, we went back to benchmarking.

Percona Server 5.5.17-22.1发布 MySQL衍生版

Percona在2011年11月19日高兴地宣布Percona Server 5.5.17-22.1http://www.aliyun.com/zixun/aggregation/18782.html">正式发布.它是基于MySQL 5.5.17,包括修复所有之前的bug,Percona Server 5.5.17-22.1是目前5.5系列中最稳定的版本.所有Percona软件都是开源和自由的,更多的细节请参阅发行说明,你可以发现5.5.17-22.1是一个里程碑式的版本. 错误修正包括:

SQL Server .NET Framework 数据提供程序连接池

server|程序|数据 有朋友建议我控制连接池的连接,说是为了提高性能,但看了下面的这个文章,感觉连接池是由系统自身进行维护的,程序没有必要去进行控制的.大家有什么意见吗?在连接问题上,是否有提高性能的方法? SQL Server .NET Framework 数据提供程序连接池池连接可以显著提高应用程序的性能和可缩放性.SQL Server .NET Framework 数据提供程序自动为 ADO.NET 客户端应用程序提供连接池.您也可以提供几个连接字符串修饰符来控制连接池行为,请参见本主

SQL Server的Execute As与连接池结合使用的测试

原文:SQL Server的Execute As与连接池结合使用的测试 简介     在SQL Server中,Execute As关键字允许当前账户在特定上下文中以另一个用户或登录名的身份执行SQL语句,比如用户张三有权限访问订单表,用户李四并没有权限访问订单表,那么给予用户李四访问订单的表的权限就有些过头了,因为李四可能只有在很特定的上下文环境中才需要访问订单表,因此可以在特定上下文中使用Execute As Login 张三,暂时以张三的身份访问订单表,从而保证更安全的权限控制.    

percona server 源码编译安装

!/bin/bash BOOSTURL="https://nchc.dl.sourceforge.net/project/boost/boost/1.59.0/boost_1_59_0.tar.gz" PERCONAURL="https://www.percona.com/downloads/Percona-Server-LATEST/Percona-Server-5.7.18-15/source/debian/percona-server-5.7_5.7.18-15.ori