MySql 架构与历史

[TOC]

1. 逻辑架构

Mysql 是C/S架构,总共可以分为三层:

  • 最上层客户端,mysql的图形化连接软件和各种编程语言的mysql连接模块,例如Python的MySQLdb模块,还有API接口等等

  • 第二层就是mysql的核心服务,也称为service层。包括:查询解析、分析、优化、缓存以及所有的内置函数(例如:日期、时间、数学和加密函数)。同时,所有的跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等

  • 第三层为存储层,包含了存储引擎,存储引擎负责数据的存储与提取,服务器通过API与存储引擎进行通信,这些接口屏蔽了不同存储引擎之间的差异,使得这些差异对于上层的查询过程透明。

2. 并发控制

每一个客户端都会在服务器中拥有一个线程,这个连接的查询只会在该线程中进行,这个线程只会轮流在某一个cpu核心或者cpu上运行,服务器负责缓存线程。只要有多个查询需要同时操作数据都会有并发控制问题。mysql在服务器层存储引擎层进行并发控制。

  • 读写锁(共享锁、排他锁)

  • 锁粒度: 行级锁、表级锁 不同类型的存储引擎会实现各自的锁策略以及锁粒度。ALTER TABLE 操作服务器层会使用表锁忽略存储引擎的锁机制;而存储引擎中的行锁实现对于服务器层也是不可见的

  • 事务: 一组原子性的SQL查询,或者一个独立的工作单元

2.1 事务

一个运行良好的事务管理系统,需要具有ACID属性:

  • 原子性(Atomicity): 一个事务是一个最小的可操作单元,要么成功,要么回滚,不可能只执行一部分

  • 一致性(Consistency):数据库总是从一个一致性状态转移到另一个一致性状态

  • 隔离性(Isolation):通常来说,一个事务所做的修改在提交之前对于其他事务是不可见的;在不同的隔离级别下,事务具有不同的可见性

  • 持久性(Durability):事务一旦提交,所做的修改就会永久保存在数据库中

2.2 隔离级别

每种存储引擎实现的隔离级别不尽相同,主要有以下隔离级别:

  • 未提交读(Read Uncommited):

    事务的修改即使没有提交,对于其他事务也是可见的,也称为脏读。这个隔离级别会导致很多问题,从性能上讲,并不会比其他隔离级别好太多,实际很少使用。

  • 提交读(Read Commited):

    一个事务开始时只能看到其他事务已提交的结果,换句话说,一个事物未提交时所做的操作修改对于其他事务都是不可见的。又称为不可重复读,两次执行查询的结果可能不一致。

  • 可重复读(Repeatable Read):

    解决了脏读的问题,该级别保证同一个事务多次读取同样记录的结果是一致的。但是理论上可重复读不能解决幻读(Phantom Read)*的问题, 幻读是指 当事务读取某一范围的数据时,另一个事务在该范围插入了新的记录,导致之前事务再次读取该范围的数据时会产生幻行 。 InnoDB通过多版本并发控制(MVCC, Multiversion Concurrency Control) 解决幻读问题 可重复读也是Mysql默认的隔离级别

  • 可串行化(Serializable)

    最高隔离级别,强制事务串行执行,避免幻读问题。可串行化通过对于每一行数据加锁,会导致大量的超时以及锁竞争问题。只有在非常需要确保数据一致,而且接受没有并发的情况下使用。

2.3 死锁

多个事务在同一资源上相互占用,并且请求锁定对方占用的资源,从而导致恶性循环的现象。多个事务试图以不同顺序锁定多个资源时就会产生死锁。数据库有多种死锁检测以及死锁超时机制。死锁发生后只有部分或者完全回滚其中一个事务才可以打破死锁。

2.4 事务日志

事务日志可以帮助提高事务的效率,进行数据修改时,只修改其内存拷贝,修改记录持久化到事务日志中,不需要立即将修改数据持久化到硬盘,之后依据日志异步进行数据持久化。事务日志采用追加方式,写日志操作只涉及一小块区域内的顺序io,效率更高。称为预写式日志(Write-Ahead Logging)

2.5 MVCC

大多数存储引擎都实现了MVCC,可以认为MVCC是行级锁的一个变种,但在很多情况下避免了加锁操作,因此开销更低。MVCC通过保存数据在某一个时间点的快照实现的,从而保证同一个事务看到的数据一致。典型的实现有乐观的并发控制以及悲观的并发控制。

InnoDB的mvcc通过在每一行记录的后面保存两个隐藏的列实现的。分别保存行的创建时间、删除时间。保存的并不是实际的时间戳,而是系统版本号。每开始一个事务,系统版本号都会加一,事务开始时刻的系统版本号作为事务版本号

对于事务A,版本号 Va

  • SELECT

    a. 创建版本号小于等于事务版本号Va的行

    b. 行的删除版本号未定义或者大于Va,确保事务读取的行在事务开始前未被删除

  • INSERT

    插入的每一行使用系统版本号作为创建版本号

  • DELETE

    为删除的行保存当前系统版本号作为行删除标志

  • UPDATE

    相当于删除原有记录,创建一条新的记录。新插入一行使用系统版本号作为创建版本号,并将原有行的删除版本号置为系统版本号

Last updated