【数据库】MYSQL学习记录一:InnoDB的架构设计

写在最前,本人也只是个大三的学生,如果你发现任何我写的不对的,请在评论中指出。

总结MYSQL的架构设计

  大部分同学对于MYSQL的了解都是在MYSQL可以用于建库建表, 然后可以执行增删改查操作里面的数据的层面, 即使出现了一些死锁、SQL性能太差、异常报错等情况都是在通过一些博客、论坛等查找解决方案, 草草了解,不懂其中的原理。 所以,全方面的了解MYSQL是必要的。
  那首先呢, 需要知道的是: MYSQL如何跟系统打交道的, 是通过谁?
  我们知道,在编写一个web项目的时候,要使用到数据库,我们都会在pom文件里引入这样一段代码:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>

  实际上,我们的操作系统要跟MYSQL打交道的话,是需要建立网络连接的(Socket),而这段代码其实就是引入MYSQL驱动, 它会在底层跟数据库建立起网络连接,有网络连接才能发送请求到数据库。


  了解了系统是如何向MYSQL发出请求, 接下来就需要知道一条语句是如何在MYSQL中被执行的(粗略)。大体上讲, MYSQL是分为两层, 一层是Service层: 包含了连接器(SQL接口)、解析器、查询缓存、优化器、执行器, 第二层是存储引擎, 存储引擎用于存储数据,提供读写接口, 目前MYSQL最知名的存储引擎是:InnoDB。
  假设我们通过连接器跟MYSQL客户端建立连接、获取权限开始向数据库编写了一条查询SQL:select id, name, age from users where id = 1

  1. MYSQL是无法直接理解这段SQL语句,所以此时会通过解析器对SQL语句进行解析,也就是说,这段语句会被翻译为:
我们现在要从users表内查询数据
查询"id"为1的那行数据
对查出来的结果提起id, name ,age三个字段返回
  1. 通常情况下,为了优化查询,还会有查询缓存这个地方,但是由于MYSQL经常进行增删改,所以缓存也会随之更新,所以本人不太提供依赖查询缓存的
  2. 然后是优化器, 优化器会为你提供最佳的查询路径,比如上面那条查询语句: ①直接定位到users表id字段等于1的那行取出三个字段 ②把users表中的每一行数据的"id, name, age" 都查出来,然后再翻到id=1的那行(这段仅供理解)
  3. 随后执行器,执行器会根据我们的优化器生成的一套的执行计划,然后不停的调用存储引擎的各种接口去完成SQL语句的执行计划
  4. 执行引擎完成读写

  最后, MYSQL架构的图解就如下:
【数据库】MYSQL学习记录一:InnoDB的架构设计_第1张图片


再聊InnoDB的存储架构

  之前我也在我的《MYSQL是如何保证原子性的》里面提供了三种日志,但是那篇讲的挺差,这里再补充一下,还是用SQL语句举例去了解, 比如我们执行一条更新SQL语句:update users set name = 'xxx' where id = 10
  在InnoDB里有块很重要的内存结构:缓冲池, 我们执行上面那条语句的时候,会把原本存储在磁盘上的旧数据(name='zhangsan')读取到缓冲池中。
  如果我们要把name=zhangsan 更新为 name=xxx ,我们是需要把原先的值,也就是name=zhangsan, id =10写到undo日志中, 我们都知道数据库有事务这个概念, 在事务提交之前,我们都可以对数据进行回滚。 也就是说当我们把旧数据从磁盘加载到缓冲池中加锁后, 并把旧数据写入到undo log中, 我们就可以正式的开始更新这条记录了
  此时,内存中的这条记录就是脏数据,为什么说它是脏数据呢? 因为磁盘的上id=10的那条数据name还是等于zhangsan, 不过这些暂时还不需要在意。
  那么现在来思考一下, 如果此时MYSQL宕机了, 我们仅仅在undo log日志里保留了旧数据用于回滚,那么缓冲池中做了修改的数据应该如何保留呢? 这里就要引入另一个概念: redo log。 redo log日志会把你修改的记录写到redo log buffer中(注意buffer 也是在内存中的),你事务提交之后,就会把这份redo log buffer中的信息刷新到redo log中(在磁盘)。 当然在你事务没提交之前MYSQL宕机了, 更新数据域redo log buffer都会丢失, 但磁盘上内容不变, 丢失的只有你做的更新(另外redo log有自己刷新策略,建议去找别的博客读读)。
  快进到binlog, redo log 是偏向物理性质的重做日志, 它记录的是类似“对哪个数据页内的数据做了什么修改”,而binlog是逻辑性的归档日志,它是类似“对user表中的id=10的那一行做了更新操作,更新后的值是什么这种感觉”。 继上面, 在我们准备提交事务,把redo log buffer中的信息刷到redo log日志文件中的时候,执行器会把准备提交事务的binlog日志写入os cache中,再由os cache刷入binlog日志文件,然后再更新redo log日志文件中,与binlog文件位置一样的地方写入commit标记, 最后由数据库的IO线程把内存中修改的值刷新到磁盘上,所以总的流程是:

【数据库】MYSQL学习记录一:InnoDB的架构设计_第2张图片
   那么这个commit标记又有什么意义? 它其实是用于保持redo log日志与binlog日志一致的。举个例子,上面的步骤5、6、7必须都执行完成才算提交事务,如果执行到了5, MYSQL宕机了, 这个时候因为redo log日志中没有commit标记, 所以判定此次的事务提交不成立, 不存在redo log日志内有事务提交, 而binlog日志没有事务提交这种情况


生产经验

生产数据库一般都是什么配置

  直白来讲,数据库部署的时候选用的机器最低配置要在8核16G以上,正常是在16核32G。然后在一些高并发的场景下, 你要知道当你大量执行SQL增删改查的时候,MYSQL数据库对内存和磁盘文件进行大量的IO操作,数据库的负载往往是最高的。所以,经验是8核16G的数据库每秒大概1、2千是没什么问题的,而16核32G每秒是两三千、甚至是三四千,飙到上万的话就容易宕机,然后是推荐SSD,不是机械

一个新的数据库服务器拿到手应该干什么

  压测, 把数据库交付给专业的DBA, 让他进行压测。当然如果你的公司跟我一样是互联网新兴的小公司,那么你自己来也可以。
  进行压测的目的是为了摸清楚当你发起1000、2000、3000甚至更高的场景下,你的服务器的CPU负载、磁盘IO负载、网络IO负载是个什么情况,在发起请求前,你需要先了解:

  • QPS: 就是说你的数据库每秒能够处理多少个请求
  • TPS: 就是说你的数据库每秒能够处理多少的事务量
  • IOPS: 指的是随机IO并发处理能力, 这个也很关键哦, 之前我们讲到内存中的脏数据要被IO线程刷回到磁盘中, 如果你的随机IO指标太低了, 那么会导致你的数据刷回磁盘效率不高导致数据库卡顿(IO线程刷新的时候)的时候延长
  • 吞吐量:磁盘每秒可以读写多少字节的数据量, 那就比如redo log 这种直接写磁盘的日志文件
  • latency: 往磁盘写入一条数据的延迟
  • CPU负载、网络负载、内存负载

拿什么去压测呢?

  sysbench工具, 这个去看看其他大佬的操作记录,我的测试操作基本都是靠文档来进行的,所以我也不太熟,不能指点江山。
  所以文章的最后,推荐去搜罗一下sysbench的使用方案,以及如何通过它对观测机器性能,以及如何为数据库的监控系统部署可视化报表。

你可能感兴趣的:(数据库,mysql)