一条更新SQL的执行全过程
为什么不将修改落盘,而是使用BufferPool?
因为数据库的update操作是随机IO,随机IO效率很低,如果直接落盘,那么MySQL支持的并发数量可能就会很少,而redo日志这些事顺序IO,比随机IO性能高。
undo日志做什么用?各种日志如何控制大小,何时会去删除?
普通的Java应用系统部署在机器上能抗多少并发?
以大量的高并发线上系统的生产经验观察而言,一般Java应用系统部署在4核8G的机器上,每秒钟抗下500左右的并发访问量,差不多是比较合适的。但是如果你每个请求花费1s,那么一台机器也许只可以处理100个请求,但是你每个请求只要花费100ms,可以处理完,那么你一台机器每秒也许可以处理几百个请求。
高并发场景下,数据库应该用什么样的机器?
通常推荐的数据库至少是8核16G,甚至是16核32G的机器。因为大部分Java系统压力大,都是集中在你依赖的那个MySQL数据库上的!对于8核16G的机器,每秒抗个一两千并发请求是没问题的,但是如果并发量再高一些,假设每秒有几千个并发请求,那么数据库有点危险,可能会宕机。对于16核32G的机器部署MySQL数据库而言,每秒扛个两三千,甚至三四千请求也可以,但是上万请求就不行了。
MySQL常用的性能监控指标:
QPS:每秒查询数
TPS:每秒事务数
IOPS:随机IO的并发能力
吞吐量:机器的磁盘存储每秒可以读写多少个字节的数据量
latency:往磁盘写入一条数据的延迟
CPU负载
网络负载
内存负载
构造MySQL压测工具及监控系统
sysbench,…
Buffer Pool这个数据内存结构
配置buffer_pool的大小,缓冲页是16KB
innodb_buffer_pool_size
=2147483648
配置的参数只是buffer_pool的缓冲页大小,实际上Buffer_Pool还会包含一部分描述数据,大概相当于缓冲页的百分之五。
Buffer_Pool的初始化过程
数据库一启动,就会按照设置的Buffer_Pool的大小去申请一块内存区域,申请完毕之后,数据库就会按照默认的缓存页的16KB大小,以及对应的800个字节左右的描述数据的大小,在Buffer Pool划分出一个一个的缓存页和一个一个他们对应的描述数据。当数据库运行起来后,我们对数据进行增删改查的时候,才会把数据对应的页从磁盘文件里读取出来,放入Buffer Pool中的缓存页中。
Free和flush链表
free链表存储的是空闲缓冲,flush存的是脏页链表。
表、列和行、表空间、数据页的关系
表、列、行都是逻辑概念,实际上数据在磁盘空间是以表空间及一个一个的数据页组织起来的。
MySQL预读机制或全面扫描给LRU带来的问题
innodb_read_ahead_threshold,意思是如果顺序访问了一个区里的多个数据页,访问的数据页的数量如果超过了这个阈值,就会触发预读机制,把下一个相邻区中所有数据页都加载到缓存里去。
如果Buffer Pool里缓存一个区里的连续13个页,而且这些数据页都比较频繁地访问,此时就会触发预读机制,把这个区里的其他的数据页都加载到缓存里去,innodb_random_read_ahead来控制的。
全表扫描,select * from users,一下子把表里所有数据页都加载到Buffer Pool中去。
预读机制导致了LRU缓存淘汰机制不好用。
基于冷热数据分离的LRU算法
innodb_old_blocks_pct参数控制的冷热数据比例,数据从磁盘加载到Buffer Pool时,会进入后半部分的冷数据区域中,如果1s(由innodb_old_bolcks_time参数控制)之后,有访问,才会将它提前到热数据区域。
为什么Redis要做热数据加载?
如果说你把访问到的数据都放在Redis,那么导致大量不怎么访问的数据都会被放在Redis缓存里,浪费内存,所以会考虑数据的缓存预加载。所以,白天的统计出哪些商品被访问得最多,到了晚上,启动定时,把热门数据加载到Redis。
LRU链表的热数据区域是如何进行优化的?
LRU热数据区域的1/4区域,即使访问了,也不会移动到链表头,因为头部非常大概率会被访问的,频率移动浪费性能,后3/4被访问了,才会移动到链表头。
将Buffer Pool的数据刷到磁盘
1.后台的定时线程将冷数据区域尾部的一些缓存刷入磁盘中
2.后台线程会在MySQL不怎么繁忙的时候,找个时间把flush链表中的缓存页刷入磁盘,只要flush链表中的缓存页刷入磁盘,那么这些缓存页也会从flush链表和lru链表中移除,加入free链表中。
3.当实在没有空闲缓存页了,从LRU链表的冷数据区域的尾部找到一个缓存页,把它刷入磁盘和清空。
多个Buffer Pool优化并发能力
如果你给Buffer Pool分 配的内存小于1GB,那么最多只会分配一个Buffer Pool。如果你的机器内存很大,那么你必然会给Buffer Pool分配较大的内存,比如给他个8G内存,那么可以设置多个Buffer Pool的优化并发能力。类似于ConcurrentHashMap的分段锁机制。
innodb_buffer_pool_size=8589934592 // 设置Buffer Pool
innodb_buufer_pool_instances=4 // Buffer Pool的实例个数
通过chunk来支持数据库运行期间的Buffer Pool动态调整
如果从8G调整到16G的时候,不需要额外申请16GB的连续内存空间及拷贝了。只需要申请一系列的chunk,然后将chunk分配给Buffer Pool就可以了。
生产环境中,基于机器配置合理的Buffer Pool
通常,如果一台专门做数据库的服务器,内存设置为机器内存的百分之60。
buffer pool总大小=(chunk大小 * buffer pool数量)*倍数
查看INNODB的运行状况
show engine innodb status
total memory allocated,指的是buffer pool最终的总大小是多少
Buffer pool size,指的是buffer pool一共能容纳多少个缓存页
Free buffers,指的是free链表一共有多少个空闲的缓存页是可用的
Database pages和Old database pages,就是lru链表中一共有多少个缓存页,以及冷数据区域里的缓存页数量。