热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

Mysql源码学习――ConnectionManager_MySQL

Mysql源码学习――ConnectionManager
bitsCN.com

1.连接的线程数

Mysql支持单线程和多线程两种连接线程数。如果是单线程,则在同一时刻,只能有一个connection连接到Mysql,

其他的连接会被挂起。如果是多线程,则同一时刻可以支持多个connection同时连接到服务器。

可以通过设置服务器的启动参数来设定连接的线程数:

mysqld.exe --thread-handling=no-threads

mysqld.exe --thread-handling=one-thread-per-connection

  

服务器如何通过参数来选择使用哪种方式的呢?且看服务器中的分支代码:

#ifdef EMBEDDED_LIBRARY

one_thread_scheduler(&thread_scheduler);

#else

if (global_system_variables.thread_handling <=

SCHEDULER_ONE_THREAD_PER_CONNECTION)

one_thread_per_connection_scheduler(&thread_scheduler);

else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)

one_thread_scheduler(&thread_scheduler);

else

pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */

#endif

  

这段代码出现在get_options函数中,此函数是根据传入的服务器参数,设置相应参数的模式。由这段代码可以看出,如果定义了EMBEDDED_LIBRARY宏定义(估计应该是嵌入式使用),则调用one_thread_scheduler,即使用单线程。如果参数小于等于SCHEDULER_ONE_THREAD_PER_CONNECTION,则调用one_thread_per_connection_scheduler,即每个连接一个线程,即多线程。 至于global_system_variables.thread_handling是如何进行设置的呢?其实就是根据我们传递给服务器的参数--thread-handling进行设置的,参数的设置统一在函数get_options中,其调用mysqld_get_one_option,其中有个分支,代码如下:

case OPT_THREAD_HANDLING:

{

global_system_variables.thread_handling=

find_type_or_exit(argument, &thread_handling_typelib, opt->name)-1;

break;

}

  

对参数初始化有兴趣的可以具体的看下get_options这个函数,这里就不详细讲解了。 我们来看下one_thread_scheduler和one_thread_per_connection_scheduler的源代码,看下他们都做了些什么?

void one_thread_scheduler(scheduler_functions* func)

{

func->max_threads= 1;

#ifndef EMBEDDED_LIBRARY

func->add_cOnnection= handle_connection_in_main_thread;

#endif

func->init_new_connection_thread= init_dummy;

func->end_thread= no_threads_end;

}

void one_thread_per_connection_scheduler(scheduler_functions* func)

{

func->max_threads= max_connections;

func->add_cOnnection= create_thread_to_handle_connection;

func->end_thread= one_thread_per_connection_end;

}

  

原来就是设置了一个结构体中scheduler_functions的参数,只不过这些参数是一些函数指针罢了,也就是说在具体的调用中,

只需要调用add_connection或end_thread即可,不需要知道到底是调用了哪个函数,这大概就是一种变形的多态性吧。

2.初始化网络配置

网络配置比较简单,就是设置端口,创建套接字,绑定端口,监听端口。实现全部集中在network_init函数中,由于这个函数确

实没什么好讲的,如果对socket不熟悉的话,可以去网上搜索下相关知识。这里直接给出相应的伪代码:

network_init

{

set_ports; //设置端口号,#define MYSQL_PORT 3306

socket;//创建套接字

bind; //绑定端口号

listen;//监听端口号

}

3.连接的方式

进程间通信的方式不止是SOCKET,还有其他很多方式。Mysql支持三种连接方式:namepipe、socket和shared memory,

即命名管道、套接字和共享内存的方式。这三种方式是可以共存的。默认只使用套接字。

TCP/IP套接字方式是MySQL在任何平台下都提供的连接方式,也是网络中使用得最多的一种方式。这种方式在TCP/IP连接上建立

一个基于网络的连接请求,一般情况下客户端在一台服务器上,而MySQL实例在另一台服务器上,这两台机器通过一个TCP/IP网络连接。

例如,我可以在Windows服务器下请求一台远程Linux服务器下的MySQL实例。

在Windows 2000、Windows XP、Windows 2003和Windows Vista以及在此之后的Windows操作系统中,如果两个需要通

信的进程在同一台服务器上,那么可以使用命名管道,SQL Server数据库默认安装后的本地连接也使用命名管道。在MySQL数据库中,

需在配置文件中启用--enable-named-pipe选项。在MySQL 4.1之后的版本中,MySQL还提供了共享内存的连接方式,在配置文件中

添加--shared-memory。如果想使用共享内存的方式,在连接时,Mysql客户端还必须使用-protocol=memory选项。

启动时可以通过下面的参数进行设置。

mysqld.exe --enable-named-pipe

mysqld.exe --shared-memory

  

除了在启动时进行参数设置外,也可以通过修改MY.INI文件进行设置。我们来看下源码中选择连接方式的分支函数handle_connections_methods:

handle_connections_methods()

{

if (hPipe != INVALID_HANDLE_VALUE)

{

handler_count++;

if (pthread_create(&hThread,&connection_attrib,

handle_connections_namedpipes, 0))

{

sql_print_warning("Can&#39;t create thread to handle named pipes");

handler_count--;

}

}

if (have_tcpip && !opt_disable_networking)

{

handler_count++;

if (pthread_create(&hThread,&connection_attrib,

handle_connections_sockets, 0))

{

sql_print_warning("Can&#39;t create thread to handle TCP/IP");

handler_count--;

}

}

if (opt_enable_shared_memory)

{

handler_count++;

if (pthread_create(&hThread,&connection_attrib,

handle_connections_shared_memory, 0))

{

sql_print_warning("Can&#39;t create thread to handle shared memory");

handler_count--;

}

}

}

  

由于对于namepipe和memory share的通信方式不太了解,这里只研究socket的通信方式。从代码中可以看出,handle_connections_sockets便是socket的设置,我们就来看下它。

4.socket管理创建新线程socket管理其实比较简单,直接给出其伪代码:

handle_connections_sockets

{

select; //监视socket文件描述符

new_socket = accept;//处理到来的客户端连接

thd = new THD;创建THD类

vio_tmp = vio_new(new_socket,VIO_TYPE_TCPIP, 0); //初始化VIO结构体

my_net_init(&thd->net, vio_tmp);//初始化thd的net结构体

create_new_thread(thd);//为这个连接创建一个新的线程,如果是单线程模式的话,就不会创建一个新线程

}

  

首先是select函数进行监视socket端口,如果监控到有连接,则通过accept函数接受客户端的连接,然后新建一个THD类,将连接参数全部设置到THD类的参数上,最后调用create_new_thread函数,这个函数便是重点。 我们进入这个函数,看下做了啥。

create_new_thread

{

++connection_count;//全局连接数自增

thread_count++; //全局线程数自增

thread_scheduler.add_connection(thd);//真正创建线程

}

  

So easy,首先将全局连接数+1,全局线程数+1,然后调用add_connection函数,这个函数就是我们在上面第一步设置连接的

线程数中,one_thread_scheduler和one_thread_per_connection_scheduler中设置的一个参数。这两者的区别便是是否创建了

一个新的线程来处理到来的连接。one_thread_scheduler是单线程方式,木有新建线程。我们重点研究one_thread_per_connection_scheduler,其设置的add_connection函数为create_thread_to_handle_connection:

create_thread_to_handle_connection(THD *thd)

{

thread_created++;

threads.append(thd); // 创建线程数自增,并加入到threads链表上

pthread_create(&thd->real_id,&connection_attrib,

handle_one_connection,

(void*) thd);//这就是真正创建线程的地方了,函数便是handle_one_connection

}

  

可见,最后调用了pthread_create函数,这个函数便是创建一个新的线程,新线程的处理函数为handle_one_connection.

5.新线程处理流程

新线程处理函数为handle_one_connection,到此位置,一个新的connection被一个新创建的线程所单独处理。我们看下其中

是如何进行处理的。

handle_one_connection(void *arg)

{

for (;;)

{

lex_start(thd); //初始化词法分析结构体

login_connection(thd); //用户认证,失败报错

prepare_new_connection_state(THD* thd);//Initialize THD to handle queries

while (!net->error && net->vio != 0 && //循环处理command

!(thd->killed == THD::KILL_CONNECTION))

{

if (do_command(thd))

break; //处理失败跳出

}

end_connection(thd); //关闭连接

close_connection(thd, 0, 1);

thread_scheduler.end_thread(thd,1);//结束线程

return 0;

}

}

  

首先进行了词法分析结构体的初始化,然后进行用户认证,认证成功后通过do_command循环执行客户端发过来的命令。

6.总结

整个connection manager的流程十分清晰,单线程的连接一般很少使用,大多使用多线程方式。多线程连接中其实还涉及到线程缓冲

池的概念,即如果一个连接断开后,其所创建的线程不会被销毁掉,而是放到缓冲池中,等待下一个新的connection到来时,首先去线程

缓冲池查找是否有空闲的线程,有的话直接使用,木有的话才去创建新的线程来管理这个connection。这些属于Thread Manage的内容,

下节进行Thread Manage的学习。

PS. 上周六迎来第一个双休,结果还是被叫道公司改BUG,我忍。不过,BOSS,前几个月的加班费啥时候发啊?不准拖欠民工工资…

踏着落叶,追寻着我的梦想。转载请注明出处



摘自 心中无码 bitsCN.com
推荐阅读
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 本文介绍了如何在MySQL中将零值替换为先前的非零值的方法,包括使用内联查询和更新查询。同时还提供了选择正确值的方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
author-avatar
喵喵妈70929
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有