数据库MySQL之总体框架、Buffer Pool

1.MySQL基本特性

1.1 MySQL整体框架

1.2 MySQL中的token

  • Token的引入:Token是在客户端频繁向服务端请求数据,服务端频繁去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应响应。在这样的背景下,Token便应运而生。
  • Token的定义:Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌。当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。
  • 使用Token的目的:为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
  • Token的优点:扩展性强和安全,非常适合用在 Web 应用或者移动应用上。
  • Token使用的地方:防止表单重复提交、anti csrf攻击(跨站点请求伪造)、身份验证(单点登录)。
  • 如何使用Token:用设备号/设备mac地址作为Token(推荐)和用session值作为Token。

2.InnoDB的Buffer Pool

2.1 Buffer Pool的基本特性

  • 默认情况下,Buffer Pool 只有128MB,但是可以在启动服务器的时候配置innodb_buffer_pool_size来更改其大小。

2.2 Buffer Pool的组成

2.1.1 FREE链表的管理

  • 当启动mysql服务器的时候,需要完成mysql初始化过程,就是先向操作系统申请Buffer Pool的内存空间,然后划分为若干个控制块和缓冲页。刚刚完成初始化的Buffer Pool中,所有的缓冲页都是空闲的,所以全部缓冲页对应的控制块都加入free链表中。例如下图所示:
  • 基节点:包含链表的头结点地址尾结点地址以及当前链表中的节点的数量等等信息。链表基节点占用40字节,但这占用的内存空间并没有包含在Buffer Pool申请的连续的内存空间中,而是另外单独申请的内存空间。
  • 如果在操作关于缓冲页的时候,实际上是操作Buffer Pool中缓冲页对应的控制块,因为通过控制块可以真正访问到真正的缓冲页。
  • 缓冲页的哈希处理:可以利用空间号+页号作为key,用缓冲页控制块的地址作为value来创建哈希表。如果需要访问某个页的数据的时候,需要从哈希表中根据空间号+页号看看是否存在相应的缓冲页控制块。如果有直接使用缓冲页即可,否则需要从free链表中选一个空闲的缓冲页然后把磁盘对应的页加载到该缓冲页的位置。

2.1.2 FLUSH链表

  • 创建一个存储脏页的链表,凡是被修改过的缓冲页对应的控制块都做为节点加入到flush链表。
  • flush链表的构造与free链表差不多。

2.1.3 LRU链表

  • 背景:Buffer Pool对应的内存大小有限,当需要缓存的页已经超过 Buffer Pool的大小,需要将旧的缓冲页从Buffer Pool中移除。
2.1.3.1 简单LRU链表
  • 如果该页不在Buffer Pool中,把该页从磁盘中加载到Buffer Pool中的缓冲页,需要将该缓冲页对应的控制块作为节点加到LRU链表的头部。
  • 如果该页已经加载到Buffer Pool中,则直接把该页对应的控制块移动到LRU链表的头部。
  • 当Buffer Pool中的空闲缓冲页使用完时,直接淘汰LRU链表的尾部缓冲页的控制块即可。
2.1.3.2 划分区域的LRU链表
  • 背景:

1)线性预读:如果顺序访问的某个区的页面超过系统变量innodb_read_ahead_threshold的值,就会触发异步读取下一个区中全部页面到Buffer Pool请求。注意异步读取意味着从磁盘中加载这些预读的页面时,并不会影响到当前线程的正常执行。innodb_read_ahead_threshold系统变量属于全局变量,默认值为56。通过SET GLOBAL命令可以在服务器启动时通过启动该选项来调整,也可以在服务器运行过程中直接调整该系统变量的值。
2)随机预读:如果某个区的13个连续的页面被加载到Buffer Pool中,无论这些页面是否顺序读取,都会触发一次异步读取本区中所有页面到Buffer Pool中。innodb_random_read_ahead系统变量默认值为OFF,表示InnoDB不会默认开启随机预读功能,可以通过修改启动选项或者直接使用SET GLOBAL命令把该变量的值设置为ON。
3)全表扫描:如果在没有建立合适的索引或者根本没有where语句,意味着需要执行将其它语句在执行过程中用到的页面排挤出Buffer Pool,之后再将需要用到的页加载到Buffer Pool中

  • 总之可能降低Buffer Pool的命中率的两种情况如下:

1)加载到Buffer Pool中的页不一定被用到。
2)如果有非常多使用频率低的页被同时加载到Buffer Pool中,则可能会把那些使用频率非常高的页从Buffer Pool中淘汰掉。

  • LUR链表的组成:

1)热数据(young)区域:存储使用率非常高的缓冲页。
2)冷数据(old)区域:存储使用率非常低的缓冲页。

  • 对于InnoDB来说,可以通过语句show variables like 'innodb_old_blocks_ptc; '来查看old区域在LRU链表中所占的比例,默认情况下为3/8。可以改变的两种情况如下:

1)服务器启动时通过修改innodb_old_blocks_pct启动选项来控制old区域在LRU链表中所占的比例。例如在配置文件中写入:innodb_old_blocks_pct=40;
2)服务器运行时可以修改innodb_old_blocks_pct系统变量的值,该系统变量属于全局变量,需要使用SET GLOBAL命令修改。例如:set GLOBAL innodb_old_blocks_pct=40;

  • 针对背景问题解决方案:

1)针对预读:当磁盘上的页面在初次加载到Buffer Pool中的某个缓冲页时,该缓冲页对应的控制块放到old区域的头部。因此预读到Buffer Pool却不进行后续访问的页面逐渐从old区域逐出,而不会影响到young区域中使用频繁的缓冲页。
2)针对全表扫描:在对于处于old区域的缓冲页进行第一次访问时,同时在对应的控制块记录访问时间。如果后续的访问时间与第一次访问的时间在某个时间间隔内那么该页面不会从old区域移动到young区域,否则将它移动到young区域。该间隔时间可以通过show variables like 'innodb_old_blocks_time';。同理,也可以在服务器启动时或者运行时修改该系统变量的值。

2.1.3.3 进一步改进的LRU链表
  • 针对于young区域的缓冲页来说每次访问都移动到LRU链表的头部开销大的问题,可以这样设置:只有访问的缓冲页位于young区域的1/4之后才会被移动到LRU链表头部。
  • 总之改进的LRU链表的目的就是为了尽量高效提高Buffer Pool的命中率。

2.3 刷新脏页到磁盘

  • BUF_FLUSH_LRU:后台线程定时从LRU链表尾部开始扫描一些页面,扫描的页面数量可以通过系统变量innodb_lru_scan_depth来指定。如果在LRU链表发现脏页,则把它们刷新到磁盘。
  • BUF_FLUSH_LIST:后台线程定时从flush链表刷新一部分到磁盘,刷新的速率取决于当时系统是否繁忙。
  • BUF_FLUSH_SINGLE_PAGE:当用户线程准备加载磁盘页到Buffer Pool时发现已满,这时就会尝试查看LRU链表尾部是否存在可以直接释放掉的未修改缓冲页。如果没有则不得不将LRU链表尾部的一个脏页同步到磁盘中,这会降低用户请求的速度。

3.相关面试题

1.多次查询或者连表查询

2.MySQL范式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值