服务热线
Service Hotline
4005-616-228
新闻中心
公司新闻
行业动态
IT知识
技术实力
服务质量
法律保障

MySQL 引擎特征:InnoDB瓦解规复

发布时间:2019-06-19????阅读:182 |
分享到:

原文出处: 水中的泪   

媒介

数据库体系与文件体系最大的区别在于数据库能担保操纵的原子性,一个操纵要么不做要么都做,纵然在数据库宕机的环境下,也不会呈现操纵一半的环境,这个就必要数据库的日记和一套完美的瓦解规复机制来担保。本文细心分解了InnoDB的瓦解规复流程,代码基于5.6分支。

基本常识

lsn: 可以领略为数据库从建设以来发生的redo日记量,这个值越大,声名数据库的更新越多,也可以领略为更新的时候。另外,每个数据页上也有一个lsn,暗示最后被修改时的lsn,值越大暗示越晚被修改。好比,数据页A的lsn为100,数据页B的lsn为200,checkpoint lsn为150,体系lsn为300,暗示当前体系已经更新到300,小于150的数据页已经被刷到磁盘上,因此数据页A的最新数据必然在磁盘上,而数据页B则不必然,有也许还在内存中。
redo日记: 当代数据库都必要写redo日记,譬喻修改一条数据,起首写redo日记,然后再写数据。在写完redo日记后,就直接给客户端返回乐成。这样固然看已往多写了一次盘,可是因为把对磁盘的随机写入(写数据)转换成了次序的写入(写redo日记),机能有很大幅度的进步。当数据库挂了之后,通过扫描redo日记,就能找出那些没有刷盘的数据页(在瓦解之前也许数据页仅仅在内存中修改了,可是还没来得及写盘),担保数据不丢。
undo日记: 数据库还提供相同取消的成果,当你发明修改错一些数据时,可以行使rollback指令回滚之前的操纵。这个成果必要undo日记来支持。另外,当代的相关型数据库为了进步并发(统一笔记录,差异线程的读取不斗嘴,读写和写读不斗嘴,只有同时写才斗嘴),都实现了相同MVCC的机制,在InnoDB中,这个也依靠undo日记。为了实现同一的打点,与redo日记差异,undo日记在Buffer Pool中有对应的数据页,与平凡的数据页一路打点,依据LRU法则也会被裁减出内存,后续再从磁盘读取。与平凡的数据页一样,对undo页的修改,也必要先写redo日记。
搜查点: 英文名为checkpoint。数据库为了进步机能,数据页在内存修改后并不是每次城市刷到磁盘上。checkpoint之前的数据页担保必然落盘了,这样之前的日记就没有效了(因为InnoDB redolog日记轮回行使,这时这部门日记就可以被包围),checkpoint之后的数据页有也许落盘,也有也许没有落盘,以是checkpoint之后的日记在瓦解规复的时辰照旧必要被行使的。InnoDB会依据脏页的革新环境,按期推进checkpoint,从而镌汰数据库瓦解规复的时刻。搜查点的信息在第一个日记文件的头部。
瓦解规复: 用户修改了数据,而且收到了乐成的动静,然而对数据库来说,也许这个时辰修改后的数据还没有落盘,假如这时辰数据库挂了,重启后,数据库必要从日记中把这些修改后的数据给捞出来,从头写入磁盘,担保用户的数据不丢。这个从日记中捞数据的进程就是瓦解规复的首要使命,也可以成为数据库前滚。虽然,在瓦解规复中还必要回滚没有提交的事宜,提交没有提交乐成的事宜。因为回滚操纵必要undo日记的支持,undo日记的完备性和靠得住性必要redo日记来担保,以是瓦解规复先做redo前滚,然后做undo回滚。

我们从源码角度细心分解一下数据库瓦解规复进程。整个进程都在引擎初始化阶段完成(innobase_init),个中最首要的函数是innobase_start_or_create_for_mysql,innodb通过这个函数完成建设和初始化,包罗瓦解规复。起首来先容一下数据库的前滚。

redo日记前滚数据库

前滚数据库,首要分为两阶段,起首是日记扫描阶段,扫描阶段凭证数据页的space_id和page_no分发redo日记到hash_table中,担保统一个数据页的日记被分发到统一个哈希桶中,且凭证lsn巨细从小到大排序。扫描完后,再遍历整个哈希表,依次应用每个数据页的日记,应用完后,在数据页的状态上至少规复到了瓦解之前的状态。我们来具体说明一下代码。
起首,打开全部的ibdata文件(open_or_create_data_files)(ibdata可以有多个),每个ibdata文件有个flush_lsn在头部,计较出这些文件中的max_flush_lsn和min_flush_lsn,由于ibdata也有也许稀有据没写完备,必要规复,后续(recv_recovery_from_checkpoint_start_func)通过较量checkpont_lsn和这两个值来确定是否必要对ibdata前滚。
接着,打开体系表空间和日记表空间的全部文件(fil_open_log_and_system_tablespace_files),防备呈现文件句柄不敷,清空buffer pool(buf_pool_invalidate)。接下来就进入最最焦点的函数:recv_recovery_from_checkpoint_start_func,留意,纵然数据库是正常封锁的,也会进入。
固然recv_recovery_from_checkpoint_start_func看已往很冗长,可是许多代码都是为了LOG_ARCHIVE特征而编写的,真正数据瓦解规复的代码着实不多。
起首,初始化一些变量,查察srv_force_recovery这个变量,假如用户配置跳过前滚阶段,函数直接返回。
接着,初始化recv_sys布局,分派hash_table的巨细,同时初始化flush list rbtree。recv_sys布局首要在瓦解规复前滚阶段行使。hash_table就是之前说的用来存差异数据页日记的哈希表,哈希表的巨细被初始化为buffer_size_in_bytes/512, 这个是哈希表最大的长度,高出就存不下了,荣幸的是,必要规复的数据页的个数不会高出这个值,由于buffer poll最多(数据库瓦解之前脏页的上线)只能存放buffer_size_in_bytes/16KB个数据页,纵然思量压缩页,最多也只有buffer_size_in_bytes/1KB个,另外关于这个哈希表内存分派的巨细,可以参考bug#53122。flush list rbtree这个首要是为了插手插入脏页列表,InnoDB的flush list必需凭证数据页的最老修改lsn(oldest_modifcation)从小到大排序,在数据库正常运行时,可以通过log_sys->mutex和log_sys->log_flush_order_mutex担保次序,在瓦解规复则没有这种担保,应用数据的时辰,是从第一个元素开始遍历哈希表,不能担保数据页凭证最老修改lsn(oldest_modifcation)从小到大排序,这样就必要线性遍历flush_list来探求插入位置,服从太低,因此引入红黑树,加速查找插入的位置。
接着,从ib_logfile0的头中读取checkpoint信息,首要包罗checkpoint_lsn和checkpoint_no。因为InnoDB日记是轮回行使的,且起码要有2个,以是ib_logfile0必然存在,把checkpoint信息存在内里很安详,不消担忧被删除。checkpoint信息着实会写在文件头的两个处所,两个checkpoint域轮番写。为什么要两个处所轮番写呢?假设只有一个checkpoint域,一向更新这个域,而checkpoint域有512字节(OS_FILE_LOG_BLOCK_SIZE),假如恰亏得写这个512字节的时辰,数据库挂了,处事器也挂了(先不思量硬件的原子写特征,早期的硬件没有这个特征),这个512字节也许只写了一半,导致整个checkpoint域不行用。这样数据库将无法做瓦解规复,从而无法启动。假若有两个checkpoint域,那么纵然一个写坏了,还可以用其它一个实行规复,固然有也许这个时辰日记已经被包围,可是至少进步了规复乐成的概率。两个checkpoint域轮番写,也能镌汰磁盘扇区妨碍带来的影响。checkpoint_lsn之前的数据页都已经落盘,不必要前滚,之后的数据页也许还祛除盘,必要从头规复出来,纵然已经落盘也不要紧,由于redo日记时幂等的,应用一次和应用两次都一样(底层实现: 假如数据页上的lsn大于便是当前redo日记的lsn,就不该用,不然应用。checkpoint_no可以领略为checkpoint域写盘的次数,每次刷盘递增1,同时这个值取模2可以用来实现checkpoint_no域的轮番写。正常逻辑下,选取checkpoint_no值大的作为最终的checkpoint信息,用来做后续瓦解规复扫描的起始点。
接着,行使checkpoint域的信息初始化recv_sys布局体的一些信息后,就进入日记理会的焦点函数recv_group_scan_log_recs,这个函数后续我们再说明,首要浸染就是理会redo日记,假如内存不足了,就直接挪用应用(recv_apply_hashed_log_recs)日记,然后再接着理会。假如必要应用的日记很少,就仅仅理会分发日记,到recv_recovery_from_checkpoint_finish函数中在应用日记。
接着,依据当前刷盘的数据页状态做一次checkpoint,由于在recv_group_scan_log_recs里也许已经应用部门日记了。至此recv_recovery_from_checkpoint_start_func函数竣事。
在recv_recovery_from_checkpoint_finish函数中,假如srv_force_recovery配置正确,就开始挪用函数recv_apply_hashed_log_recs应用日记,然后守候刷脏的线程退出(线程是瓦解规复时姑且启动的),最后开释recv_sys的相干资源以及hash_table占用的内存。
至此,数据库前滚竣事。接下来,我们具体说明一下redo日记理会函数以及redo日记应用函数的实现细节。

redo日记理会函数
收缩
  • 400-616-2280
  • 0531-88532317