MySQL日志

445 阅读8分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

binlog

binlog是Mysql sever层维护的一种二进制日志,主要是用来记录对mysql数据更新SQL语句,并以"事务"的形式保存在磁盘中。

作用主要有:

  • 复制:MySQL Replication在Master端开启binlog,Master把它的二进制日志传递给slaves并回放来达到master-slave数据一致的目的
  • 数据恢复:通过mysqlbinlog工具恢复数据
  • 增量备份

复制

  • a.Master将数据改变记录到二进制日志(binary log)中
  • b.Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容
  • c.Master接收到来自Slave的IO进程的请求后,负责复制的IO进程会根据请求信息读取日志指定位置之后的日志信息,返回给Slave的IO进程。 返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的位置
  • d.Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的relay-log文件的最末端,并将读取到的Master端的 bin-log的 文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉Master从某个bin-log的哪个位置开始往后的日志内容
  • e.Slave的Sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行

恢复

mysqlbinlog   --start-position=1847  --stop-position=2585  mysql-bin.000008  > test.sql
mysql> source /var/lib/mysql/3306/test.sql

落盘设置

sync_binlog: 是MySQL 的二进制日志(binary log)同步到磁盘的频率。其可取的值是: 0 ~ N

  1. sync_binlog=0: 当事务提交之后,MySQL不做fsync之类的磁盘同步指令刷新binlog_cache中的信息到磁盘,而让Filesystem自行决定什么时候来做同步,或者cache满了之后才同步到磁盘。这个是性能最好的。
  2. sync_binlog=1: 当每进行1次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。
  3. sync_binlog=N: 当每进行n次事务提交之后,MySQL将进行一次fsync之类的磁盘同步指令来将binlog_cache中的数据强制写入磁盘。

腾讯工程师带你深入解析 MySQL binlog - 腾讯云技术社区的文章 - 知乎

redolog

redolog是InnoDB特有的物理日志。当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log里 面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面,而这个更新往往是在系统比较空闲的时候。这其实就是MySQL中的WAL(write ahead logging,先写日志,再写磁盘)。

Crash-Safe

一个固定大小,“循环写”的日志文件,记录的是物理日志——“在某个数据页上做了某个修改”。

binlog 是什么?

一个无限大小,“追加写”的日志文件,记录的是逻辑日志——“给 ID=2 这一行的 c 字段加1”。

redo log 和 binlog 有一个很大的区别就是,一个是循环写,一个是追加写。也就是说 redo log 只会记录未刷盘的日志,已经刷入磁盘的数据都会从 redo log 这个有限大小的日志文件里删除。binlog 是追加日志,保存的是全量的日志。

当数据库 crash 后,想要恢复未刷盘但已经写入 redo log 和 binlog 的数据到内存时,binlog 是无法恢复的。虽然 binlog 拥有全量的日志,但没有一个标志让 innoDB 判断哪些数据已经刷盘,哪些数据还没有。 ———————————————— 版权声明:本文为CSDN博主「Zzz-_-ch」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/weixin_4369…

落盘设置

innodb_flush_log_at_trx_commit:是 InnoDB 引擎特有的,ib_logfile的刷新方式( ib_logfile:记录的是redo log和undo log的信息), 其取值可以为0, 1, 2

innodb_flush_log_at_trx_commit=0: Innodb 中的Log Thread每隔1 秒钟会将log buffer中的数据写入到文件,同时还会通知文件系统进行文件同步的flush 操作,保证数据确实已经写入到磁盘上面的物理文件。但是,每次事务的结束(commit 或者是rollback)并不会触发Log Thread 将log buffer 中的数据写入文件。所以,当设置为0 的时候,当MySQL Crash 和OS Crash 或者主机断电之后,最极端的情况是丢失1 秒时间的数据变更。

innodb_flush_log_at_trx_commit=1: Innodb 的默认设置,表示在每次事务提交的时候,都把log buffer刷到文件系统中(os buffer)去,并且调用文件系统的“flush”操作将缓存刷新到磁盘上去。这样的话,数据库对IO的要求就非常高了,如果底层的硬件提供的IOPS比较差,那么MySQL数据库的并发很快就会由于硬件IO的问题而无法提升。

innodb_flush_log_at_trx_commit=2: 表示在每次事务提交的时候会把log buffer刷到文件系统中去,但并不会立即刷写到磁盘。如果只是MySQL数据库挂掉了,由于文件系统没有问题,那么对应的事务数据并没有丢失。只有在数据库所在的主机操作系统损坏或者突然掉电的情况下,数据库的事务数据可能丢失1秒之类的事务数据。这样的好处,减少了事务数据丢失的概率,而对底层硬件的IO要求也没有那么高(log buffer写到文件系统中,一般只是从log buffer的内存转移的文件系统的内存缓存中,对底层IO没有压力)。

undolog

在 RU 隔离级别下,直接读取版本的最新记录就可以。
对于 SERIALIZABLE隔离级别,则是通过加锁互斥来访问数据。

使用MVCC实现了隔离级别中的读提交和可重复读

读提交和可重复读依赖MVCC实现。

MVCC依赖undo log 和 ReadView实现。其中undo log 提供了数据行的版本链,ReadView决定了事务能够看到的版本。

每一行数据都有两个隐藏列,DATA_TRX_ID(事务ID,6个字节),用来记录最近更新这条记录的事务ID;和DATA_ROLL_PTR(回滚指针,7个字节),指向这行数据的上一个版本,这样就形成了数据行的版本链。每次对数据进行更新操作时,都会copy 当前数据,保存到undo log 中。并修改 当前行的 回滚指针指向 undo log 中的 旧数据行。

ReadView是当前活跃的事务 ID 列表,称之为m_ids,其中最小值为 up_limit_id,最大值为 low_limit_id

/* The last active transaction has the smallest id: */
view->up_limit_id = view->trx_ids[view->n_trx_ids - 1];

view->low_limit_id = trx_sys->max_trx_id;

/*
Additional trx ids which the read should not see: typically, these are the read-write active transactions at the time when the read is serialized, except the reading transaction itself; the trx ids in this array are in a descending order. These trx_ids should be between the "low" and "high" water marks, that is, up_limit_id and low_limit_id.
*/
trx_ids

依据下面的规则判断可见性:

  1. DB_TRX_ID < up_limit_id,修改该记录的事务在当前事务开启之前都已经提交完成,对当前事务可见。
  2. DB_TRX_ID >= low_limit_id,说明修改该记录的事务在当前事务之后,对当前事务不可见。
  3. up_limit_id <= DB_TRX_ID < low_limit_id,如果DB_TRX_ID在trx_ids中且不等于当前事务ID,对当前事务不可见,否则可见。

在读提交隔离级别下,在每次查询时都会生成新的ReadView;在可重复读隔离级别下,只在事务的第一次查询时建立ReadView

高性能MySQL-如何实现可重复读?

Mysql MVCC 原理 low_limit_id ReadView

MySQL MVCC mechanism

MySQL InnoDB MVCC实现 - 温正湖的文章 - 知乎:有误

常见问题

redolog和binlog的区别

  1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
  2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的 是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
  3. binlog是全量日志。redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件 写到一定大小后会切换到下一个,并不会覆盖以前的日志。

两阶段提交:

redo log和binlog采用两阶段提交,为了让两份日志之间的逻辑一致。

  • 如果redolog处于commit,事务直接提交,
  • 如果redolog处于prepare、binlog完整,事务也提交,
  • 在binlog不完整时,事务会回滚,以前更新数据页会丢失。

redo log如何和binlog联系在一起?

XID,在服务重启启动时,会扫描redolog中xid字段到binlog中,找相对应的事务,判断binlog的状态是否需要提交

redo log和redo buffer的联系?

即在数据更新时,会先写redo buffer,因为这样可以在写redo log时,先把数据保存起来,在commit时在把数据写入redo log中,因为这样更新的时候会更快,直接更新内存,在事务处于cmmit时,才将内存中的数据写到redo log中