Redis GET と SET の習得: 基本データ操作

この包括的なガイドで、Redis データ管理の基礎を習得しましょう。`GET` コマンドと `SET` コマンドについて学び、基本的な文字列の保存と取得、さらにアトミック設定 (`NX`/`XX`) や統合キー期限切れ (`EX`/`PX`) などの高度なオプションを探求します。これらの基本コマンドが、高性能キャッシングレイヤーの構築にどのように不可欠かを発見してください。

Redis GET と SET の習得: 基本データ操作

Redis の GETSET は非常にシンプルに見えます。値を書き込み、値を読み取る。実際のアプリケーションでは、これら 2 つのコマンドは、ログインセッション、フィーチャーフラグ、レート制限、キャッシュエントリ、短期ロック、そして「データベースに再度クエリを実行しないでください」というショートカットの背後にあります。

詳細は重要です。なぜなら、Redis はあなたが要求したことを正確に実行するからです。誤ってキーを上書きしても、意図したかどうかを尋ねることはありません。キャッシュデータの有効期限を忘れると、データソースよりも長く存続する可能性があります。欠落しているキーを空の文字列と同じように扱うと、アプリケーションが誤った判断を下す可能性があります。

Redis のキーと値のモデル

コマンドの詳細に入る前に、Redis がシンプルな キーと値のストア モデルで動作することを覚えておくことが重要です。すべてのデータ(値)は、一意の識別子(キー)を使用してアクセスされます。キーは文字列であり、値はさまざまなデータ型(文字列、リスト、セット、ハッシュなど)にすることができます。SETGET は主に 文字列 データ型を扱います。これは Redis で最も基本的で頻繁に使用される型です。

1. データの設定: SET コマンド

SET コマンドは、キーに値を割り当てるために使用されます。キーがすでにデータを保持している場合、SET コマンドは既存の値を上書きします。その基本的な構文は簡単です。

基本的な構文と使用法

最も単純な形式では、キーと値のみが必要です。

SET key value

例: ユーザーの表示名を保存する:

127.0.0.1:6379> SET user:100:name "Alice Johnson"
OK

127.0.0.1:6379> GET user:100:name
"Alice Johnson"

高度な SET オプション: NX、XX、および有効期限

SET の威力は、そのオプションの引数にあります。これにより、アトミックな条件付き設定と Time-To-Live (TTL) 管理が可能になります。これらのオプションは、ロックとキャッシュを正しく実装するために不可欠です。

条件付き設定: NXXX

これらのオプションは、設定操作が いつ 実行されるかを制御し、誤った上書きを防いだり、キーが存在する場合にのみ上書きが行われるようにします。

  • NX (存在しない場合): キーが まだ 存在しない場合にのみ設定します。これは「作成のみ」の操作や単純なロックパターンに役立ちます。

    SET my_lock_key some_unique_value NX
    
  • XX (存在する場合): キーが すでに 存在する場合にのみ設定します。これは、誤って新しいキーを作成せずに既知のキーを更新したい場合に役立ちます。

    SET session:token:456 new_value XX
    

B. 有効期限の設定 (TTL)

メモリを管理し、時間ベースのキャッシュを実装するには、SET コマンド内で直接有効期限を設定できます。これは、キーを設定してから別途 EXPIRE を呼び出すよりもはるかに効率的です。

  • EX seconds: 有効期限を 単位で設定します。
  • PX milliseconds: 有効期限を ミリ秒 単位で設定します。
  • EXAT timestamp: 特定の Unix タイムスタンプ(秒)に有効期限を設定します。
  • PXAT timestamp: 特定の Unix タイムスタンプ(ミリ秒)に有効期限を設定します。

例: 1 時間で期限切れになるキーを設定する:

127.0.0.1:6379> SET cache:product:500 "Product Details" EX 3600
OK

127.0.0.1:6379> TTL cache:product:500 
(integer) 3598 

キャッシュエントリには SET key value EX N または PX N を使用してください。これにより、書き込みと有効期限が 1 つのコマンドの一部になり、アプリケーションがキャッシュキーを書き込んで EXPIRE を呼び出す前にクラッシュするという一般的なバグを回避できます。

オプションの組み合わせ

すべてのオプションは、複雑なアトミック操作のために組み合わせることができます:

# キーが存在しない場合にのみ設定し、60 秒で期限切れにする
SET my_config_setting "active" NX EX 60

2. データの取得: GET コマンド

GET コマンドは、指定されたキーに関連付けられた文字列値を取得します。これは Redis が実行する最も高速な操作の 1 つであり、多くの場合マイクロ秒で完了します。

基本的な構文と使用法

GET key

例: 保存されたユーザー名を取得する

127.0.0.1:6379> GET user:100:name
"Alice Johnson"

存在しないキーの処理

キーが存在しない場合、GET は何も見つからなかったことを示す特別な応答を返します:

127.0.0.1:6379> GET non_existent_key
(nil)

アプリケーションコードでは、(nil) を受け取ることは、データが欠落していることを判断する標準的な方法であり、通常はキャッシュミスをトリガーし、アプリケーションはプライマリソース(データベースなど)からデータをフェッチし、その後 Redis に書き戻す必要があります。

有効期限を変更しながら値を取得する: GETEX

基本的な GET コマンドは値のみを返します。残りの TTL は返しません。TTL が必要な場合は、別のコマンドとして TTL key または PTTL key を使用します。

GETEX は異なります: 値を返し、同時にキーの有効期限を変更します。これは、読み取りのたびにセッションの有効期間が延長されるスライディングセッション動作に役立ちます。

GETEX session:abc123 EX 1800

これにより、セッション値が読み取られ、有効期限が 30 分にリセットされます。通常のキャッシュ読み取りでこれを軽率に使用しないでください。すべての読み取りがキーメタデータを変更する書き込みのような操作になるためです。

3. 実用的なアプリケーション: GETSET を使用したキャッシング

GETSET の基本的なユースケースは、シンプルなキャッシュアサイドパターンを実装することです。

アプリケーションロジックの手順:

  1. GET product:500 を試行します。
  2. Redis が値を返した場合、それをデコードして返します。
  3. Redis が nil を返した場合、プライマリデータベースから製品をフェッチします。
  4. シリアル化された結果を SET product:500 <json> EX 300 で保存します。
  5. 結果を呼び出し元に返します。

このパターンはデータベースの負荷を軽減できますが、古いデータのウィンドウも作成します。データベースで製品が変更された場合、TTL が期限切れになるか、アプリケーションがキーを無効にするまで、Redis は古い値を提供し続ける可能性があります。TTL は、節約したいトラフィックの量だけでなく、データがどの程度間違っていても許容されるかに基づいて選択してください。

混乱を招かないキーの命名

Redis は命名規則を必要としませんが、将来の自分は必要とするでしょう。user:100:nameproduct:500:summaryrate:user:100:login のような読み取り可能なパターンにより、redis-cli でのデバッグがはるかに簡単になります。

キーは明確で、適度に短く保ってください。キーに u:100:n という名前を付けて数バイトを節約することは、非常に大規模に運用していてキーのオーバーヘッドを測定した場合を除き、混乱を招く価値はほとんどありません。ほとんどのチームにとって、一貫性は極端な簡潔さよりも重要です。

キーにユーザー指定の値を含める場合は注意してください。電子メールアドレス、URL、またはテナント名がキーの一部になる場合は、最初に正規化してください。そうしないと、小さなフォーマットの違いにより、重複したキャッシュエントリが作成される可能性があります:

[email protected]
[email protected]
 [email protected]

これらはすべて、アプリケーションにとっては同じユーザーを表している可能性がありますが、Redis にとっては異なるキーです。

上書き、空の値、および Nil

SET はデフォルトで上書きします:

SET config:mode "safe"
SET config:mode "fast"
GET config:mode

最終的な値は "fast" です。上書きが危険な場合は、NX または XX を使用してください。

また、欠落しているキーと空の値を区別してください。Redis の nil はキーが欠落していることを意味します。空の文字列は実際に保存された値です:

SET user:100:nickname ""
GET user:100:nickname

クライアントライブラリはこれらを異なる方法で表現する場合があります: nullNonenil、空のバイト文字列、または空の文字列。推測する代わりに、クライアントの動作を確認してください。

安全なロックパターン(注意事項あり)

このパターンはよく見かけます:

SET lock:invoice:123 "worker-7:1700000000" NX EX 30

これは、「このロックが存在しない場合にのみ作成し、30 秒後に期限切れにする」ことを意味します。有効期限は必須です。有効期限がないと、クラッシュしたワーカーがロックを永久に残す可能性があります。

単純なシングルインスタンスの Redis セットアップの場合、このパターンは低リスクの調整には十分なことがよくあります。障害、クロックスキュー、および複数の Redis ノードにわたる重要な分散ロックには、十分にレビューされたライブラリを使用し、そのトレードオフを理解してください。ロックのバグは、データ破損のバグになる可能性があります。

redis-cli を使用したデバッグ

GET または SET パスが異常に動作する場合は、キーを直接確認してください:

redis-cli GET product:500
redis-cli TTL product:500
redis-cli TYPE product:500

TYPE は、GET が文字列値に対してのみ機能するため便利です。キーがハッシュ、リスト、セット、またはソート済みセットを保持している場合、Redis は間違った型のエラーを返します。これは通常、アプリケーションの 2 つの部分が異なる目的で同じキー名を使用していることを意味します。

開発中に関連するいくつかのキーを検査する必要がある場合は、ビジーな本番サーバーでは KEYS よりも SCAN の方が安全です:

redis-cli SCAN 0 MATCH 'product:500:*' COUNT 100

KEYS * は、キースペースをスキャンしている間、Redis をブロックする可能性があります。小さなローカルインスタンスでは問題ありません。本番環境では悪い習慣です。

実際のシステムでの TTL の選択

TTL の選択は、製品と運用上の決定であり、Redis のトリックではありません。ユーザープロファイルキャッシュは、5 分間の古さを許容する場合があります。権限チェックには、はるかに短い TTL または明示的な無効化が必要な場合があります。フィーチャーフラグは、リスクの高いロールアウトを制御する場合、ほぼ即時の更新が必要になる場合があります。

一般的な 3 つのパターンを次に示します:

SET cache:product:500 "<json>" EX 300
SET session:abc123 "<json>" EX 1800
SET rate:user:100:login "1" EX 60 NX

製品キャッシュは少し古くなってもかまいません。セッションには明確な有効期間があります。レート制限キーは NX を使用するため、最初の試行でウィンドウが作成され、後続の試行では設計に応じて関連キーをインクリメントまたはチェックできます。

明確な無効化パスがない限り、「永久キャッシュ」キーは避けてください。永久キャッシュは、最終的にセカンダリデータベースになりますが、通常は実際のデータベースに適用する運用規律がありません。

シリアル化の詳細

Redis 文字列はバイナリセーフです。JSON、MessagePack、圧縮データ、カウンター、またはプレーンテキストを保持できます。コマンドは気にしません。あなたのアプリケーションが気にします。

JSON は検査が簡単です:

SET product:500 "{\"id\":500,\"name\":\"Desk Lamp\"}" EX 300

バイナリ形式は、一部のアプリケーションでスペースまたは CPU を節約できますが、ターミナルでのデバッグが難しくなります。圧縮は、大きな繰り返しデータに役立ちますが、CPU コストも追加し、キャッシュしているオブジェクトが大きすぎるという事実を隠す可能性があります。

カウンターの場合、複数のクライアントが同じキーを更新する可能性がある場合は、GET で読み取り、アプリケーションで追加し、SET で書き込みを行わないでください。代わりに、Redis のアトミックカウンターコマンドを使用してください:

INCR page:view:500
EXPIRE page:view:500 86400

初回書き込みと有効期限付きカウンターの場合は、厳密な動作が必要な場合はトランザクションまたは小さな Lua スクリプトを使用してください。それ以外の場合は、受け入れている競合について明確にしてください。

キーの衝突を避ける

同じ Redis データベースを使用している 2 つのチームが、誤って user:100 のようなキーを再利用する可能性があります。一方のチームは SET で JSON を保存し、もう一方のチームは HSET でフィールドを保存します。次の GET は間違った型のエラーを返し、両方のチームが時間を失います。

名前空間が役立ちます:

shop:prod:user:100:profile
shop:prod:session:abc123
billing:prod:invoice:9001

痛いほど長いキーは必要ありませんが、環境、サービス、およびデータ型間の衝突を避けるために十分なコンテキストを含めてください。アプリケーション間で Redis を共有する場合、命名規則はインターフェースの一部です。

GETSET を使用すべきでない場合

文字列は出発点であり、Redis モデル全体ではありません。大きな JSON ブロブ内の 1 つのフィールドを頻繁に更新する場合は、ハッシュの方がクリーンな場合があります:

HSET user:100 name "Alice Johnson" email "[email protected]"
HGET user:100 email

順序付けられたイベントが必要な場合は、ストリームまたはリストを使用してください。メンバーシップチェックが必要な場合は、セットを使用してください。ランキングが必要な場合は、ソート済みセットを使用してください。小さな変更ごとにシリアル化された文字列全体を書き換えるのは、最初は簡単ですが、オブジェクトが大きくなるにつれて、コストがかかり扱いにくくなる可能性があります。

出荷前の小さなチェックリスト

新しい GETSET のパスを出荷する前に、いくつかの簡単な質問を自問してください。

  • 正確なキー名は何ですか?
  • 2 つのサービスが誤って同じキーを使用する可能性がありますか?
  • キーは期限切れになるべきですか?
  • Redis が nil を返した場合、どうなりますか?
  • 上書きは許容されますか、それとも書き込みは NX または XX を使用するべきですか?
  • 値は、1 つの文字列として読み書きするのに十分小さいですか?
  • 本番環境の動作がおかしい場合、redis-cli から値をデバッグできますか?

これらの質問は、ほとんどの基本的な Redis 文字列の間違いがインシデントになる前にキャッチします。コマンドの構文は簡単です。キーを中心としたライフサイクルに、通常バグが潜んでいます。

GETSET は、運用上の負荷が大きい小さなコマンドです。キャッシュデータには有効期限を使用し、上書きが重要な場合は NX または XX を使用し、nil を別の状態として扱い、誰かがターミナルからデバッグできるようにキー名を十分に一貫性のあるものにしてください。文字列が窮屈に感じ始めたら、関連フィールドをハッシュに移動し、アクセスパターンに一致するデータ構造を使用してください。