21-4-26_innodb内幕

一、第1章 MySQL体系结构和存储引擎

1.1 定义数据库和实例

数据库

​ 物理操作系统文件或者起形式文件类型的集合。

​ 可以是frm、MYD、ibd等文件,或者内存之中的文件。

实例

​ 后台线程以及一个共享内存区组成,数据库实例才是真正操纵数据库文件。

单机情况

数据库 < -- > 实例

​ 一 一对应

集群情况

​ 可能存在一个数据库多个实例使用。

MySQL

​ 单进程多线程架构。

读取配置文件

​ 以读取到的最后一个配置文件为准

​ 查看顺序:

  • linux:mysql --help | grep my.cnf
  • windows:mysql --help

1.2 MySQL体系结构

MySQL体系结构

  • 连接池组件
  • 管理服务和工具组件
  • SQL接口组件
  • 查询分析器组件
  • 优化器组件
  • 缓冲组件
  • 插件式存储引擎:区别于其他数据库
  • 物理文件

存储引擎基于表而不是数据库。

1.3 MySQL存储引擎

1.3.1 InnoDB存储引擎

  • 支持事务、行锁、外键

  • MySQL5.5.8默认存储引擎

  • 将数据放在逻辑的表空间

  • MVVC(多版本并发控制)来获得高并发性,四种隔离级别,默认repeatable read可重复读,next-key locking来避免幻读,插入缓冲、二次写、自适应哈希索引、预读

  • 聚集索引,每张表的存储都是按主键的顺序进行存放,没有显示指定主键则有6字节的rowid作为主键

1.3.2 MyISAM存储引擎

  • 不支持事务
  • 表锁
  • 全文索引
  • 缓冲池只缓存索引文件
  • 存储引擎表由MYD和MYI组成
    • MYD存储数据文件
    • MYI存放索引文件
  • 只缓存索引文件,数据文件交由操作系统本身

1.3.3 NDB存储引擎

  • 集群存储引擎
  • 数据全部放在内存中(5.1版本可将索引数据放在磁盘上),主键查找速度快
  • 连接操作(JOIN)在数据库层完成,而不是在存储引擎层,网络开销大,查询速度慢

1.3.4 Memory存储引擎

  • 之前称 HEAP引擎
  • 表中数据在内存中,数据库重启或崩溃,数据消失
  • 适用临时存储数据的临时表
  • 哈希索引
  • 表锁
  • 并发性能差
  • 不支持TEXT和BOLB类型

1.3.5 Archive存储引擎

  • Insert、select操作
  • 压缩后存储,1:10
  • 适合存储归档数据:日志
  • 行锁,告诉的插入和压缩

1.4 各种存储引擎对比

各种存储引擎对比

查看存储引擎:

show engines \G

1.5 连接MySQL

1.5.1 TCP/IP

在任何平台都提供的连接方式,也是使用得最多的一种方式。

在通过TCP/IP 连接到MySQL实例时,数据库会先检查一张权限视图,用来判断发起请求的客户端IP是否允许连接到数据库实例。

1.5.2 命名管道和共享内存

配置文件中配置:

  • 命名管道:

    --enable-names-pipe

  • 共享内存:

    --shared-memory

    • 客户端需要使用 --protocl=memory

1.5.3 UNIX域套接字

  • linux、unix环境下
  • 配置文件: -socket=/tmp/mysql.sock
  • unix域套接字文件查找:show variables like 'socket';

第2章 InnoDB存储引擎

2.3 InnoDB体系架构

InnoDB存储引擎体系结构

InnoDB存储引擎有多个内存块,可认为组成了内存池,负责:

  • 维护所有进程/线程需要访问的多个内部数据结构
  • 缓存磁盘数据,方便快速读取,同时把内存中的缓存写入磁盘数据
  • redo日志缓冲

后台线程主要是刷新内存池的数据,保证缓冲池中的内存是最新数据;同时将已修改文件刷新到磁盘;保证数据库发生异常下InnoDB能恢复到正常运行状态

2.3.1 后台线程

InnoDB存储引擎是多线程模型,后台有多个不同的后台线程

1、Master Thread

  • 核心
  • 将缓冲池的数据异步刷新到磁盘
    • 脏页
    • 合并插入缓冲
    • undo页的回收

2、IO Thread

  • 负责AIO来处理写IO请求的回调处理
mysql> show variables like 'innodb_version' ;
+----------------+--------+
| Variable_name  | Value  |
+----------------+--------+
| innodb_version | 8.0.19 |
+----------------+--------+
1 row in set, 1 warning (0.00 sec)
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, 1 warning (0.00 sec)

innodb_read_io_threadsinnodb_write_io_threads设置读写IO Thread线程个数

mysql> show engine innodb status \G
I/O thread 0 state: wait Windows aio (insert buffer thread)
I/O thread 1 state: wait Windows aio (log thread)
I/O thread 2 state: wait Windows aio (read thread)
I/O thread 3 state: wait Windows aio (read thread)
I/O thread 4 state: wait Windows aio (read thread)
I/O thread 5 state: wait Windows aio (read thread)
I/O thread 6 state: wait Windows aio (write thread)
I/O thread 7 state: wait Windows aio (write thread)
I/O thread 8 state: wait Windows aio (write thread)
I/O thread 9 state: wait Windows aio (write thread)

IO 0 Thread是insert buffer thread

IO 1 Thread是log thread

其他是上述两个参数进行设置,且读线程的ID小于写线程

3、Purge Thread

事务提交后,Purge Thread来回收可能不再需要的undo日志

mysql> select version()\G
*************************** 1. row ***************************
version(): 8.0.19
1 row in set (0.06 sec)
mysql> show variables like 'innodb_purge_threads' \G
*************************** 1. row ***************************
Variable_name: innodb_purge_threads
        Value: 4
1 row in set, 1 warning (0.00 sec)

4、Page Cleaner Thread

将之前版本中的脏页的刷新操作都放入到单独的线程中来完成,为了减轻Master Thread的工作及对于用户查询线程的阻塞,提高性能

2.3.2 内存

1、缓冲池

读取页时,将从磁盘的页放到缓冲池中(FLX),下一次再读相同的页时先进行判断,若在缓冲池中则称该页被命中,直接读取,否则在磁盘上读取

页操作,修改缓冲池中的页,再一定频率刷入磁盘,通过CheckPoint机制刷新

InnoDB内存数据对象

缓冲池中有:索引页,数据页,undo页,插入缓冲,自适应哈希索引,InnoDB存储的锁信息,数据字典信息

缓冲池实例数

mysql> show variables like 'innodb_buffer_pool_instances'\G
*************************** 1. row ***************************
Variable_name: innodb_buffer_pool_instances
        Value: 1
1 row in set, 1 warning (0.00 sec)

innodb_buffer_pool_instances设置大于1则可以得到多个实例

可以通过informeation_schema的表innod_buffer_pool_stats来观察缓冲池状态

mysql> select pool_id, pool_size,free_buffers, database_pages from innodb_buffer_pool_stats;
+---------+-----------+--------------+----------------+
| pool_id | pool_size | free_buffers | database_pages |
+---------+-----------+--------------+----------------+
|       0 |      8192 |         6971 |           1212 |
+---------+-----------+--------------+----------------+
1 row in set (0.00 sec)

2、LRU List、Free List和Flush List

LRU:最近最少使用算法

最频繁使用的页在LRU列表前端,最少使用的页在LRU列表的尾端, 当缓冲池不能存放新读取的页,将首选LRU列表尾端的页

缓冲池中页默认大小是16KB

midpoint位置,最新读取的页放在此位置,此算法称midpoint insertion strategy

mysql> show variables like 'innodb_old_blocks_pct'
    -> ;
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
1 row in set, 1 warning (0.00 sec)

占比37%,由innodb_old_blocks_pc控制

midponit之前的页称为new列表,热度高,之后的称old列表

不采用的话全表扫描时可能会将经常使用的页淘汰

innodb_old_blocks_time来管理,表示页读取到mid位置需要等待多久才会被移到前端,表示在这时间内多次访问一个页不需要将其放在new区域

Free列表:

服务器启动时LRU列表为空,页都在Free列表中。

当需要从缓冲池中分页时,首先从Free列表查找是否有空闲页,有则从Free列表移除,放入LRU列表中,否则淘汰LRU列表末尾的页,将该内存空间分配给新的页

当页从old移到new部分时,称page made young

因为innodb_old_blocks_time的设置导致没有从old到new则称page not made young

压缩页功能会将16KB的页压缩至1KB2KB4KB8KB,此时由unzip_LRU列表进行管理

LRU列表包含unzip_LRU列表的数量

unzip_LRU列表分配:

在列表中对不同压缩页大小进行分别管理,其次通过算法进行内存的分配

例如对需要从缓冲池中申请4KB的页:

  • 检查4KB的unzip_LRU列表,检查检查是否有空闲页
  • 若有直接使用
  • 否则,检查8KB的unzip_LRU列表
  • 若能得到空闲页,则将此页分成2个4KB的页,放入4KB的unzip_LRU列表
  • 若不能,从LRU列表申请一个16KB的空闲页,分成1个8KB的页,2个4KB的页,分别放入对应的列表

unzip_lru

LRU列表中的页被修改后,成为脏页,即缓冲池的页和磁盘上的页的数据不一致,数据库会通过checkoint机制将脏页刷回磁盘,Flush列表中的页即为脏页列表脏页既存在LRU列表,也存在于Flush列表中

LRU列表管理缓冲池页的可用性,Flush列表来管理将页刷新到磁盘,互不影响。

Flush列表

3、redo日志缓冲

InnoDB将redo日志先放入重做日志缓冲(redo log buffer),然后按一定的频率将其刷新到redo日志文件。

innodb_log_buffer_size控制缓冲大小

mysql> show variables like 'innodb_log_buffer_size'
    -> ;
+------------------------+----------+
| Variable_name          | Value    |
+------------------------+----------+
| innodb_log_buffer_size | 16777216 |
+------------------------+----------+
1 row in set, 1 warning (0.00 sec)

redo日志刷新到磁盘的情况:

  • Master Thread将redo日志缓冲刷新到redo日志文件
  • 事务提交会刷新到redo文件
  • 当redo日志缓冲池空间小于 1 / 2

4、额外的内存池

innodb对内存的管理是通过内存堆进行的

对一些数据结构本身的内存进行分配时,需要从额外的内存池进行申请,如缓冲池的帧缓冲、对应的缓冲控制对象(记录LRU、锁、等待信息),这些需要从额外的内存池进行申请

当额外的内存池空间不够时则向缓冲池进行申请

posted @ 2021-04-26 22:17  zephxu  阅读(82)  评论(0)    收藏  举报