[整理] MySQL日志系统:redo log、binlog、undo log

日志系统主要有redo log(重做日志)和binlog(归档日志)。redo log是InnoDB存储引擎层的日志,binlog是MySQL Server层记录的日志,两者都是记录了某些操作的日志(不是所有)自然有些重复(但两者记录的格式不同)。

  1. 重做日志(redo log)
    作用:
    确保事务的持久性。防止在发生故障的时间点,尚有脏页未写入磁盘,在重启mysql服务的时候,根据redo log进行重做,从而达到事务的持久性这一特性。

  2. 回滚日志(undo log)
    作用:
    保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制(MVCC)下的读,也即非锁定读

  3. 二进制日志(binlog):
    作用:
    用于复制,在主从复制中,从库利用主库上的binlog进行重播,实现主从同步。
    用于数据库的基于时间点的还原。

另外还有:错误日志(errorlog)、慢查询日志(slow query log)、一般查询日志(general log),中继日志(relay log)。其中:

  1. 中继日志(relay log)
    Mysql 主节点将binlog写入本地,从节点定时请求增量binlog,主节点将binlog同步到从节点。
    从节点单独进程会将binlog 拷贝至本地 relaylog中。
    从节点定时重放relay log。

  2. WAL技术
    在一条更新语句进行执行的时候,InnoDB引擎会把更新记录写到redo log日志中,然后更新内存,此时算是语句执行完了,然后在空闲的时候或者是按照设定的更新策略将redo log中的内容更新到磁盘中,这里涉及到WAL即Write Ahead logging技术,他的关键点是先写日志,再写磁盘。

有了redo log日志,那么在数据库进行异常重启的时候,可以根据redo log日志进行恢复,也就达到了crash-safe。
redo log日志的大小是固定的,即记录满了以后就从头循环写。

一组4个文件的redo log日志,checkpoint之前表示擦除完了的,即可以进行写的,擦除之前会更新到磁盘中,write pos是指写的位置,当write pos和checkpoint相遇的时候表明redo log已经满了,这个时候数据库停止进行数据库更新语句的执行,转而进行redo log日志同步到磁盘中。

  1. redo log和binlog区别

    • redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
    • redo log是物理日志,记录该数据页更新的内容,有crash-safe能力;binlog是逻辑日志,记录的是这个更新语句的原始逻辑,是没有crash-safe能力的
    • redo log是循环写,日志空间大小固定;undo log会定期回收;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
    • binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。
  2. 事务的四个特征(ACID)

    • 原子性( Atomicity [ˌætəˈmɪsəti]):数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做
    • 一致性( Consistency [kənˈsɪstənsi]):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
    • 隔离性( Isolation [ˌaɪsəˈleɪʃn]):一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
    • 持续性( Durability [ˌdjʊərəˈbɪlɪti]):也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
  3. Mysql的四种隔离级别
    SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

    • Read Uncommitted(读取未提交内容)
      在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

    • Read Committed(读取提交内容)
      这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

    • Repeatable Read(可重读)
      这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。
      不过理论上,这会导致另一个棘手的问题:幻读(Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。【注】解决机制见回复1

    • Serializable(可串行化)
      这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

  4. 不同隔离级别可能的出现的问题
    这四种隔离级别采取不同的锁类型来实现,若读取的是同一个数据的话,就容易发生问题。例如:

    • 脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了操作,则后一个事务所读取的数据就会是不正确的。
    • 不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新的原有的数据。
    • 幻读(Phantom Read):在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

在MySQL中,实现了这四种隔离级别,分别有可能产生问题如下所示:

posted @ 2020-11-20 15:45  哆啦梦乐园  阅读(161)  评论(1编辑  收藏  举报