MySQL 结构体系 及 InnoDB存储引擎

119 阅读8分钟

1、mysql体系结构

image.png

从图可发现,mysql有以下几部分组成:

  • 连接词组件
  • 管理服务和工具组件
  • SQL接口组件
  • 查询分析器组件
  • 优化器组件
  • 缓冲(Cache)组件
  • 插件式存储引擎
  • 物理文件

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

2、常用存储引擎

InnoDB、MyISAM、NDB。

InnoDB

特点 :

  • 1、支持事务,设计目标面向OLTP(在线事务处理)应用,行锁设计、支持外键。
  • 2、InnoDB存储引擎将数据放在逻辑表空间中,这个表空间就像黑盒一样由InnoDB存储引擎自身进行管理;可以将Innodb存储引擎的表单独放在独立ibd的文件中。
  • 3、InnoDB使用多版本并发控制(MVCC)来获得高并发性,实现了SQL标准的四种隔离级别,默认Repeatable级别;同时使用next-key locking的策略来避免幻读。
  • 4、InnoDB存储引擎采用了聚集(clustered)的方式,因此每张表的存储方式是按主键的顺序存放,如果没有显示的定义主键,InnoDB存储引擎会为每行生成6字节的RowID,以此为主键。
  • 5、InnoDB还提供了插入缓冲(insert buff)、二次写(double write)、自适应哈希索引(adaptive hash index)、预读等高性能和高可用的功能。

MyISAM

NDB

InnoDB存储引擎

后台线程

MasterThread

核心的后台线程,负责将缓冲区的数据异步刷新到磁盘,保证数据的一致性,包括脏页的刷新、合并插入缓冲(insert buffer)、undo页的回收。

IO Thread

四类io thead :read、write 、insert buffer 和 log io thread。 可通过命令查看 mysql> show engine innodb status;\G 结果中的InnoDB IO Thread

Purge Thread

事务提交之后,其所使用的undolog可能不再需要,因此需要purge thrad来回收已使用且不再需要的undolog。 可通过命令查看purge thread个数 show VARIABLES like 'innodb_purge_threads' ;

Page Cleaner Thread

脏页的刷新操作,减轻Master Thread的工作。

内存

缓冲池

缓冲池简单来说是内存的一块区域,通过内存的速度来弥补磁盘速度较慢对数据库的影响。在数据库进行读取页的操作,首先从磁盘读取到的页先放入缓冲池中,这过程称为将页“Fix”在缓冲池中,下一次再读取该页时,先判断是否在缓存池中,若在缓冲池中,称该页在缓冲池中被命中,直接读取该页,否则读取磁盘上的页。 对于数据库页的修改操作,首先修改在缓冲池的页,然后再以一定的频率刷新到磁盘。页从缓存区刷新到磁盘并不是每次页发生变更时触发,而是通过一种Checkpoint机制刷新回磁盘。

缓冲池的大小影响数据库的性能。对InnoDB而言,可通过innodb_buffer_pool_size 可进行设置。 show VARIABLES like 'innodb_buffer_pool_size' ; InnoDB的存储结构如下 : image.png 可设置多个缓冲池,每个页根据hash值分配到不同的页,减少内部资源的竞争。 show VARIABLES like 'innodb_buffer_pool_instances' ;

查看pool的状态 mysql> show engine innodb status;\G结果中的InnoDB pool

mysql5.6之后,可通过information_schema架构下的表innodb_buffer_pool_stats来观察缓冲的状态,如 select pool_id,pool_size from innodb_buffer_pool_stats

LRU List、Free List 和 Flush List

数据库的缓冲池是通过LRU(last recent used,最近最少使用)算法进行管理的。频繁使用的放在LRU列表的前端,很少使用的放在尾端。Innodb存储引擎中,缓存池中页的大小16KB。

LRU List :管理已读取到的页,数据库刚启动LRU List是没有页的。当需要从缓冲池获取页时,首页判断是否Free List是否有空闲页,若有则将该页从Free List中删除,放入到LRU List中;否则根据淘汰算法,淘汰LRU List 末尾的页,将该内存空间分配给新的页。

可通过show engine innodb status;\G 查看LRU 、Free 列表状态:


BUFFER POOL AND MEMORY

  • Total large memory allocated 137039872
  • Dictionary memory allocated 435492
  • Buffer pool size 8192
  • Free buffers 7077
  • Database pages 1110
  • Old database pages 429
  • Modified db pages 0
  • Pending reads 0
  • Pending writes: LRU 0, flush list 0, single page 0
  • Pages made young 1, not young 0
  • 0.00 youngs/s, 0.00 non-youngs/s
  • Pages read 968, created 142, written 187
  • 0.00 reads/s, 0.00 creates/s, 0.00 writes/s
  • No buffer pool page gets since the last printout
  • Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
  • LRU len: 1110, unzip_LRU len: 0
  • I/O sum[0]:cur[0], unzip sum[0]:cur[0]

当前Buffer pool size 共有8192个页,即 8192 * 16k ,总共128M。 Free buffers :Free List 中页的数量,当前7077个 Database pages :LRU list中的数量,当前1110 Free buffers + Database pages 不等于 Buffer pool size,因为缓冲区中可能还会分配给哈希索引、Lock信息、Insert Buffer等页,而这不需要LRU算法维护,不存在LRU列表中。 Pages made young : LRU列表中页移动到前端次数

还可通过表 InnoDB_buffer_pool_stats观察缓冲池的状态,可通过表innodb_buffer_page_lru观察每个页的具体信息。

重做日志缓冲区

InnoDB存储引擎先把重做日志信息先放入到缓冲区,然后按照一定的频率刷新到重做日志文件。 大小通过参数** innodb_log_buffer_size** 控制 , show VARIABLES like 'innodb_log_buffer_size' ; +------------------------+----------+ | Variable_name | Value | +------------------------+----------+ | innodb_log_buffer_size | 16777216 | +------------------------+----------+ innodb_log_buffer_size 比较小,一般8、16M可满足绝大部分应用,重做日志缓冲期在以下几种情况下会被刷新到磁盘的重做日志文件中 :

  • Master Thread 每一秒将重做日志缓存刷到重做日志文件
  • 每个事务提交时将重做日志缓存刷到重做日志文件
  • 当重做日志缓冲池剩下空间小于1/2时,刷缓冲区信息到重做日志文件

Check Point技术

checkpoint(检查点)解决以下问题 :

  • 缩短数据库恢复时间 :当数据库宕机时,数据库不需要重做所有日志,因为checkpoint之前的页已经刷新回磁盘,故数据库只需对checkpoint之后的重做日志进行恢复。
  • 缓冲池不够用时,将脏页刷新到磁盘:当缓冲池不够用时,根据LRU算法会溢出最近最少使用的页,若此页为脏页,则会强制执行checkpoint,将脏页的新版本刷新回磁盘。
  • 重做日志不可用时,刷新脏页: 重做日志被设计成可循环使用,当日志文件写满时,重做日志中对应数据已经被刷新到磁盘的那部分不再需要的日志可以被覆盖重用。

InnoDB通过LSN(Log Sequence Number)来标记版本,LSN是8字节的数字。每页、重做日志、checkpoint都有LSN,可通过命令 show engine innodb status 查看

  • LOG

  • Log sequence number 20819721
  • Log buffer assigned up to 20819721
  • Log buffer completed up to 20819721
  • Log written up to 20819721
  • Log flushed up to 20819721
  • Added dirty pages up to 20819721
  • Pages flushed up to 20819721
  • Last checkpoint at 20819721
  • 46 log i/o's done, 0.00 log i/o's/second

Log flushed up : 重做日志的LSN Last checkpoint at : checkpoint的LSN

InnoDB有两种checkpoint

  • Sharp Checkpoint:数据库关闭时,将所有的脏页都刷新回磁盘,这是默认的工作方式,即参数innodb_fast_shutdown=1。但是若数据库在运行时也使用Sharp Checkpoint,那么数据库的可用性就会受到很大的影响。
  • Fuzzy Checkpoint :在InnoDB存储引擎内部使用Fuzzy Checkpoint进行页的刷新,即只刷新一部分脏页,而不是刷新所有的脏页回磁盘。

(Fuzzy Checkpoint)部分脏页刷新有以下几种:

  • Master Thread Checkpoint
  • FLUSH_LRU_LIST Checkpoint
  • Async/Sync Flush Checkpoint
  • Dirty Page too much Checkpoint

Master Thread Checkpoint

Master Thread以每秒或每十秒的速度从缓冲池的脏页列表中刷新一定比例的页回磁盘。这个过程是异步的,不会阻塞查询线程。

Flush LRU List Checkpoint

InnoDB要保证LRU列表中有100左右空闲页可使用。在InnoDB1.1.X版本前,要检查LRU中是否有足够的页用于用户查询操作线程,如果没有,会将LRU列表尾端的页淘汰,如果被淘汰的页中有脏页,会强制执行Checkpoint刷回脏页数据到磁盘,显然这会阻塞用户查询线程。从InnoDB1.2.X版本开始,这个检查放到单独的Page Cleaner Thread中进行,并且用户可以通过innodb_lru_scan_depth控制LRU列表中可用页的数量,默认值为1024。

Async/Sync Flush Checkpoint

是指重做日志文件不可用时,需要强制将脏页列表中的一些页刷新回磁盘。这可以保证重做日志文件可循环使用。在InnoDB1.2.X版本之前,Async Flush Checkpoint会阻塞发现问题的用户查询线程,Sync Flush Checkpoint会阻塞所有查询线程。InnoDB1.2.X之后放到单独的Page Cleaner Thread。

Dirty Page Too Much Checkpoint

脏页数量太多时,InnoDB引擎会强制进行Checkpoint。目的还是为了保证缓冲池中有足够可用的空闲页。其可以通过参数innodb_max_dirty_pages_pct来设置,默认为75%。