先把当时的情况摆出来。MySQL 5.7 主库上 query_cache_size 给了 512M,读多写少的站点,压测到三百并发时 QPS 不升反降,threads_running 一路走高,Qcache_lowmem_prunes 涨得飞快。
把日志和配置对完,能解释这个现象的基本就这几处。查询缓存由一把全局互斥锁保护,所有查询都要先排队拿锁。另一种情况是任何一条写语句都会让相关表上的缓存条目全部失效,失效也要拿同一把锁。
另外,缓存块碎片化严重,命中率不高却一直触发修剪,白耗 CPU。少数情况下是写多的库上缓存几乎一直在失效,等于只承担了开销没有收益。
先看命中与修剪的比例
mysql -e 'show global status like "Qcache%"; show variables like "query_cache_size";'
再往下在线把缓存关掉,观察 QPS 变化
mysql -e 'set global query_cache_size=0; set global query_cache_type=0;'
然后确认后续不再产生命中
mysql -e 'show global status like "Qcache_hits";'
末了把关闭写进配置文件,避免重启回来
sed -i '/^\[mysqld\]/a query_cache_type=0\nquery_cache_size=0' /etc/my.cnf
恢复的判定其实很直接。Qcache_hits 不再增长,三百并发下 QPS 回到线性区间,threads_running 稳定在个位数,慢查询数量明显减少。
5.7 之后这个功能已经被移除,别再花时间调它的参数;热点查询用应用层缓存替代效果更好。这类问题最好一次改到位,反复小改反而容易把原因搅混。
