概念题

未匹配的标注

Mysql 事务

基本概念

事务(transaction)是一个不可分割的最小工作单元, 其中的操作要么都做, 要么都不做。

特性

  1. 原子性(Atomicity):一个事务中的所有操作,要么全部完成,要么全部不完成。
  2. 一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。换一种方式理解就是:事务按照预期生效,数据的状态是预期的状态。
  3. 隔离性(Isolation):事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
  4. 持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会有任何影响。

事务的并发问题

多个事务对相同的数据同时进行操作,这叫做事务并发。

  1. 脏读(Dirty Reads):一个事务读到另一个事务的未提交更新数据,即读取到了脏数据;
  2. 不可重复读(Non-Repeatable Reads):一个事务读取到了另一个事务已经提交的数据, 也就是说一个事务可以看到其他事务所做的修改(是针对修改操作);
  3. 幻读(Phantom Reads): 一个事务内读取到了别的事务插入的数据,或者读取不到被别的事务删除的数据, 导致前后读取不一致。(是针对插入或删除操作)。

事务的隔离级别

  • read uncommited(读未提交):事务中的修改即使没有提交,对其他事务也都是可见的。安全级别最低。

  • read commited(读已提交):事务在提交之前,所做的任何修改对其他事务都是不可见的。Oracle默认。

  • repeatable read(可重复读):同一个事务中多次读取同样记录(指一行数据)时是一致的。Mysql 默认。

  • serializable(序列化):强制事务串行执行。

事务隔离级别会产生的并发问题

事务隔离级别 脏读 不可重复读 幻读
读未提交(read uncommited)
读已提交(read commited) ×
可重复读(repeatable read) × ×
串行化(serializable) × × ×

Mysql 日志系统

日志类型

mysql 日志主要包括错误日志、查询日志、慢查询日志、事务日志(redo log、undo log)、二进制日志(binlog)几大类。redo log 是 InnoDB 存储引擎层的日志,binlog 是 Server层记录的日志, 两者都是记录了某些操作的日志(不是所有),自然有些重复(但两者记录的格式不同)。

Mysql逻辑架构

物理日志和逻辑日志

  • 物理日志:通俗的讲,就是只有”我”自己可以使用,别人无法共享我的”物理格式,私有化。
  • 逻辑日志:可以给别的引擎使用,是所有引擎共享的。

redo log 日志模块

  1. 基本概念

    redo log 是 InnoDB 存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来。而这种先写日志,后写磁盘的技术就是mysql里面经常提及到的WAL(Write Ahead Logging)技术。

  2. 记录方式

    由于 redo log 记录的是数据页的变更,而这种记录是没有必要永久保存的,因此 redolog 实现上采用来大小固定,循环写入的方式,当记录写到末尾时,又会从头开始写。

  3. 使用场景

    用于系统奔溃恢复(crash-safe)

undo 日志模块

  1. 基本概念

    undo log 是回滚日志,是记录每条数据的所有版本,比如 update 语句,那么它首先会将该条记录的数据记录到 undo log日志中,并且将最新版本的 roll_pointer 指针指向上一个版本,这样就可以形成当前记录的所有版本,这也是MVCC的实现机制。

  2. 使用场景

    • MVCC多版本控制

binlog 日志模块

  1. 基本概念

    binlog 又称为归档日志,属于逻辑日志,并且由 mysql 数据库的 service 层执行,是所有存储引擎共享的日志模块,它用于记录数据库执行的写入性操作,也就是在事务 commit 阶段进行记录,以二进制的形式保存于磁盘中。

  2. 记录方式

    binlog 是以追加的方式进行写入的,可以通过 max_binlog_size参数设置 binlog 文件大小,当文件大小达到某个值时,会生成新的文件来保存日志。

    binlog 是以二进制的形式记录的是这个语句的原始逻辑,依靠 binlog 是没有crash-safe能力的。

  3. 刷盘机制

    对于 InnoDB 引擎而言,在每次事务 commit 提交时才会记录 binlog 日志,此时记录仍然在内存中,那么什么时候存储到磁盘中呢?mysql通过 sync_binlog 参数控制 binlog 刷盘时机,取值范围:0~N:

    0:不去强求,由系统自行判断何时写入磁盘;

    1:每次事务 commit 的时候都要将 binlog 写入磁盘;(建议设置为1,保证异常重启之后日志不会丢失。)

    N:每 N 个事务 commit ,才会将 binlog 写入磁盘;

  4. 使用场景

    • 主从复制:在 master 端开启 binlog,然后将 binlog 发送给各个 slaver 端,slaver 端读取 binlog 日志,从而使得主从数据库中数据一致。
    • 数据恢复:通过 binlog 获取想要恢复的时间段数据。

binlog/redo log/undo log区别

bin log redo log undo log
存储位置 server层,所有引擎共享 InnoDB引擎独有
文件大小 可通过max_binlog_ize设置 redo log大小是固定的
日志名称 归档日志 重写日志 回滚日志
记录方式 通过追加方式进行记录 通过循环写方式进行记录,写到末尾又从开头接着写
适用场景 主从复制和数据恢复 奔溃恢复 MVCC多版本并发

MVCC 机制

  1. 基本概念

    多版本并发控制(MVCC),是一种用来解决读-写冲突的无锁并发控制,也就是为事务分配单向增长的时间戳,为每个修改保存一个版本,版本与事务戳关联,读操作只读事务开始前的数据库的快照。这样在读操作的时候不会阻塞写操作,写操作不会阻塞读操作的同时,也避免了脏读和不可重复读。

  2. 当前读和快照读概念

    • 当前读:指的就是它读取的记录是最新版本的。由于它要读取记录的版本是最新版本,所以读取时须保证其他事务不能修改当前记录,因此需要对读取的记录进行加锁。

    • 快照读:可以理解为不加锁的 select 操作就是快照读。快照读的前提是隔离级别不是串行级别,因为在串行隔离级别,快照读可以理解为当前读;快照读的出现,主要解决了在不加锁的情况下也可以进行读取,降低了锁开销;它的实现是基于 MVCC,故使用快照读读取的记录并不一定是最新记录。

  3. 当前读、快照读和 MVCC 的关系

    • MVCC主要基于”维护一条数据的多个版本,进而保证在读操作的同时不会阻塞写操作,写操作的同时也不会阻塞读操作”。
    • 快照读其实就是 MVCC 的一种体现方式,进行非阻塞读。而相对而言,当前读就是悲观锁的体现,每次进行查询操作时,mysql都认为其是不安全操作,为其加锁保证安全,但每次读取的数据为最新数据。
  4. MVCC、乐观锁、悲观锁的关系

    • MVCC + 乐观锁:MVCC 解决读写冲突,乐观锁解决写写冲突

    • MVCC + 悲观锁:MVCC 解决读写冲突,悲观锁解决写写冲突

    这样组合的方式最大程度的提高数据库并发性能,解决读写冲突以及写写冲突所导致的问题。

  5. MVCC实现原理

    它主要由隐藏字段,undolog日志,read-view来配合完成的。

Mysql 主从复制

主从复制-概念

主从复制是指数据可以从一个 Mysql 数据库服务器主节点复制到一个或多个从节点。Mysql 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。

主从复制-原理

Mysql 主从复制涉及到三个线程,一个运行在主节点(log dump thread),其余两个(I/O thread, SQL thread)运行在从节点,如下图所示:

Mysql主从复制流程图

开始 =》Master 更新数据 =》写 binlog =》I/O 线程 =》relay log 更新 =》SQL 线程 =》执行更新。

主从复制-流程

Mysql 的主从复制是基于如下 3 个线程的交互,多线程复制里面应该是 4 类线程:

  • Master 上面的 binlog dump 线程,该线程负责将 master 的 binlog event 传到 slave 。
  • Slave 上面的 IO 线程,该线程负责接收 Master 传过来的 binlog,并写入 relay log 。
  • Slave 上面的 SQL 线程,该线程负责读取 relay log 并执行。
  • 如果是多线程复制,SQL 线程只做 coordinator ,只负责把 relay log 中的 binlog 读出来然后交给 worker 线程, woker 线程负责具体 binlog event 的执行。

主从复制-模式

主从复制如何保证数据一致性?

  1. 异步模式:master 将事务 binlog 事件写入到 binlog 文件中,此时 master 只会通知一下 dump 线程发送这些新的 Binlog,然后主库就会继续处理提交操作,而此时不会保证这些 binlog 传到任何一个从库节点上。

    主从复制异步模式

  2. 半同步模式:master 只需要等待至少一个从库节点收到并且 Flush Binlog 到 Relay Log 文件即可,主库不需要等待所有从库给主库反馈。(这里只是一个收到的反馈,而不是已经执行完成并且提交的反馈。)

    主从复制半同步模式

  3. 全同步模式:指当 master 执行完一个事务,所有的从库都执行了该事务才返回给客户端。

主从复制-方式

  1. 基于SQL语句的复制(statement-based replication,SBR):记录 sql 语句在 binlog 中。

    优点是只需要记录会修改数据的 sql 语句到 binlog 中,减少了 binlog 的量,节约 I/O,提高性能。

    缺点是在某些情况下,会导致主从节点中数据不一致(比如sleep(),now()等)。

  2. 基于行的复制(row-based replication,RBR): 只记录哪条数据被修改了,修改成什么样。

    优点是不会出现某些特定情况下的存储过程、或者函数、或者trigger的调用或者触发无法被正确复制的问题。

    缺点是会产生大量的日志,尤其是修改table的时候会让日志暴增,同时增加bin log同步时间。也不能通过bin log解析获取执行过的sql语句,只能看到发生的data变更。

  3. 混合模式复制(mixed-based replication,MBR):是以上两种模式的混合,对于一般的复制使用 STATEMENT 模式保存到 binlog,对于 STATEMENT 模式无法复制的操作则使用 ROW 模式来保存,MySQL会根据执行的SQL语句选择日志保存方式。

Mysql 备份方式

逻辑备份

使用 MySQL 自带的 mysqldump 工具进行备份。备份成 sql 文件形式。

  • 优点:最大好处是能够与正在运行的 MySQL 自动协同工作,在运行期间可以确保备份是当时的点,它会自动将对应操作的表锁定,不允许其他用户修改(只能访问)。可能会阻止修改操作。SQL 文件通用方便移植。
  • 缺点:备份的速度比较慢。如果是数据量很多的时候,就很耗时间。如果数据库服务器处在提供给用户服务状态,在这段长时间操作过程中,意味着要锁定表(一般是读锁定,只能读不能写入数据),那么服务就会影响的。

物理备份

因为现在主流是 InnoDB ,所以基本不再考虑这种方式。

直接拷贝只适用于 MyISAM 类型的表。这种类型的表是与机器独立的。但实际情况是,你设计数据库的时候不可能全部使用 MyISAM 类型表。

  • 缺点:你不能去操作正在运行的 MySQL 服务器(在拷贝的过程中有用户通过应用程序访问更新数据,这样就无法备份当时的数据),可能无法移植到其他机器上去。

双机热备份

当数据量太大的时候备份是一个很大的问题,MySQL 数据库提供了一种主从备份的机制,也就是双机热备。

  • 优点:适合数据量大的时候。现在明白了,大的互联网公司对于 MySQL 数据备份,都是采用热机备份。搭建多台数据库服务器,进行主从复制。

Mysql 锁机制

锁的类型

Mysql 的共享锁和排他锁,就是读锁和写锁。

  • 共享锁:不堵塞,多个用户可以同时读一个资源,互不干扰。
  • 排他锁:一个写锁会阻塞其他的读锁和写锁,这样可以只允许一个用户进行写入,防止其他用户读取正在写入的资源。

锁的粒度

  • 表锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低;MyIsam 使用表锁。
  • 行锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。InnoDB 使用行锁。

悲观锁和乐观锁

  1. 悲观锁:总假设最坏的情况, 每次拿数据时都认为别人会修改, 所以在每次拿数据的时候都会上锁。 锁同时只能有一个。
  2. 乐观锁:总假设最好的情况, 每次拿数据的时候都认为别人不会修改, 所以不会上锁。但是在更新的时候会判断一下在此期间这个数据有没有被更新。

死锁

  1. 死锁的发生

    两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.

  2. 死锁的发生的四个必要条件

    • 互斥条件:一个资源每次只能被一个进程使用。
    • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
    • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
    • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

  1. 处理死锁的四种方法

    死锁预防:破坏死锁的四个条件中的一个或几个,保证不会发生死锁。

    死锁检测:允许死锁的发生,但是可以通过系统设置的检测结构及时的检测出死锁的发生,采取一些措施,将死锁清除掉。

    死锁避免:在资源分配过程中,使用某种方法避免系统进入不安全的状态,从而避免发生死锁。

    • 进程启动拒绝:如果一个进程的请求会导致死锁,则不启动该进程。
    • 资源分配拒绝:如果一个进程增加的资源请求会导致死锁,则不允许此分配(银行家算法)。

    死锁解除:与死锁检测相配套的一种措施。当检测到系统中已发生死锁,需将进程从死锁状态中解脱出来。

    • 资源剥夺法:挂起某些死锁进程,并抢占它的资源,将这些资源分配给其他的死锁进程。但应防止被挂起的进程长时间得不到资源,而处于资源匮乏的状态。
    • 撤销进程法:强制撤销部分、甚至全部死锁进程并剥夺这些进程的资源。撤销的原则可以按进程优先级和撤销进程代价的高低进行。

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~