MySQL详解(8)----------MySQL线程池总结(二)

这篇文章是对上篇文章的一个补充,主要围绕以下两点展开,one-connection-per-thread的实现方式以及线程池中epoll的使用。

one-connection-per-thread

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

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在线程中是如何使用的。

  1. 线程池初始化,epoll通过epoll_create函数创建epoll文件描述符,实现函数是thread_group_init;
  2. 端口监听线程监听到请求后,创建socket,并创建THD和connection对象,放在对应的group队列中;
  3. 工作线程获取该connection对象时,若还未登录,则进行登录验证
  4. 若socket还未注册到epoll,则调用epoll_ctl进行注册,注册方式是EPOLL_CTL_ADD,并将connection对象放入epoll_event结构体中
  5. 若是老连接的请求,仍然需要调用epoll_ctl注册,注册方式是EPOLL_CTL_MOD
  6. group内的监听线程调用epoll_wait来监听注册的fd,epoll是一种同步IO方式,所以会进行等待
  7. 请求到来时,获取epoll_event结构体中的connection,放入到group中的队列
  8. 线程池销毁时,调用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)相同

参考文档

http://www.cnblogs.com/Anker/p/3265058.html

http://blog.csdn.net/zhanglu5227/article/details/7960677

版权声明:欢迎转转载,希望转载的同时添加原文地址,谢谢合作,学习快乐!

时间: 2024-08-28 02:53:49

MySQL详解(8)----------MySQL线程池总结(二)的相关文章

JAVAWEB开发之事务详解(mysql与JDBC下使用方法、事务的特性、锁机制)和连接池的详细使用(dbcp以d3p0)

事务简介 事务的概念:事务指逻辑上的一组操作,组成这组操作的各个单元,要么全部成功,要么全部不成功 在开发中,有事务的存在,可以保证数据的完整性. 注意:数据库默认事务是自动提交的,也就是发一条SQL 就执行一条.如果想多条SQL语句放在一个事务中执行,需要添加事务有关的语句. 如何开启事务? 事务的操作方式: 创建表: create table account( id int primary key auto_increment, name varchar(20), money double

MySQL配置文件mysql.ini参数详解、MySQL性能优化

MySQL配置文件mysql.ini参数详解.MySQL性能优化 my.ini(Linux系统下是my.cnf),当mysql服务器启动时它会读取这个文件,设置相关的运行环境参数. my.ini分为两块:Client Section和Server Section.   Client Section用来配置MySQL客户端参数.   要查看配置参数可以用下面的命令: show variables like '%innodb%'; # 查看innodb相关配置参数 show status like

Linux下彻底卸载mysql详解

Linux下彻底卸载mysql详解 一.使用以下命令查看当前安装mysql情况,查找以前是否装有mysql 1 rpm -qa|grep -i mysql 可以看到如下图的所示: 显示之前安装了: MySQL-client-5.5.25a-1.rhel5 MySQL-server-5.5.25a-1.rhel5 2.停止mysql服务.删除之前安装的mysql 删除命令:rpm -e –nodeps 包名 1 2 rpm -ev MySQL-client-5.5.25a-1.rhel5  rpm

linux上源码安装MySQL详解

最近需要使用MySQL Fabric,这货是MySQL5.6.10之后才出现的utility.手头机器装的是MySQL5.1,所以需要先把旧版MySQL升级成5.6版本.之前没有玩过MySQL,所以这次稍微费了点事.在此,把过程记录下来,希望能给有需求的人提供一点帮助.下面我们就正式开始. 1. 删除老版本MySQL 其实删除老版MySQL是一件很简单的事,但是开始时候由于担心各个包的依赖会导致各种问题,亦步亦趋来得很慢.其实只需要做到这么几步就可以了: 1.1 查看已安装的mysql版本并删除

Ubuntu 16.04下安装MySQL详解

Ubuntu 16.04下安装MySQL详解分别依次输入以下3个命令: sudo apt-get install mysql-server sudo apt install mysql-client sudo apt install libmysqlclient-dev 安装成功后可以通过下面的命令测试是否安装成功: sudo netstat -tap | grep mysql 出现如下信息证明安装成功: >>> sudo netstat -tap | grep mysql tcp 0

Animation动画详解(六)——ValueAnimator高级进阶(二)

前言:人生总有不平时,无论何时,不后悔就好. 相关文章: 1.<Animation 动画详解(一)--alpha.scale.translate.rotate.set的xml属性及用法>2.<Animation动画详解(二)--Interpolator插值器>3.<Animation动画详解(三)-- 代码生成alpha.scale.translate.rotate.set及插值器动画>4.<Animation动画详解(四)--ValueAnimator基本使用&

maven详解之生命周期与插件(二)

插件配置 定义解释:插件目标 当我们了解了maven插件之后,我们发现如果为每一个功能编写一个独立的插件显然是不可取的,因为这些任务背后有很多可以复用的代码,因此,把这些功能聚集在一个插件里,每一个功能我们就称之为一个插件目标. 举个例子: maven-dependency-plugin有十多个目标,每个目标对应了一个功能 分析项目依赖:dependency:analyze 列出项目依赖树:dependency: tree 列出项目所有已解析的依赖:dependency:list POM中插件全

MySQL详解(7)-----------MySQL线程池总结(一)

线程池是Mysql5.6的一个核心功能,对于服务器应用而言,无论是web应用服务还是DB服务,高并发请求始终是一个绕不开的话题.当有大量请求并发访问时,一定伴随着资源的不断创建和释放,导致资源利用率低,降低了服务质量.线程池是一种通用的技术,通过预先创建一定数量的线程,当有请求达到时,线程池分配一个线程提供服务,请求结束后,该线程又去服务其他请求. 通过这种方式,避免了线程和内存对象的频繁创建和释放,降低了服务端的并发度,减少了上下文切换和资源的竞争,提高资源利用效率.所有服务的线程池本质都是位

mysql详解安装

三种安装方式 1 二进制  解压就用 2 YUM/RPM   适用于很多台服务器安装,编译好后,做成RPM包 适用于yum仓库 3 编译安装     自定安装,相当于自己DIY了...5.1安装用make,5.5安装要用cmake 安装二进制详解演示!! 显示系统名.节点名称.操作系统的发行版号.操作系统版本.运行系统的机器 ID 号. [[email protected] ~]# uname -aLinux sky-mysql 2.6.32-573.el6.x86_64 #1 SMP Thu