メモリ不足で処理が重くなるのは分かるが、具体的にどういう流れなのかよく分かってなかったので、InnoDB のメモリ、ディスク周りを整理
メモリとディスクは別物
基本的な話。
- メモリ・・・作業中のデータを置く場所。一時的。
- ディスク・・・データの保管場所。永続的。
InnoDBの更新処理
UPDATE や INSERT が来たとき、InnoDB はいきなりディスクに書きにいかず、更新対象のページ(16KB)をバッファプールに読み込み、まずメモリ上で書き換える。
更新されたページは「汚れたページ(Dirty Page)」という扱い。
ディスクのデータは古いまま、メモリのほうが最新の状態。SELECTはメモリのデータを返してくれるので、ユーザー体験として遅延はなし。
ディスクの整合性を保つ仕組み – Write-Ahead Logging
メモリだけ更新して電源が落ちたら、最新のデータは消えるので、Redo Logでそれを防いでいる。
更新内容をログとしてシーケンシャルに書き出し、仮にメモリが吹き飛んでも Redo Log を再生すれば復旧可能→永続性担保
Dirty Pageからディスクに書き込むタイミング
負荷の少ないタイミングでInnoDB が少しずつ書き戻す(flush)。
例)
- Dirty Page の割合が増えてきたとき
- Redo Log が詰まりそうなとき
- バッファプールに空きがなく、新しいページを載せたいとき
- バックグラウンドで余裕があるとき
「暇なときに勝手に掃除する」イメージ。
アクセスが少ない時間帯ほどディスクへの書き戻しが進むので、業務が混んでいる時間に余計な負荷が乗りにくい。
メモリ不足になると重くなる仕組み
- Dirty Page をディスクに書き戻さないとバッファプールから追い出せない。
- メモリが足りなくなってくると、追い出すために強制的に flush が走り始める。
これが頻繁になると、ディスク I/O はどうしても増えてしまい、結果として遅延が体感できるようになってくる。
悪化すると、OS がディスクをメモリとして使い始めてしまい、遅さが桁違いになる。(スワップ)
InnoDB の状態確認
SHOW ENGINE INNODB STATUS;
最低限見るべきポイントメモ
- TRANSACTIONS
→ History list length と長時間トランザクション - LOG
→ redo log の詰まり具合 - BUFFER POOL
→ Dirty Page、Pending writes、hit rate - ROW OPERATIONS
→ InnoDB 内部の詰まり具合
TRANSACTIONS(長時間トランザクション & 履歴の溜まり具合)
------------
TRANSACTIONS
------------
Trx id counter 493829303
Purge done for trx's n:o < 493829211
History list length 42
---TRANSACTION 493829298, ACTIVE 52 sec
5 lock struct(s), 10 row lock(s)
UPDATE big_table SET processed = 1 WHERE status = 'pending'
- History list length
- 100〜200 → 普通
- 数千〜 → パージ遅延。長時間トランザクションの可能性
- ACTIVE が長いトランザクション
- 数秒〜数十秒 → よくある
- 数分〜数時間 → だいたい何か詰まっている
LOG(redo log が詰まりそうか)
LOG
-------------------------------------
Log sequence number 225405840928
Last checkpoint at 225405700000
- LSN – checkpoint の差 が log ファイル総容量に近づくと危険
- 差が大きくなりすぎると、InnoDB は Dirty Page の強制 flush を始め、
UPDATE/INSERT が急に遅くなる原因 になる
BUFFER POOL AND MEMORY(Dirty Page と I/O の詰まり)
BUFFER POOL AND MEMORY
-------------------------------------
Buffer pool size 2048000
Database pages 544290
Modified db pages 1120
Pending writes LRU 0, flush list 3
Buffer pool hit rate 999 / 1000
- Modified db pages(Dirty Page)
- Dirty 割合が 数%以下 → 健全
- Dirty 割合が 高止まり(例:30〜50%) → 書き込みが追いついてない
- Pending writes
- 0〜数個 → 普通
- ずっと 100 以上 → ディスク I/O が悲鳴
- Buffer pool hit rate
- 995/1000 以上 → ほぼメモリだけで動いている
- 950/1000 を切る → バッファプール不足を疑う
ROW OPERATIONS(いまの負荷感)
ROW OPERATIONS
-------------------------------------
0 queries inside InnoDB, 2 queries queued
0.12 inserts/s, 0.30 updates/s, 10.30 reads/s
- queries queued が増える
→ 何かのリソース待ち(ロック・I/O)が発生 - 行ベースの秒間処理量をざっくり見ることで、
「今負荷が高いか」だけ判断できる
まとめ
InnoDB は、メモリを中心に動くストレージエンジンで、ディスクはあくまで後追い。
メモリ上で最新の状態を保ち、ディスクへの書き込みは最適なタイミングで行われる仕組み。
また気づきがあれば追記していく予定です。

コメント