一.日志模块:redo log
存在问题:
- 每一次的更新操作都需要写进磁盘,然后磁盘找到对应的那条记录,然后再更新,整个过程IO成本,查找成本很高。
解决方案:
WAL技术,Write-Ahead Logging
- 先写日志,再写磁盘 ----与Redis正相反
二.WAL技术
- 当有一条记录需要更新的时候,InnoDB引擎会先把记录写道redo log里面再更新内存,这时候就算更新完成。
- InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,这个更新往往会在系统空闲时进行。
三. redo log
InnoDB的red log是固定的,可以配置为一组4个文件,每个文件的大小是1GB
InnoDB可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力被称为crash-safe。
四.日志模块:binlog
- Server层的日志-binlog(归档日志)
- 引擎层,负责存储相应的具体事宜,innoDB日志-redo log
两者不同点:
- redo log是InnoDb引擎特有的;binlog是MySQL的server层实现的,所有引擎都可以使用。
- redo log是物理日志,记录的是“在某个数据页上做了什么修改”,binlog是逻辑日志,记录执行语句
- redo log是循环写,空间固定会用完;binlog是可以追加写,指binlog文件会一直追加,不会覆盖之前的日志。
五.执行update语句时的内部流程
- 执行器先找引擎ID=2这一行。ID是主键,引擎直接用树搜索找到这行 ,如果ID=2这一行所在的数据页本来就在内存中,就直接返回给执行器,否则从磁盘读入内存再返回。
- 执行器拿到引擎行数据,值加一,再调用引擎接口写入
- 引擎将这行新数据更新至内存中,同时这个更新操作记录到redo log中,此时redo log处于prepare状态,然后告知执行器完成,可以提交事务。
- 执行器生成这个操作的 binlog,并把 binlog 写入磁盘。
- 执行器调用引擎的提交事务接口,引擎刚把写入的redo log改成提交(commit)状态,更新完成。
六.两阶段提交
- 为什么必须要两阶段提交?
- 让两份日志之间的逻辑一致
怎样让数据库恢复到半个月内任意一秒的状态
解决方案:
- binlog会记录所有的逻辑操作,并且采用"追加写"的形式
- 备份系统可以保存最近半个月的所有binlog,同时系统会定期做整库备份
- 这个定期可以取决于系统的重要性,可以一天一备份,也可以一周一备份。
恢复场景:某天下午两点发现中午十二点有一次误删表
- 找最近一次全量备份,恢复到临时库;
- 从备份的时间点开始,将备份的binlog依次取出来,重新放到中午误删表之前那个时刻。
- 表数据从临时库取出来,按需要恢复到线上库去。
不做两提交的缺点:
先写 redo log 后写 binlog
- 假设redo log写完,binlog写之前,musql崩溃
- redo log写完以后,系统崩溃,让能把数据恢复过来
- binlog没写完就crash了,这时候binlog没有记录这个语句。
- 但是通过binlog同步的从库会导致从库缺失命令。
先写binlog再写redo log
- binlog写完以后crash住,但是redo log还没写,这时候事务无效
- 但是binlog日志已经记录
- 那么通过binlog同步的从库会导致从库增加了这个命令的执行。
- redo log用于保证crash-safe能力
- innodb_flush_log_at_trx_commit 为1 保证每次事务的redo_log都直接持久化到磁盘,mysql重启之后数据不丢失。
- sync_binlog这个参数设置成1的时候,表示每次事务的binlog都会持久化到磁盘保证mysql异常重启之后binlog不丢失。