最適化するかクラッシュするか：Redisの大きなキー問題

[![表紙](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/66690192-0bf9-4e6f-b250-369560aec61b.png)](https://leapcell.io/?lc_t=q_redisbigkey)

## Redis の大きなキー（Big Key）問題とは

Redis の大きなキー（Big Key）問題とは、特定のキー（key）に対応する値（value）のメモリ使用量が非常に大きくなることで、Redis のパフォーマンス低下、メモリ不足、データの不均衡、マスター・スレーブ同期の遅延などの問題を引き起こす現象を指します。

### どのくらいのデータ量が「大きなキー」と見なされるのか？

明確な基準はありませんが、一般的に以下の条件を満たす場合、大きなキーと見なされます。

- **文字列（String）型**の値が**1MB 以上**のメモリを消費する場合
- **集合（Set、List、Hash、Zset）型**の要素数が**1 万件以上**の場合

ただし、大きなキーの定義や判断基準は固定的なものではなく、Redis の運用状況やビジネス要件に応じて評価する必要があります。  
例えば、高負荷かつ低遅延が求められる環境では、たとえ 10KB のキーでも「大きなキー」となる可能性があります。一方で、低負荷で大容量が許容される環境では、100KB が閾値になることもあります。したがって、Redis を設計・運用する際には、ビジネス要件やパフォーマンス指標に基づいて適切な閾値を設定することが重要です。

## 大きなキーが引き起こす影響

- **メモリ消費の増加**  
  大きなキーが大量のメモリを占有すると、使用可能なメモリが不足し、Redis のメモリ管理ポリシー（Eviction Policy）が発動する可能性があります。最悪の場合、メモリ枯渇により Redis がクラッシュし、システム全体の安定性が損なわれることもあります。

- **パフォーマンスの低下**  
  大きなキーはメモリの断片化を引き起こし、Redis のパフォーマンスに悪影響を及ぼします。また、大きなキーの読み取り・書き込み・削除操作には、通常よりも多くの CPU 時間とメモリリソースが必要となるため、システム全体のパフォーマンスが低下する可能性があります。

- **他の操作のブロック**  
  大きなキーに対する特定の操作が Redis のレスポンスをブロックすることがあります。  
  例えば、`DEL` コマンドを使用して大きなキーを削除すると、その処理に時間がかかり、Redis が一定時間応答しなくなる可能性があります。これにより、他のクライアントリクエストが処理できなくなり、システムの応答速度やスループットに影響を及ぼします。

- **ネットワークの混雑**  
  大きなキーを取得する際には大量のデータ転送が発生し、ネットワーク帯域を圧迫することがあります。  
  例えば、1MB のデータを持つキーがあり、それが 1 秒間に 1000 回アクセスされると、**毎秒 1000MB の通信量**が発生し、ネットワークに負荷をかける可能性があります。

- **マスター・スレーブ間の同期遅延**  
  Redis がレプリケーション（マスター・スレーブ構成）を使用している場合、大きなキーが原因でデータ同期に遅延が発生する可能性があります。  
  これは、大きなキーが大量のメモリを消費し、マスターからスレーブへのデータ転送時に膨大なデータが流れるため、ネットワーク遅延やデータ不整合の原因となるためです。

- **データの偏り（スキュー）**  
  Redis クラスタ環境では、大きなキーが特定のノードに集中し、そのノードのメモリ使用率が他のノードよりも大幅に高くなることがあります。  
  これにより、クラスタ全体の負荷分散が崩れ、**maxmemory** 設定に達した際に重要なキーが削除されるリスクが高まります。最悪の場合、メモリオーバーフローによるクラッシュを引き起こす可能性もあります。

## 大きなキーが発生する原因

- **不適切なデータ設計**  
  1 つのキーに大量のデータを格納するのではなく、複数のキーに分割すべきです。  
  例えば、全国のデータを都道府県ごとに**34 個のキー**に分割したり、市区町村ごとに**300 個のキー**に分割することで、大きなキーの発生を抑えることができます。

- **値の増加を予測できていない**  
  データを無制限に追加し続け、削除や有効期限の管理を行わない場合、時間の経過とともに大きなキーが発生します。  
  例えば、**有名人のフォロワーリストや人気コメントリスト** などがこれに該当します。

- **不適切な有効期限設定**  
  キーに適切な有効期限を設定しない、または長すぎる有効期限を設定すると、データが蓄積されて大きなキーが生成されます。

- **プログラムのバグ**  
  例外処理の不足により、キーのライフサイクルが意図しない形で延長されると、値の肥大化につながり、大きなキーを生む原因となります。

## 大きなキーの検出方法

### SCAN コマンドを使用する

Redis の`SCAN` コマンドを使うと、データベース全体をブロックせずにキーを順次スキャンできます。  
さらに、`STRLEN`、`LLEN`、`SCARD`、`HLEN` などのコマンドと組み合わせることで、大きなキーを特定できます。

### `bigkeys` パラメータを利用する

Redis CLI で以下のように`—bigkeys` オプションを使用すると、各データ型で最も大きなキーをスキャンできます。

```bash
redis-cli -h 127.0.0.1 -p 6379 —bigkeys
```

### Redis RDB Tools を利用する

オープンソースの `Redis RDB Tools` を使用すると、RDB ファイルを分析し、大きなキーをスキャンできます。  
例えば、**1KB 以上のメモリを消費する上位 3 つのキーを特定する場合**、以下のコマンドを実行します。

```bash
rdb —commond memory —bytes 1024 —largest 3 dump.rbd
```

続きは次のメッセージで送ります。

### 大きなキーの解決策

- **キーを分割する**  
  もっともシンプルな解決策は、1 つの大きなキーを複数の小さなキーに分割することです。  
  例えば、1 つのキーに格納していたデータを複数のキーに分散し、`MGET` などのバッチ取得を活用することで、Redis のパフォーマンスを向上させることができます。

- **データ圧縮**  
  文字列（String）型のデータを格納する場合、**圧縮アルゴリズム**を使用することで、値（value）のサイズを削減できます。  
  また、**Hash 型**を活用するのも有効な手段です。Redis の Hash 型は内部的に**圧縮リスト（ZipList）**を使用するため、単純な文字列型よりもメモリ効率が良くなります。

- **適切な有効期限を設定する**  
  すべてのキーに適切な有効期限（TTL）を設定することで、データが不要になった際に自動的に削除されるようにし、大きなキーの蓄積を防ぐことができます。

- **メモリ管理ポリシーを有効にする**  
  Redis には**LRU（Least Recently Used: 最近最も使われていないキーの削除）**などのメモリ管理ポリシーが用意されています。  
  これを適切に設定することで、メモリ使用量を抑えつつ、大きなキーが長期間残ることを防ぐことができます。

- **データの分散（シャーディング）**  
  **Redis Cluster** を活用することで、データを複数の Redis ノードに分散し、1 つのインスタンスに過剰な負荷がかかるのを防ぐことができます。  
  これにより、1 つのノードに大きなキーが集中するリスクを低減できます。

- **非同期でキーを削除する**  
  大きなキーを削除する際には、**`UNLINK` コマンド**を使用するのが推奨されます。  
  `DEL` コマンドはブロッキング処理（同期削除）ですが、`UNLINK` はバックグラウンドで非同期にキーを削除できるため、Redis のレスポンスに影響を与えずに安全に大きなキーを削除できます。

## まとめ

Redis における**大きなキー（Big Key）問題**は、パフォーマンス低下、メモリ使用量の増加、処理のブロック、マスター・スレーブ同期の遅延など、さまざまな問題を引き起こします。

本記事では、大きなキーの原因、影響、検出方法、そして効果的な解決策について詳しく解説しました。  
データ構造の最適化、適切な TTL の設定、システムアーキテクチャの調整、非同期削除の活用など、適切な対策を講じることで、大きなキーの問題を防ぎ、Redis の**安定性**と**パフォーマンス**を向上させることができます。

---

### [私たちはLeapcell、バックエンド・プロジェクトのホスティングの最適解です、組み込みのサーバーレスRedisを搭載しています。](https://leapcell.io/?lc_t=q_redisbigkey)

[![Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/b3f82efd-2548-4c89-8bc6-b67fc32a8ee7.png)](https://leapcell.io/?lc_t=q_redisbigkey)

[Leapcell](https://leapcell.io/?lc_t=q_redisbigkey)は、Webホスティング、非同期タスク、Redis向けの次世代サーバーレスプラットフォームです：

**複数言語サポート**

- Node.js、Python、Go、Rustで開発できます。

**無制限のプロジェクトデプロイ**

- 使用量に応じて料金を支払い、リクエストがなければ料金は発生しません。

**比類のないコスト効率**

- 使用量に応じた支払い、アイドル時間は課金されません。
- 例: $25で6.94Mリクエスト、平均応答時間60ms。

**洗練された開発者体験**

- 直感的なUIで簡単に設定できます。
- 完全自動化されたCI/CDパイプラインとGitOps統合。
- 実行可能なインサイトのためのリアルタイムのメトリクスとログ。

**簡単なスケーラビリティと高パフォーマンス**

- 高い同時実行性を容易に処理するためのオートスケーリング。
- ゼロ運用オーバーヘッド — 構築に集中できます。

[ドキュメントで詳細を確認！](https://docs.leapcell.io/)

[![Try Leapcell](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3967621/909af759-d028-44ed-801c-0edf9c39fe3b.png)](https://leapcell.io/?lc_t=q_redisbigkey)

Xでフォローする：[@LeapcellHQ](https://x.com/LeapcellHQ)

---

[ブログでこの記事を読む](https://leapcell.io/blog/how-to-optimize-big-key-problem-in-redis)