Fork me on GitHub

InnoDB 读书笔记 1

数据库内容纵览

副标题:姜承尧《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
  • 数据库是由一个个文件(二进制)组成的,要对这些文件执行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存储引擎有多个内存块,组成了一个大的内存池,负责:

    1. 维护所有进程/线程 需要访问的多个内部数据结构
    2. 缓存磁盘上的数据,方便快速的读取,同时在对磁盘文件的数据修改之前在这里缓存
    3. redo log缓冲
  • 因为是多线程的模型,负责处理不同的任务:

多线程的任务

  1. Master Thread。负责将缓冲池的数据异步刷到磁盘,保证数据的一致性

  2. 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总是小于写线程

  3. Purge Thread。事务被提交后,所使用的undolog可能不再需要,因此需要PurgeThread来回收已经使用并分配的undo页。在InnoDB高版本中,还支持多个PurgeThread,可以进一步加快undo页的回收,同时由于PurgeThread需要离散的读取undo页,这样也能更近一步利用磁盘的随机读取性能

    1
    2
    3
    4
    5
    mysql> 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个

  4. Page Cleaner Thread。将脏页的刷新操作放入单独的线程中完成

    1
    2
    3
    4
    5
    mysql> show variables like 'innodb_page_cleaners'\G
    *************************** 1. row ***************************
    Variable_name: innodb_page_cleaners
    Value: 1
    1 row in set (0.00 sec)

完成全书36页

-------------The End-------------