admin管理员组文章数量:1487745
Mysql详解
主从备份
在使用 Mysql 集群时,通常master节点负责写操作,slave节点负责读操作。主节点写入的数据同步到从节点的具体实现是:
mysql使⽤3个线程来执⾏复制功能(其中1个在主服务器上,另两个在从服务器上)。当发出start slave时,从服务器创建⼀个I/O线程,以连接主服务器并让它发送记录在其⼆进制⽇志中的语句。主服务器创建⼀个线程将⼆进制⽇志中的内容发送到从服务器,也就是Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷⻉到从服务器数据⽬录中的本地⽂件中(中继⽇志)。第3个线程是sql线程,由从服务器创建,⽤于读取中继⽇志并执⾏⽇志中包含的更新。在从服务器上,读取和执⾏更新语句被分成两个独⽴的任务。当从服务器启动时,其I/O线程可以很快地从主服务器索取所有⼆进制⽇志内容。
binlog & redo-log
binlog & redo-log 区别
binlog 记录了对数据库执⾏更改的所有的写操作,包括所有对数据库的数据、表结构、索引等等变更的操作。
redo-log是属于引擎层(innodb)的⽇志,称为重做⽇志,当MySQL服务器意外崩溃或者宕机后,保证已经提交的事务持久化到磁盘中(持久性)。它能保证对于已经 COMMIT 的事务产⽣的数据变更,即使是系统宕机崩溃也可以通过它来进⾏数据重做,达到数据的持久性,⼀旦事务成功提交后,不会因为异常、宕机⽽造成数据错误或丢失。
为什么有了binlog还要有redo-log?这是因为MySQL 是以⻚为单位进⾏刷盘的,每⼀⻚的数据单位为16K,所以在刷盘的过程中需要把数据刷新到磁盘的多个扇区中去。⽽把16K数据刷到磁盘的每个扇区⾥这个过程是⽆法保证原⼦性的,如果数据库宕机,那么就可能会造成⼀部分数据成功,另⼀部分数据失败的情况。⽽通过 binlog 这种级别的⽇志是⽆法恢复的,因为⼀个update可能更改了多个磁盘区域的数据,所以这个时候得需要通过redo log这种记录到磁盘数据级别的⽇志进⾏数据恢复。总的来说:
- redo log是物理⽇志,记录内容是在某个数据⻚上做了什么修改,属于InnoDB 存储引擎层,在事务过程中是不断写⼊的。
- bin log 是逻辑⽇志,记录内容是语句的原始逻辑,属于Server层,只在事务提交时才写⼊。
如何配合⼯作
MySQL 将redo log的写⼊操作拆成了两个步骤prepare和commit进⾏,在事务执⾏期间,写⼊的redo log标记为prepare阶段,待事务提交且bin log写⼊成功时,才将redo log标记为commit阶段。具体流程如图:
下⾯具体分析写⼊log时发⽣异常的情况:
- 写⼊bin log时发⽣异常:使⽤两阶段提交后,写⼊bin log时发⽣异常也不会有影响,因为MySQL在使⽤redo log恢复时,发下redo log还处于prepare阶段,⽽且此时没有bin log,认为该事务操作尚未完成提交,会回滚此操作。
- redo log在commit阶段发⽣异常:虽然 MySQL 重启后发现redo log是处于prepare阶段,但是能通过事务id找到了对应的bin log记录,所以MySQL认为此事务执⾏是完整的,就会提交事务恢复数据。
多版本并发控制(MVCC)
多版本并发控制全称Multi-Version Concurrency Control,是⼀种并发控制的⽅法,⼀般在数据库管理系统中,实现对数据库的并发访问。MVCC 在 MySQL InnoDB 中的实现主要是为了提⾼数据库并发性能,⽤更好的⽅式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,能够⾮阻塞并发读取。
当前读 & 快照读
在了解 MVCC 之前,需要先区分两个概念:当前读和快照读。MySQL 在读取数据时,可以分为当前读和快照读两种形式。
- 当前读:读取的是事务最新的版本,读取的过程中其他并发事务不能进⾏修改,需要对读取的记录进⾏加锁。在串⾏化隔离级别下,每次select都是⼀次当前读,因为每次读取都会加锁。
- 快照读:不加任何锁的select语句就是快照读。在 RC 隔离级别下(读已提交),每次select都是⼀次快照读,都会生成新的readView,能读取到的是其他事务已经提交的增删改操作。在 RR 隔离级别下(可重复读),开启事务后第⼀次select才是快照读,因为其后的select读取不到其他事务提交的增删改操作。
有了这个基础后,就可以继续探讨 MVCC 的具体实现了。
实现原理
MVCC 主要是通过 undo_log 多版本链条,加上开启事务时产⽣的 readView(不同隔离级别有不同产⽣策略)来实现的。当查询的时候,根据 readView 进⾏判断,来决定读取哪个版本的数据。
版本链 undo-log
在 MySQL 中,每个数据⾏都有⼀个版本链,包含了该数据⾏的所有历史版本。每次更新操作都会⽣成⼀个新的数据版本,⽽不是覆盖旧版本。这些版本按照时间顺序连接在⼀起,形成版本链。下图是undo log的主要结构。
在insert的时候,undo log只在回滚的时候需要,在事务提交后可以⽴即删除,不需要记录上⼀个版本该⾏的数据(因为上⼀版本该⾏不存在);在 update 和 delete 的时候,不仅回滚的时候需要,多版本并发控制的时候也需要⽤来记录上⼀数据版本,因此事务提交后也不会⽴即删除。
读视图 read-view
当⼀个事务开始时,它会创建⼀个读视图(Read View)。ReadView 其实就是一个保存事务ID的列表。记录的是本事务执行时,MySQL 还有哪些事务在执行,且还没有提交。读视图主要包括以下信息:
- m_ids,当前有哪些事务正在执行,且还没有提交,这些事务的 id 就会存在这里。
- min_trx_id,是指 m_ids 里最小的值。
- max_trx_id,表示创建 ReadView 时系统中应该分配给下一个事务的id值,当前最大事务ID+1。
- creator_trx_id,每开启一个事务都会生成一个 ReadView,而 creator_trx_id 就是这个开启的事务的 id。
版本链数据的访问规则主要依赖于undo log记录的当前事务的id,即隐藏字段 DB_TRX_ID,⽤这个id去匹配下⾯的规则,如果符合其中某⼀条件,说明当前版本是可以读取的;如果不符合条件,说明这个版本的数据不能读,就会顺着版本链去寻找更⽼的版本的数据
- 当 trx_id = creator_trx_id 时 ,说明数据就是当前事务修改的,因此是可以读取到的。
- 当 trx_id < min_trx_id 时,说明当前事务不是活跃中的事务(已经提交),已提交的数据版本是可以读取到的。
- 当 trx_id > max_trx_id时,说明当前事务是在 readview ⽣成后才开启的,因此不可以访问该版本的数据。
- 当 min_trx_id <= trx_id <= max_trx_id 时,如果 trx_id 在 m_ids 中,则代表Read View生成时刻,这个事务还在活跃,版本记录在前事务不可见;如果不在m_ids中,则说明该事务数据已经提交,版本记录在当前事务可见。
MVCC 作用
在不同隔离级别下,readview ⽣成的时机不同。
- 如果是读已提交隔离级别,那么在事务中每次执⾏快照读都会⽣成readview;
- 如果是可重复读隔离级别,那么只在事务第⼀次执⾏快照读的时候⽣成readview,后续会复⽤这个readview。
所以MVCC可以解决不可重复读问题,但是不能解决幻读问题。幻读只能通过范围锁(Range Locking)来解决。范围锁允许事务锁定⼀定范围的数据,以确保其他事务不能在这个范围内插⼊新数据或修改已有数据。因为事务可以锁定整个范围,从⽽保持了数据的⼀致性。例如,在⼀个订单表中,如果⼀个事务正在检查某个时间范围内的所有订单,并且希望防⽌其他事务在这个范围内插⼊新订单,就可以使⽤范围锁来锁定这个时间范围。
本文标签: Mysql详解
版权声明:本文标题:Mysql详解 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/shuma/1754835307a3180218.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论