【入門編】 データ型別のメモリ最適化 – Redis

こんにちは!Redisの世界へようこそ。
私はこれまで数多くのシステムの裏側を見てきましたが、Redisほど「メモリの使い方を知っているかどうかで、パフォーマンスが10倍も100倍も変わる」面白いデータベースはありません。

初心者の方だと、「データをポンポン放り込んでおけばいいや」と思いがちですが、実はRedisは「いかにメモリという限られたスペースを極限まで節約するか」に命をかけている、すごく健気で賢い仕組みを持っています。

今回は、Redisのデータ型がどうやってメモリを節約しているのか、その裏側のからくりを、日常の例えを交えながら分かりやすく解き明かしていきますね。ここをクリアすれば、あなたのRedisの使い方は一気にプロの領域に到達しますよ!

—

1. Redisのメモリ最適化の基本思想:形を変える「変身能力」

いきなりですが、想像してみてください。
あなたは引っ越し業者です。中身がほんの少しのペンと消しゴムだけなのに、わざわざ巨大な段ボール箱を1個ずつ使いますか? 使いませんよね。ポケットに入れるか、小さな封筒に入れますよね。

Redisも全く同じことをやっています。
Redisのデータ型(文字列やハッシュなど)は、「中身の量や大きさによって、内部のデータ構造(=入れ物の形)を自動的にゴリゴリと変える」という凄まじい特技を持っています。これを専門用語でエンコーディング(符号化)の切り替えと呼びます。

この「変身能力」の仕組みを知ることが、Redisを極める第一歩です。それでは、主なデータ型ごとの裏側の仕掛けを見ていきましょう!

—

2. 文字列型(String):数字ならケチケチと整数で持つ

まずは一番基本の「文字列型」です。
「文字列なんだから、文字として保存するんでしょ?」と思いますよね。実は、保存する中身が「数字」だった場合、Redisはそれを文字(テキスト)としてではなく、純粋な数値(整数)としてメモリに保持します。

  • 通常の姿子(RAW / EMBSTR): 普通の文字。例えば `”Hello”` なら、文字ごとの箱を用意します。
  • 節約の姿子(INT): 中身が `”12345″` のような数字の場合。文字としてではなく、コンピュータが計算しやすい「数字そのもの」として、極小のメモリにギュッと押し込みます。

さらに、Redisはよく使われる小さな整数(0〜9999)をあらかじめメモリ上に作り置きしています(シェアード・インティジャー)。そのため、これらの数字を何度使い回しても、メモリがほとんど増えないという超省エネ設計になっています。

—

3. ハッシュ型(Hash)の裏側:ziplistという「お弁当箱」

ユーザー情報(名前、年齢、住所など)を保存するのに便利な「ハッシュ型」。
これを普通に作ると、メモリをたくさん食いそうに見えますよね? でも、データ数が少ないうちは、Redisは`ziplist`(ジップリスト)という、メモリを極限まで節約する特殊な「お弁当箱」モードでデータを管理します。

日常の例え:お弁当箱と仕切り

普通のデータベースや通常のハッシュは、項目ごとに別々の小部屋(ポインタやメタデータ)を用意します。これは、大きなお皿に料理を1品ずつ乗せてテーブルに並べるようなもので、お皿の数だけスペースが無駄になります。

一方、`ziplist` は、「1つの長いお弁当箱の中に、具材をギュッと隙間なく詰めていく」方法です。

[ 項目Aのキー ] [ 項目Aの値 ] [ 項目Bのキー ] [ 項目Bの値 ] ・・・

このように、メモリ上の連続した一つの領域にデータを隙間なく並べることで、余計な隙間(オーバーヘッド)を徹底的に排除しているのです。

ただし、キャパシティには注意!

このお弁当箱、無限に入るわけではありません。データが増えすぎると、お弁当箱の詰め替えに時間がかかるようになるため、Redisは自動的に通常モード(`hashtable`:大きなお皿を並べるモード)に「変身」します。

この境界線は、設定ファイル(`redis.conf`)で変更できます。

  • `hash-max-ziplist-entries`(要素数の上限、デフォルトは512)
  • `hash-max-ziplist-value`(1つのデータのバイト数の上限、デフォルトは64バイト)

「小さなハッシュを大量に持つ」のが、Redisのメモリ効率を最大化する黄金律です。

—

4. リスト(List)・セット(Set)・ソート済みセット(ZSet)の変身技

他のデータ型も、基本の哲学は一緒です。

リスト(List):両端キューから巨大な連結リストへ

リストも最初は `ziplist`(お弁当箱)としてスタートします。要素が少なくなっているうちは、メモリ効率は抜群です。要素が数万件レベルに増えてくると、`quicklist`という「お弁当箱をいくつも鎖で繋いだような構造」に変身し、メモリ効率とスピードのバランスを取ります。

セット(Set):数字の集まりなら `intset`

重複のない要素を管理する「セット型」ですが、もし中身がすべて整数であれば、Redisは`intset`(イントセット)という超コンパクトな配列に変身します。
しかもこの `intset`、中に入っている数字の最大値に合わせて、2バイト、4バイト、8バイトと、必要な最小限の大きさの箱に自動で縮小・拡大します。徹底的なケチっぷりが美しいですね。

ソート済みセット(ZSet):スキップリストとziplistの二刀流

ランキングなどで使われるソート済みセットも、データが少ないうちは `ziplist` で省メモリに動作し、データが大きくなると「スキップリスト(SkipList)」という高速検索用の構造に進化します。

—

5. 実務で使える!メモリ最適化の3大奥義

さて、ここまで仕組みが分かったところで、現場で即座に使える「メモリを爆発させないための3つのコツ」をお伝えします。

1. 「小さなハッシュ」をたくさん作るデザインにする

  • 例えば、ユーザーIDごとのデータを保持するとき、1つの大きなJSON文字列として保存するよりも、ハッシュ型で `user:1001` のように細かく分けて保存し、かつフィールド数を数百個以内に抑えると、`ziplist` の恩恵を受けられてメモリが劇的に軽くなります。

2. 不要なキーには必ず「有効期限(TTL)」を設定する

  • メモリ管理の最大の敵は「ゴミデータの放置」です。使われなくなったセッション情報やキャッシュには、`EXPIRE` コマンドで必ず寿命を持たせましょう。

3. `INFO memory` コマンドを愛する

  • 定期的に `INFO memory` を叩いて、`used_memory`(実際に使っているメモリ)や、`mem_fragmentation_ratio`(メモリの断片化率)を監視してください。ここを見る習慣がつければ、あなたやり手インフラエンジニアの仲間入りです。

—

おわりに

いかがでしたでしょうか?
Redisがメモリを節約するために、裏側でどれほど健気にデータの形を変えているか、そのドラマを感じていただけたなら幸いです。

「ただデータを保存する箱」としてではなく、「中身に合わせて姿を変えるスマートな生き物」としてRedis手なずけられるようになると、バックエンドの設計が何倍も楽しく、そして強固になりますよ。

ここをクリアしたあなたなら、もうRedisのメモリ管理で迷うことはありません。自信を持って、最高のシステムを作り上げてくださいね! それではまた!

コメント

タイトルとURLをコピーしました