Mysql中Connection Manager的作用是什么

68次阅读
没有评论

共计 5613 个字符,预计需要花费 15 分钟才能阅读完成。

这篇文章给大家介绍 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。这些属于 Thread Manage 的内容,

关于 Mysql 中 Connection Manager 的作用是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-03发表,共计5613字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)