转-----------让InnoDB_Buffer_Pool缓冲池中的热数据存活更久

本文介绍了MySQL中InnoDB存储引擎的缓冲区管理机制,包括sublistofnewblocks和sublistofoldblocks两个区域的作用,以及如何通过调整innodb_old_blocks_pct和innodb_old_blocks_time参数来优化缓冲区性能。

nnoDB_Buffer_Pool缓冲区有两个区域,一个是sublist of new blocks区域(经常被访问的数据——热数据),一个是sublist of old blocks区域(不经常访问的数据)。当用户访问数据时,如果缓冲区里有相应的数据则直接返回,否则会从磁盘读入缓冲区的sublist of old blocks区域,然后再移动到sublist of new blocks区域,并通过LRU最近最少使用算法来踢出旧数据页。

但是这其中也许会存在一个问题,假如有些sql语句做统计用全表扫描,例如select * from t1,或者做一次MySQLdump,这时就会进入sublist of new blocks区域,把一些真正的热数据“踢走”,这样就会造成缓冲区的数据进进出出,导致磁盘I/O频繁。

所以从MySQL5.5.X版本开始,innodb_old_blocks_pct参数可以控制进入缓冲区sublist of old blocks区域的数量,默认是37,占整个缓冲池的比例为3/8。当全表扫描一个大表,或者做MySQLdump时,就可以将innodb_old_blocks_pct设置得小些,例如,设置innodb_old_blocks_pct=5,使数据块进入少量sublist of old blocks区域,并移动到sublist of new blocks区域,从而让更多的热数据不被踢出。当你访问一个小表,或者select查询结果很少时,则可以保持默认的innodb_old_blocks_pct=37,或者设置得更大,比如innodb_old_blocks_pct=50。

在该过程中,还会涉及另一个参数innodb_old_blocks_time。在访问sublist of old blocks区域里的数据块时,并不是马上就移动到sublist of new blocks区域,而是会先让数据停留在sublist of old blocks区域innodb_old_blocks_time(微秒),然后再移动到sublist of new blocks区域,这样就保证了sublist of new blocks区域里的数据不会马上被踢出。

用“show engine innodb status\G;”命令可以查看当前的信息:
Total memory allocated 1107296256; in additional pool allocated 0
Dictionary memory allocated 80360
Buffer pool size 65535
Free buffers 0
Database pages 63920
Old database pages 23600
Modified db pages 34969
Pending reads 32
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 414946, not young 2930673
1274.75 youngs/s, 16521.90 non-youngs/s
Pages read 486005, created 3178, written 160585
2132.37 reads/s, 3.40 creates/s, 323.74 writes/s
Buffer pool hit rate 950 / 1000, young-making rate 30 / 1000 not 392 / 1000
Pages read ahead 1510.10/s, evicted without access 0.00/s
LRU len: 63920, unzip_LRU len: 0
I/O sum[43690]:cur[221], unzip sum[0]:cur[0]

其中,状态信息如下所示:

Old database pages 23600:在旧区域存放着多少个页。

Pages made young:移动到新区域的有多少个页。

Pages made not young:没有移动到新区域的有多少个页。

youngs/s:每秒移动到新区域的有多少个页。

non-youngs/s:每秒没有移动到新区域的有多少个页。

young-making rate:移动到新区域的比例。

young-making not rate:没有移动到新区域的比例。

如果你没有全表扫描,发现youngs/s的值很小,那么就应该增大innodb_old_blocks_pct或者减少innodb_old_blocks_time。如果你进行了全表扫描,发现non-youngs/s的值很小,那么就应该增大innodb_old_blocks_time。

关于innodb_old_blocks_pct和innodb_old_blocks_time参数的介绍,请参见MySQL5.5手册:

 

<think> 我们正在解决两个MySQL问题: 1. Aborted connection错误(Got an error reading communication packets) 2. InnoDB page_cleaner循环耗时过长(1000ms intended loop) 结合引用内容和实践经验,分别给出解决方案。 一、Aborted connection错误(Got an error reading communication packets) 原因:客户端连接异常中断、超时参数设置不合理、网络问题等。 解决方案: 1. 调整超时参数(参考引用[1][3]): - 注意:引用[1]中批评了将wait_timeout设置为一年(31536000秒)的做法,这是不合理的,会导致资源浪费。 - 合理做法:根据应用实际情况调整,一般可以设置为几小时(如28800秒,即8小时)。同时确保应用连接池的最大存活时间小于wait_timeout。 - 修改my.cnf(或my.ini): ``` [mysqld] wait_timeout = 28800 interactive_timeout = 28800 connect_timeout = 30 # 连接建立超时时间,适当增加 net_read_timeout = 120 # 读操作超时 net_write_timeout = 120 # 写操作超时 ``` 注意:修改后重启MySQL服务生效。 2. 检查网络问题: - 确保客户端和服务器之间的网络稳定,避免丢包和延迟过高。 - 使用tcpdump抓包分析是否有异常中断(如RST包)。 3. 检查是否有无效的监控程序(如telnet): - 如引用[4]提到,有些监控程序(如telnet)可能导致虚假的连接中断日志。应使用专门的MySQL监控工具(如mysqladmin ping)代替。 4. 调整max_allowed_packet(引用[2]): - 如果传输的数据包过大,可能导致连接中断。适当增大该参数: ``` max_allowed_packet = 64M ``` 二、InnoDB page_cleaner循环耗时过长(1000ms intended loop) 原因:InnoDB的后台线程page_cleaner负责将脏页刷新到磁盘。如果刷新速度跟不上数据修改速度,可能导致耗时过长。 解决方案: 1. 增加InnoDB缓冲池大小(innodb_buffer_pool_size): - 引用[2]提到增加innodb_buffer_pool_size(设置为1G或大,根据服务器内存)。这可以减少磁盘I/O频率。 - 设置建议:通常设置为系统内存的70%-80%。 ``` innodb_buffer_pool_size = 8G # 根据实际情况调整 ``` 2. 调整InnoDB刷新相关参数(在my.cnf中): - `innodb_io_capacity`:表示InnoDB每秒可用的I/O操作次数(根据磁盘性能调整,如SSD可设置成2000以上)。 - `innodb_max_dirty_pages_pct_lwm`:设置脏页比例的低水位线,当超过这个比例时开始刷新脏页(默认0,可适当调整)。 - `innodb_flush_neighbors`:对于机械硬盘设置为1(刷新相邻脏页)可提升性能;对于SSD设置为0(关闭)。 - `innodb_lru_scan_depth`:降低此值可减少page_cleaner线程的工作量(默认1024,可尝试调整为256或512)。 示例配置: ``` innodb_io_capacity = 2000 innodb_max_dirty_pages_pct_lwm = 10 innodb_flush_neighbors = 0 # SSD建议关闭 innodb_lru_scan_depth = 512 ``` 3. 检查磁盘性能: - 使用工具(如fio)测试磁盘的随机写性能,确保磁盘能够满足数据库的I/O需求。 4. 考虑调整日志文件大小(innodb_log_file_size): - 较大的日志文件可以减少刷新频率。建议设置为1G-2G(需要关闭MySQL后调整,步骤较复杂)。 三、总结步骤: 1. 修改MySQL配置文件(my.cnf或my.ini),添加或修改以下参数(根据实际情况调整值): ``` [mysqld] # 解决Aborted connection wait_timeout=28800 interactive_timeout=28800 connect_timeout=30 net_read_timeout=120 net_write_timeout=120 max_allowed_packet=64M # 解决page_cleaner耗时 innodb_buffer_pool_size=8G innodb_io_capacity=2000 innodb_max_dirty_pages_pct_lwm=10 innodb_flush_neighbors=0 innodb_lru_scan_depth=512 ``` 2. 重启MySQL服务使配置生效。 3. 监控参数调整后的效果,观察错误日志和性能。 四、注意事项: - 修改配置前备份原配置文件。 - 参数调整需要根据服务器硬件(内存、磁盘类型)和负载情况进行优化。 如果问题仍然存在,需要进一步分析: - 对于连接中断:抓包分析网络问题,检查客户端程序是否有异常退出。 - 对于page_cleaner:监控脏页比例(`show global status like 'Innodb_buffer_pool_pages_dirty'`)和刷新速度。 生成相关问题: 1. 如何监控MySQL的脏页刷新情况? 2. 除了调整参数,还有哪些方法可以优化InnoDB的写入性能? 3. 如何诊断和解决MySQL连接数过多的问题? </think> ### 解决方案:MySQL连接中断与InnoDB性能优化 #### **一、解决Aborted Connection错误** 1. **调整超时参数**(核心方案[^1][^3]) ```ini [mysqld] connect_timeout = 30 # 默认10秒 → 延长连接握手时间 wait_timeout = 86400 # 空闲连接超时(秒),建议8-24小时 interactive_timeout = 86400 # 交互连接超时 net_read_timeout = 120 # 读操作超时 net_write_timeout = 120 # 写操作超时 max_allowed_packet = 256M # 增大传输包限制[^2] ``` **操作**: ```bash sudo systemctl restart mysql # 重启生效 ``` 2. **排查干扰源** - 禁用无效监控:检查并移除周期性`telnet 3306`的脚本[^4] - 网络诊断: ```bash mtr -r -c 100 172.21.5.13 # 持续追踪到客户端IP的路由稳定性 ``` 3. **连接池优化** - 应用层配置(如HikariCP): ```java dataSource.setMaxLifetime(85000); // 小于wait_timeout 10% dataSource.setIdleTimeout(60000); // 主动回收空闲连接 ``` --- #### **二、优化InnoDB page_cleaner耗时** 1. **关键参数调整** ```ini [mysqld] innodb_buffer_pool_size = 16G # 调整为物理内存的70-80%[^2] innodb_io_capacity = 4000 # SSD建议2000-10000, HDD建议200-1000 innodb_max_dirty_pages_pct = 75 # 提高脏页比例阈值 innodb_lru_scan_depth = 256 # 降低LRU扫描深度(默认1024) innodb_flush_method = O_DIRECT_NO_FSYNC # Linux专用,跳过双缓冲 ``` 2. **监控脏页刷新** ```sql SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty'; SHOW ENGINE INNODB STATUS\G -- 关注BUFFER POOL AND MEMORY段落 ``` - **安全指标**:`Innodb_buffer_pool_pages_dirty / Innodb_buffer_pool_pages_total < 0.75` 3. **磁盘I/O优化** - **SSD配置**: ```ini innodb_flush_neighbors = 0 # 禁用邻页刷新(SSD必需) innodb_page_cleaners = 8 # 并行清理线程数=CPU核心数 ``` - **机械硬盘**: ```ini innodb_flush_neighbors = 1 # 启用邻页刷新减少寻道 ``` --- #### **三、验证方案有效性** | **指标** | **优化前** | **优化后目标** | **检查命令** | |------------------------|------------------|-------------------|----------------------------------| | Aborted Connections | >10/分钟 | ≈0 | `grep 'Aborted' /var/log/mysql/error.log` | | page_cleaner耗时 | >1000ms | <500ms | `SHOW ENGINE INNODB STATUS` | | 脏页比例 | >90% | <75% | `SHOW STATUS LIKE '%dirty%'` | > **关键提示**: > - 修改配置后需重启MySQL > - 机械硬盘环境需权衡`innodb_flush_neighbors`参数[^2] --- ### 相关问题 1. `wait_timeout`设置过长会导致什么风险?如何平衡资源占用与连接稳定性? 2. 如何根据服务器硬件(内存/磁盘类型)计算`innodb_buffer_pool_size`的最佳值? 3. 除了参数优化,哪些架构设计能根本解决InnoDB写入性能瓶颈? [^1]: 避免将`wait_timeout`设为极值(如31536000秒),需根据业务负载合理设定 [^2]: 缓冲区参数需匹配物理内存,避免OOM或交换分区抖动 [^3]: 连接超时参数需协同调整,而非孤立修改单一值 [^4]: 无效监控工具(如telnet)会触发虚假中断日志,应改用`mysqladmin ping`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值