一、Mysql日志分类
二、重做日志(redo log)
三、回滚日志(undo log)
3.1 undo log的作用
3.2 undo log 的工作原理
3.3 undo log数据结构
3.4 undo log的存储机制
四、二进制日志(bin log)
4.1 什么是 Bin Log
4.2 redo log与binlog的区别?
4.3 如何开启Binlog?
对于线上数据库应用系统,突然遭遇数据库宕机的情况下,可以查看数据库错误日志来定位具体的问题。因为日志中记录了数据库运行中的诊断信息,包含错误,警告与注解等信息。数据日志除了可以发现错误,日志在数据复制,数据恢复,操作审计及确保数据的永久性和一致性等方面,都有着不可替代的作用。一、Mysql日志分类
下面会结合场景详解讲解每个日志应用及其使用场景。
二、重做日志(redo log)
它是一个物理日志,记录的是对哪个表空间的哪个数据页的什么偏移量的地方做了什么修改。解释:redo 日志是为了在系统因奔溃而重启时恢复奔溃前的状态而提出的。lnnoDB 存储引擎是以页为单位来管理存储空间的,我们进行的增删改查操作从本质上来说都是在访问数据页面(包括读页面、写页面、创建新页面等操作)。在真正访问页面之前,需要先把在磁盘中的页加载到内存中的[[Buffer Pool]] 中,之后才可以访问。事务的持久性的特征要求对于一个己经提交的事务,在事务提交后即使系统发生了崩溃,这个事务对数据库所做的更改也不能丢失。如果我们只在内存的 Buffer Pool 中修改了页面,假设在事务提交后突然发生了某个故障,导致内存中的数据都失效了,那么这个已经提交的事务在数据库中所做的更改也就跟着丢失了,那么如何保证数据的持久性呢?只需要把修改的内容记录一下就好。redo log是记录的事务提交之后的数据修改,如果脏页(未持久化到磁盘的数据)中的修改记录还没有被写回磁盘,mysql就发生异常崩溃了,这个时候虽然缓冲池中的脏页数据丢失了,但是redo log中还保存了相应的数据,mysql重启后,可以根据redo log中的内容将数据库恢复到最新状态。为了防止内存中的缓冲池数据丢失,每次修改缓冲池中的数据页后,mysql都会将本页的修改记录在redo log中,后续再由专门的后台线程负责将缓存在缓冲池中的脏页刷新到磁盘中。这就是WAL技术(Witre-Ahead Logging)。WAL技术指的是,Mysql的写操作不是直接向数写到磁盘,而是先以日志的形式记录下修改的内容,然后在合适的时间再写回磁盘。Tip:数据更新后,缓冲池中的undo页面也会被修改,也同样会记录到redo log中。
因此,通过redo log和WAL技术,mysql拥有crash-safe的能力,也就是保证了事务的持久性。
- redo 日志占用的空间非常小;在存储表空间 ID、页号、偏移量以及需要更新的值时,需要的存储空间很小。
- redo 日志是顺序写入磁盘;在执行事务的过程中,每执行一条语句,就可能产生若干条 redo 日志,这些日志是按照产生的顺序写入磁盘的,也就是使用顺序 I/O。
三、回滚日志(undo log)
undo log是一种用于撤销回退的日志,在数据库事务开始之前,MySQL会先记录更新前的数据到undo log日志文件里面,当事务回滚时或者数据库崩溃时,可以利用 undo log来进行回退。
undo log产生和销毁:Undo Log在事务开始前产生;事务在提交时,并不会立刻删除undo log,innodb会将该事务对应的undo log放入到删除列表中,后面会通过后台线程purge thread进行回收处理。
注意: undo log也会产生redo log,因为undo log也要实现持久性保护。
3.1、undo log的作用
1、提供回滚操作【undo log实现事务的原子性】
在数据修改的时候,不仅记录了redo log,还记录了相对应的undo log,如果因为某些原因导致事务执行失败了,可以借助undo log进行回滚。undo log 和 redo log 记录物理日志不一样,它是逻辑日志。可以认为当delete一条记录时, undo log中会记录一条对应的insert记录,反之亦然,当update一条记录时,它记录一条对应相反的update记录。2. 提供多版本控制(MVCC)【undo log实现多版本并发控制(MVCC)】MVCC,即多版本控制。在MySQL数据库InnoDB存储引擎中,用undo Log来实现多版本并发控制(MVCC)。当读取的某一行被其他事务锁定时,它可以从undo log中分析出该行记录以前的数据版本是怎样的,从而让用户能够读取到当前事务操作之前的数据【快照读】快照读:SQL读取的数据是快照版本【可见版本】,也就是历史版本,不用加锁,普通的SELECT就是快照读。当前读:SQL读取的数据是最新版本(最新版本指的是修改且已经提交的数据)。除了在执行修改语句的时候,需要执行当前读,然后再更新数据之外,select语句也有可能是当前读,比如: select … lock in share mode、select … for update。3.2、 undo log 的工作原理
在更新数据之前,MySQL会提前生成undo log日志,当事务提交的时候,并不会立即删除undo log,因为后面可能需要进行回滚操作,要执行回滚(rollback)操作时,从缓存中读取数据。undo log日志的删除是通过通过后台purge线程进行回收处理的。
事务A执行update更新操作,在事务没有提交之前,会将旧版本数据备份到对应的undo buffer中,然后再由undo buffer持久化到磁盘中的undo log文件中, 之后才会对user进行更新操作,然后持久化到磁盘。
在事务A执行的过程中,事务B对User进行了查询。
3.3、undo log数据结构
DB_ROW_ID:和MVCC的关系不大,这个是我们创建表的时候,如果没有加主键PRIMARY KEY,那么InnoDB就自动生成主键列id(DB_ROW_ID),通过这个id作为主键创建索引树,在B+树的叶子节点上存放数据。由于InnoDB的数据和索引是存放在一起的,如果我们没有设置主键,InnoDB会自动生成主键。
DB_TRX_ID:事务ID,我们每打开一个客户端session,输入begin,向服务器请求开启一个事务。事务开启请求发到MySQL server上,MySQL server为每个事务都会分配一个全局的,不冲突的事务ID(InnoDB存储引擎分配的,因为它才支持事务)。当某个事务修改数据时,DB_TRX_ID放的就是该事务的ID,同一个事务无论怎么更改数据,这个事务ID都不会改变。
DB_ROLL_PTR:回滚指针,我们看到,存放的是地址,这个地址表示的是一个数据的内存的位置。3.4 undo log的存储机制
为了保证事务并发操作时,在写各自的undo log时不产生冲突,InnoDB采用回滚段的方式来维护undo log的并发写入和持久化。
rollback segment 称为回滚段 共有128个,每个回滚段中有1024个 undo log segment ,即支持 128*1024 个 undo 操作,最多支持131072个并发事务执行。
四、二进制日志(bin log)
mysql在进行更新操作后,server层还会生成一条binlog,事务提交后,事务执行过程中产生的所有binlog都会统一写到binlog文件中。Bin Log是一个二进制格式的文件,是MySQL最重要的日志,它记录了所有的DDL及DML语句(除了数据查询select、show等),以事件形式记录,还包含语句所执行的消耗时间,MySQL的二进制日志是事务安全型的。binlog 的主要目的是复制和恢复。4.2 redo log与binlog的区别?
(1)、适用对象不同
binlog是mysql的Server层实现的日志,所有存储引擎都可以使用,redo log是InnoDB存储引擎实现的日志,其它存储引擎不可以用。
(2)、文件格式不同
binlog有三种格式类型:
a.Statement(逻辑日志):记录的是每一条修改数据的sql。缺点就是sql中使用的同一个动态函数,可能在主从数据库中得到的结果并不一致。(比如now(),uuid()等)。b.Row(非物理日志):记录的是每一行记录的变化过程。缺点是记录了每一行数据的变更细节,导致binlog文件过大(比如批量的update操作,在statement中只记录一条sql,但是row中会产生每一次修改的变更情况)。c.Mixed:根据情况选择上面两种类型中的一种。redo log是物理日志,记录的是在某个数据页做了什么修改。比如对哪个表空间的哪个数据页的多少偏移量的地方进行了什么更新操作。
(3)、写入方式不同
redo log是循环写,日志大小固定,保存未被刷入磁盘的的脏页日志。
binlog是追加写,写满一个文件就创建一个新的文件继续写,保存的是全量的日志。
(4)、用途不同
redo log用于掉电等故障恢复。(有crash-safe能力)
binlog用于备份恢复、主从复制。(无crash-safe能力)
Q:为什么binlog没有crash-safe能力?
A:因为事务提交后,虽然更新操作都在binlog中,但是它没有一个标志判断哪些是已经刷盘,哪些还未刷盘,那么就无法达到crash-safe的能力,但是redo log不一样,它记录的就是未刷盘的数据,只要mysql重启后,直接将这些数据恢复至内存即可。
一般来说开启binlog日志大概会有1%的性能损耗。启用binlog,通过配置 etc/my.cnf 或 etc/mysql/mysql.conf.d/mysqld.cnf 配置文件的 log-bin 选项在配置文件中加入 log-bin配置,表示启用binlog,如果没有给定值,写成 log-bin=,则默认名称为主机名。(注:名称若带有小数点,则只取第一个小数点前的部分作为名称)
[mysqld]
log-bin=my-binlog-name
也可以通过SET SQL_LOG_BIN = 1命令来启用Bin Log,通过SET SQL_LOG_BIN =0 命令停用Bin Log
启用 binlog 之后须重启MySQL才能生效。
---THE END---