mysql 启动 连接_MySQL启动流程与连接简析

最近两天自己简单分析了MySQL的启动过程,以及连接建立等过程,参考了几本经典的资料,整理下,也算是个小结。

MySQL 源码是C++的,所以入口是main() 函数。

main 函数中只有一个mysqld_main 函数。

1 各种系统变量的初始化

进入mysqld_main ,首先看到了好多变量的初始化。好多目前我还不知道具体是干嘛用的,就只展示几个核心的。如果感兴趣,可以看下《MySQL运维内参》。

if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))

{

flush_error_log_messages();

return 1;

}

复制代码

这个是加载配置。在我们启动mysqld 时指定了default-file 就用了这个函数。

system_charset_info= &my_charset_utf8_general_ci;

复制代码

这个配置了系统默认的编码格式,因为系统启动时传入了好多参数,需要解析。

在初始化部分,有一个是核心模块的初始化,单独拿出来说下。

2 核心模块的初始化

if (init_server_components())

unireg_abort(MYSQLD_ABORT_EXIT);

复制代码

这个是初始化核心组件。里面有query cache 初始化,随机数初始化, transaction cache 初始化, bin log 相关的配置,慢查询日志相关,还有最重要的是存储引擎的设定。 后面其他初始化就不写了,暂时也不知道什么用途,用到了再回头看。

3 启动socket连接

MySQL也是C/S结构,所以服务端需要启动起来,等待客户端的连接,那我们就简单看下。

tcp/ip 模式,bind /listen/ accept 等待客户端请求的到来。代码如下:

mysqld_socket_acceptor->connection_event_loop();

void connection_event_loop()

{

Connection_handler_manager *mgr= Connection_handler_manager::get_instance();

while (!abort_loop)

{

Channel_info *channel_info= m_listener->listen_for_connection_event();

if (channel_info != NULL)

mgr->process_new_connection(channel_info);

}

}

复制代码

上述函数的作用是:

Connection acceptor loop to accept connections from clients.

其核心函数是

connection_event_loop 是个while循环,利用 listen_for_connection_event 进行poll或者select监听,如果发现有请求,就调用process_new_connection 产生一个新的连接。

下面我们简单看下上述提到的几个函数的主要用途:

listen_for_connection_event,有如下三种方式:

e0c604ccbbd38d8304b8bf22317c353f.png

我们来看下socket的方式:

Channel_info* Mysqld_socket_listener::listen_for_connection_event()

{

// 通过poll监听

int retval= poll(&m_poll_info.m_fds[0], m_socket_map.size(), -1);

...

MYSQL_SOCKET connect_sock;

struct sockaddr_storage cAddr;

// 通过mysql_socket_accept 建立socket连接。

for (uint retry= 0; retry < MAX_ACCEPT_RETRY; retry++)

{

socket_len_t length= sizeof(struct sockaddr_storage);

connect_sock= mysql_socket_accept(key_socket_client_connection, listen_sock,

(struct sockaddr *)(&cAddr), &length);

if (mysql_socket_getfd(connect_sock) != INVALID_SOCKET ||

(socket_errno != SOCKET_EINTR && socket_errno != SOCKET_EAGAIN))

break;

}

...

...

复制代码

通过上述代码,可以看到,利用了poll模型,进行监听,然后建立连接。

下面看下 process_new_connection:

Connection_handler_manager::process_new_connection(Channel_info* channel_info)

{

...

if (m_connection_handler->add_connection(channel_info))

{

inc_aborted_connects();

delete channel_info;

}

}

复制代码

核心是add_connection 。 有几个实现,我们就看下One_thread_connection_handler::add_connection 吧。

bool One_thread_connection_handler::add_connection(Channel_info* channel_info)

{

// 线程初始化, 为线程设置堆栈

if (my_thread_init())

{

...

}

THD* thd= channel_info->create_thd();

thd->set_new_thread_id();

thd->start_utime= thd->thr_create_utime= my_micro_time();

thd_set_thread_stack(thd, (char*) &thd);

...

bool error= false;

if (thd_prepare_connection(thd))

...

else

{

delete channel_info;

// 这儿是重点,如果连接一直活着,则执行while循环,进行do_command 处理。

while (thd_connection_alive(thd))

{

if (do_command(thd))

break;

}

end_connection(thd);

}

// 如果连接死了,则回收资源。

close_connection(thd, 0, false, false);

thd->release_resources();

thd_manager->remove_thd(thd);

Connection_handler_manager::dec_connection_count();

delete thd;

return error;

}

复制代码

负责执行的是sql_parse.cc的 do_command, 负责从连接中读取指令(比如query活着其他)并执行。

do_command 就暂时不分析了,后面到具体的使用时,我们再分析。

4 服务退出

如果最后服务停了,最后会是clean_up 跟 mysqld_exit 退出操作。

clean_up(1);

mysqld_exit(MYSQLD_SUCCESS_EXIT);

复制代码

5 总结

本文从MySQL初始化,到服务端启动,连接建立,以及如何为连接设定处理方法等环节,简单地分析了一下,整体流程算是明白了一点,算作是流水账吧。毕竟自己对MySQL的了解还太浅,等分析一段时间之后,再回头来看这篇文章,加油~

6 参考文献

《MySQL运维内参》

《MySQL 是怎样运行的:从根儿上理解 MySQL》

MySQL 5.7 源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值