mysql线程池怎么样 mysql 线程数与cpu的关系

php 怎么做mysql的线程池

one-connection-per-thread

从事成都移动机房,服务器租用,云主机,网站空间域名申请,CDN,网络代维等服务。

根据scheduler_functions的模板,我们也可以列出one-connection-per-thread方式的几个关键函数。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

static scheduler_functions con_per_functions=

{ max_connection+1, // max_threads

NULL,

NULL,

NULL, // init

Init_new_connection_handler_thread, // init_new_connection_thread

create_thread_to_handle_connection, // add_connection

NULL, // thd_wait_begin

NULL, // thd_wait_end

NULL, // post_kill_notification

one_thread_per_connection_end, // end_thread

NULL // end

};

1.init_new_connection_handler_thread

这个接口比较简单,主要是调用pthread_detach,将线程设置为detach状态,线程结束后自动释放所有资源。

2.create_thread_to_handle_connection

这个接口是处理新连接的接口,对于线程池而言,会从thread_id%group_size对应的group中获取一个线程来处理,而one-connection-per-thread方式则会判断是否有thread_cache可以使用,如果没有则新建线程来处理。具体逻辑如下:

(1).判断缓存的线程数是否使用完(比较blocked_pthread_count 和wake_pthread大小)

(2).若还有缓存线程,将thd加入waiting_thd_list的队列,唤醒一个等待COND_thread_cache的线程

(3).若没有,创建一个新的线程处理,线程的入口函数是do_handle_one_connection

(4).调用add_global_thread加入thd数组。

3.do_handle_one_connection

这个接口被create_thread_to_handle_connection调用,处理请求的主要实现接口。

(1).循环调用do_command,从socket中读取网络包,并且解析执行;

(2). 当远程客户端发送关闭连接COMMAND(比如COM_QUIT,COM_SHUTDOWN)时,退出循环

(3).调用close_connection关闭连接(thd-disconnect());

(4).调用one_thread_per_connection_end函数,确认是否可以复用线程

(5).根据返回结果,确定退出工作线程还是继续循环执行命令。

4.one_thread_per_connection_end

判断是否可以复用线程(thread_cache)的主要函数,逻辑如下:

(1).调用remove_global_thread,移除线程对应的thd实例

(2).调用block_until_new_connection判断是否可以重用thread

(3).判断缓存的线程是否超过阀值,若没有,则blocked_pthread_count++;

(4).阻塞等待条件变量COND_thread_cache

(5).被唤醒后,表示有新的thd需要重用线程,将thd从waiting_thd_list中移除,使用thd初始化线程的thd-thread_stack

(6).调用add_global_thread加入thd数组。

(7).如果可以重用,返回false,否则返回ture

线程池与epoll

在引入线程池之前,server层只有一个监听线程,负责监听mysql端口和本地unixsocket的请求,对于每个新的连接,都会分配一个独立线程来处理,因此监听线程的任务比较轻松,mysql通过poll或select方式来实现IO的多路复用。引入线程池后,除了server层的监听线程,每个group都有一个监听线程负责监听group内的所有连接socket的连接请求,工作线程不负责监听,只处理请求。对于overscribe为1000的线程池设置,每个监听线程需要监听1000个socket的请求,监听线程采用epoll方式来实现监听。

Select,poll,epoll都是IO多路复用机制,IO多路复用通过一种机制,可以监听多个fd(描述符),比如socket,一旦某个fd就绪(读就绪或写就绪),能够通知程序进行相应的读写操作。epoll相对于select和poll有了很大的改进,首先epoll通过epoll_ctl函数注册,注册时,将所有fd拷贝进内核,只拷贝一次不需要重复拷贝,而每次调用poll或select时,都需要将fd集合从用户空间拷贝到内核空间(epoll通过epoll_wait进行等待);其次,epoll为每个描述符指定了一个回调函数,当设备就绪时,唤醒等待者,通过回调函数将描述符加入到就绪链表,无需像select,poll方式采用轮询方式;最后select默认只支持1024个fd,epoll则没有限制,具体数字可以参考cat /proc/sys/fs/file-max的设置。epoll贯穿在线程池使用的过程中,下面我就epoll的创建,使用和销毁生命周期来描述epoll在线程中是如何使用的。

线程池初始化,epoll通过epoll_create函数创建epoll文件描述符,实现函数是thread_group_init;

端口监听线程监听到请求后,创建socket,并创建THD和connection对象,放在对应的group队列中;

工作线程获取该connection对象时,若还未登录,则进行登录验证

若socket还未注册到epoll,则调用epoll_ctl进行注册,注册方式是EPOLL_CTL_ADD,并将connection对象放入epoll_event结构体中

若是老连接的请求,仍然需要调用epoll_ctl注册,注册方式是EPOLL_CTL_MOD

group内的监听线程调用epoll_wait来监听注册的fd,epoll是一种同步IO方式,所以会进行等待

请求到来时,获取epoll_event结构体中的connection,放入到group中的队列

线程池销毁时,调用thread_group_close将epoll关闭。

备注:

1.注册在epoll的fd,若请求就绪,则将对应的event放入到events数组,并将该fd的事务类型清空,因此对于老的连接请求,依然需要调用epoll_ctl(pollfd, EPOLL_CTL_MOD, fd, ev)来注册。

线程池函数调用关系

(1)创建epoll

tp_init-thread_group_init-tp_set_threadpool_size-io_poll_create-epoll_create

(2)关闭epoll

tp_end-thread_group_close-thread_group_destroy-close(pollfd)

(3)关联socket描述符

handle_event-start_io-io_poll_associate_fd-io_poll_start_read-epoll_ctl

(4)处理连接请求

handle_event-threadpool_process_request-do_command-dispatch_command-mysql_parse-mysql_execute_command

(5)工作线程空闲时

worker_main-get_event-pthread_cond_timedwait

等待thread_pool_idle_timeout后,退出。

(6)监听epoll

worker_main-get_event-listener-io_poll_wait-epoll_wait

(7)端口监听线程

main-mysqld_main-handle_connections_sockets-poll

one-connection-per-thread函数调用关系

(1) 工作线程等待请求

handle_one_connection-do_handle_one_connection-do_command-

my_net_read-net_read_packet-net_read_packet_header-net_read_raw_loop-

vio_read-vio_socket_io_wait-vio_io_wait-poll

备注:与线程池的工作线程有监听线程帮助其监听请求不同,one-connection-per-thread方式的工作线程在空闲时,会调用poll阻塞等待网络包过来;

而线程池的工作线程只需要专心处理请求即可,所以使用也更充分。

(2)端口监听线程

与线程池的(7)相同

参考文档

mysql数据库每次查询是一条线程吗

MySQL的查询使用的是线程池。当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低,降低了服务质量。线程池技术,预先会创建一定数量的线程,当有请求达到时,线程池分配一个线程提供服务,请求结束后,该线程又去服务其他请求。 通过这种方式,避免了线程和内存对象的频繁创建和释放,降低了服务端的并发度,减少了上下文切换和资源的竞争,提高资源利用效率。在MySQL早期的版本中,处理连接的方式是One-Connection-Per-Thread,即对于每一个数据库连接,MySQL-Server都会创建一个独立的线程服务,请求结束后,销毁线程。再来一个连接请求,则再创建一个连接,结束后再进行销毁。但是,这种方式在高并发情况下,会导致线程的频繁创建和释放。当然,通过thread-cache,我们可以将线程缓存起来,以供下次使用,避免频繁创建和释放的问题,但是无法解决高连接数的问题。One-Connection-Per-Thread方式随着连接数暴增,导致需要创建同样多的服务线程,高并发线程意味着高的内存消耗,更多的上下文切换(cpu cache命中率降低)以及更多的资源竞争,导致服务出现抖动。相对于One-Thread-Per-Connection方式,一个线程对应一个连接,Thread-Pool实现方式中,线程处理的最小单位是statement(语句),一个线程可以处理多个连接的请求。这样,在保证充分利用硬件资源情况下(合理设置线程池大小),可以避免瞬间连接数暴增导致的服务器抖动。

mysql如何写线程池保证长时间链接不断开自

用Fsocket获取数据时能够控制超时的。

如果用

File_get_contents($url);

可以临时设定环境变量:

设定默认socket超时时间

ini_set("default_socket_timeout", 3);养成好习惯,使用fsocket获取数据。

如果使用Curl,也可以在Curl中控制超时时间:

curl_setopt($ch, CURLOPT_TIMEOUT, 15);

PHP中mysql函数是不提供类似mysql超时选项的,但是php.ini的mysql.connect_timeout可设置

; Maximum time (in seconds) for connect timeout. -1 means nolimit

mysql.connect_timeout = 60

也可以在php脚本中调用设置ini_set();

MySQL数据库是一个多用户,多线程的关系数据库管理系统,其主要技术都包括哪些

在MySQL 8.0 之前, 我们假设一下有一条烂SQL,

mysqlselect * from t1 order by rand() ;

以多个线程在跑,导致CPU被跑满了,其他的请求只能被阻塞进不来。那这种情况怎么办?

大概有以下几种解决办法:

设置max_execution_time 来阻止太长的读SQL。那可能存在的问题是会把所有长SQL都给KILL 掉。有些必须要执行很长时间的也会被误杀。

自己写个脚本检测这类语句,比如order by rand(), 超过一定时间用Kill query thread_id 给杀掉。

那能不能不要杀掉而让他正常运行,但是又不影响其他的请求呢?

那mysql 8.0 引入的资源组(resource group,后面简写微RG)可以基本上解决这类问题。

比如我可以用 RG 来在SQL层面给他限制在特定的一个CPU核上,这样我就不管他,让他继续运行,如果有新的此类语句,让他排队好了。

为什么说基本呢?目前只能绑定CPU资源,其他的暂时不行。

那我来演示下如何使用RG。

创建一个资源组user_ytt. 这里解释下各个参数的含义,

type = user 表示这是一个用户态线程,也就是前台的请求线程。如果type=system,表示后台线程,用来限制mysql自己的线程,比如Innodb purge thread,innodb read thread等等。

vcpu 代表cpu的逻辑核数,这里0-1代表前两个核被绑定到这个RG。可以用lscpu,top等列出自己的CPU相关信息。

thread_priority 设置优先级。user 级优先级设置大于0。

mysqlmysql create resource group user_ytt type = user  vcpu = 0-1 thread_priority=19 enable;Query OK, 0 rows affected (0.03 sec)

RG相关信息可以从 information_schema.resource_groups 系统表里检索。

mysqlmysql select * from information_schema.resource_groups;+---------------------+---------------------+------------------------+----------+-----------------+| RESOURCE_GROUP_NAME | RESOURCE_GROUP_TYPE | RESOURCE_GROUP_ENABLED | VCPU_IDS | THREAD_PRIORITY |+---------------------+---------------------+------------------------+----------+-----------------+| USR_default         | USER                |                      1 | 0-3      |               0 || SYS_default         | SYSTEM              |                      1 | 0-3      |               0 || user_ytt            | USER                |                      1 | 0-1      |              19 |+---------------------+---------------------+------------------------+----------+-----------------+3 rows in set (0.00 sec)

我们来给语句select guid from t1 group by left(guid,8) order by rand() 赋予RG user_ytt。

mysql show processlist;+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+| Id  | User            | Host      | db   | Command | Time  | State                  | Info                                                      |+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+|   4 | event_scheduler | localhost | NULL | Daemon  | 10179 | Waiting on empty queue | NULL                                                      || 240 | root            | localhost | ytt  | Query   |   101 | Creating sort index    | select guid from t1 group by left(guid,8) order by rand() || 245 | root            | localhost | ytt  | Query   |     0 | starting               | show processlist                                          |+-----+-----------------+-----------+------+---------+-------+------------------------+-----------------------------------------------------------+3 rows in set (0.00 sec)

找到连接240对应的thread_id。

mysqlmysql select thread_id from performance_schema.threads where processlist_id = 240;+-----------+| thread_id |+-----------+|       278 |+-----------+1 row in set (0.00 sec)

给这个线程278赋予RG user_ytt。没报错就算成功了。

mysqlmysql set resource group user_ytt for 278;Query OK, 0 rows affected (0.00 sec)

当然这个是在运维层面来做的,我们也可以在开发层面结合 MYSQL HINT 来单独给这个语句赋予RG。比如:

mysqlmysql select /*+ resource_group(user_ytt) */guid from t1 group by left(guid,8) order by rand()....8388602 rows in set (4 min 46.09 sec)

RG的限制:

Linux 平台上需要开启 CAPSYSNICE 特性。比如我机器上用systemd 给mysql 服务加上

systemctl edit mysql@80 [Service]AmbientCapabilities=CAP_SYS_NICE

mysql 线程池开启后RG失效。

freebsd,solaris 平台thread_priority 失效。

目前只能绑定CPU,不能绑定其他资源。


网站栏目:mysql线程池怎么样 mysql 线程数与cpu的关系
文章分享:http://azwzsj.com/article/dddchee.html