MySQL源码学习之Connection Manager详解

MySQL数据库Connection Manager的相关知识是本文我们主要要介绍到内容,接下来就让我们一起来了解一下吧。

1.连接的线程数

MySQL支持单线程和多线程两种连接线程数。如果是单线程,则在同一时刻,只能有一个connection连接到MySQL,其他的连接会被挂起。如果是多线程,则同一时刻可以支持多个connection同时连接到服务器。可以通过设置服务器的启动参数来设定连接的线程数:

  1. mysqld.exe --thread-handling=no-threads  
  2. mysqld.exe --thread-handling=one-thread-per-connection 

 

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

  1. #ifdef EMBEDDED_LIBRARY  
  2. one_thread_scheduler(&thread_scheduler);  
  3. #else  
  4. if (global_system_variables.thread_handling <=  
  5. SCHEDULER_ONE_THREAD_PER_CONNECTION)  
  6. one_thread_per_connection_scheduler(&thread_scheduler);  
  7. else if (global_system_variables.thread_handling == SCHEDULER_NO_THREADS)  
  8. one_thread_scheduler(&thread_scheduler);  
  9. else  
  10. pool_of_threads_scheduler(&thread_scheduler); /* purecov: tested */  
  11. #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,其中有个分支,代码如下:

 

  1. case OPT_THREAD_HANDLING:  
  2. {  
  3. global_system_variables.thread_handling=  
  4. find_type_or_exit(argument, &thread_handling_typelib, opt->name)-1;  
  5. break;  

 

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

 

  1. void one_thread_scheduler(scheduler_functions* func)  
  2. {  
  3. func->max_threads1;  
  4. #ifndef EMBEDDED_LIBRARY  
  5. func->add_connectionhandle_connection_in_main_thread;  
  6. #endif  
  7. func->init_new_connection_threadinit_dummy;  
  8. func->end_threadno_threads_end;  
  9. }  
  10.  
  11. void one_thread_per_connection_scheduler(scheduler_functions* func)  
  12. {  
  13. func->max_threadsmax_connections;  
  14. func->add_connectioncreate_thread_to_handle_connection;  
  15. func->end_threadone_thread_per_connection_end;  
  16. }  

 

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

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

2.初始化网络配置

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

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

 

  1. network_init  
  2. {  
  3. set_ports; //设置端口号,#define MYSQL_PORT 3306  
  4. socket; //创建套接字  
  5. bind; //绑定端口号  
  6. 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选项。启动时可以通过下面的参数进行设置。

 

  1. mysqld.exe --enable-named-pipe  
  2. mysqld.exe --shared-memory 

 

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

 

  1. handle_connections_methods()  
  2. {  
  3. if (hPipe != INVALID_HANDLE_VALUE)  
  4. {  
  5. handler_count++;  
  6. if (pthread_create(&hThread,&connection_attrib,  
  7. handle_connections_namedpipes, 0))  
  8. {  
  9. sql_print_warning("Can't create thread to handle named pipes");  
  10. handler_count--;  
  11. }  
  12. }  
  13. if (have_tcpip && !opt_disable_networking)  
  14. {  
  15. handler_count++;  
  16. if (pthread_create(&hThread,&connection_attrib,  
  17. handle_connections_sockets, 0))  
  18. {  
  19. sql_print_warning("Can't create thread to handle TCP/IP");  
  20. handler_count--;  
  21. }  
  22. }  
  23.  
  24. if (opt_enable_shared_memory)  
  25. {  
  26. handler_count++;  
  27. if (pthread_create(&hThread,&connection_attrib,  
  28. handle_connections_shared_memory, 0))  
  29. {  
  30. sql_print_warning("Can't create thread to handle shared memory");  
  31. handler_count--;  
  32. }  
  33. }  

 

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

4.socket管理创建新线程

socket管理其实比较简单,直接给出其伪代码:

 

  1. handle_connections_sockets  
  2. {  
  3. select; //监视socket文件描述符  
  4. new_socket = accept;//处理到来的客户端连接  
  5. thd = new THD;创建THD类  
  6. vio_tmp = vio_new(new_socket,VIO_TYPE_TCPIP, 0); //初始化VIO结构体  
  7. my_net_init(&thd->net, vio_tmp);//初始化thd的net结构体  
  8. create_new_thread(thd);//为这个连接创建一个新的线程,如果是单线程模式的话,就不会创建一个新线程  

 

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

 

  1. create_new_thread  
  2. {  
  3. ++connection_count;//全局连接数自增  
  4. thread_count++; //全局线程数自增  
  5. 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:

 

  1. create_thread_to_handle_connection(THD *thd)  
  2. {  
  3. thread_created++;  
  4. threads.append(thd); // 创建线程数自增,并加入到threads链表上  
  5. pthread_create(&thd->real_id,&connection_attrib,  
  6. handle_one_connection,  
  7. (void*) thd);//这就是真正创建线程的地方了,函数便是handle_one_connection  

 

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

5.新线程处理流程

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

是如何进行处理的。

 

  1. handle_one_connection(void *arg)  
  2. {  
  3. for (;;)  
  4. {  
  5. lex_start(thd); //初始化词法分析结构体  
  6. login_connection(thd); //用户认证,失败报错  
  7. prepare_new_connection_state(THD* thd);//Initialize THD to handle queries  
  8. while (!net->error && net->vio != 0 && //循环处理command  
  9. !(thd->killed == THD::KILL_CONNECTION))  
  10. {  
  11. if (do_command(thd))  
  12. break; //处理失败跳出  
  13. }  
  14. end_connection(thd); //关闭连接  
  15. close_connection(thd, 0, 1);  
  16. thread_scheduler.end_thread(thd,1);//结束线程  
  17. return 0;  
  18. }  

 

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

6.总结

整个connection manager的流程十分清晰,单线程的连接一般很少使用,大多使用多线程方式。多线程连接中其实还涉及到线程缓冲池的概念,即如果一个连接断开后,其所创建的线程不会被销毁掉,而是放到缓冲池中,等待下一个新的connection到来时,首先去线程缓冲池查找是否有空闲的线程,有的话直接使用,木有的话才去创建新的线程来管理这个connection。

关于MySQL数据库Connection Manager的相关知识就介绍到这里了,希望本次的介绍能够对您有所收获!

【编辑推荐】

  1. MySQL数据库my.cnf配置文件注释详解
  2. SQL Server数据库复制失败的原因及解决方案
  3. SQL Server 2005数据库游标调用函数实例解析
  4. MySQL数据库中EXPLAIN的使用及其注意事项详解
  5. SQL Server数据库用视图来处理复杂的数据查询关系

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/225480.html<

(0)
运维的头像运维
上一篇2025-04-16 22:20
下一篇 2025-04-16 22:21

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注