存储引擎是基于表的存在。
InnoDB把表数据放在一个黑盒里,自己管理,它可以把每一个InnoDB存储引擎的表单独放到一个ibd里。InnoDB是聚集存放,每张表都按照主键的顺序存储。
MyISAM不一样的一点是它的缓存只缓存索引,而不缓存数据,数据文件的缓存交给操作系统来做,这个其他使用LRU算法缓存数据的大部分数据库不同。
一、连接Mysql
连接其实是一个连接进程和实例(程序)之间进行通信,本质上是进程通信,所以那些常用的进程通信方式:管道、命名管道、TCP/IP套接字,等等基本就这些。
1.TCP/IP套接字
这是非常常用的方式,比如连接进程和实例不在一台机器上,所以连接的时候就要使用tcp/ip,当然mysql在接收到请求之后会看请求的用户名和密码有无权限。
InnoDB存储引擎不是表级别的吗?所以这个体系架构也是基于表的?
二、InnoDB体系架构
后台线程、缓冲池
1.后台线程
多线程模型,用来处理不同的任务。
(1)Master Thread
把缓冲池数据异步刷新到磁盘,包括脏页、合并插入缓冲、undo页回收。
(2)IO Thread
innodb使用大量AIO处理写IO请求。IO Thread的作用就是负责这些IO请求的回调。
(3)Purge Thread
事物提交后,使用的undolog可能不再需要,需要purge 回收已经分配的undo页。
(4)Page cleaner Thread
脏页的刷盘都放到这个线程了。
2.内存
(1)缓冲池
Innodb存储是基于磁盘,存储按照页进行管理,所以需要缓冲池来中和一下cpu和磁盘速度,在数据库读页的时候,先从磁盘读到缓冲池,下一次读的时候先看缓冲池有没有。对数据修改时,也修改缓冲池里的(如果没有命中,是先读取出来到缓存?再改?还是直接刷磁盘?),再以一定的频率刷回磁盘,但它也不是你每次改了缓冲池之后就一定会触发刷盘操作,它使用了一种检查点机制。
缓冲池里的数据有什么呢?
有索引页,数据页,undo页,插入缓存,自适应哈希,锁信息,数据字典等,不能任务缓冲池只缓存数据页和索引页,只是他们占很大一部分而已。
毕竟缓存有限的,那么当容量不够了怎么办呢?一般情况下缓存里的数据都是通过LRU算法管理,Innodb在LRU基础上做了优化,它加入了midPoint,新读取到的页,虽然是最新访问的,但并不直接插到头部,而是放到LRU列表的midPoint位置,在LRU列表长度的5/8处,midPoint之后的都叫old列表,之前的都叫new 列表,可以认为new列表都是热点数据。
为什么不采用朴素LRU?比如你做了一个扫描全表的操作,这些操作其实这是在这一次用到了,如果你把真正的热点数据都替换掉了,下次就还要找磁盘。
LRU是来管理页的一种方式,数据刚启动的时候肯定是没有什么热点数据的,LRU是空的,页空间都是Free在管理,当来了新的页先看free有没有空间,如果没有就用LRU替换了。一般来说缓冲池的命中应该在95%以上,如果达不到可能就是全表扫描让LRU污染(真正的热点数据被搞没了)。
LRU List里面的页被修改之后,称为脏页,缓冲池里的页和磁盘里的不一致了,这时候这个页也会挂到Flush List上,这两个list不冲突。
缓冲池允许有多个,页根据哈希值平均分配到不同的缓冲池实例。(当我查找页数据或者索引时,根据一个数据怎么确定是哪个缓冲池?还是说要遍历缓冲池。)
缓冲池里还有redo log缓冲,和额外的缓冲空间。
Innodb首先把redolog放在缓冲池,然后按照一定的频率刷到重做日志文件。redolog缓冲不需要很大,只要能存下1s的就可以,在下面三种情况时就把redolog刷到磁盘日志文件:
1.Master Thread每1s把重做日志缓冲刷到重做日志文件
2.当有新事务提交的时候刷。
3.当重做缓冲池剩余空间小于1/2时刷。
(2)checkPoint
如果你把数据写到缓存之后掉电了,这个修改要怎么同步给磁盘?
事务数据库系统普遍采用Write Ahead Log 策略,当事务提交时:先写重做日志,再修改页。
检查点机制的作用是:缩短数据库恢复时间 | 缓存池不够用时,把脏页刷新到磁盘 | 重做日志不可用时,刷新脏页。
当数据库宕机,checkPonit之前的都是好的,需要对checkPonit之后的数据进行恢复。另外当缓冲池不够用时,LRU换掉的如果是脏页,也会强制执行checkPoint。
那么checkPoint在什么时候产生?但凡是重做日志还有能用的,要强制产生checkPoint,将缓冲池中的页至少刷新到重做日志。
InnoDB有两种checkPoint:
sharp checkPoint(默认的工作方式)
fuzzy checkPoint
sharp checkPoint是在数据库关闭时把所有脏页刷到磁盘,但是数据库在运行的时候肯定不能这样。
Fuzzy是只刷新一部分,InnoDB引擎使用这种刷新方式,下面是发生fuzzy checkPoint的几种方式:
1)Master Thread checkPoint,对master thread发生的checkPoint差不多以每1s或者每10s的速度从缓冲池的脏页列表中刷一定比例的页到磁盘。
2)FLUSH_LRU_List
(3)mysql日志
现在只说说mysql 的日志redolog 和 binlog ,redolog 是独属于 innodb 的日志,binlog 则是属于 server 层的日志。
redolog是什么?
redo log包括两部分:一是内存中的日志缓冲(redo log buffer),该部分日志是易失性的;二是磁盘上的重做日志文件(redo log file),该部分日志是持久的。
在概念上,innodb通过force log at commit机制实现事务的持久性,即在事务提交的时候,必须先将该事务的所有事务日志写入到磁盘上的redo log file和undo log file中进行持久化。
为了确保每次日志都能写入到事务日志文件中,在每次将log buffer中的日志写入日志文件的过程中都会调用一次操作系统的fsync操作(即fsync()系统调用)。因为MySQL是工作在用户空间的,MySQL的log buffer处于用户空间的内存中。要写入到磁盘上的log file中,中间还要经过操作系统内核空间的os buffer,调用fsync()的作用就是将os buffer中的日志刷到磁盘上的log file中。
redolog 是物理日志,记录的是某个表的数据做了哪些修改,redolog 是固定大小的,也就是说后面的日志会覆盖前面的日志。
binlog 又称作归档日志,它记录了对 MySQL 数据库执行更改的所有操作,但是不包括 SELECT 和 SHOW 这类操作。binlog 是逻辑日志,记录的是某个表执行了哪些操作。binlog 是追加形式的写入日志,后面的日志不会被前面的覆盖。
3.1 数据更新过程
我们执行一个更新操作是这样的:读取对应的数据到内存—>更新数据—>写 redolog 日志—> redolog 状态为 prepare —>写 binlog 日志—>提交事务—> redolog 状态为 commit ,数据正式写入日志文件。我们发现 redolog 的提交方式为“两段式提交”,这样做的目的是为了数据恢复的时候确保数据恢复的准确性,因为数据恢复是通过备份的 binlog 来完成的,所以要确保 redolog 要和 binlog 一致。
前面说宕机有redolog,现在又说用binlog,到底用啥?
那么,binlog和redolog有什么区别?
三、Innodb关键特性
插入缓冲、两次写、自适应哈希索引、异步IO、刷新邻接页
1.插入缓冲
InnoDB中,主键是行唯一的标志,通常应用程序中记录的插入顺序是按照主键的递增顺序进行插入。因此插入聚集索引都是顺序的,不用在磁盘上随机读。
但更多时候你需要去建一些非聚集索引去辅助查询,因为B+树叶子的数据根据主键顺序存放,所以可能用你建的索引去插入的时候就是离散的了。
所以对于非聚集索引中数据的的插入和更新,如果索引页在缓冲池就直接插入,如果缓冲池没有,就放到一个insert buffer对象中,再以一定的频率把insert buffer和辅助索引的叶子节点merge,这时通常可以把多个merge合并成一个操作。要想使用insert buffer需要满足两个条件:索引是辅助索引,索引不要求value唯一(如果要求唯一,那还要去索引页上找是不是唯一的,没法用)。
Change buffer是insert buffer的升级,可以分成:insert buffer,delete buffer,purge buffer,可以对insert、delete和update都进行缓冲。和insert一样change buffer适用的对象还是不唯一的辅助索引。
比如update操作,Delete buffer对应update的第一个操作,purge buffer对应update的第二个操作,即将真正的记录删除。
2.两次写(double write)
部分写失效情况:如果在从缓冲中的数据页写到磁盘时,写到一半挂了。这样页就被损坏了,也许会想到用重做日志去恢复,但redo log存的是对页的物理操作,页已经坏了没办法恢复??所以需要一个页副本,当写失效发生,先还原受损的页,再进行重做。
在对缓冲池的脏页进行刷新时,并不直接写磁盘,而是先把脏页复制到内存中的double write buffer。
3.自适应哈希
就是Innodb会监控B+索引,如果它觉得给你建和自适应哈希会让查询速度更快就会给你建。自适应hash是根据缓冲池的B+树来构造,而且不要求对整张表建立hash索引,它会自动给某些热点页建立hash索引。
自适应hash有一个要求:对这个页的连续访问模式必须是一样的,例如对于(a,b)这样的联合索引页,访问方式可以是:
where a = xxx 或者 where a = xxx and b = xxx
必须是其中一种,不能两种交替,而且要以该模式访问100次,页通过该模式访问了N次,N=页中记录*1/16。
4.异步IO(AIO)
为了提高性能,当前数据库都采用异步IO,用户发一个IO请求之后可以再发送一个IO请求,而且它可以把多个IO请求优化成一个,比如发了一个(8,6),(8,7),(8,8),AIO判断这些页是连续的,就可以发一个读(8,6)的IO。
5.刷新邻接页
就是把脏页刷到磁盘时,会检查页所在的区还有没有其他脏页,如果有就一起刷回去。好处就是AIO可以把多个IO合成一个。
五、锁
lock和latch
lock的对象是事务,用来锁定数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同隔离级别可能不一样)。
1.Innodb锁的类型
InnoDB引擎实现两种标准的行级锁:
共享锁,允许事务读一行数据
排他锁,允许事务删除或更新一行数据
Innodb支持多粒度锁定,允许行级锁和表级锁同时存在,为了支持多粒度锁定,Innodb还支持意向锁,就是事务希望在更细粒度加锁。意向锁可以理解为表锁,比如你想给记录里的r加锁,那你需要先给数据库A,表1,和页加上意向锁IX,最后给r上x锁,如果粗粒度的锁不成功,那么就要等上一个表锁完成。
Innodb支持的两种意向锁:
意向共享锁:事务想要获得一张表中某几行的共享锁
意向排他锁:事务想要获得一张表中某几行的排他锁。
因为Innodb支持的是行级锁,其实意向锁其实不会阻塞全表扫意外的任何请求。
image.png
网友评论