一、缓冲池
首先,关系型数据库是基于磁盘的,而非关系型数据库是基于内存的。
mysql就是一个基于磁盘的数据库,那么是如何减少mysql的i/o次数,提高mysql的性能呢。在mysql中是有一个缓冲池的,mysql每次查询时是按页进行查询的,每个页中会有大量的数据,将这些数据加载到内存中的缓冲池中,下次再进行查找的时候,会先去内存中进行查找,若找不到才会去磁盘中读取。这种方式是很好的,但是会出现缓冲池污染和预读失效的问题,这个就不再详细说了,大家自行了解。
二、刷脏页
对于mysql来说,那么查询的效率是有了,但是另一个问题是增删改的在缓冲池的基础上是怎么解决的,以下以修改进行说明。在修改的时候,mysql会首先将缓冲池中的数据进行修改,而磁盘上的数据和内存中的数据不一致了,此时该页就是脏页,然后需要将缓冲池中的数据页刷到磁盘中,这个被称为刷脏页。
刷脏页的时机(看一下即可)
- 每 10 秒必刷新一次
- 脏页太多时(默认占比超过
innodb_max_dirty_pages_pct
配置的值时刷新) - redo log 空间不足时
- 数据库关闭时
三、binlog
binlog是mysql的一种二进制日志,用于记录所有对数据库的增删改操作,你每修改一条数据,就会增加一条记录,会记录发生的时间,具体的操作,事务id。
基于 binlog 的这种特性,一般我们会将 binlog 用于以下几个方面:
数据库增量备份与恢复:使用备份还原数据后,可以使用 binlog 中记录的内容对备份时间点后的数据进行恢复,所以 binlog 可以恢复到某一具体时间点的数据
主从复制:通过binlog 实现对主服务器的增量复制。
审计:通过对 binlog 中的数据进行审计,判断是否存在安全问题,比如 SQL 注入。
bin log的持久化:
bin log cache 是内存中的一块区域,用于临时存放bin log记录,事务提交后,MySQL 会将 Binlog Cache 中的数据一次性刷新到 binlog 文件中。
当事务提交(COMMIT
)时,MySQL 会将 Binlog Cache 中的内容一次性写入 binlog 文件。若事务回滚(ROLLBACK
),则会丢弃 Binlog Cache 中的内容。
那么现在有一些问题,当数据在内存中更改后,还需要更改磁盘中的数据和bin_log中的数据,
1、内存更改后,磁盘中的数据更改了,但是bin_log未更改
2、内存更改后,bin_log更改了,但是磁盘中的数据未更改
3、内存更改后,bin_log和磁盘中的数据均未更改
4、bin_log中存放的数据会不会越来越大,又可能比源数据存放占用的位置都大
前三个均为事务不能持久化的问题,所有就有了redo_log
四、redo_log 重做日志
主要用于崩溃恢复。
数据页在缓冲池中被修改会变成脏页。如果这时宕机,脏页就会失效,这就导致我们修改的数据丢失了,也就无法保证事务的持久性。若一修改就刷脏页,会出现大量i/o,效率降低。
保证数据不丢,就是 redo log 的一个重要功能——保证事务的持久化
WAL(Write-Ahead Logging,日志先行),即:事务提交前先写日志,再修改页。也就是说,事务提交,修改内存中的数据,然后写入redo log一条记录,然后mysql的后台线程会根据情况进行脏页的刷新。
然后一旦脏页刷新,那么redo log中的相关记录就会失效,所以redo log该文件可以回头继续使用。
redo log的持久化(将redo log文件放在磁盘中)
redo log buffer 是内存中的一片区域,即先在内存中存放redo log 的记录,然后等到事务结束会将redo log buffer 写入磁盘中的redo log文件中。
总结:开始事务——用户写sql修改数据——修改内存中的数据——每修改一次就会写到redo log buffer 中一条数据——用户sql执行完毕,事务结束——将redo log buffer 中的所有数据写入到磁盘中——mysql的服务器会在合适的时候将脏页刷入磁盘中——此时redo log 中的记录这些操作的相关数据就失效了——下次将redo log buffer中的数据写入磁盘中时,可以从头开始。
redo_log buffer并不一定是每次都是在事务结束后才把数据写入磁盘中的,那样有的情况下就太慢了。
可以在以下时机将 redo log buffer 中的记录刷新到磁盘
- 每秒刷新一次
- 事务提交时
- redo log buffer 剩余空间小于 1/2 时
五、如何利用redo log恢复宕机的数据呢
InnoDB 为 redo log 记录了序列号,这被称为 LSN(Log Sequence Number),可以理解为偏移量,越新的日志 LSN 越大。InnoDB 用检查点(checkpoint_lsn
)记录未被同步到磁盘中的数据,即记录redo log中的数据 ,记录哪一部分还有用。
六、当我们执行一条update sql的流程
innodb
- 服务器收到事务开始的指令,为事务生成一个全局唯一的事务 id。这个事务 id 在记录 binlog 和 redo log 时都会使用。
- 如果缓存池中没有 no=1 所在数据页的数据,从磁盘中找到对应的数据页(注意,这里是一个数据页,不是一条记录),把数据页加载到缓存。
- 修改缓存数据页中 no=1 的数据。
- 记录数据到 redo log buffer、binlog cache。根据 redo log 刷盘的策略,这个过程中 redo log buffer 可能会被刷新到磁盘。
- 服务器收到事务提交的指令。
- 刷新 redo log buffer 到磁盘,并标记该事务的状态为 prepare。此操作称为 redo log prepare。
- 刷新 binlog cache 到磁盘。
- 刷新 redo log buffer 到磁盘,并标记该事务的状态为 commit。此操作称为 redo log commit。
- 向客户端返回事务执行的结果。
七、两段式提交机制:
主要是redo log文件和bin log文件
第一段:主要是将redo log buffer 中数据写到redo log中
InnoDB 事务提交前,写入 redo log(prepare 阶段)。当一个事务执行 COMMIT
操作时,InnoDB 首先将修改操作写入 redo log,并将 redo log 标记为 “prepare” 状态,然后刷新到磁盘。
第二段:主要是将bin log cacahe 中数据写到bin log中
写入 binlog 并将事务标记为提交。MySQL 将事务的 binlog 记录到 binlog cache,并将其刷新到 binlog 文件。之后,InnoDB 将 redo log 从 “prepare” 状态改为 “commit” 状态,表示事务已提交。
bin log 文件是不是会越来越大
文件可能会越来越大,但它通常不会比存储实际数据的文件大,bin log中存储的是逻辑日志,也就是说,并不保存完整的行数据,而是保存每个操作的 SQL 或修改后的数据的快照。
binlog 默认会定期轮换生成新的日志文件,旧的 binlog 会保留一段时间(根据 MySQL 配置的 expire_logs_days
设置),这会导致磁盘空间占用增加。
binlog 有三种日志格式——STATEMENT
、ROW
和 MIXED
。
Statement-based(基于语句)
Row-based(基于行),这种情况下,bin log 文件大小是有可能比数据的大小更加占用空间,更加大
Mixed-based(混合模式):
MySQL 提供了多种方法来控制 binlog 文件的大小和数量:
自动轮换和清理:即当大小到一定程度后会生成新的文件,而旧文件会有一个过期时间,时间一到就会清理。
手动清理:使用命令 PURGE BINARY LOGS
来手动删除旧的 binlog 文件。
开启 binlog 压缩:8.0版本以后