数据库内容纵览
副标题:姜承尧《MySQL技术内幕 InnoDB存储引擎》读书笔记 1
MySQL被设计为 一个单进程多线程架构的数据库,故MySQL数据库实例在系统上的表现就是一个进程
1
2
3
4
5[root@VM_0_2_centos bin]# mysql --help | grep my.cnf
order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf- 可以看出,MySQL数据库实例启动时,是按照
/etc/my.cnf
->/etc/mysql/my.cnf
->/usr/etc/my.cnf
->~/.my.cnf
的顺序读取配置文件。 - 配置文件有一个参数
datadir
指定了数据库所在的路径,如datadir=/var/lib/mysql
- 可以看出,MySQL数据库实例启动时,是按照
数据库是由一个个文件(二进制)组成的,要对这些文件执行SELECT、INSERT等操作,不能通过操作文件更改数据库的内容,需要通过数据库实例来完成
MySQL组成部分:
- 连接池组件
- 管理服务和工具组件
- SQL接口组件
- 查询分析器组件
- 优化器组件
- 缓冲组件
- 插件式存储引擎(important)
- 物理文件
InnoDB存储引擎支持事务,通过使用多版本并发控制(MVCC)来获得高并发性,并实现SQL标准的4种隔离级别。同时使用next-key locking的策略(也就是间隙锁)来避免幻读(phantom)现象的产生。此外,提供了插入缓存 、二次写、自适应哈希索引、预读等高性能和高可用的功能(其他引擎略过)
- MVCC,是行锁的一种妥协,很多情况下避免使用锁,同时提供更小的开销,根据实现的不同,可以允许非阻塞式读,写操作时只锁定必要的记录
- MVCC是通过保存数据在某个时间点的快照来实现的,在每行后面保存两个隐藏列(创建时系统version、销毁时系统version),每开始一个新的事务,系统version会递增
- SELECT时,InnoDB按照以下两个条件检查每行记录:
- 只会查找创建version早于(小于)当前事务version的数据行,这样可以确保事务读取的行,要么是事务开始前已经存在的,要么是事务自身插入或修改过的(属于快照读的方式,另一种方式当前读即加锁读)
- 行的删除version要么未定义,要么大于当前的事务version,这样可以确保事务读取到的行,在事务开始之前未被删除
- 只有同时满足了以上两点,才能返回作为查询结果
- DELEDE时,会将当前事务version,写入该行的销毁version项中
- UPDATE时,会生成新的一行,version写入新行的创建时间中,同时在原来要修改的行的销毁version项上,写上当前事务的version
- 进程连接MySQL数据库实例进行通信
- 常用的方式有:管道、命名管道、命名字、TCP/IP套接字、UNIX套接字
- 用户在客户端,可以请求一台远程服务器上的MySQL实例
InnoDB特性
InnoDB存储引擎有多个内存块,组成了一个大的内存池,负责:
- 维护所有进程/线程 需要访问的多个内部数据结构
- 缓存磁盘上的数据,方便快速的读取,同时在对磁盘文件的数据修改之前在这里缓存
- redo log缓冲
因为是多线程的模型,负责处理不同的任务:
多线程的任务
Master Thread。负责将缓冲池的数据异步刷到磁盘,保证数据的一致性
IO Thread。InnoDB使用了大量的AIO(Async)来处理IO请求,此线程的作用就是负责这些IO请求的回调处理。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38//查看InnoDB版本
mysql> show variables like 'innodb_version'\G
*************************** 1. row ***************************
Variable_name: innodb_version
Value: 5.7.22
1 row in set (0.00 sec)
//read和write线程各4个
mysql> show variables like 'innodb_%io_threads'\G;
*************************** 1. row ***************************
Variable_name: innodb_read_io_threads
Value: 4
*************************** 2. row ***************************
Variable_name: innodb_write_io_threads
Value: 4
2 rows in set (0.00 sec)
//查看IO Thread细节(放上部分关键代码 )
mysql> show engine innodb status\G;
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
318 OS file reads, 13231 OS file writes, 5396 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
-------------------------------------说明:
可以看到IO Thread 0 为insert buffer thread。IO Thread 1 为log thread,之后就是根据innodb_read_io_threads和innodb_write_io_threads来设置的读写线程,并且读线程的ID总是小于写线程
Purge Thread。事务被提交后,所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。在InnoDB高版本中,还支持多个PurgeThread,可以进一步加快undo页的回收,同时由于PurgeThread需要离散的读取undo页,这样也能更近一步利用磁盘的随机读取性能
1
2
3
4
5mysql> show variables like 'innodb_purge_threads'\G
*************************** 1. row ***************************
Variable_name: innodb_purge_threads
Value: 4
1 row in set (0.00 sec)以上显示PurgeThread有4个
Page Cleaner Thread。将脏页的刷新操作放入单独的线程中完成
1
2
3
4
5mysql> show variables like 'innodb_page_cleaners'\G
*************************** 1. row ***************************
Variable_name: innodb_page_cleaners
Value: 1
1 row in set (0.00 sec)
完成全书36页