关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » MySQL »MySQL源码学习之Connection Manager详解

    MySQL源码学习之Connection Manager详解

    2011-08-23 13:56:00 出处:ITJS
    分享

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

    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'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'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'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。

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

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    Cornell大神Kleinberg的经典教材《算法设计》是最好入门的算法教材

    从 Microsoft 下载中心安装 Windows 7 SP1 和 Windows Server 2008 R2 SP1 之前要执行的步骤

    Llama 2基于UCloud UK8S的创新应用

    火山引擎DataTester:如何使用A/B测试优化全域营销效果

    腾讯云、移动云继阿里云降价后宣布大幅度降价

    字节跳动数据平台论文被ICDE2023国际顶会收录,将通过火山引擎开放相关成果

    这个话题被围观超10000次,火山引擎VeDI如此解答

    误删库怎么办?火山引擎DataLeap“3招”守护数据安全

    IT头条

    平替CUDA!摩尔线程发布MUSA 4性能分析工具

    00:43

    三起案件揭开侵犯个人信息犯罪的黑灰产业链

    13:59

    百度三年开放2.1万实习岗,全力培育AI领域未来领袖

    00:36

    工信部:一季度,电信业务总量同比增长7.7%,业务收入累计完成4469亿元

    23:42

    Gartner:2024年全球半导体营收6559亿美元,AI助力英伟达首登榜首

    18:04

    技术热点

    iOS 8 中如何集成 Touch ID 功能

    windows7系统中鼠标滑轮键(中键)的快捷应用

    MySQL数据库的23个特别注意的安全事项

    Kruskal 最小生成树算法

    Ubuntu 14.10上安装新的字体图文教程

    Ubuntu14更新后无法进入系统卡在光标界面解怎么办?

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。