
0. 背景
决定将mysql的代码看一下,并且记录下来,希望能够学习一下mysql的内核相关知识。
目前是采取这么一种策略,即看到哪里记录到哪里,也不知道最后会有多少产出。
当然因为是初次阅读,当然会存在很多错误或遗漏,也希望相关人士能够指出。估计在后续的阅读中也会进一步对之前的笔记进行修改,望见谅。
1. MySQL初始化
当然第一篇就是mysql的启动初始化和终止阶段逻辑。以下是初始化简单的小结,更多的话可以在后面的代码函数栈可以看到。终止阶段的逻辑相对简单些。
代码路径:https://github.com/mysql
入口函数:mysql-server-8.0/sql/mysqld.cc::mysqld_main
初始化的内容
- 参数配置解析:
- 分别从/etc/my.conf, /etc/mysql/my.conf, SYSCONFDIR/my.cnf, "$MYSQL_HOME"/my.conf, defaults-extra-file, ~/my.conf, DATADIR/mysqld-auto.cnf, 命令行 加载配置文件中的配置项。SYSCONFDIR/my.cnf是在编译时指定的路径,DATADIR是指定的数据目录 ,如果不指定特定的配置的,将按照上面逐步查找配置。
- performance schema interface(PSI)初始化;PSI主要用于监控/诊断MySQL服务运行状态,可以阅读官方文档:https://dev.mysql.com/doc/refman/8.0/en/performance-schema.html 和(PFS)初始化
- 初始化定时器timer;
- 时间相关的
- 基础的锁结构;
- 资源池,通知消息等初始化;
- 字符集/collation
- 元数据
- 系统库表,information_schema
- DDL/DQL/DML/ACL支持的命令
- plugin,存储引擎
- binlog
- 优化器optimizer代价
- 恢复持久化中的事务数据,
- ACL相关的初始化,授权相关的初始化
- SSL
- 信号处理
- 审计相关初始化
- 各类管理器
- MySQL中的线程
MySQL中的线程
MySQL中主要会启动以下线程处理各种任务:
- 连接监听主线程,用于监听处理客户端的连接请求,然后将连接请求分发到单独的线程,并处理该连接上的所有请求;
- 处理线程,是一个线程池,具体在后面会介绍;
- slave/relay线程,连接到主服务的线程,并且从主服务器中读取binlog更新,在本机上应用更新;
- 信号处理线程,用来处理信号,具体的信号包括了:SIGTERM, SIGQUIT, SIGHUP, SIGUSR1 and SIGUSR2
- event_scheduler_thread,事件调度线程,用来调度执行每个表上定义事件,即Event。
- compress_gtid_table_thread,开启一个线程用来压缩GTID_Table,具体的压缩逻辑在mysql-server-8.0/sql/http://rpl_gtid_persist.cc中,估计后续会进一步阅读。
- helper_thread,辅助线程来分发计时器timer到期通知消息,具体逻辑在timer_notify_thread_func。
- admin_socket_thread,如果开启了该线程,并且以端口监听,则可以用handle_admin_socket处理请求的逻辑,具体的连接也会用一个新的线程处理。
2. 函数调用链
代码块为初始化的调用链,每一个缩进表示函数调用。
substitute_progpath:将命令行的程序名替换成全路径的程序名,可能是“全路径”,home路径解释,环境变量PATH解释。
sysd::notify_connect:在环境变量(“NOTIFY_SOCKET“)中查找socket的文件名,如果存在的话则连接该Socket
sysd::notify:向Notify Socket发送正在启动的消息。
my_init:初始化my_sys函数,资源和变量
my_thread_global_init:初始化线程的环境(初始化一堆资源锁)
PSI_mutex_key 结构
my_thread_init:申请mysys线程的内存,主要用于debug
load_defaults -> my_load_defaults:从配置文件中读取配置项
init_default_directories:获取配置的目录
my_search_option_files:处理在缺省目录下的配置文件,即上一步结果
get_defaults_options:从命令行中获取配置选项;
init_variable_default_paths:初始化配置文件的作用域(enum_variable_source)
search_default_file:如果是绝对路径,直接读取;
search_default_file_with_ext:从输入配置的文件中读取;
my_default_get_login_file:从login集群中读取配置。
my_search_option_files
set_args_separator:分隔符
persisted_variables_cache:持久化的参数配置缓存,采用JSON进行存储,
Init:初始化,从命令行或者是环境变量“MYSQL_DATADIR“中获取文件
my_handle_options:主要处理参数的逻辑。
load_persist_file:加载持久化文件的配置,并且转成JSON格式,分析出K/V结构;
append_read_only_variables:将上一步分解出的只读配置参数追加到命令行参数中。
init_variable_default_paths:初始化配置文件的作用域(enum_variable_source)
init_pfs_instrument_array: PSI: performance schema interface; PFS:performance storage
handle_early_options:处理早期的选项,包括:performance schema;与help或者启动相关的参数
sys_var_add_options:增加系统参数;
增加命令行中的早期选项;
add_terminator:增加终结。
handle_options->my_handle_options:处理参数
init_sql_statement_names: 初始化与sql语句相关的名字(com_status_vars),包括各种dml/ddl/acl/dql等
sys_var_init:初始化系统变量(mysql-server-8.0/sql/sys_vars.cc中定义静态变量)
mysql_add_sys_var_chain
init_error_log:初始化错误日志
adjust_related_options:调整相关的参数,
adjust_open_files_limit
adjust_max_connections
adjust_table_cache_size
adjust_table_def_size
initialize_performance_schema:初始化performance_schema
pfs_automated_sizing:将ps相关的参数都置为0;
init_timers:根据系统进行初始化performance_schema的计数器,并且获得当前值;可以从performance_timers表获取
my_timer_init
my_timer_cycles
my_timer_nanoseconds
my_timer_milliseconds
初始化histograms(表的统计量)的定时器,
init_event_name_sizing:初始化全局表I/O,表锁/元数据等的事件
register_global_classes:初始化全局的仪表,包括类型有:表I/O,表锁,Idle类,元数据类,错误类,事物类。
接下来是申请一堆仪表的内存
并且从参数里头获取配置
init_pfs_plugin_table:初始化pfs内置的table
PFS_dynamic_table_shares::init_mutex
init_pfs_plugin_table
LO_init:初始化Lock Order,主要用Lock Order Graph描述锁依赖关系:https://dev.mysql.com/doc/refman/8.0/en/lock-order-tool.html
//START与psi相关的服务
设置psi相关的服务:thread_service,mutex_service,rwlock_service,cond_service,file_service,socket_service,table_service,mdl_service,idle_service,stage_service,statement_service,transaction_service,memory_service,error_service,data_lock_service,system_service
init_server_psi_keys:注册psi key的函数,包括psi服务的mutex,rwlock,conds,threads,files,stage,socket;内存的key,sql语句的信息(init_sql_statement_names中提到的),psi_api,与store procedures相关的key,与调度(scheduler)相关的(主要是evengt),与client公用的key,vio的key(与通信相关的)
my_thread_global_reinit:重新初始化一些比较开始与锁相关的,因为需要考虑一些仪表
// 与psi相关的服务 END
component_infrastructure_init
mysql_services_bootstrap:启动服务注册,动态加载器,和基础的服务
registry_init:创建注册服务套件,内部的结构mysql_registry
把加载器的实现写入到服务注册表
dynamic_loader_init:初始化动态加载器,其实就是初始化锁
dynamic_loader_scheme_file_init:初始化scheme文件
pfs_init_services: ps是performance storage
register_pfs_notification_service
register_pfs_resource_group_service
Resource_group_mgr::init:初始化资源组管理器,
与资源相关的服务,包括: registry service,mysql_service_pfs_resource_group_v3_t,mysql_service_pfs_notification_v3_t
注册线程创建/断开连接的回调
创建用户级/系统级的资源组对象
调用psi_thread_service相关函数:new_thread,set_thread_os_id,set_thread
mysql_audit_initialize:初始化与audit相关的变量;
Srv_session::module_init:初始化srv_session模块
query_logger.init:查询日志初始化
init_common_variables:
init_thread_environment:初始化与线程相关的锁;
mysql_init_variables:初始化全局变量为缺省值
mysql_bin_log.set_psi_keys完成bin log的初始化,让仪表相关的对bin log可见
mysql_bin_log.init_pthread_objects:初始化bin log与线程相关的锁
get_options,剩余的可选项,binlog,压缩算法,页的大小,线程缓存大小,back_log
Connection_handler_manager::init,初始化连接池
Per_thread_connection_handler::init,初始化Per_thread_connection_handler,初始化锁
初始化mysql client的plugin
选字符集/collation
日志配置
创建数据目录
表的大小写等
my_init_signals:初始化信号处理
线程栈大小检查
Migrate_keyring::init:初始化Migrate_keyring(一种mysql数据搬运模式)相关的,如压缩方式,并且连接到数据源主机
Migrate_keyring::execute
fetch_and_store_keys
// 如果启动方式为Migrate_keyring,则数据搬完后退出
set_ports:确定tcp端口
init_server_components
mdl_init:metadata locking subsystem元数据锁子系统,
MDL_map::init, MDL_key,一个重要的数据结构:元数据锁
partitioning_init
table_def_init:表定义缓存(Table_definition_cache)
Table_cache_manager::init:表缓存初始化
Table_cache::init
hostname_cache_init:初始化(client)主机名缓存,Host_entry
my_timer_initialize:初始化内部组建,fd,
start_helper_thread:时间通知线程,timer_notify_thread_func
init_slave_list:初始化从机列表
transaction_cache_init:初始化事务缓存的psi键
MDL_context_backup_manager::init,MDL_context_backup_manager
:维护XA事务中元数据锁
delegates_init:初始化外部observer的委托,包括事务,bin log,服务状态,bin log传输,relay IO
与bin/relay log相关的初始化
process_key_caches:用ha_init_key_cache函数初始化所有的key缓存
ha_init_errors:初始化错误信息
gtid_server_init:GTID server初始化
udf_init_globals:初始化udf结构体
init_ssl:配置SSL包
ssl_start:
SSL_library_init
OpenSSL_add_all_algorithms
init_ssl_locks:初始化ssl锁,
init_lock_callback_functions:锁回调函数
plugin_register_early_plugins
plugin_init_internals:初始化内部plugin,资源/锁
plugin_load_list
plugin_dl_add
plugin_add
plugin_init_initialize_and_reap:重试失败的plugin
plugin_register_builtin_and_init_core_se,初始化内置plugin,包含MyIsam,CSV,InnoDB
init_sql_command_flags:初始化sql命令flag
dd::init:
cache::Shared_dictionary_cache::init,包括字符/collation,抽象表,事件,routine,schema,column,tablespace,资源组等字典初始化
System_tables::instance()->add_inert_dd_tables()
System_views::instance()->init() 系统视图,主要是information_schema下的
Dictionary_impl::init
plugin_register_dynamic_and_init_all,注册动态的plugin和初始化所有的plugin
确定线程池组织方式:SCHEDULER_ONE_THREAD_PER_CONNECTION/SCHEDULER_NO_THREADS
从5.7升级到8.0相关的处理
dd::performance_schema::init_pfs_tables:处理好pfs相关的表
upgrade_system_schemas:升级系统库表
Resource_group_mgr::post_init从磁盘读取资源组数据
handle_options:处理剩余的参数可选项
ha_init:初始化
query_logger相关的处理
initialize_storage_engine:初始化缺省(或临时)的存储引擎
Recovered_xa_transactions::init:恢复XA事务初始化
Recovered_xa_transactions::recover_prepared_xa_transactions恢复预处理的XA事务
init_server_auto_options:初始化服务自动项,
MYSQL_BIN_LOG::open_binlog,打开一个bin log文件,分析主备bin log,也会purge一些日志
init_optimizer_cost_module:初始化优化器(应该是物理优化器)代价的模块
init_cache_tmp_engine_properties
Cache_temp_engine_properties::init,临时的引擎特性,HEAP/TempTable/INNODB
ft_init_stopwords:停用词
init_max_user_conn:client连接
Gtid_state::init,将server_uuid放至sid_map中
MYSQL_BIN_LOG::init_gtid_sets,从gtid_executed表和binlog文件中初始化GLOBAL.GTID_EXECUTED 和 GLOBAL.GTID_PURGED 的值,分别应该是已经执行的GTID和回收的GTID
init_ssl_communication:
set_fips_mode:设置openssl包的fips
SslAcceptorContext::singleton_init,初始化ssl接收器
do_auto_cert_generation,生成证书
init_rsa_keys,从磁盘中加载RSA键值对,sha256
network_init,初始化服务的listener,三种,Mysqld_socket_listener/Named_pipe_listener/Shared_mem_listener,后两者仅在windows下会启动
Connection_acceptor::init_connection_acceptor
Mysqld_socket_listener::setup_listener,如果是Mysqld_socket_listener,并且需要开通管理员socket
spawn_admin_thread,启动admin的listener线程。
admin_socket_thread
handle_admin_socket,开始监听管理请求
create_pid_file,创建pid文件
reload_optimizer_cost_constants,重新加载优化器的计算成本常量
Cost_constant_cache::reload
mysql_component_infrastructure_init,通过初始化动态加载器来初始化mysql服务组建
persistent_dynamic_loader_init,恢复持久化文件中的数据
mysql_persistent_dynamic_loader_imp::init
open_component_table
读取组件table中的数据
mysql_dynamic_loader_imp::load
dd::sdi_file::load
trans_rollback_stmt:回滚单语句的事务
ha_rollback_trans
trans_rollback:回滚当前的事务
server_component_init,除第一个函数外,其他均为dummy空函数,
mysql_comp_sys_var_services_init
mysql_string_services_init();
mysql_comp_status_var_services_init();
mysql_comp_system_variable_source_init();
mysql_backup_lock_service_init();
clone_protocol_service_init();
page_track_service_init();
mysql_security_context_init();
mysql_server_ongoing_transactions_query_init();
host_application_signal_imp_init();
mysql_audit_api_service_init();
mysql_current_thread_reader_imp_init();
mysql_keyring_iterator_service_init();
mysql_comp_udf_extension_init();
mysql_connection_attributes_iterator_imp_init();
trans_commit_stmt,提交语句事务
trans_commit,提交当前事务
mysql_rm_tmp_tables,删除之前服务遗留的临时文件
acl_init
init_acl_cache
check_engine_type_for_acl_table,
check_acl_tables_intact
notify_flush_event
init_acl_memory,出事acl的内存
my_tz_init:初始化时区
open_trans_system_tables_for_read
open_tables
open_tables_check_upgradable_mdl
find_table_for_mdl_upgrade
lock_table_names
lock_tables
mysql_lock_tables
lock_tables_check
get_lock_data:获得表的锁结构
check_lock_and_start_stmt
闰秒相关的初始化逻辑
grant_init:
grant_reload:加载授权
open_and_lock_tables
grant_load:从授权表中加载表/列的权限检查信息
grant_reload_procs_priv:从procs_priv表中读取权限信息
commit_and_close_mysql_tables:
dynamic_privilege_init:
mysql_plugin_registry_acquire
初始化管理相关的权限
servers_init:从mysql库中初始化结构数据
servers_reload:初始化mysql.servers表的数据
udf_read_functions_table:从mysql.func中加载数据
init_status_vars:
init_slave:初始化slave线程,并开启
Rpl_info_factory::create_slave_info_objects
start_slave_threads,对多个channel开启
start_slave_thread::handle_slave_sql处理relay日志
initialize_performance_schema_acl
ACL_internal_schema_registry::register_schema
Events::init:初始化event结构
load_events_from_db
Event_scheduler::start
pre_init_event_thread
event_scheduler_thread
start_signal_handler,启动单独的线程signal_hand来处理信号,如SIGTERM, SIGQUIT, SIGHUP, SIGUSR1 and SIGUSR2
process_bootstrap:
server_components_initialized
run_bootstrap_thread:启动单独处理init_file 中的sql语句
handle_bootstrap
handle_bootstrap_impl
process_iterator
dd::init
mysql_audit_notify:
mysql_audit_acquire_plugins,获取plugins
event_class_dispatch
plugins_dispatch,通过调用plugin的event_notify函数分发时间
start_handle_manager,开启handler管理线程
handle_manager,线程函数,监听COND_manager信号等
create_compress_gtid_table_thread,开启一个线程调用以下函数
compress_gtid_table,根据压缩COND_compress_gtid_table信号对gtid_executed表进行压缩
Gtid_state::compress
Gtid_table_persistor::compress,更多详细的逻辑在mysql-server-8.0/sql/rpl_gtid_persist.cc中
Connection_acceptor::connection_event_loop:开启监听服务。 window会进入setup_conn_event_handler_threads函数,并启动三个单独线程处理不同的连接方式,即Mysqld_socket_listener/Named_pipe_listener/Shared_mem_listener
// 以下为结束阶段的代码
待收到结束信号后,
terminate_compress_gtid_table_thread,终止compress_gtid_table_thread
save_gtids_of_last_binlog_into_table,保存gtid的最新值到表中
发送信号给监听线程
close_connections:关闭连接,SIGQUIT信号
Per_thread_connection_handler::kill_blocked_pthreads
Mysqld_socket_listener/Shared_mem_listener/Named_pipe_listener::close_listener
mysql_socket_shutdown
mysql_socket_close
Connection_acceptor::close_listener
Events::stop,停止Event调度器
Set_kill_conn,对连接设置KILL_CONNECTION flag
Events::deinit,清理调度器的资源,
关闭所有连接,Call_close_conn::close_connection
Connection_handler_manager::wait_till_no_connection,等待所有连接结束
delete_slave_info_objects,释放slave线程占用的资源
终止仪表线程
3. 总结
mysql服务的初始化还是很复杂的,但是一般情况下都不会被关注到。这次也是阅读不是细致,肯定会存在一些问题,也希望在后续能够继续阅读初始化/终止的每一块代码。
下篇:
Wenguang Liu:MySQL源码阅读2-连接与线程管理zhuanlan.zhihu.com