当前位置: 首页 > news >正文

企业网站建设开题报告无锡网站建设哪家做得比较好

企业网站建设开题报告,无锡网站建设哪家做得比较好,深圳宝安天气,沧州网页设计百胜前言InnoDB 有两块非常重要的日志#xff0c;一个是undo log#xff0c;另外一个是redo log#xff0c;前者用来保证事务的原子性以及InnoDB的MVCC#xff0c;后者用来保证事务的持久性。和大多数关系型数据库一样#xff0c;InnoDB记录了对数据文件的物理更改#xff0c…前言InnoDB 有两块非常重要的日志一个是undo log另外一个是redo log前者用来保证事务的原子性以及InnoDB的MVCC后者用来保证事务的持久性。和大多数关系型数据库一样InnoDB记录了对数据文件的物理更改并保证总是日志先行也就是所谓的WAL即在持久化数据文件前保证之前的redo日志已经写到磁盘。LSN(log sequence number) 用于记录日志序号它是一个不断递增的 unsigned long long 类型整数。在 InnoDB 的日志系统中LSN 无处不在它既用于表示修改脏页时的日志序号也用于记录checkpoint通过LSN可以具体的定位到其在redo log文件中的位置。为了管理脏页在 Buffer Pool 的每个instance上都维持了一个flush listflush list 上的 page 按照修改这些 page 的LSN号进行排序。因此定期做redo checkpoint点时选择的 LSN 总是所有 bp instance 的 flush list 上最老的那个page(拥有最小的LSN)。由于采用WAL的策略每次事务提交时需要持久化 redo log 才能保证事务不丢。而延迟刷脏页则起到了合并多次修改的效果避免频繁写数据文件造成的性能问题。由于 InnoDB 日志组的特性已经被废弃(redo日志写多份)归档日志(InnoDB archive log)特性也在5.7被彻底移除本文在描述相关逻辑时会忽略这些逻辑。另外限于篇幅InnoDB崩溃恢复的逻辑将在下期讲述本文重点阐述redo log 产生的生命周期以及MySQL 5.7的一些改进点。本文的分析基于最新的MySQL 5.7.7-RC版本。InnoDB 日志文件InnoDB的redo log可以通过参数innodb_log_files_in_group配置成多个文件另外一个参数innodb_log_file_size表示每个文件的大小。因此总的redo log大小为innodb_log_files_in_group * innodb_log_file_size。Redo log文件以ib_logfile[number]命名日志目录可以通过参数innodb_log_group_home_dir控制。Redo log 以顺序的方式写入文件文件写满时则回溯到第一个文件进行覆盖写。(但在做redo checkpoint时也会更新第一个日志文件的头部checkpoint标记所以严格来讲也不算顺序写)。在InnoDB内部逻辑上ib_logfile被当成了一个文件对应同一个space id。由于是使用512字节block对齐写入文件可以很方便的根据全局维护的LSN号计算出要写入到哪一个文件以及对应的偏移量。Redo log文件是循环写入的在覆盖写之前总是要保证对应的脏页已经刷到了磁盘。在非常大的负载下Redo log可能产生的速度非常快导致频繁的刷脏操作进而导致性能下降通常在未做checkpoint的日志超过文件总大小的76%之后InnoDB 认为这可能是个不安全的点会强制的preflush脏页导致大量用户线程stall住。如果可预期会有这样的场景我们建议调大redo log文件的大小。可以做一次干净的shutdown然后修改Redo log配置重启实例。除了redo log文件外InnoDB还有其他的日志文件例如为了保证truncate操作而产生的中间日志文件包括 truncate innodb 表以及truncate undo log tablespace都会产生一个中间文件来标识这些操作是成功还是失败如果truncate没有完成则需要在 crash recovery 时进行重做。有意思的是根据官方worklog的描述最初实现truncate操作的原子化时是通过增加新的redo log类型来实现的但后来不知道为什么又改成了采用日志文件的方式也许是考虑到低版本兼容的问题吧。关键结构体log_sys对象log_sys是InnoDB日志系统的中枢及核心对象控制着日志的拷贝、写入、checkpoint等核心功能。它同时也是大写入负载场景下的热点模块是连接InnoDB日志文件及log buffer的枢纽对应结构体为log_t。其中与 redo log 文件相关的成员变量包括变量名描述log_groups日志组当前版本仅支持一组日志对应类型为 log_group_t 包含了当前日志组的文件个数、每个文件的大小、space id等信息lsn_t log_group_capacity表示当前日志文件的总容量值为:(Redo log文件总大小 - redo 文件个数 * LOG_FILE_HDR_SIZE) * 0.9LOG_FILE_HDR_SIZE 为 4*512 字节lsn_t max_modified_age_async异步 preflush dirty page 点lsn_t max_modified_age_sync同步 preflush dirty page 点lsn_t max_checkpoint_age_async异步 checkpoint 点lsn_t max_checkpoint_age同步 checkpoint 点上述几个sync/async点的计算方式可以参阅函数log_calc_max_ages以如下实例配置为例innodb_log_files_in_group4innodb_log_file_size4G总文件大小: 17179869184各个成员变量值及占总文件大小的比例log_sys-log_group_capacity 15461874893 (90%)log_sys-max_modified_age_async 12175607164 (71%)log_sys-max_modified_age_sync 13045293390 (76%)log_sys-max_checkpoint_age_async 13480136503 (78%)log_sys-max_checkpoint_age 13914979615 (81%)通常的当当前未刷脏的最老lsn和当前lsn的距离超过max_modified_age_async(71%)时且开启了选项innodb_adaptive_flushing时page cleaner线程会去尝试做更多的dirty page flush工作避免脏页堆积。 当当前未刷脏的最老lsn和当前Lsn的距离超过max_modified_age_sync(76%)时用户线程需要去做同步刷脏这是一个性能下降的临界点会极大的影响整体吞吐量和响应时间。 当上次checkpoint的lsn和当前lsn超过max_checkpoint_age(81%)用户线程需要同步地做一次checkpoint需要等待checkpoint写入完成。 当上次checkpoint的lsn和当前lsn的距离超过max_checkpoint_age_async(78%)但小于max_checkpoint_age(81%)时用户线程做一次异步checkpoint(后台异步线程执行CHECKPOINT信息写入操作)无需等待checkpoint完成。log_group_t结构体主要成员如下表所示变量名描述ulint n_filesIb_logfile的文件个数lsn_t file_size文件大小ulint space_idRedo log 的space id, 固定大小值为SRV_LOG_SPACE_FIRST_IDulint stateLOG_GROUP_OK 或者 LOG_GROUP_CORRUPTEDlsn_t lsn该group内写到的lsnlsn_t lsn_offset上述lsn对应的文件偏移量byte** file_header_bufsBuffer区域用于设定日志文件头信息并写入ib logfile。当切换到新的ib_logfile时更新该文件的起始lsn写入头部。 头部信息还包含 LOG_GROUP_ID, LOG_FILE_START_LSN(当前文件起始lsn)、LOG_FILE_WAS_CREATED_BY_HOT_BACKUP(函数log_group_file_header_flush)lsn_t scanned_lsn用于崩溃恢复时辅助记录扫描到的lsn号byte* checkpoint_bufCheckpoint缓冲区用于向日志文件写入checkpoint信息(下文详细描述)与redo log 内存缓冲区相关的成员变量包括变量名描述ulint buf_freeLog buffer中当前空闲可写的位置byte* bufLog buffer起始位置指针ulint buf_sizeLog buffer 大小受参数innodb_log_buffer_size控制但可能会自动extendulint max_buf_free值为log_sys-buf_size / LOG_BUF_FLUSH_RATIO - LOG_BUF_FLUSH_MARGIN, 其中 LOG_BUF_FLUSH_RATIO2, LOG_BUF_FLUSH_MARGIN(4 * 512 4* page_size) ,page_size默认为16k,当buf_free超过该值时可能触发用户线程去写redo在事务拷redo 到buffer后也会判断该值如果超过buf_free设置log_sys-check_flush_or_checkpoint为trueulint buf_next_to_writeLog buffer偏移量下次写入redo文件的起始位置即本次写入的结束位置volatile bool is_extendingLog buffer是否正在进行扩展 (防止过大的redo log entry无法写入buffer), 实际上当写入的redo log长度超过buf_size/2时就会去调用函数log_buffer_extend,一旦扩展Buffer就不会在缩减回去了ulint write_end_offset本次写入的结束位置偏移量(从逻辑来看有点多余直接用log_sys-buf_free就行了)和Checkpoint检查点相关的成员变量变量名描述ib_uint64_t next_checkpoint_no每完成一次checkpoint递增该值lsn_t last_checkpoint_lsn最近一次checkpoint时的lsn每完成一次checkpoint将next_checkpoint_lsn的值赋给last_checkpoint_lsnlsn_t next_checkpoint_lsn下次checkpoint的lsn(本次发起的checkpoint的lsn)mtr_buf_t* append_on_checkpoint5.7新增在做DDL时(例如增删列)会先将包含MLOG_FILE_RENAME2日志记录的buf挂到这个变量上。 在DDL完成后再清理掉。(log_append_on_checkpoint),主要是防止DDL期间crash产生的数据词典不一致。 该变量在如下commit加上 a5ecc38f44abb66aa2024c70e37d1f4aa4c8ace9ulint n_pending_checkpoint_writes大于0时表示有一个checkpoint写入操作正在进行。用户发起checkpoint时递增该值。后台线程完成checkpoint写入后递减该值(log_io_complete)rw_lock_t checkpoint_lockcheckpoint锁每次写checkpoint信息时需要加x锁。由异步io线程释放该x锁byte* checkpoint_bufCheckpoint信息缓冲区每次checkpoint前先写该buf再将buf刷到磁盘其他状态变量变量名描述bool check_flush_or_checkpoint当该变量被设置时用户线程可能需要去检查释放要刷log buffer、或是做preflush、checkpoint等以防止Redo 空间不足lsn_t write_lsn最近一次完成写入到文件的LSNlsn_t current_flush_lsn当前正在fsync到的LSNlsn_t flushed_to_disk_lsn最近一次完成fsync到文件的LSNulint n_pending_flushes表示pending的redo fsync这个值最大为1os_event_t flush_event若当前有正在进行的fsync并且本次请求也是fsync操作则需要等待上次fsync操作完成log_sys与日志文件和日志缓冲区的关系可用下图来表示Mini transactionMini transaction(简称mtr)是InnoDB对物理数据文件操作的最小事务单元用于管理对Page加锁、修改、释放、以及日志提交到公共buffer等工作。一个mtr操作必须是原子的一个事务可以包含多个mtr。每个mtr完成后需要将本地产生的日志拷贝到公共缓冲区将修改的脏页放到flush list上。mtr事务对应的类为mtr_t, mtr_t::Impl中保存了当前mtr的相关信息包括:变量名描述mtr_buf_t m_memo用于存储该mtr持有的锁类型mtr_buf_t m_log存储redo log记录bool m_made_dirty是否产生了至少一个脏页bool m_inside_ibuf是否在操作change bufferbool m_modifications是否修改了buffer pool pageib_uint32_t m_n_log_recs该mtr log记录个数mtr_log_t m_log_modeMtr的工作模式包括四种 MTR_LOG_ALL默认模式记录所有会修改磁盘数据的操作MTR_LOG_NONE不记录redo脏页也不放到flush list上MTR_LOG_NO_REDO不记录redo但脏页放到flush list上MTR_LOG_SHORT_INSERTS插入记录操作REDO在将记录从一个page拷贝到另外一个新建的page时用到此时忽略写索引信息到redo log中。(参阅函数page_cur_insert_rec_write_log)fil_space_t* m_user_space当前mtr修改的用户表空间fil_space_t* m_undo_space当前mtr修改的undo表空间fil_space_t* m_sys_space当前mtr修改的系统表空间mtr_state_t m_state包含四种状态: MTR_STATE_INIT、MTR_STATE_COMMITTING、 MTR_STATE_COMMITTED在修改或读一个数据文件中的数据时一般是通过mtr来控制对对应page或者索引树的加锁在5.7中有以下几种锁类型(mtr_memo_type_t)变量名描述MTR_MEMO_PAGE_S_FIX用于PAGE上的S锁MTR_MEMO_PAGE_X_FIX用于PAGE上的X锁MTR_MEMO_PAGE_SX_FIX用于PAGE上的SX锁以上锁通过mtr_memo_push 保存到mtr中MTR_MEMO_BUF_FIXPAGE上未加读写锁仅做buf fixMTR_MEMO_S_LOCKS锁通常用于索引锁MTR_MEMO_X_LOCKX锁通常用于索引锁MTR_MEMO_SX_LOCKSX锁通常用于索引锁以上3个锁通过mtr_s/x/sx_lock加锁通过mtr_memo_release释放锁mtr log生成InnoDB的redo log都是通过mtr产生的先写到mtr的cache中然后再提交到公共buffer中本小节以INSERT一条记录对page产生的修改为例阐述一个mtr的典型生命周期。入口函数row_ins_clust_index_entry_low开启mtr执行如下代码块mtr_start(mtr);mtr.set_named_space(index-space);mtr_start主要包括初始化mtr的各个状态变量默认模式为MTR_LOG_ALL表示记录所有的数据变更mtr状态设置为ACTIVE状态(MTR_STATE_ACTIVE)为锁管理对象和日志管理对象初始化内存(mtr_buf_t),初始化对象链表mtr.set_named_space 是5.7新增的逻辑将当前修改的表空间对象fil_space_t保存下来如果是系统表空间则赋值给m_impl.m_sys_space, 否则赋值给m_impl.m_user_space。Tips 在5.7里针对临时表做了优化直接关闭redo记录 mtr.set_log_mode(MTR_LOG_NO_REDO)定位记录插入的位置主要入口函数 btr_cur_search_to_nth_level不管插入还是更新操作都是先以乐观方式进行因此先加索引S锁 mtr_s_lock(dict_index_get_lock(index),mtr)对应mtr_t::s_lock函数 如果以悲观方式插入记录意味着可能产生索引分裂在5.7之前会加索引X锁而5.7版本则会加SX锁(但某些情况下也会退化成X锁) 加X锁 mtr_x_lock(dict_index_get_lock(index), mtr),对应mtr_t::x_lock函数 加SX锁mtr_sx_lock(dict_index_get_lock(index),mtr)对应mtr_t::sx_lock函数对应到内部实现实际上就是加上对应的锁对象然后将该锁的指针和类型构建的mtr_memo_slot_t对象插入到mtr.m_impl.m_memo中。当找到预插入page对应的block还需要加block锁并把对应的锁类型加入到mtrmtr_memo_push(mtr, block, fix_type)如果对page加的是MTR_MEMO_PAGE_X_FIX或者MTR_MEMO_PAGE_SX_FIX锁并且当前block是clean的则将m_impl.m_made_dirty设置成true表示即将修改一个干净的page。如果加锁类型为MTR_MEMO_BUF_FIX实际上是不加锁对象的但需要判断临时表的场景临时表page的修改不加latch但需要将m_impl.m_made_dirty设置为true(根据block的成员m_impl.m_made_dirty来判断)这也是5.7对InnoDB临时表场景的一种优化。同样的根据锁类型和锁对象构建mtr_memo_slot_t加入到m_impl.m_memo中。插入数据在插入数据过程中包含大量的redo写cache逻辑例如更新二级索引页的max trx id、写undo log产生的redo(嵌套另外一个mtr)、修改数据页产生的日志。这里我们只讨论修改数据页产生的日志进入函数page_cur_insert_rec_write_log:Step 1: 调用函数mlog_open_and_write_index记录索引相关信息调用mlog_open分配足够日志写入的内存地址并返回内存指针初始化日志记录mlog_write_initial_log_record_fast 写入 |类型MLOG\_COMP\_REC\_INSERT1字节|space id | page no| space id 和page no采用一种压缩写入的方式(mach_write_compressed)根据数字的具体大小选择从1到4个字节记录整数节约redo空间对应的解压函数为mach_read_compressed写入当前索引列个数占两个字节写入行记录上决定唯一性的列的个数占两个字节(dict_index_get_n_unique_in_tree) 对于聚集索引就是PK上的列数对于二级索引就是二级索引列PK列个数写入每个列的长度信息每个列占两个字节 如果这是 varchar 列且最大长度超过255字节, len 0x7fff如果该列非空len | 0x8000其他情况直接写入列长度。Step 2: 写入记录在page上的偏移量占两个字节mach_write_to_2(log_ptr, page_offset(cursor_rec));Step 3: 写入记录其它相关信息 (rec size, extra size, info bit关于InnoDB的数据文件物理描述我们以后再介绍本文不展开)Step 4: 将插入的记录拷贝到redo文件同时关闭mlogmemcpy(log_ptr, ins_ptr, rec_size);mlog_close(mtr, log_ptr rec_size);通过上述流程我们写入了一个类型为MLOG_COMP_REC_INSERT的日志记录。由于特定类型的记录都基于约定的格式在崩溃恢复时也可以基于这样的约定解析出日志。这里只举了一个非常简单的例子该mtr中只包含一条redo记录。实际上mtr遍布整个InnoDB的逻辑但只要遵循相同的写入和读取约定并对写入的单元(page)加上互斥锁就能从崩溃恢复。更多的redo log记录类型参见enum mlog_id_t。在这个过程中产生的redo log都记录在mtr.m_impl.m_log中只有显式提交mtr时才会写到公共buffer中。提交mtr log当提交一个mini transaction时需要将对数据的更改记录提交到公共buffer中并将对应的脏页加到flush list上。入口函数为mtr_t::commit()当修改产生脏页或者日志记录时调用mtr_t::Command::execute执行过程如下Step 1: mtr_t::Command::prepare_write()若当前mtr的模式为MTR_LOG_NO_REDO 或者MTR_LOG_NONE则获取log_sys-mutex从函数返回若当前要写入的redo log记录的大小超过log buffer的二分之一则去扩大log buffer大小约为原来的两倍。持有log_sys-mutex调用函数log_margin_checkpoint_age检查本次写入 如果本次产生的redo log size的两倍超过redo log文件capacity则打印一条错误信息若本次写入可能覆盖检查点还需要去强制做一次同步chekpoint检查本次修改的表空间是否是上次checkpoint后第一次修改调用函数(fil_names_write_if_was_clean) 如果space-max_lsn 0表示自上次checkpoint后第一次修改该表空间 a. 修改space-max_lsn为当前log_sys-lsn b. 调用fil_names_dirty_and_write将该tablespace加入到fil_system-named_spaces链表上 c. 调用fil_names_write写入一条类型为MLOG_FILE_NAME的日志写入类型、spaceid, page no(0)、文件路径长度、以及文件路径名。在mtr日志末尾追加一个字节的MLOG_MULTI_REC_END类型的标记表示这是多个日志类型的mtr。Tips在5.6及之前的版本中每次crash recovery时都需要打开所有的ibd文件如果表的数量非常多时会非常影响崩溃恢复性能因此从5.7版本开始每次checkpoint后第一次修改的文件名被记录到redo log中这样在重启从检查点恢复时就只打开那些需要打开的文件即可(WL#7142)如果不是从上一次checkpoint后第一次修改该表则根据mtr中log的个数或标识日志头最高位为MLOG_SINGLE_REC_FLAG或附加一个1字节的MLOG_MULTI_REC_END日志。注意从prepare_write函数返回时是持有log_sys-mutex锁的。至此一条插入操作产生的mtr日志格式有可能如下图所示Step 2: mtr_t::Command::finish_write将日志从mtr中拷贝到公共log buffer。这里有两种方式如果mtr中的日志较小则调用函数log_reserve_and_write_fast尝试将日志拷贝到log buffer最近的一个block。如果空间不足走逻辑b)否则直接拷贝检查是否有足够的空闲空间后返回当前的lsn赋值给m_start_lsn(log_reserve_and_open(len))随后将日志记录写入到log buffer中。m_start_lsn log_reserve_and_open(len);mtr_write_log_t write_log;m_impl-m_log.for_each_block(write_log);在完成将redo 拷贝到log buffer后需要调用log_close, 如果最后一个block未写满则设置该block头部的LOG_BLOCK_FIRST_REC_GROUP信息 满足如下情况时设置log_sys-check_flush_or_checkpoint为true当前写入buffer的位置超过log buffer的一半bp中最老lsn和当前lsn的距离超过log_sys-max_modified_age_sync当前未checkpoint的lsn age超过log_sys-max_checkpoint_age_async当前bp中最老lsn为0 (没有脏页)当check_flush_or_checkpoint被设置时用户线程在每次修改数据前调用log_free_check时会根据该标记决定是否刷redo日志或者脏页。注意log buffer遵循一定的格式它以512字节对齐和redo log文件的block size必须完全匹配。由于以固定block size组织结构因此一个block中可能包含多个mtr提交的记录也可能一个mtr的日志占用多个block。如下图所示Step 3如果本次修改产生了脏页获取log_sys-log_flush_order_mutex随后释放log_sys-mutex。Step 4. 将当前Mtr修改的脏页加入到flush list上脏页上记录的lsn为当前mtr写入的结束点lsn。基于上述加锁逻辑能够保证flush list上的脏页总是以LSN排序。Step 5. 释放log_sys-log_flush_order_mutex锁Step 6. 释放当前mtr持有的锁(主要是page latch)及分配的内存mtr完成提交。Redo 写盘操作有几种场景可能会触发redo log写文件Redo log buffer空间不足时事务提交后台线程做checkpoint实例shutdown时binlog切换时我们所熟悉的参数innodb_flush_log_at_trx_commit 作用于事务提交时这也是最常见的场景当设置该值为1时每次事务提交都要做一次fsync这是最安全的配置即使宕机也不会丢失事务当设置为2时则在事务提交时只做write操作只保证写到系统的page cache因此实例crash不会丢失事务但宕机则可能丢失事务当设置为0时事务提交不会触发redo写操作而是留给后台线程每秒一次的刷盘操作因此实例crash将最多丢失1秒钟内的事务。下图表示了不同配置值的持久化程度显然对性能的影响是随着持久化程度的增加而增加的。通常我们建议在日常场景将该值设置为1但在系统高峰期临时修改成2以应对大负载。由于各个事务可以交叉的将事务日志拷贝到log buffer中因而一次事务提交触发的写redo到文件可能隐式的帮别的线程“顺便”也写了redo log从而达到group commit的效果。写redo log的入口函数为log_write_up_to该函数的逻辑比较简单这里不详细描述但有几点说明下。log_write_up_to逻辑重构首先是在该代码逻辑上相比5.6及之前的版本5.7在没有更改日志写主要架构的基础上重写了log_write_up_to让其代码更加可读同时消除一次多余的获取log_sys-mutex具体的(WL#7050)早期版本的innodb支持将redo写到多个group中但现在只支持一个group因此移除相关的变量消除log_write_up_to的第二个传参write redo操作一直持有log_sys-mutex, 所有随后的write请求不再进入condition wait, 而是通过log_sys-mutex序列化之前的逻辑中在write一次redo后需要释放log_sys-mutex再重新获取更新相关变量新的逻辑消除了第二次获取 log_sys-mutexwrite请求的写redo无需等待fsync这意味着写redo log文件和fsync文件可以同时进行。理论上该改动可以帮助优化innodb_flush_log_at_trx_commit2时的性能。log write ahead上面已经介绍过InnoDB以512字节一个block的方式对齐写入ib_logfile文件但现代文件系统一般以4096字节为一个block单位。如果即将写入的日志文件块不在OS Cache时就需要将对应的4096字节的block读入内存修改其中的512字节然后再把该block写回磁盘。为了解决这个问题MySQL 5.7引入了一个新参数innodb_log_write_ahead_size。当当前写入文件的偏移量不能整除该值时则补0多写一部分数据。这样当写入的数据是以磁盘block size对齐时就可以直接write磁盘而无需read-modify-write这三步了。注意innodb_log_write_ahead_size的默认值为8196你可能需要根据你的系统配置来修改该值以获得更好的效果。Innodb redo log checksum在写入redo log到文件之前redo log的每一个block都需要加上checksum校验位以防止apply了损坏的redo log。然而在5.7.7版本之前版本都是使用的InnoDB的默认checksum算法(称为InnoDB checksum)这种算法的效率较低。因此在MySQL5.7.8以及Percona Server 5.6版本都支持使用CRC32的checksum算法该算法可以引用硬件特性因而具有非常高的效率。在我的sysbench测试中使用update_non_index128个并发下TPS可以从55000上升到60000(非双1)效果还是非常明显的。Redo checkpointInnoDB的redo log采用覆盖循环写的方式而不是拥有无限的redo空间即使拥有理论上极大的redo log空间为了从崩溃中快速恢复及时做checkpoint也是非常有必要的。InnoDB的master线程大约每隔10秒会做一次redo checkpoint但不会去preflush脏页来推进checkpoint点。通常普通的低压力负载下page cleaner线程的刷脏速度足以保证可作为检查点的lsn被及时的推进。但如果系统负载很高时redo log推进速度过快而page cleaner来不及刷脏这时候就会出现用户线程陷入同步刷脏并做同checkpoint的境地这种策略的目的是为了保证redo log能够安全的写入文件而不会覆盖最近的检查点。redo checkpoint的入口函数为log_checkpoint其执行流程如下Step1. 持有log_sys-mutex锁并获取buffer pool的flush list链表尾的block上的lsn这个lsn是buffer pool中未写入数据文件的最老lsn在该lsn之前的数据都保证已经写入了磁盘。Step 2. 调用函数fil_names_clear如果log_sys-append_on_checkpoint被设置表示当前有会话正处于DDL的commit阶段但还没有完成向redo log buffer中追加一个新的redo log记录 该逻辑由commita5ecc38f44abb66aa2024c70e37d1f4aa4c8ace9引入用于解决DDL过程中crash的问题扫描fil_system-named_spaces上的fil_space_t对象如果表空间fil_space_t-max_lsn小于当前准备做checkpoint的Lsn则从链表上移除并将max_lsn重置为0。同时为每个被修改的表空间构建MLOG_FILE_NAME类型的redo记录。(这一步未来可能会移除只要跟踪第一次修改该表空间的min_lsn并且min_lsn大于当前checkpoint的lsn就可以忽略调用fil_names_write)写入一个MLOG_CHECKPOINT类型的CHECKPOINT REDO记录并记入当前的checkpoint LSNStep3 . fsync redo log到当前的lsnStep4. 写入checkpoint信息函数log_write_checkpoint_info -- log_group_checkpointcheckpoint信息被写入到了第一个iblogfile的头部但写入的文件偏移位置比较有意思当log_sys-next_checkpoint_no为奇数时写入到LOG_CHECKPOINT_2(3 *512字节)位置为偶数时写入到LOG_CHECKPOINT_1(512字节)位置。大致结构如下图所示在crash recover重启时会读取记录在checkpoint中的lsn信息然后从该lsn开始扫描redo日志。Checkpoint操作由异步IO线程执行写入操作当完成写入后会调用函数log_io_complete执行如下操作fsync 被修改的redo log文件更新相关变量log_sys-next_checkpoint_nolog_sys-last_checkpoint_lsn log_sys-next_checkpoint_lsn释放log_sys-checkpoint_lock锁然而在5.7之前的版本中我们并没有根据即将写入的数据大小来预测当前是否需要做checkpoint而是在写之前检测保证redo log文件中有”足够安全”的空间(而非绝对安全)。假定我们的ib_logfile文件很小如果我们更新一个非常大的blob字段就有可能覆盖掉未checkpoint的redo log 大神Jeremy cole 在buglist上提了一个Bug#69477。为了解决该问题在MySQL 5.6.22版本开始对blob列做了限制: 当redo log的大小超过 (innodb_log_file_size *innodb_log_files_in_group)的十分之一时就会给应用报错然而这可能会带来不兼容问题用户会发现早期版本用的好好的SQL在最新版本的5.6里居然跑不动了。在5.7.5及之后版本则没有5.6的限制其核心思路是每操作4个外部存储页就检查一次redo log是否足够用如果不够就会推进checkpoint的lsn。当然具体的实现比较复杂感兴趣的参考如下comitf88a5151b18d24303746138a199db910fbb3d071文件日志除了普通的redo log日志外InnoDB还增加了一种文件日志类型即通过创建特定文件赋予特定的文件名来标示某种操作。目前有两种类型undo table space truncate操作及用户表空间truncate操作。通过文件日志可以保证这些操作的原子性。Undo tablespace truncate我们知道undo log是MVCC多版本控制的核心模块一直以来undo log都存储在ibdata系统表空间中而从5.6开始用户可以把undo log存储到独立的tablespace中并拆分成多个Undo log文件但无法缩小文件的大小。而长时间未提交事务导致大量undo空间的浪费的例子在我们的生产场景也不是一次两次了。5.7版本的undo log的truncate操作是基于独立undo 表空间来实现的。在purge线程选定需要清理的undo tablespace后开始做truncate操作之前会先创建一个命名为undo_space_id_trunc.log的文件然后将undo tablespace truncate 到10M大小在完成truncate后删除日志文件。如果在truncate过程中实例崩溃重启若发现该文件存在则认为truncate操作没有完成需要重做一遍。注意这种文件操作是无法回滚的。User tablespace truncate类似的在5.7版本里也是通过日志文件来保证用户表空间truncate操作的原子性。在做实际的文件操作前创建一个命名为ib_space-id_table-id_trunc.log的文件。在完成操作后删除。同样的在崩溃重启时如果检查到该文件存在需要确认是否重做。InnoDB shutdown实例关闭分为两种一种是正常shutdown(非fast shutdown)实例重启时无需apply日志另外一种是异常shutdown包括实例crash以及fast shutdown。当正常shutdown实例时会将所有的脏页都刷到磁盘并做一次完全同步的checkpoint同时将最后的lsn写到系统表ibdata的第一个page中(函数fil_write_flushed_lsn)。在重启时可以根据该lsn来判断这是不是一次正常的shutdown如果不是就需要去做崩溃恢复逻辑。参阅函数logs_empty_and_mark_files_at_shutdown。关于异常重启的逻辑由于崩溃恢复涉及到的模块众多逻辑复杂我们将在下期月报单独进行描述。
http://www.ihoyoo.com/news/96948.html

相关文章:

  • 江苏和城乡建设厅网站中国工程监理人才网
  • 企业建筑网站内容营销的定义
  • 高权重网站做js代码跳转php网站建设参考文献
  • 小说网站的阅读界面怎么做的焊接球网架公司
  • 网站推广的途径和推广要点中山市两学一做网站
  • 《网站推广策划》哪家网站开发公司好
  • 临西网站建设价格wordpress去掉category
  • 容县网站开发网店营销推广方案论文
  • 住房城乡建设厅网站准考证网站备案 内容
  • 夸克建站系统官网网站建设为了什么
  • 常德论坛市民留言合肥seo建站
  • fms 视频网站建设秦皇岛市海港区邮编
  • 中国化工网网站建设建议网页设计是干嘛的
  • 建一个商城网站需要多少钱大连金普新区规划建设局网站
  • 学做简单网站江苏网站建设哪家快点
  • 境外建网站东莞 网站建设多少钱
  • 建网站要花费多少钱实业有限公司网站怎么做
  • 网站打开慢什么原因服务器创建wordpress
  • 阜宁做网站哪家公司最好鄢陵网站建设电脑建站
  • 温州市网站建设哪家公司好北京到安阳防疫政策
  • 温州建设监理协会网站网页浏览历史记录在哪
  • 如何用百度云文件做网站天津做网站贵吗
  • 西宁网站seo公司狗头网网站
  • 阿里小说网站模板岫岩做网站
  • 佛山微网站推广小内存安装wordpress
  • 上海网站策划韩国化妆品网站模板
  • 做网站就是做appwordpress 多个注册表单
  • 济南住房与城乡建设局网站华为最新版
  • 怎么弄网站做网站卖东西深圳专业英文网站建设
  • 网站建设成功案例宣传网站建设模板元素是什么