mysqld启动流程
1、设置断点break mysqld_main
2、启动时的bt栈
(gdb) bt
#0 mysqld_main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:4408
#1 0x0000000000e96ff0 in main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/main.cc:25
…………………………………………
…………………………………………
3、调整相关limits
adjust_related_options(&requested_open_files);
包括三个子函数
//调整open_files_limit
void adjust_open_files_limit(ulong *requested_open_files){
/* MyISAM requires two file handles per table. */
/*table_cache_size对应table_open_cache变量,表示所有线程同时打开表的最大数量(我们的配置4096)*/
limit_1= 10 + max_connections + table_cache_size * 2;//10+3000+4096*2=11202
/*
We are trying to allocate no less than max_connections*5 file
handles (i.e. we are trying to set the limit so that they will
be available).
*/
limit_2= max_connections * 5;
/* Try to allocate no less than 5000 by default. */
limit_3= open_files_limit ? open_files_limit : 5000;//默认为5000
request_open_files= max<ulong>(max<ulong>(limit_1, limit_2), limit_3);
/* Notice: my_set_max_open_files() may return more than requested. */
effective_open_files= my_set_max_open_files(request_open_files);
if (effective_open_files < request_open_files)//131072<15000
{
if (open_files_limit == 0)
{
sql_print_warning("Changed limits: max_open_files: %lu (requested %lu)",
effective_open_files, request_open_files);
}
else
{
sql_print_warning("Could not increase number of max_open_files to "
"more than %lu (request: %lu)",
effective_open_files, request_open_files);
}
}
open_files_limit= effective_open_files;
if (requested_open_files)
//将requested的值设置为effective_open_files
*requested_open_files= min<ulong>(effective_open_files,request_open_files);
}
调整最大连接数
void adjust_max_connections(ulong requested_open_files)
{
ulong limit;
limit= requested_open_files - 10 - TABLE_OPEN_CACHE_MIN * 2;
if (limit < max_connections)
{
sql_print_warning("Changed limits: max_connections: %lu (requested %lu)",
limit, max_connections);
// This can be done unprotected since it is only called on startup.
max_connections= limit;
}
}
//思考:在平时运维过程中,为什么我们设置了最大连接数为3000,但我们show最大连接数时候仍看到214
调整table_cache_size
void adjust_table_cache_size(ulong requested_open_files)
{
ulong limit;
limit= max<ulong>((requested_open_files - 10 - max_connections) / 2,
TABLE_OPEN_CACHE_MIN);
if (limit < table_cache_size)
{
sql_print_warning("Changed limits: table_open_cache: %lu (requested %lu)",
limit, table_cache_size);
table_cache_size= limit;
}
table_cache_size_per_instance= table_cache_size / table_cache_instances;
}
思考题:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YfIjHEtf-1572922906868)(C:\Users\zxz\AppData\Roaming\Typora\typora-user-images\1572835651351.png)]
void adjust_table_def_size()
{
ulong default_value;
sys_var *var;
default_value= min<ulong> (400 + table_cache_size / 2, 2000);
var= intern_find_sys_var(STRING_WITH_LEN("table_definition_cache"));
DBUG_ASSERT(var != NULL);
var->update_default(default_value);
if (! table_definition_cache_specified)
table_def_size= default_value;
}
线程池的初始化
(gdb) bt
#0 Connection_handler_manager::init () at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/connection_handler_manager.cc:175
#1 0x0000000000e9ee53 in mysqld_main (argc=326, argv=0x2e19728) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:4605
#2 0x0000000000e96ff0 in main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/main.cc:25
初始化流程
1、初始化连接管理类
预备知识:teledb的mysql的连接分为3类,分别是一个线程处理所有连接、一个连接对应对应一个线程(每连接每线程)、线程池,这3种处理连接的方式被封装成C++类,它们有一个共同的基类Connection_handler
bool Connection_handler_manager::init()
{
/*
This is a static member function.
Per_thread_connection_handler's static members need to be initialized
even if One_thread_connection_handler is used instead.
*/
/*
每连接每线程的初始化函数,
该函数的具体实现如下
*/
Per_thread_connection_handler::init();
/*
将connection_handler定义为线程池
ulong Connection_handler_manager::thread_handling=
SCHEDULER_THREAD_POOL;
*/
Connection_handler *connection_handler= NULL;
switch (Connection_handler_manager::thread_handling)
{
………………
………………
case SCHEDULER_THREAD_POOL:
connection_handler= new (std::nothrow) Thread_pool_connection_handler();
………………
………………
}
//Unix socket connection handler. By teledb 2018-1-25.
Connection_handler *extra_connection_handler=
new (std::nothrow) Per_thread_connection_handler();
if (connection_handler == NULL || extra_connection_handler == NULL)
{
// This is a static member function.
Per_thread_connection_handler::destroy();
return true;
}
/*
初始化连接管理类,封装每连接每线程类
*/
m_instance= new (std::nothrow) Connection_handler_manager(connection_handler, extra_connection_handler);
if (m_instance == NULL)
{
delete connection_handler;
// This is a static member function.
Per_thread_connection_handler::destroy();
return true;
}
………………
………………
return false;
}
network_init分析
功能:set_ports进行相应的初始化端口,另一个很重要的功能就是创建监听对象Mysqld_socket_listener,并对其进行相应的初始化操作,然后对listener进行相应的监听动作,最终是调用setup_listener()的方法来初始化listener的主要信息;(判断后续的连接是socket还是tcp连接的重要依据)
bt信息如下
(gdb) bt
#0 Mysqld_socket_listener::setup_listener (this=0x2f7aee0) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/socket_connection.cc:807
#1 0x0000000000ea8329 in Connection_acceptor<Mysqld_socket_listener>::init_connection_acceptor (this=0x99382000)
at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/connection_acceptor.h:55
#2 0x0000000000e99bae in network_init () at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:1651
#3 0x0000000000e9f90c in mysqld_main (argc=326, argv=0x2e19728) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:4927
#4 0x0000000000e96ff0 in main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/main.cc:25
setup_listenener的代码流程处理如下
bool Mysqld_socket_listener::setup_listener()
{
// Setup tcp socket listener
if (m_tcp_port)//9482
{
TCP_socket tcp_socket(m_bind_addr_str, m_tcp_port,
m_backlog, m_port_timeout);
MYSQL_SOCKET mysql_socket= tcp_socket.get_listener_socket();
if (mysql_socket.fd == INVALID_SOCKET)
return true;
m_socket_map.insert(std::pair<MYSQL_SOCKET,bool>(mysql_socket, false));
}
#if defined(HAVE_SYS_UN_H)
// Setup unix socket listener
if (m_unix_sockname != "")
{
Unix_socket unix_socket(&m_unix_sockname, m_backlog);
MYSQL_SOCKET mysql_socket= unix_socket.get_listener_socket();
if (mysql_socket.fd == INVALID_SOCKET)
return true;
m_socket_map.insert(std::pair<MYSQL_SOCKET,bool>(mysql_socket, true));
m_unlink_sockname= true;
}
#endif /* HAVE_SYS_UN_H */
// Setup for connection events for poll or select
#ifdef HAVE_POLL
int count= 0;
#endif
for (socket_map_iterator_t sock_map_iter= m_socket_map.begin();
sock_map_iter != m_socket_map.end(); ++sock_map_iter)
{
MYSQL_SOCKET listen_socket= sock_map_iter->first;
mysql_socket_set_thread_owner(listen_socket);
#ifdef HAVE_POLL
m_poll_info.m_fds[count].fd= mysql_socket_getfd(listen_socket);
m_poll_info.m_fds[count].events= POLLIN;
m_poll_info.m_pfs_fds[count]= listen_socket;
count++;
#else // HAVE_POLL
FD_SET(mysql_socket_getfd(listen_socket), &m_select_info.m_client_fds);
if ((uint) mysql_socket_getfd(listen_socket) > m_select_info.m_max_used_connection)
m_select_info.m_max_used_connection= mysql_socket_getfd(listen_socket);
#endif // HAVE_POLL
}
return false;
}
客户端连接处理流程分析
创建channel_info
(gdb) bt
#0 0x00002aaaac03abcd in poll () from /lib64/libc.so.6
#1 0x0000000001664389 in Mysqld_socket_listener::listen_for_connection_event (this=0x994e0070)
at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/socket_connection.cc:860
#2 0x0000000000ea8352 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop (this=0x99381c40)
at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/connection_acceptor.h:66
#3 0x0000000000e9fdd9 in mysqld_main (argc=326, argv=0x2e19728) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:5135
#4 0x0000000000e96ff0 in main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/main.cc:25
1、通过如下方式判断到底是socket请求还是tcp请求,然后获取相应的listen_sock
#ifdef HAVE_POLL
for (uint i= 0; i < m_socket_map.size(); ++i)
{
if (m_poll_info.m_fds[i].revents & POLLIN)
{
listen_sock= m_poll_info.m_pfs_fds[i];
is_unix_socket= m_socket_map[listen_sock];
break;
}
}
2、获取mysql_socket
connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,
(struct sockaddr *)(&cAddr), &length);
3、根据sock类型建立相应的channel通道
Channel_info* channel_info= NULL;
if (is_unix_socket)
channel_info= new (std::nothrow) Channel_info_local_socket(connect_sock);
else
channel_info= new (std::nothrow) Channel_info_tcpip_socket(connect_sock);
创建新的连接
(gdb) bt
#0 Connection_handler_manager::process_new_connection (this=0x2f2c010, channel_info=0x99641540)
at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/connection_handler_manager.cc:301
#1 0x0000000000ea8370 in Connection_acceptor<Mysqld_socket_listener>::connection_event_loop (this=0x2f81ee0)
at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/conn_handler/connection_acceptor.h:68
#2 0x0000000000e9fdd9 in mysqld_main (argc=326, argv=0x2e19728) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/mysqld.cc:5135
#3 0x0000000000e96ff0 in main (argc=4, argv=0x7fffffffdee8) at /mysql/zxz/tianyicloud/mysql-5.7.21/sql/main.cc:25
1、process_new_connection代码如下:
void Connection_handler_manager::process_new_connection(Channel_info* channel_info)
{
/*
判断是哪种类型的连接,是socket还是tcp
*/
bool is_unix_socket_connection = channel_info->vio_type() == VIO_TYPE_SOCKET;
/*
通过check_and_incr_conn_count函数来判断socket连接数或者tcp连接数是否超过预设值,socket目前代码里固定为20,tcp连接数根据配置文件以及相关的open_files_limits来决定
*/
if (abort_loop || !check_and_incr_conn_count(is_unix_socket_connection))
{
channel_info->send_error_and_close_channel(ER_CON_COUNT_ERROR, 0, true);
delete channel_info;
return;
}
/*
根据是socket连接类型还是tcp连接类型来决定Connection_handler,继而使用后面的add_connection
*/
Connection_handler* handler= is_unix_socket_connection ? m_extra_connection_handler : m_connection_handler;
if (handler->add_connection(channel_info))
{
inc_aborted_connects();
delete channel_info;
}
}