キャッシュヒット率が低い (buffer/cache hit)
キャッシュヒット率が低く、データが常にディスク (またはソース) から読み取られている。問題が DB のバッファ/共有キャッシュにあるのか、Redis/アプリケーションキャッシュにあるのかを判断し、測定して修正する。
どのキャッシュのヒット率が低いか?
ヒット率を測定して問題を切り分ける: データベースのバッファ/共有キャッシュが低い (物理読み取りが多い) のか、それとも 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';- DB のバッファ/共有キャッシュのヒット率が低い
- Redis/アプリケーションキャッシュでミス / エビクションが多い
なぜディスクから読み取っているのか: サイズか、スキャンパターンか?
バッファヒット率が低い典型的な原因は 2 つ: 頻繁にアクセスされるデータ (ワーキングセット) がメモリに収まらない (キャッシュが小さすぎる)、または大規模なフルテーブルスキャンが 1 回しか使わないブロックでキャッシュを汚染し、有用なページを追い出している。
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/キーのパターンが弱い (再利用が少ない)
根本原因: ワーキングセットに対してキャッシュが小さすぎる
頻繁にアクセスされるデータが割り当てられたバッファ/キャッシュより大きいため、常に追い出されてディスクから再読み取りされている。ヒット率が低く、物理読み取りが多い。
根本原因: スキャンパターンがキャッシュを汚染している
大規模なフルテーブルスキャンが、一度使われて破棄されるブロックでキャッシュを埋め、ホットなページを追い出している。これがヒット率を下げる。
根本原因: Redis の maxmemory によるエビクション
Redis のメモリが maxmemory の上限に達し、新しいキーの領域を確保するために古いキーがエビクトされている (evicted_keys が増え続ける)。これにより、まだ必要なエントリが失われ、ヒット率が下がる。
根本原因: 弱い TTL / キャッシュパターン
キーに TTL がまったく設定されずメモリがコールドなデータで埋まっているか、キャッシュパターンの再利用率が低く、ほとんどのリクエストがミスになっている。