MySQL timed_mutexes
提要:
MySQL 5.5.39 Release版本正式从源码里删除了全局参数timed_mutexes。timed_mutexes原本用来控制是否对Innodb引擎的mutex wait进行 计时统计,以方便进行性能诊断。为什么要删除这个参数呢? 下面介绍下相关背景:
Innodb的同步锁机制:
Innodb封装了mutex和rw_lock结构来保护内存的变量和结构进行多线程同步,考虑可移植性, mutex使用lock_word或者OS mutex来保证原子操作,并使用event条件变量进行阻塞和唤醒操作。
os_event_t event;
volatile lock_word_t lock_word;
os_fast_mutex_t os_fast_mutex;
Innodb同步锁引入的数据结构和开销
1. 全局mutex链表
Innodb引入了一个全局的链表ut_list_base_node_t mutex_list,并使用一个单独的mutex来保护链表。 所有的mutex在create或者free的时候来修改链表,有了全局链表,也使统计汇总有了可能性,参考命令“show engine innodb mutex”. 虽然需要维护一个全局的链表,但这并不会影响太多的性能,因为大部分的mutex的生命周期都是从Innodb启动一直到shutdown。
2. 统计信息
mutex的结构中,有几个统计信息:
count_os_wait:请求mutex进入等待的次数
count_using: 请求mutex的次数
count_spin_loop: 请求mutex时spin的轮数
count_spin_rounds: 请求mutex的spin次数
count_os_yield:请求mutex spin失败后os等待次数
lspent_time: 统计等待mutex的时间
lock mutex的主要步骤:
1. 首先trylock mutex,如果没有获取到mutex,并不马上进行wait,而是进行spin。
2. 尝试spin,如果在SYNC_SPIN_ROUNDS次后,仍然没有lock,那么就进入等待队列,等待唤醒。
在MySQL5.5的版本里,非UNIV_DEBUG模式下,Innodb仅仅保留了count_os_wait的次数,这也是为了性能的考虑。所以5.5的版本后, timed_mutexes在Release下,其实已经不再起作用,所以5.5.39,以及5.6以后,源码里都不再保留timed_mutexes。 要么在debug模式下,启用这些统计,但上线版本又不可能使用DEBUG模式,所以对于mutex的统计,MySQL在后面的版本中使用了performance_schema的等待事件来代替,即:
mysql> SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES -> WHERE TABLE_SCHEMA = 'performance_schema' -> AND TABLE_NAME LIKE '%instances'; +------------------+ | TABLE_NAME | +------------------+ | cond_instances | | file_instances | | mutex_instances | | rwlock_instances | +------------------+
3. 全局等待队列
Innodb为所有的等待状态的线程准备了一个队列,如果获取mutex失败,那么就申请一个cell,进入阻塞状态,等待signal。 sync_primary_wait_array,有了这个全局的队列,Innodb就可以对这些wait的线程进行统计,比如long semaphore waits就是 根据这个队列进行的查询。
4. signal丢失
这里再讨论下signal丢失的情况,我们重新再看下lock mutex的步骤:
线程1: 1. try lock mutex 2. fail,然后spin 3. fail,然后进入队列,然后wait event 线程2: 1.own mutex 2.free mutex 3.signal event
如果按照这个时序,在线程2 signal event后,线程1才进入队列,那么线程1就永远处在阻塞状态,无法唤醒。为了解决signal丢失的情况, Innodb启动了一个后台线程:sync_arr_wake_threads_if_sema_free,每隔1s就轮询wait数组,如果可以lock,就signal这个event来唤醒线程。
从上面来看,Innodb为了mutex和rwlock的移植性,以及为了监控和诊断,添加了多个全局的数据结构,这样实时的统计才有可能,但也带来了维护数据结构的开销。 而timed_mutexes控制的mutex wait时间统计,因为只在debug模式下进行编译,而且5.6以后使用performance schema的等待事件进行替代,所以参数做了删除处理。