日志是mysql
数据库的重要组成部分,记录着数据库运行期间各种状态信息。mysql
日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。
以下是mysql数据库中常用的几种日志类型:
关于每种日志的类型的功能可参考:
关于如何查询日志是否开启,可使用以下命令:
mysql 中的binlog和redolog是两种核心日志机制,它们在数据库的数据持久化、主从复制和崩溃恢复中扮演关键角色。
关于两者如何进行相互联系的,可参考如下:
1、表空间结构
1.1、分类
mysql数据表以文件方式存放在磁盘中,默认使用共享表空间(0)存储。
1.对于 innodb:
ibdata 文件:
当使用共享表空间时,所有表的数据和索引会存储在一个共享的 ibdata 文件中。表结构以.frm
文件的形式存储在与表对应的文件夹中。
.ibd 文件:
如果使用了独立表空间,innodb 会将每个表的结构和数据存储在独立的 .ibd 文件中。每当表的数据或索引被更新时,文件也会随之变化。表的结构仍然以.frm
文件存储。
2.对于 myisam:
每个表的数据和索引不属于共享空间或独立空间的问题,而是直接通过三个文件来管理的:
myisam 数据表通常使用三种文件,分别是:
- .frm:存储表的结构信息。
- .myd:存储表的数据。
- .myi:存储表的索引。
3. 设置
使用共享表空间:
- 只需将innodb_file_per_table设置为0或不设置(默认值)。
使用独立表空间:
- 可以在 mysql 配置文件(my.cnf或my.ini)中启用独立表空间,添加如下配置:
[mysqld] innodb_file_per_table=1
这将允许每个 innodb 表都有其独立的.ibd
文件。
1.2、物理结构
如下图所示:
独立表空间文件(.ibd),每个独立表在磁盘上对应一个.ibd文件(test_table.ibd)
主要包括以下部分:
1.表空间头(header)
存储表空间的基本信息,如:
- 表空间 id。
- 区(extent)的分配状态。
- 空闲列表(free list)、碎片列表(fragment list)等。
用于管理表空间的物理分配和回收。
2.段(segment)
innodb 的存储结构是分层的:段 → 区 → 页。每个表空间文件包含多个段,主要分为以下几类:
数据段(data segment):
- 存储 b+ 树的叶子节点(数据页),即实际的行数据。
- 对于主键索引(聚簇索引),数据段直接存储完整的行数据。
索引段(index segment):
- 存储 b+ 树的非叶子节点(索引页),即索引键值和子节点指针。
- 用于加速数据检索。
回滚段(rollback segment):
- 存储事务的undo log(回滚数据),用于实现事务回滚和 mvcc(多版本并发控制)。
- 每个事务可能关联一个或多个回滚段。
3.区(extent)
每个段由多个区(extent)组成,一个区固定包含64 个连续页(默认页大小为 16kb,因此一个区大小为 1mb)。
区是 innodb 分配存储空间的基本单位,用于提高分配效率。
4.页(page)
页是 innodb 的最小存储单元,大小默认为16kb。
如下图所示:
页的类型取决于其所属的段:
- 数据页:存储 b+ 树叶子节点的数据(如主键索引的行数据)。
- 索引页:存储 b+ 树非叶子节点的索引键值和子节点指针。
- 回滚页:存储 undo log(回滚数据)。
- 系统页:存储表空间的元数据(如空闲列表、区分配信息等)。
5.空闲列表(free list)
- 记录表空间中未被使用的页,供后续分配。
- 当插入新数据或更新索引时,innodb 会从空闲列表中分配页。
小结
一张表的空间由页节点段、非页节点段、回滚段、和表空间组成。页节点段由多个区(1mb)组成,每个区由64个页(16kb)组成,每个页有多行组成。
如下图所示:
注意:此处图中的页仅代表的是叶子结点的page页。对于非叶子节点,也有相应的索引键值的页。
1.3、逻辑结构
b+ 树索引与数据组织,innodb 的表逻辑上通过b+ 树索引组织数据。
具体如下:
1.主键索引(聚簇索引)
- 叶子节点:存储完整的行数据(包括所有列的值)。
- 非叶子节点:存储主键值和指向子节点的指针。
- 聚簇索引决定了数据在磁盘上的物理存储顺序,因此主键选择直接影响性能。
2.二级索引(辅助索引)
- 叶子节点:存储主键值(而非完整行数据)。
- 非叶子节点:存储索引键值和子节点指针。
- 查询时,innodb 会先通过二级索引定位到主键值,再通过聚簇索引查找完整行数据。
3.事务与 mvcc 机制
undo log(回滚段中的页):
- 记录事务修改前的数据版本。
- 支持事务回滚(rollback)和并发读取(mvcc)。
版本链(version chain):
- 每个行记录通过 undo log 构建版本链,供不同事务读取一致性视图。
关于独立表和共享表的区别:
2、binlog
2.1. 定义
binlog(binary log)是 mysql 的服务层日志,属于二进制日志,记录所有对数据库的增删改操作(不包含查询)。由 mysql server 层生成,与存储引擎无关(如 innodb、myisam)。默认情况下二进制日志是关闭的。
结构如下所示:
2.2. 核心作用
1.主从复制(replication)
主库将 binlog 发送给从库,从库重放 binlog 实现数据同步。
2.数据恢复(point-in-time recovery)
通过 binlog 恢复到某个时间点的数据状态。
2.3. 存储位置
默认存储在 mysql 数据目录下的mysql-bin.xxxxxx
文件中。
binlog
是通过追加的方式进行写入的,可以通过max_binlog_size
参数设置每个binlog
文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
如下图所示:
mysql> show binary logs; +------------------+-----------+ | log_name | file_size | +------------------+-----------+ | mysql-bin.000001 | 201 | | mysql-bin.000002 | 154 | +------------------+-----------+ 2 rows in set (0.00 sec)
2.4. 格式
在mysql 5.7.7
之前,默认的格式是statement
,mysql 5.7.7
之后,默认值是row
。日志格式通过binlog-format
指定。
可使用以下命令,查看到:
- row-based:记录每一行的变更(5.7.7后默认)。
- statement-based:记录 sql 语句(5.7.7之前默认)。
- mixed:混合模式。
三种不同格式的优缺点:
配置如下:
[mysqld] log-bin=mysql-bin # 开启 binlog server-id=1 # 主库 id
2.5、binlog刷盘时机
对于innodb
存储引擎而言,只有在事务提交时才会记录biglog
,此时记录还在内存中,那么biglog
是什么时候刷到磁盘中的呢?
mysql
通过sync_binlog
参数控制biglog
的刷盘时机,取值范围是0-n
:
- 0:不去强制要求,由系统自行判断何时写入磁盘;
- 1:每次
commit
的时候都要将binlog
写入磁盘; - n:每n个事务,才会将
binlog
写入磁盘。
从上面可以看出,sync_binlog
最安全的是设置是1
,这也是mysql 5.7.7
之后版本的默认值。
设置一个大一些的值可以提升数据库性能,因此实际情况下也可以将值适当调大,牺牲一定的一致性来获取更好的性能。
3、redlog
持久性:只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态。
那么mysql
是如何保证一致性的呢?
在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中。但是这么做会有严重的性能问题。
主要体现在两个方面:
- 因为
innodb
是以页
为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了! - 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机io写入性能太差!
因此使用redo log
,就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序io)。
关于流程如下图所示:
3.1、原理及流程
redo log
包括两部分:一个是内存中的日志缓冲(redo log buffer
),另一个是磁盘上的日志文件(redo logfile
)。
- redolog(redo log)是innodb 存储引擎的事务日志,记录事务对数据页的物理修改。
- 用于保证事务的持久性(durability),防止数据丢失。
mysql
每执行一条dml
语句,先将记录写入redo log buffer
,后续某个时间点再一次性将多个操作记录写到redo log file
。这种先写日志,再写磁盘的技术就是mysql
里经常说到的wal(write-ahead logging)
技术。
在计算机操作系统中,用户空间(user space
)下的缓冲区数据一般情况下是无法直接写入磁盘的,中间必须经过操作系统内核空间(kernel space
)缓冲区(os buffer
)。
因此,redo log buffer
写入redo logfile
实际上是先写入os buffer
,然后再通过系统调用fsync()
将其刷到redo log file
中。
过程如下:
可以通过innodb_flush_log_at_trx_commit
参数配置将redo log buffer
写入redo log file
的时机,
3.2、核心作用
如下图所示:
事务持久化
- 事务提交时,先将修改写入 redolog,再异步刷盘到数据文件。
崩溃恢复(crash recovery)
- 数据库重启时,通过 redolog 恢复未落盘的数据。
3.3、存储位置
- 默认存储在
ib_logfile0
和ib_logfile1
文件中(innodb 专属)。
3.4、特性
- 固定大小:默认 4gb(可通过
innodb_log_file_size
配置)。 - 循环写入:当文件写满时,覆盖旧日志。
- 物理日志:记录的是数据页的物理修改(如某个页的某个偏移量被修改)。
redo log
实际上记录数据页的变更,而这种变更记录是没必要全部保存,因此redo log
实现上采用了大小固定,循环写入的方式,当写到结尾时,会回到开头循环写日志。
启动innodb
的时候,不管上次是正常关闭还是异常关闭,总是会进行恢复操作。因为redo log
记录的是数据页的物理变化,因此恢复的时候速度比逻辑日志(如binlog
)要快很多。
配置如下:
[mysqld] innodb_log_file_size = 1g # 设置 redolog 大小 innodb_flush_log_at_trx_commit = 1 # 事务提交时立即刷盘
关于redlog buffer的内存结构如下:
关于redlog buffer到redo log file持久化的流程如下图:
关于binlog和redlog的区别联系如图所示:
3.5、联系
binlog 与 redolog的联系。
1. 事务提交流程中的协作
- 事务执行:修改数据页(内存中)。
- 写入 redolog:事务提交时,将修改写入 redolog(确保持久性)。
- 写入 binlog:事务提交后,将修改写入 binlog(用于主从复制和恢复)。
关键区别:
- redolog 是 innodb 的事务日志,确保事务的原子性和持久性。
- binlog 是 mysql 的逻辑日志,用于主从复制和数据恢复。
2. 数据一致性保障
- redolog:确保事务的修改不会因宕机丢失。
- binlog:确保主从节点的数据一致性。
3. 崩溃恢复流程
- 恢复 redolog:数据库重启时,通过 redolog 恢复未落盘的事务。
- 恢复 binlog:通过 binlog 恢复到某个时间点(需结合 redo log)。
3.6、应用场景
1. 主从复制
- 主库:将 binlog 发送给从库。
- 从库:重放 binlog 实现数据同步。
2. 数据恢复
- 基于 binlog:恢复到某个时间点(如误删数据后回滚)。
- 基于 redolog:恢复未落盘的事务(数据库崩溃后自动恢复)。
3. 数据一致性
- binlog + redolog:共同保证 acid 中的d(durability)和主从一致性。
区别如下所示:
4、undolog
4.1、介绍
原子性底层就是通过undo log
实现的。undo log
主要记录了数据的逻辑变化,比如一条insert
语句,对应一条delete
的undo log
,对于每个update
语句,对应一条相反的update
的undo log
,这样在发生错误时,就能回滚到事务之前的数据状态。
同时,undo log
也是mvcc
(多版本并发控制)实现的关键。
4.2、流程
关于undolog的流程如下图所示:
4.3、日志结构
关于undolog的日志结构如下图所示:
5、常见问题与优化
1. binlog 导致磁盘空间不足
- 问题:binlog 无限增长,占用磁盘空间。
- 解决方案:
-- 查看 binlog 状态 show variables like 'expire_logs_days'; -- 设置自动清理(单位:天) set global expire_logs_days = 7;
2. redolog 刷盘性能问题
问题:innodb_flush_log_at_trx_commit=1
会降低性能。
优化建议:
- 生产环境:保持默认值
1
(保证数据安全)。 - 性能优先场景:可设置为
2
(每秒刷盘一次,风险略高)。
总结
mysql中的binlog、redolog和undolog日志类型,包括它们的作用、格式和刷盘机制。binlog主要用于主从复制和数据恢复,redolog确保事务的持久性,而undolog则实现了事务的原子性。
通过理解这些日志机制,可以更好地保障数据库的安全性和性能。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
发表评论