本文是MySQL实战专栏第二篇,关于mysql日志系统
MySQL日志
- slq更新流程会涉及两个重要日志模块
- 重做日志,redo log
- 二进制日志 binlog
重做日志 redo log
- mysql每次更新操作都需要写磁盘,在此盘找到对应的纪录,然后更新,整个过程成本非常高,为了解决此问题,mysql采取了下面的策略:
- write-ahead logging:有记录需要更新时,innodb引擎会先把记录写到redo log,并更新内存,存储引擎会在适当时候,将更新记录写到磁盘
- redo log有固定大小,比如配置一组四个文件,编号为ib_logfile0,ib_logfile1,ib_logfile2,ib_logfile3每个文件大小1g,总共就是4g,从头开始写,写到末尾又回到开头写,write pos是当前记录位置,一边写,一边后移,写到3号文件末尾又回到0号开头,check point是当前要擦除的位置,也是往后移动并循环,擦除记录前要把记录更新到数据文件,write pos与checkpoint之间空着的部分,可以用来记录新纪录,如果write pos追上checkpoint,表示空间满了,此时不能再执行更新操作,得先擦除一些记录,把checkpoint推进以下
- 有了redo log innodb就可以保证数据库发生异常重启,之前的提交记录不会丢失,这个能力叫crash-safe
- redo log是存储引擎层特有的日志
- innodb_flush_log_at_trx_commit 参数设为1,表示每次事务的redo log都直接持久化到磁盘,保证mysql异常重启之后数据不丢失,建议设置为1
二进制日志 binglog
- binlog是server层日志
- binlog只能用于归档,没有crash-safe能力,所以需要redo log来实现
- sync_binlog设置为1,表示每次事务的binlog都持久化到磁盘,保证mysql异常重启后binlog比丢失,建议设置为1
- binglog有两种模式:一种是statement,记录sql语句,另一个是row,会记录行的内容,更新前,更新后都有,记两条
两种日志有三点不同:
- redo log是innodb存储引擎层特有,binlog是server层的,所有存储引擎都可以使用
- redo log是物理日志,记录的是在某个数据页做了啥修改,binlog记录的是逻辑日志,记录语句的原始逻辑。比如,给id=2的这行的某个字段加1
- redo log是循环写,binlog是追加写入,binlog文件写到一定大小会切换到下一个,并不覆盖之前的日志
innodb存储引擎执行update语句时的流程
以 update t1 set c=c+1 where id =2 这条语句为例说明
(1)执行器找存储引擎取id=2这行,如果此行数据页在内存中,就直接返回给执行器,否则,先从磁盘读到内存,然后返回
(2)执行器拿到这行数据,把值加1,得到新数据c+1,调用接口写入新数据
(3)引擎将新数据更新到内存,同时将更新记录写到redo log,此时redo log处于prepare状态,告知执行器执行完毕,随时可以提交事务
(4)执行器生成这个操作的binlog,并写入磁盘
(5)执行器调用引擎提交事务接口,引擎把刚刚写入的redo log改写成commit状态
上面redo log的prepare和commit这两个状态就是两阶段提交
为什么要实行两阶段提交?
- 为了让两个日志之间的逻辑一致
- 不使用两阶段提交,会导致数据库状态有可能与用它日志恢复出来的库状态不一致,