缓存命中率低(buffer/cache hit)
缓存命中率低;数据不断从磁盘(或数据源)读取。确定问题出在数据库 buffer/shared cache 还是 Redis/应用缓存,然后进行测量和修复。
哪个缓存的命中率低?
测量命中率并隔离问题:是数据库 buffer/shared cache 命中率低(物理读高),还是 Redis/应用缓存出现大量未命中和淘汰?
SELECT ROUND((1-(pr.value/(dbg.value+cg.value)))*100,2) AS buffer_hit_pct
FROM v$sysstat pr, v$sysstat dbg, v$sysstat cg
WHERE pr.name='physical reads' AND dbg.name='db block gets' AND cg.name='consistent gets';- 数据库 buffer/shared cache 命中率低
- Redis/应用缓存中大量未命中 / 淘汰
为什么从磁盘读取:容量问题还是扫描模式问题?
buffer 命中率低有两个典型原因:频繁访问的数据(工作集)放不进内存(缓存太小),或者大型全表扫描用一次性数据块污染缓存,将有用的页挤出。
SELECT component, current_size/1024/1024 AS mb FROM v$sga_dynamic_components WHERE component LIKE '%buffer cache%';
SELECT sql_id, disk_reads, executions FROM v$sql ORDER BY disk_reads DESC FETCH FIRST 10 ROWS ONLY;- 工作集放不进 RAM(缓存太小)
- 全表扫描污染缓存
Redis 为什么未命中:maxmemory 淘汰还是 TTL/键管理?
如果 Redis 命中率低,要么是内存达到 maxmemory、键正在被淘汰,要么是键的 TTL 管理/缓存模式较弱(冷键、复用率低)。
INFO memory
# used_memory, maxmemory, maxmemory_policy, evicted_keys
CONFIG GET maxmemory-policy
INFO keyspace
# Key count and expires (keys with TTL) ratio per db- maxmemory 已满,淘汰率高
- TTL/键模式较弱(复用率低)
根本原因:缓存相对于工作集太小
频繁访问的数据大于分配的 buffer/cache,因此不断被淘汰并从磁盘重新读取。命中率低,物理读高。
根本原因:扫描模式污染缓存
大型全表扫描用只使用一次就丢弃的数据块填满缓存,将热页挤出;这会降低命中率。
根本原因:Redis maxmemory 淘汰
Redis 内存已达到 maxmemory 上限;旧键被淘汰以便为新键腾出空间(evicted_keys 持续上升)。这会丢失仍然需要的条目,并降低命中率。
根本原因:TTL / 缓存模式较弱
要么键根本没有设置 TTL,导致内存被冷数据填满,要么缓存模式的复用率低,导致大多数请求最终都未命中。