SQL日志

  • 1,binlog
  • 1.1 特点
  • 1.2 binlog 写入机制
  • 1.3 binlog 三种日志格式
  • 2,redo log
  • 2.1 特点
  • 2.2 脏数据刷盘(redo log日志擦除)
  • 2.3 脏日志刷盘
  • 2.4 缓冲池(buffer pool)
  • 2.5 redo log 的写入机制
  • 3,undo log
  • 3.1 特点
  • 3.2 作用


1,binlog
1.1 特点
二进制日志binlog(服务层的日志),又称归档日志。
binlog是逻辑日志,记录的是SQL语句的原始逻辑,比如”给ID=2这一行的a字段加1 ",日志内容是二进制的,根据日记格式参数的不同,可能基于SQL语句、基于数据本身或者二者的混合
binlog主要记录数据库的变化情况(逻辑日志),内容包括数据库所有的更新操作。所有涉及数据变动的操作,都要记录进二进制日志中。
binlog可对数据进行复制和备份,常用作主从库的同步、数据回滚/恢复。
binlog有两种模式
	statement 模式是记录sql语句,
	row模式记录行的内容,更新前和更新后都有;
1.2 binlog 写入机制

mysql 历史数据归档怎么操作 mysql 归档日志_mysql

事务执行过程中,先把日志写到 binlog cache,事务提交的时候,再把 binlog cache 写到 binlog 文件中。
一个事务的 binlog 不能拆开,不论事务多大要确保一次性写入。
系统给 binlog cache 分配一片内存,每个线程一个,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。超过参数规定大小,就暂存到磁盘。
事务提交时,执行器把 binlog cache 里完整事务写入 binlog 中,并清空 binlog cache

每个线程有自己 binlog cache,但是共用同一份 binlog 文件
	write:把日志写入到文件系统的 page cache,并没有把数据持久化到磁盘,速度快
	fsync:将数据持久化到磁盘,fsync 才会占磁盘 IOPS

write 和 fsync 的时机,是由参数 sync_binlog 控制的:
	sync_binlog=0 :表示每次提交事务都只 write,不 fsync;
	sync_binlog=1 :表示每次提交事务都会执行 fsync;
	sync_binlog=N(N>1) :表示每次提交事务都 write,但累积 N 个事务后才 fsync。
出现 IO 瓶颈的场景里,将 sync_binlog 设置成比较大的值,可以提升性能。实际业务中,考虑到丢失日志量的可控性,不建议参数设成 0,建议设置为 100~1000 中的某个数值。
sync_binlog 设置为 N风险是:主机发生异常重启,丢失最近 N 个事务 binlog 日志
1.3 binlog 三种日志格式

Statement:每一条会修改数据的sql都会记录在binlog中。

优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比row能节约多少性能与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式所产生的日志量还小于Statement产生的日志量,但是考虑到如果带条件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所产生的日志量会增加多少,以及带来的IO性能问题。)

缺点:statement 格式的 binlog 可能会导致主备不一致。由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, last_insert_id(),以及user-defined functions(udf)会出现问题).

Row:不记录sql语句上下文相关信息,仅保存哪条记录被修改。

优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题

缺点: row 格式很占空间,所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。

mixed: 是以上两种的混合使用,

statement 格式的 binlog 可能会导致主备不一致,所以要使用 row 格式。但 row 格式的很占空间,mixed 格式可以利用 statment 格式的优点,同时又避免了数据不一致的风险,
mixed 格式,MySQL 会判断SQL 语句是否可能引起主备不一致,如可能,就用 row 格式,否则就用 statement 格式
一般的语句修改使用statment格式保存binlog,如一些函数,statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种,新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。
至于update或者delete等修改数据的语句,还是会记录所有行的变更。
2,redo log
2.1 特点
重做日志(物理日志),InnoDB特有,用来记录事务操作引起数据的变化,记录的是数据页的物理修改。
redo log是物理日志,记录实际的SQL语句,如“update T set c=c+1 where ID=2; ”
redo log日志可分为两个部分
	保存在易失性内存中的缓存日志redo log buff
	保存在磁盘上的redo log日志文件redo log file
crash-safe(崩溃安全能力):redo log保证即使数据库发生异常重启,之前提交的记录都不会丢失;

WAL技术

一条记录需要更新时,InnoDB引擎就会先把记录写到redo log ,并更新内存。InnoDB引擎在适当时,将操作记录更新刷入磁盘,往往是在系统空闲的时候,即WAL技术(Write-Ahead Logging):先写日志,再写磁盘;
redo log是固定大小的,每次写redo log满的时候会将前面的更新到磁盘,擦除redo log在重写开始记录;
redo log 和 binlog 都是顺序写,磁盘的顺序写比随机写速度要快;
组提交机制,可以大幅度降低磁盘的 IOPS 消耗。
2.2 脏数据刷盘(redo log日志擦除)
脏数据(脏页):指内存中未刷到磁盘的数据。

由于redo log日志的大小固定,为能够持续不断对更新记录写入,在redo log日志中设置了两个标志位置,checkpoint和write_pos,分别表示记录擦除和记录写入的位置。redo log日志的数据写入示意图可见下图。

mysql 历史数据归档怎么操作 mysql 归档日志_mysql 历史数据归档怎么操作_02


当write_pos标志到了日志结尾时,会从结尾跳至日志头部进行重新循环写入。所以redo log的逻辑结构并不是线性的,而是可看作一个圆周运动。write_pos与checkpoint中间的空间可用于写入新数据,写入和擦除都是往后推移,循环往复的。

mysql 历史数据归档怎么操作 mysql 归档日志_mysql 历史数据归档怎么操作_03

当write_pos追上checkpoint时,表示redo log日志已经写满。这时不能继续执行新的数据库更新语句,需要停下来先删除一些记录,执行checkpoint规则腾出可写空间。

checkpoint规则:checkpoint触发后,将buffer中脏数据页和脏日志页都刷到磁盘。

InnoDB 刷脏页策略

正确地设置 innodb_io_capacity 参数,可设置为磁盘的 IOPS,告诉 InnoDB 你磁盘的能力
刷盘策略
	脏页比例,参数 innodb_max_dirty_pages_pct 是脏页比例上限,默认 75%,最好不要接近 75%
	redo log 写盘速度
2.3 脏日志刷盘

上面对脏数据刷盘,为保证日志文件持久化,要将日志记录从内存写入到磁盘。
为确保每次记录都能够写入到磁盘中的日志中,每次将redo log buffer中的日志写入redo log file的过程中都会调用一次操作系统的fsync操作。

fsync函数:包含在UNIX系统头文件#include <unistd.h>中,用于同步内存中所有已修改的文件数据到储存设备。
写入的过程中,还需要经过操作系统内核空间的os buffer
2.4 缓冲池(buffer pool)

缓冲池buffer pool(redo log中最重要的概念),在内存中分配的一个区域,包含了磁盘中部分数据页的映射,作为访问数据库的缓冲。

当请求读取数据时,会先判断是否在缓冲池命中,如果未命中才会在磁盘上进行检索后放入缓冲池;
当请求写入数据时,会先写入缓冲池,缓冲池中修改的数据会定期刷新到磁盘中。这一过程也被称之为刷脏 。

因此,当数据修改时,除了修改buffer pool中的数据,还会在redo log中记录这次操作;当事务提交时,会根据redo log的记录对数据进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复,从而保证了事务的持久性,使得数据库获得crash-safe能力。

2.5 redo log 的写入机制

redo log 三种状态

日志存入 redo log buffer 中,物理上是在 MySQL 进程内存;
写到磁盘 (write),但没有持久化(fsync),物理上是在文件系统的 page cache 里面;
hard disk持久化到磁盘

innodb_flush_log_at_trx_commit 参数,控制 redo log 的写入策略

设置为 0 :表示每次事务提交都只把 redo log 留在 redo log buffer 中 ;
设置为 1 :表示每次事务提交时都将 redo log 直接持久化到磁盘;
设置为 2 :表示每次事务提交时都只是把 redo log 写到 page cache。

刷盘时机

InnoDB 有一个后台线程,每隔 1 秒把 redo log buffer 中的日志,调用 write 写到文件系统的 page cache,然后调用 fsync 持久化到磁盘
redo log buffer 占用的空间即将达到 innodb_log_buffer_size 一半的时候,后台线程会主动写盘。由于这个事务可能没有提交,这个写盘动作只是 write,没有 fsync,只到 page cache
并行的事务提交的时候,顺带将这个事务的 redo log buffer 持久化到磁盘。假设一个事务 A 执行到一半,已经写了一些 redo log 到 buffer 中,这时候有另外一个线程的事务 B 提交,如果 innodb_flush_log_at_trx_commit 设置的是 1,那么按照这个参数的逻辑,事务 B 要把 redo log buffer 里的日志全部持久化到磁盘。会带上事务 A 在 redo log buffer 里的日志一起持久化到磁盘

组提交机制(group commit)

LSN:日志逻辑序列号(log sequence number)单调递增的,对应 redo log 的一个个写入点。每次写入长度为 length 的 redo log, LSN 的值就会加上 length。
LSN 也会写到 InnoDB 的数据页中,确保数据页不会被多次执行重复的 redo log。

mysql 历史数据归档怎么操作 mysql 归档日志_mysql_04

trx1 是第一个到达的,会被选为这组的 leader;
rx1 开始写盘时,组里已有三个事务,这时候 LSN 变成 160;
trx1 去写盘时,带的就是 LSN=160,因此等 trx1 返回时,所有 LSN 小于等于 160 的 redo log,都已经被持久化到磁盘
这时 trx2 和 trx3 就可以直接返回了。所以一次组提交里面,组员越多,节约磁盘 IOPS 的效果越好。
并发更新场景下,第一个事务写完 redo log buffer 以后,接下来这个 fsync 越晚调用,组员可能越多,节约 IOPS 的效果就越好。

不同点

binlog

redo log

试用引擎

mysql的server层实现的日志记录功能,所有引擎都可以使用

InnoDB引擎所特有

日志属性

逻辑日志,记录了sql语句的原始逻辑

物理日志,记录在什么数据上做了什么修改

记录方式

日志追加方式,binlog会自动追加写日志,当写到一定大小时会自动切换新文件继续记录

循环方式,redo log 大小固定,空间用完需要写磁盘擦除才能继续记录

3,undo log
3.1 特点
回滚日志,InnoDB特有,对失败的回滚数据进行回滚
当事务对数据库进行修改,InnoDB引擎不仅会记录redo log,还会生成对应的undo log日志;
事务执行失败或调用rollback,导致事务需要回滚,就可以利用undo log中的信息将数据回滚到修改之前的样子。
undo log属于逻辑日志,对修改/插入的数据做反向记录(用于反向执行修改),插入操作(insert),回滚时会执行数据删除操作(delete)
3.2 作用

undo log由两个作用,提供回滚,实现MVCC。