MySQL服务器进程的启动、运行与退出,都始于 `sql/main.cc` 中的 `main()` 函数,最终汇聚于 `sql/mysqld.cc` 的 `mysqld_main()` 函数。这个过程可以分为**启动初始化**、**网络与连接处理**、**命令执行循环**和**优雅关闭**四个主要阶段。
🚀 启动初始化:从 main() 到 mysqld_main()
这是服务的"唤醒"阶段,主要为后续运行准备环境和资源。
-
入口函数 (
sql/main.cc) : MySQL的源码入口是sql/main.cc中的main()函数。它的代码非常简洁,核心作用就是调用真正的入口点:cppextern int mysqld_main(int argc, char **argv); int main(int argc, char **argv) { return mysqld_main(argc, argv); } -
主服务函数 (
sql/mysqld.cc) : 所有的核心启动逻辑都在mysqld_main()函数中。它会按严格顺序执行一系列初始化任务:- 基础环境设置 :初始化全局变量、字符集(
system_charset_info)、错误日志钩子函数等。 - 参数解析与配置加载 :解析命令行参数和配置文件(
my.cnf)。 - 核心模块初始化 (
init_server_components):按顺序初始化存储引擎(如InnoDB)、事务、日志等核心组件。 - 网络与信号初始化:初始化网络接口,准备监听客户端连接;设置信号处理器,以便安全关闭。
- 启动后台线程:创建处理网络连接、刷新日志、清理数据等任务的各类后台线程。
- 基础环境设置 :初始化全局变量、字符集(
🌐 网络与连接处理:进入服务循环
初始化完成后,MySQL进入主循环,开始接受和处理客户端请求。
- 监听与接受连接 :通过
connection_event_loop()函数,在一个无限循环中使用poll()或select()模型监听端口。当新连接到达时,接受并封装为Channel_info对象。 - 创建/分配线程 :主循环将
Channel_info对象交给Connection_handler_manager。MySQL默认采用一个连接一个线程(one-thread-per-connection)模型,会为新连接创建线程或从线程池中分配一个空闲线程来处理。
⚙️ 命令执行循环:处理客户端请求
每个客户端连接都有独立的线程负责交互,其执行循环如下:
- 读取命令 :线程调用
do_command()函数,从网络连接中读取客户端的命令或SQL语句。 - 分发命令 :
do_command()调用dispatch_command()函数,根据命令类型进行分发。- 对于SQL查询 (
COM_QUERY等):- 解析 :
mysql_parse()对SQL文本进行词法和语法分析,生成解析树(Parse Tree)。 - 优化 :
JOIN::optimize()负责生成最优执行计划,包括选择索引和确定表连接顺序。 - 执行 :
JOIN::exec()执行计划,通过存储引擎的handler接口(如ha_innobase::index_read)与底层引擎交互,读取或修改数据。
- 解析 :
- 对于其他命令 (
COM_PING,COM_QUIT等):直接处理并返回结果。
- 对于SQL查询 (
🛑 优雅关闭:安全退出
当收到关闭信号(如SIGTERM)时,MySQL会启动关闭流程:
- 停止接收新连接。
- 等待现有事务完成。
- 刷新所有脏页到磁盘。
- 关闭所有日志文件。
- 释放内存等资源,进程退出。
💎 总结
MySQL的主函数流程清晰体现了经典C/S架构服务器的设计范式:
- 准备 :
mysqld_main()函数负责完成所有复杂的初始化工作。 - 循环 :通过
connection_event_loop()循环监听,并为每个连接创建线程。 - 处理 :连接线程内通过
do_command()→dispatch_command()循环处理请求。 - 退出:接收信号后,执行一系列清理工作后安全退出。