初心者向けRedisプロトコル(RESP)入門ガイド
Redisの優れた機能の中でも、あまり知られていないもののひとつがワイヤープロトコルです。これこそが、Redisが高品質なクライアントライブラリの大規模なエコシステムを持つ理由となっています。Redisのワイヤープロトコルは非常にシンプルに設計されており、Redisの主要な機能をすべて実装したクライアントを容易に構築できます。さらに、高速かつ効率的なクライアントライブラリを書きやすいよう工夫されている点も大きな魅力です。
RESPとは何か?
RESP(REdis Serialization Protocol)は、RedisのクライアントとサーバーがTCP上で相互通信するために使用するテキストベースのプロトコルの名称です。サーバーとクライアント間のすべての通信は、以下の5つの基本型で構成されています。
- シンプル文字列(Simple Strings): 書き込みコマンド成功後の「OK」や、PINGコマンドへの正常応答である「PONG」など、一般的なサーバー応答に使用されます。
- バルク文字列(Bulk Strings): GET、LPOP、HGETなど、ほぼすべての単一値を読み取るコマンドの応答として返されます。バルク文字列はシンプル文字列とは異なり、改行や制御文字、さらには有効なRESPデータさえも、エスケープやエンコードなしでそのまま格納できる点が特徴です。
- 整数(Integers): STRLEN、HLEN、BITCOUNTなどのカウント系コマンドの応答として使用されます。
- 配列(Arrays): 他の配列を含む任意の数のRESPオブジェクトを格納できます。サーバーへのコマンド送信や、HGETALL、LRANGE、MGETのように複数の要素を返す応答に使われます。
- エラー(Errors): 誤ったデータ型のキーに対してコマンドを実行しようとした場合など、Redisがコマンド処理中にエラーに遭遇した際に返されます。
RESPの読み書きでは、キーや値に対してエスケープやエンコードを行う必要は一切ありません。実際にパースが必要なのは、各RESPオブジェクトに付随する単純なメタデータだけです。
RESPはどのような形式か?
すべてのRESPオブジェクトはプレフィックス文字で始まり、行終端記号で終わります(ただし配列は例外で、配列自体には行終端記号が含まれません)。最もシンプルなRESPオブジェクトの例が、OKというシンプル文字列の応答です。
+OK\r\n
(RESPは人間にも読みやすいプロトコルですが、わかりやすさのため、本記事のすべてのRESP例では改行(\r\n)を明示的に表記します。)
上記のシンプル文字列では、+がシンプル文字列のプレフィックス、OKが本文、\r\nがこのシンプル文字列の終わりを示す行終端記号です。
シンプル文字列を読み取るには、次の\r\nまで読み進め、その手前のバイト列(+を除く)を返信文字列として取得します。これは、RESPのシンプル文字列には改行文字が含まれないため可能になっています。
エラーと整数もシンプル文字列と同様の形式ですが、使用するプレフィックスが異なります。エラーは-で始まります。
-ERR unknown command 'GETT'\r\n
一方、整数は:で始まります。
:99\r\n
バルク文字列は他の型とは少し異なり、「長さ指定」と「本体」の2つの部分から構成されます。
$13\r\nHello, World!\r\n
$がバルク文字列のプレフィックス、13が文字列本体のバイト数、続く\r\nが長さ指定の終端です。Hello, World!が13バイトの文字列本体で、これも\r\nで終わります(この\r\nは文字列本体には含まれません)。
バルク文字列は本体の正確な長さを事前に提供するため、本文を解析して終端を見つける必要がありません。ソケットから13バイト(+最後の行終端記号)を読み込むだけでよく、文字列の内容を検査する必要すらありません。つまり、エンコードやエスケープを一切行わずに、任意のデータを文字列本体として扱えるのです。
配列も長さ指定で始まりますが、この長さフィールドが示すのは配列の内容のバイト数ではなく、配列内のオブジェクト数です。
*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
上記の例では、2つのバルク文字列(fooとbar)を含む配列を表しています。配列の長さ指定では、バルク文字列を読むときのように一気にスキップすることはできませんが、クライアント側での配列実装は非常に容易になります。配列サイズを読み取り、その数だけオブジェクトを読み込み、それらすべてを最終的な配列として返すだけです。
すべてのRedisコマンドは、バルク文字列の配列として送信されます。たとえば「SET mykey ‘my value’」というコマンドは、次のように書き込んで送信されます。
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$8\r\nmy value\r\n
RESPのその他の詳細
RESPで採用されているプレフィックス付きの長さ指定のおかげで、複雑な状態管理やデータの複数回走査を必要としないパーサーを実装でき、非常に高速なパーサーを構築することが可能になっています。
本記事で取り上げていない詳細もいくつかあります。たとえばnullバルク文字列やnull配列などです。より詳しい情報については、公式ドキュメントにRESPに関する非常に読みやすく包括的なページが用意されていますので、そちらをご参照ください。
プロトコルへの理解を深める最良の方法は、自分でシンプルなクライアントを実装してみることです。ぜひ、Go言語でRedisプロトコルを読み書きする方法を解説したガイドも併せてチェックしてみてください。
-
Redis SETRANGEコマンドの使い方 – 文字列値の一部を更新する方法
このチュートリアルでは、Redisデータストア内の指定したキーに保存された文字列値の一部を更新する方法を解説します。そのために、RedisのSETRANGEコマンドを使用します。 SETRANGEコマンドとは SETRANGEコマンドは、開始オフセット(start offset)を受け取り、その位置から文字列値の上書きを行います。開始オフセットが現在の文字列値の長さよりも大きい場合は、指定されたオフセットの位置に届くまで文字列値がゼロバイト(0x00)でパディングされます。インデックスはゼロベースで扱われるため、0は先頭の文字、1は2番目の文字を意味します。 また、指定したキーがRedisデー
-
Redis STRLENコマンド徹底解説 – キーに保存された文字列値の長さを取得する方法
このチュートリアルでは、RedisのSTRLENコマンドを使用して、キーに保存された文字列値の長さ(文字数)を取得する方法について解説します。 STRLENコマンドとは STRLENコマンドは、指定したキーに保存されている文字列値の長さ(文字数)を返すコマンドです。キーがRedisデータストアに存在しない場合は空文字列として解釈され、0が返されます。また、キーは存在するものの、その値が文字列型でない場合にはエラーが発生します。 構文 redis host:post> STRLEN <key name> 戻り値 (integer) 数値:文字列に含まれる文字数を表します。 (