日志
两阶段提交
二阶段提交(2PC)是一种用于分布式数据库或系统中确保事务原子性的协议,它通过一个协调者和多个参与者共同协作,保证所有节点要么全部提交事务,要么全部回滚。
它的执行分为两个阶段:
- 投票阶段:协调者向所有参与者发送“准备提交”请求。参与者执行事务操作,并锁定资源,然后向协调者反馈“同意”或“中止”。
- 提交阶段:如果协调者收到所有参与者的“同意”,则发送“提交”命令,参与者完成提交并释放资源;如果任何参与者反馈“中止”或超时,则协调者发送“回滚”命令,所有参与者进行回滚。
undo log
MVCC
MVCC依靠undo log实现
回滚
记录阶段: “事务修改数据前,InnoDB会先将旧数据拷贝到Undo Log中,形成一条版本记录。不同操作记录不同内容:
UPDATE记录旧值
INSERT记录主键
DELETE记录完整数据”
构建版本链: “每条记录都有DB_ROLL_PTR指针,指向它的上一个版本。修改时,当前记录指向新的Undo Log,形成版本链”
回滚执行: “执行ROLLBACK时,==从后向前==遍历事务的所有Undo Log:
UPDATE:用旧值覆盖新值
INSERT:删除插入的记录
DELETE:清除删除标记,恢复数据 回滚完成后,这些Undo Log会被清理”
redo log
核心作用是确保事务的持久性(Durability),防止在发生故障时数据丢失。==它记录的是物理日志,即“在某个数据页上做了什么修改”==
工作流程:
事务修改数据:当一个事务对某行数据进行修改(如UPDATE)时,InnoDB会先将该数据所在的数据页从磁盘加载到内存的Buffer Pool中(如果尚未在内存中)。
生成Redo Log记录:在内存中修改数据页的同时,会生成一条对应的redo log记录。这条记录包含了“在哪个表空间的哪个数据页的哪个偏移量处,将数据改成了什么值”等信息。
写入Log Buffer:生成的redo log记录首先被写入内存中的Log Buffer(日志缓冲区)。==合并多次内存写操作,减少系统调用次数==
写入OS Cache:当事务提交时(默认设置下),根据一定的策略(如innodb_flush_log_at_trx_commit参数控制),Log Buffer中的内容会被写入到OS Cache的redo log文件(通常是ib_logfile0, ib_logfile1)。注意,这个“写入”通常只是写到了操作系统的文件系统缓存(OS Cache)中,并没有真正“落盘”。==合并多次磁盘写操作,减少物理I/O次数==
刷盘(fsync):操作系统会在合适的时机(或根据数据库的刷盘策略)将OS Cache中的数据真正同步到物理磁盘上。只有完成这一步,修改才算拥有了持久化的保证。
前面是redo log日志流程↑,后面是具体的数据流程↓
后台刷脏页:InnoDB有后台线程,会定期或不定期地将Buffer Pool中已被修改的“脏页”刷新到磁盘的数据文件中。即使这个刷盘动作在事务提交后很久才发生,或者发生故障导致丢失,因为redo log已经持久化,数据也不会丢失。
循环写入与检查点:Redo log文件是固定大小、循环写入的。它由两个或多个文件组成。当写满一个文件时,会切换到下一个文件继续写。当最后一个文件也被写满时,会回到第一个文件开头覆盖写入。为了避免覆盖掉还未将对应脏页刷盘的有效日志,InnoDB引入了检查点(Checkpoint)。检查点标记了在此之前的redo log对应的脏页都已经刷回磁盘,这部分日志空间就可以被安全地覆盖重用。
bin log
Binlog是MySQL Server层记录的逻辑日志,==记录的是SQL语句的原始逻辑或行变更前后的值==,其核心作用与Redo Log(存储引擎层物理日志)形成互补
第1步:事务执行与日志生成
- 事务执行过程中,其修改数据的原始逻辑(取决于Binlog格式)会被记录到每个线程各自的
Binlog Cache内存区域中。 - 这个缓存是每个连接线程独享的,目的是不影响其他事务。
第2步:事务提交与日志写入
- 事务提交时,该事务在Binlog Cache中的完整日志会被一次性写入到操作系统的文件系统缓存中,这个文件就是Binlog文件(如
binlog.000001)。 - 此时,对于MySQL Server来说,事务已经可以返回提交成功。但数据是否安全,取决于下一步。
第3步:日志刷盘(持久化)
- 这是由核心参数
sync_binlog控制的:- **
sync_binlog = 0**:MySQL不主动调用fsync(),依赖操作系统定期将缓存刷盘。性能最好,但若系统崩溃,可能丢失多个事务的Binlog。 sync_binlog = 1:默认且最安全。每次事务提交后,立即调用fsync()将Binlog强制刷入物理磁盘。这保证了只要事务提交成功,其Binlog就一定不会丢失。- **
sync_binlog = N (N>1)**:每累计N个事务提交,才调用一次fsync()进行刷盘。这是性能与安全的折中,若系统崩溃,最多丢失N个事务的Binlog。
- **
bin实习主从复制
- 主库提交事务,写入binlog
- 主库开线程同步,从库开线程接收binlog到relay log
- 从库开线程回放读取relay log,回放binlo
一般一主两从【因为同步需要开销】
redo 和 bin的两阶段提交
准备阶段:redo log写磁盘,但还未真正提交
提交阶段:binlog写磁盘,redo log中写入提交记录,事务真正提交
【保证redo和bin的一致性】
