关于MYSQL 5.7 新连接建立流程源码接口(和5.6不同)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 原创 水平有限 今天在看运维内参第三章源码的时候,发现书上很多代码入口函数和我用的5.7.14的源码对不上,然后再看了一下5.6的源码, 书上写的基本都是5.6的源码(书是2015年开始写的)5.7.14在连接这一块做了相当大的改动,加了很多抽象类,变得更加复杂了。
原创 水平有限

今天在看运维内参第三章源码的时候,发现书上很多代码入口函数和我用的5.7.14的源码对不上,然后再看了一下5.6的源码,
书上写的基本都是5.6的源码(书是2015年开始写的)5.7.14在连接这一块做了相当大的改动,加了很多抽象类,变得更加复杂了。
当然这也是软件模块划分的更加清晰的必然的结果,顺便说一下MYSQL在UNIX上使用的select/poll 这种多路I/O转接模型来监听
客户端的连接,监听的只是读操作,当客户端发起连接的时候select/poll通过监听LISTEN scoket上的是否有读取信息来判断,是否
有新的连接到来,然后调用线程回调函数建立新的线程来处理这个新的accpet的socket通道(还会判断是否有空闲的线程队列而不需要
新建立新的线程来处理),线程的建立我们说是比进程代价小很多,他没有独立的内存三区(共享区,代码段和堆内存),但是他也有PCB
有独立的栈空间所以能节约一点是一点吧。
关于MYSQL的源码各种多态太多了,真是眼花缭乱

下面是我使用到一些断点。

(gdb) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x0000000000ebd333 in main(int, char**) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25
        breakpoint already hit 1 time
2       breakpoint     keep y   0x00000000016e350d in inline_mysql_socket_accept(char const*, uint, PSI_socket_key, MYSQL_SOCKET, sockaddr*, socklen_t*) at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
        breakpoint already hit 18 times
6       breakpoint     keep y   0x0000000000f1b8d9 in Connection_handler_manager::process_new_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
        breakpoint already hit 15 times
8       breakpoint     keep y   0x00000000016e197f in handle_connection(void*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:239
        breakpoint already hit 6 times
9      breakpoint     keep y   0x0000000000f1b1d5 in Connection_handler_manager::check_and_incr_conn_count(bool) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
        breakpoint already hit 1 time
12      breakpoint     keep y   0x00000000016e1f41 in Per_thread_connection_handler::add_connection(Channel_info*) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399


下面按照调用流程解释一下这几个函数作用,希望帮到在5.7.14下使用GDB调试MYSQL连接的同学一点帮助
1、不解释主函数main

2、  inline_mysql_socket_accept
 当然也就是sokcet accept返回新的socket文件描述符的函数,因为找不到多路I/O转接 select和poll的入口用了这招去找
  找到多路I/O转接接口变为了Channel_info* Mysqld_socket_listener::listen_for_connection_event()
  Channel_info就是一个抽象类,这个函数会返回连接socket的相关信息给   Channel_info这个基类指针
  又有多太发生了擦。
  
这里贴出一点和运维内参同样的代码,但是入口函数全部变了,而且除了逻辑相似,很多实现都变了
大量的用 多态

点击(此处)折叠或打开

  1. #ifdef HAVE_POLL //多路I/O转接判断是否有写连接到来
  2.   int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
  3. #else
  4.   m_select_info.m_read_fds= m_select_info.m_client_fds;
  5.   int retval= select((int) m_select_info.m_max_used_connection,
  6.                      &m_select_info.m_read_fds, 0, 0, 0);
  7. #endif


点击(此处)折叠或打开

  1. #ifdef HAVE_POLL //多路I/O转接判断是否有写连接到来
  2.   int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);
  3. #else
  4.   m_select_info.m_read_fds= m_select_info.m_client_fds;
  5.   int retval= select((int) m_select_info.m_max_used_connection,
  6.                      &m_select_info.m_read_fds, 0, 0, 0);
  7. #endif

点击(此处)折叠或打开

  1. for (uint retry= 0; retry < MAX_ACCEPT_RETRY; retry++) //重试次数MAX_ACCEPT_RETRY好像是10
  2.   {
  3.     socket_len_t length= sizeof(struct sockaddr_storage);
  4.     connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,
  5.                                       (struct sockaddr *)(&cAddr), &length);//这里没什么好说的返回新的sokcet文件描述符了
  6.     if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||//返回的新的socket文件描述符无效(-1)
  7.         (socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN)) //如果是信号中断或者eagain重试没关系再来
  8.       break;
  9.   }

点击(此处)折叠或打开

  1. Channel_info* channel_info= NULL;
  2. //注意下面有多态发生这里和5.6很多不同了
  3.   if (is_unix_socket) //是否是本地UNIX_DOMAIN SOCKET
  4.     channel_info= new (std::nothrow) Channel_info_local_socket(connect_sock);
  5.   else//不是就是远程TCP/IP SCOKET
  6.     channel_info= new (std::nothrow)
  7.       Channel_info_tcpip_socket(connect_sock,
  8.                                 (mysql_socket_getfd(listen_sock)
  9.                                  == m_extra_tcp_port_fd)); //根据connect_scok 建立channel_info
  10.  
  11.   if (channel_info == NULL) //分配内存是否正常不正常搞下面的。
  12.   {
  13.     (void) mysql_socket_shutdown(connect_sock, SHUT_RDWR);
  14.     (void) mysql_socket_close(connect_sock);
  15.     connection_errors_internal++;
  16.     return NULL;
  17.   }

  18.   return channel_info;

栈帧
#0  inline_mysql_socket_accept (src_file=0x21c5f30 "/root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc", src_line=928, key=3, socket_listen=..., addr=0x7fffffffdc50, addr_len=0x7fffffffdcdc)
    at /root/mysql5.7.14/percona-server-5.7.14-7/include/mysql/psi/mysql_socket.h:1110
#1  0x00000000016e4981 in Mysqld_socket_listener::listen_for_connection_event (this=0x2fca760) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/socket_connection.cc:928
#2  0x0000000000ecf016 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:66
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25

6、 Connection_handler_manager::process_new_connection,通过 Channel_info指针指向的SCOKET信息建立新线程

栈帧
#1  0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25

9、  Connection_handler_manager::check_and_incr_conn_count(bool) 
   这里判断 MAX_CONNECTIONS是否合适这里也和运维内参说的5.6的代码有了
很大的不同,但是逻辑一样如下:


点击(此处)折叠或打开

  1. if (extra_port_connection)
  2.   {
  3.     if (extra_connection_count > extra_max_connections)
  4.     {
  5.       connection_accepted= false;
  6.       m_connection_errors_max_connection++;
  7.     }
  8.     else
  9.     {
  10.       ++extra_connection_count;
  11.     }
  12.   }
  13.   else if (connection_count > max_connections)
  14.   {
  15.     connection_accepted= false;
  16.     m_connection_errors_max_connection++;
  17.   }
GDB如下:

(gdb) n
106       mysql_mutex_lock(&LOCK_connection_count);
(gdb) n
115       if (extra_port_connection)
(gdb) n
127       else if (connection_count > max_connections)
(gdb) P  max_connections
$4 = 6
(gdb) p connection_count
$5 = 7
(gdb) n
129         connection_accepted= false;
(gdb) n
130         m_connection_errors_max_connection++;
(gdb) n
141       mysql_mutex_unlock(&LOCK_connection_count);
(gdb) n
142       return connection_accepted;

栈帧
#0  Connection_handler_manager::check_and_incr_conn_count (this=0x2e98fc0, extra_port_connection=false) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:105
#1  0x0000000000f1b904 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:289
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25


12、  Per_thread_connection_handler::add_connection(Channel_info*) 这个函数会判断连接队列是否有空闲的,如果没有调用 mysql_thread_create建立新的线程
截取如下:

点击(此处)折叠或打开

  1. if (!check_idle_thread_and_enqueue_connection(channel_info)) //判断是否有空闲的连接队里
  2.     DBUG_RETURN(false);
  3.   /*
  4.     There are no idle threads avaliable to take up the new
  5.     connection. Create a new thread to handle the connection
  6.   */
  7.   error= mysql_thread_create(key_thread_one_connection, &id, //建立新的线程对接
  8.                              &connection_attrib,
  9.                              handle_connection,
  10.                              (void*) channel_info);
栈帧
#0  Per_thread_connection_handler::add_connection (this=0x2f67b10, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_per_thread.cc:399
#1  0x0000000000f1b9c6 in Connection_handler_manager::process_new_connection (this=0x2e98fc0, channel_info=0x34c4a30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_handler_manager.cc:301
#2  0x0000000000ecf034 in Connection_acceptor::connection_event_loop (this=0x2fc9b30) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/conn_handler/connection_acceptor.h:68
#3  0x0000000000ec6a06 in mysqld_main (argc=52, argv=0x2e97438) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/mysqld.cc:5287
#4  0x0000000000ebd344 in main (argc=9, argv=0x7fffffffe418) at /root/mysql5.7.14/percona-server-5.7.14-7/sql/main.cc:25

8、  handle_connection(void*)  这里就是5.7.16真正的回调函数用于建立线程,这里就不解释了,因为这里只是分析流程,以后在详细研究




这里终于找到了建立线程的回调函数,调试有时候不知道入口函数名字也是一种悲剧




作者微信:

               

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
5天前
|
SQL 存储 缓存
MySQL执行流程
本文介绍了MySQL的执行流程,分为server层和引擎层。server层包含连接器、查询缓存、解析器、预处理器、优化器等组件,负责SQL的接收、解析、优化及执行;引擎层负责数据的存储与读取。文章详细解释了各组件的功能,如连接器负责用户身份认证,查询缓存提高查询效率,解析器进行SQL的词法和语法分析,预处理器验证表和字段的存在性,优化器选择最优执行计划,最终由查询执行引擎完成查询并将结果返回给客户端。
MySQL执行流程
|
12天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
18天前
|
关系型数据库 MySQL 网络安全
DBeaver连接MySQL提示Access denied for user ‘‘@‘ip‘ (using password: YES)
“Access denied for user ''@'ip' (using password: YES)”错误通常与MySQL用户权限配置或网络设置有关。通过检查并正确配置用户名和密码、用户权限、MySQL配置文件及防火墙设置,可以有效解决此问题。希望本文能帮助您成功连接MySQL数据库。
32 4
|
1月前
|
安全 关系型数据库 MySQL
【赵渝强老师】MySQL的连接方式
本文介绍了MySQL数据库服务器启动后的三种连接方式:本地连接、远程连接和安全连接。详细步骤包括使用root用户登录、修改密码、创建新用户、授权及配置SSL等。并附有视频讲解,帮助读者更好地理解和操作。
|
1月前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,并与使用 RPM 包安装进行了对比
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,并与使用 RPM 包安装进行了对比。通过具体案例,读者可以了解如何准备环境、下载源码、编译安装、配置服务及登录 MySQL。编译源码安装虽然复杂,但提供了更高的定制性和灵活性,适用于需要高度定制的场景。
97 3
|
1月前
|
关系型数据库 MySQL Linux
在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。
本文介绍了在 CentOS 7 中通过编译源码方式安装 MySQL 数据库的详细步骤,包括准备工作、下载源码、编译安装、配置 MySQL 服务、登录设置等。同时,文章还对比了编译源码安装与使用 RPM 包安装的优缺点,帮助读者根据需求选择最合适的方法。通过具体案例,展示了编译源码安装的灵活性和定制性。
128 2
|
2月前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
120 6
|
1月前
|
存储 SQL NoSQL
|
2月前
|
SQL JavaScript 关系型数据库
node博客小项目:接口开发、连接mysql数据库
【10月更文挑战第14天】node博客小项目:接口开发、连接mysql数据库
|
8天前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
71 15