开源数据库 - mysql - innodb源码阅读 - 线程启动
线程启动源码
/** Start up the InnoDB service threads which are independent of DDL recovery.
*/
void srv_start_threads() {
if (!srv_read_only_mode) {
/* Before 8.0, it was master thread that was doing periodical
checkpoints (every 7s). Since 8.0, it is the log checkpointer
thread, which is owned by log_sys, that is responsible for
periodical checkpoints (every innodb_log_checkpoint_every ms).
Note that the log checkpointer thread was created earlier and
is already active, but the periodical checkpoints were disabled.
Only the required checkpoints were allowed, which includes:
- checkpoints because of too old last_checkpoint_lsn,
- checkpoints explicitly requested (because of call to
log_make_latest_checkpoint()).
The reason was to make the situation more deterministic during
the startup, because then:
- it is easier to write mtr tests,
- there are less possible flows - smaller risk of bug.
Now we start allowing periodical checkpoints! Since now, it's
hard to predict when checkpoints are written! */
log_limits_mutex_enter(*log_sys);
log_sys->periodical_checkpoints_enabled = true; // log_checkpoint 周期性检查点,检查点线程
log_limits_mutex_exit(*log_sys);
}
srv_threads.m_buf_resize =
os_thread_create(buf_resize_thread_key, 0, buf_resize_thread); // 后台线程,用于收缩表空间。这个线程 m_buf_resize 是用于缓冲池(buffer pool)的大小调整
srv_threads.m_buf_resize.start();
if (srv_read_only_mode) {
purge_sys->state = PURGE_STATE_DISABLED; // 只读模式 关闭purge 线程
return;
}
/* Create the master thread which does purge and other utility
operations */
srv_threads.m_master =
os_thread_create(srv_master_thread_key, 0, srv_master_thread); // 创建主线程
srv_threads.m_master.start();
if (srv_force_recovery == 0) { // 根据恢复级别来判断是否需要更新缓存区的最大表空间id
/* In the insert buffer we may have even bigger tablespace
id's, because we may have dropped those tablespaces, but
insert buffer merge has not had time to clean the records from
the ibuf tree. */
ibuf_update_max_tablespace_id();
}
/* Create the dict stats gathering thread */
srv_threads.m_dict_stats =
os_thread_create(dict_stats_thread_key, 0, dict_stats_thread); // 启动 统计线程
dict_stats_thread_init();
srv_threads.m_dict_stats.start();
/* Create the thread that will optimize the FTS sub-system. */
fts_optimize_init(); // 启动 FTS优化线程
srv_start_state_set(SRV_START_STATE_STAT); // 设置状态为 SRV_START_STATE_STAT
}
线程启动
if (!srv_read_only_mode) {
/* Before 8.0, it was master thread that was doing periodical
checkpoints (every 7s). Since 8.0, it is the log checkpointer
thread, which is owned by log_sys, that is responsible for
periodical checkpoints (every innodb_log_checkpoint_every ms).
Note that the log checkpointer thread was created earlier and
is already active, but the periodical checkpoints were disabled.
Only the required checkpoints were allowed, which includes:
- checkpoints because of too old last_checkpoint_lsn,
- checkpoints explicitly requested (because of call to
log_make_latest_checkpoint()).
The reason was to make the situation more deterministic during
the startup, because then:
- it is easier to write mtr tests,
- there are less possible flows - smaller risk of bug.
Now we start allowing periodical checkpoints! Since now, it's
hard to predict when checkpoints are written! */
log_limits_mutex_enter(*log_sys);
log_sys->periodical_checkpoints_enabled = true; // log_checkpoint 周期性检查点,检查点线程
log_limits_mutex_exit(*log_sys);
}
这段代码是用于在InnoDB存储引擎中启动周期性检查点(checkpoints)的逻辑。以下是对代码的逐行解释:
-
if (!srv_read_only_mode) {
:这行代码检查服务器是否不是只读模式。如果服务器不是只读模式,则执行下面的代码块。 -
/* Before 8.0, it was master thread that was doing periodical checkpoints (every 7s). Since 8.0, it is the log checkpointer thread, which is owned by log_sys, that is responsible for periodical checkpoints (every innodb_log_checkpoint_every ms). */
:这段注释说明了在8.0版本之前,是由主(master)线程负责周期性检查点(每7秒一次)。而从8.0版本开始,这个任务由log_sys拥有的日志检查点(log checkpointer)线程负责,该线程会按照innodb_log_checkpoint_every毫秒的频率进行周期性检查点。 -
Note that the log checkpointer thread was created earlier and is already active, but the periodical checkpoints were disabled.
:这行注释指出日志检查点线程已经创建并且处于活动状态,但周期性检查点被禁用。 -
Only the required checkpoints were allowed, which includes: - checkpoints because of too old last_checkpoint_lsn, - checkpoints explicitly requested (because of call to log_make_latest_checkpoint()).
:这行注释说明了在启动阶段,只允许必要的检查点,包括因为最后一个检查点LSN太旧而触发的检查点,以及通过调用log_make_latest_checkpoint()显式请求的检查点。 -
The reason was to make the situation more deterministic during the startup, because then: - it is easier to write mtr tests, - there are less possible flows - smaller risk of bug.
:这行注释解释了在启动阶段限制检查点的原因,是为了使情况更加确定,从而更容易编写mtr测试,减少可能的流程,降低错误风险。 -
Now we start allowing periodical checkpoints! Since now, it's hard to predict when checkpoints are written! */
:这行注释表明现在开始允许周期性检查点,这意味着从现在开始,很难预测检查点何时被写入。 -
log_limits_mutex_enter(*log_sys);
:这行代码进入log_sys的互斥锁(mutex)。 -
log_sys->periodical_checkpoints_enabled = true;
:这行代码将log_sys的periodical_checkpoints_enabled属性设置为true,从而启用周期性检查点。 -
log_limits_mutex_exit(*log_sys);
:这行代码退出log_sys的互斥锁。
总的来说,这段代码的作用是在服务器不是只读模式的情况下,启用InnoDB存储引擎的日志检查点线程的周期性检查点功能。
srv_threads.m_buf_resize =
os_thread_create(buf_resize_thread_key, 0, buf_resize_thread); // 后台线程,用于收缩表空间。这个线程 m_buf_resize 是用于缓冲池(buffer pool)的大小调整
srv_threads.m_buf_resize.start();
这个线程 m_buf_resize
是用于缓冲池(buffer pool)的大小调整。在InnoDB存储引擎中,缓冲池是一个内存区域,用于缓存数据库页面,以减少对磁盘的访问次数,从而提高数据库的性能。缓冲池的大小对于数据库的性能至关重要,因为它直接影响到数据库能够缓存的数据量。
m_buf_resize
线程的主要职责是监控缓冲池的使用情况,并根据需要调整缓冲池的大小。这可能涉及增加或减少缓冲池的内存分配,以适应数据库的工作负载。例如,如果数据库的查询负载增加,可能需要增加缓冲池的大小以容纳更多的缓存页面;反之,如果负载减少,可能需要减少缓冲池的大小以释放内存资源。
调整缓冲池大小的过程通常是动态的,并且是基于一些预定义的策略或阈值。例如,InnoDB可能会根据缓冲池的命中率、脏页的比例、可用内存的大小等因素来决定是否需要调整缓冲池的大小。
在实际的数据库管理中,管理员可以通过配置参数来影响 m_buf_resize
线程的行为,例如设置缓冲池的最小和最大大小,以及调整大小的步长和频率等。
总的来说,m_buf_resize
线程是InnoDB存储引擎中一个重要的后台线程,它通过动态调整缓冲池的大小来优化数据库的性能和资源使用。
m_dict_stats
线程在 InnoDB 存储引擎中负责收集和更新数据字典的统计信息。数据字典是 InnoDB 存储引擎中用于存储数据库对象(如表、索引、列等)元数据的核心组件。这些统计信息对于查询优化器来说非常重要,因为它们帮助优化器做出更明智的决策,例如选择最佳的查询执行计划。
具体来说,m_dict_stats
线程的主要职责包括:
- 收集统计信息:定期扫描数据字典中的对象,收集关于表大小、索引使用情况、列数据分布等统计信息。
- 更新统计信息:根据收集到的数据,更新数据字典中的统计信息表。
- 监控数据变化:持续监控数据库中的数据变化,以便在数据发生变化时及时更新统计信息。
通过这些操作,m_dict_stats
线程确保查询优化器能够基于最新的统计信息做出最优的查询计划决策,从而提高数据库的整体性能。
在 InnoDB 中,统计信息的收集和更新是一个后台任务,它会在数据库运行期间持续进行,以保证统计信息的准确性和实时性。
FTS 子系统(FTS sub-system)全称为 Full-Text Search 子系统,它是 InnoDB 存储引擎中的一个组件,用于支持全文搜索功能。全文搜索是一种能够在文本数据中搜索特定关键词或短语的技术,它允许用户在大量文本数据中快速找到所需的信息。
在 InnoDB 中,FTS 子系统通过创建和维护一个特殊的索引来实现全文搜索。这个索引包含了文档中所有单词的信息,以及它们在文档中的位置。当用户执行全文搜索查询时,FTS 子系统会使用这个索引来快速定位包含查询关键词的文档,并返回搜索结果。
FTS 子系统的主要功能包括:
- 索引管理:创建、更新和删除全文索引。
- 查询处理:解析和执行全文搜索查询。
- 结果排序:根据相关性对搜索结果进行排序。
- 性能优化:通过缓存和其他技术提高搜索性能。
在 InnoDB 中,FTS 子系统的实现基于 MyISAM 存储引擎的全文搜索功能,但它在 InnoDB 中进行了优化和改进,以提供更好的性能和可靠性。
在当前的代码片段中,srv_start_threads()
函数正在启动 InnoDB 服务线程,其中包括创建一个优化 FTS 子系统的线程。这个线程的主要职责是监控和优化 FTS 索引的性能,确保全文搜索功能能够高效运行。
扩展
只读模式
MySQL服务器的只读模式是一个重要的功能,它在多个方面发挥着关键作用。以下是对MySQL服务器只读模式作用的详细阐述:
一、保护关键数据
只读模式的核心作用是保护数据库中的关键数据不被意外修改或删除。在只读模式下,用户只能执行查询操作(如SELECT),而无法进行插入(INSERT)、更新(UPDATE)或删除(DELETE)等写操作。这有助于防止因误操作或恶意攻击而导致的数据损坏或丢失。
二、确保数据一致性
在数据库维护、备份或迁移等过程中,确保数据一致性至关重要。通过将数据库设置为只读模式,可以防止在这些操作期间对数据进行修改,从而确保数据的一致性和完整性。这对于维护数据库的可靠性和稳定性具有重要意义。
三、提高读取性能
在只读模式下,由于不允许进行写操作,因此可以减少锁的竞争,从而提高读取性能。这对于需要频繁读取数据的应用场景来说是一个显著的优势。然而,也需要注意到,在只读模式下,一些写入相关的缓存和日志功能可能会被关闭,这可能会对某些性能产生一定影响,但通常这种影响较小。
四、实现主从复制中的只读服务器
在MySQL的主从复制架构中,只读模式可以用于实现只读服务器。通过将从服务器设置为只读模式,可以确保它只用于查询操作,而不会干扰主服务器的写操作。这有助于实现读写分离,提高系统的可扩展性和性能。
五、应用场景
- 数据库备份:在进行数据库备份时,为了防止备份过程中数据被修改,可以将数据库设置为只读模式。
- 维护期间的数据保护:在数据库维护期间,如升级、修复或优化等操作时,可以通过设置只读模式来限制对数据库的写操作,确保数据的一致性。
- 只读分析场景:在需要进行大量数据分析的场景下,可以通过设置只读模式来限制对数据库的写操作,从而提高读取性能并保护数据不被修改。
六、注意事项
- 全局影响:只读模式是全局的,会影响整个数据库实例。因此,在设置只读模式前,需要评估其对业务的影响,并通知相关团队。
- 权限绕过:具有SUPER权限的用户可以绕过只读模式的限制进行写操作。因此,在设置只读模式时,需要考虑权限管理问题。
- 恢复写操作:在完成查询任务或维护操作后,需要及时关闭只读模式以恢复写操作功能。
综上所述,MySQL服务器的只读模式在保护关键数据、确保数据一致性、提高读取性能以及实现主从复制中的只读服务器等方面发挥着重要作用。然而,在使用时也需要注意其全局影响、权限绕过以及恢复写操作等注意事项。
参考资料
mysql源码
本博客中出现源码在mysql-server-trunk -> storage -> innobase -> srv -> srv0start.cc中
文心一言
MarsCode AI