TL;DR: クイックフィックス
このエラーは、Redisが**RESP (Redis Serialization Protocol)**形式に従わないリクエストを受信したときに発生します。通常、バルク文字列($で始まる部分)の長さプレフィックスが欠落しているか、間違っているか、有効な数値ではないことを意味します。
- TelnetやNetcatを使用している場合: 正確なRESP形式に従う必要があります。rawモードでは単純な
GET keyは機能しません。*2\r\n$3\r\nGET\r\n$4\r\nkey1\r\nのように入力する必要があります。 - ブラウザで表示される場合: Redisポートに対してHTTPトラフィックを送信している可能性があります。RedisはHTTPをサポートしていません。
- クライアントライブラリを使用している場合: データサイズを確認してください。デフォルトで512MBに設定されている
proto-max-bulk-lenを超えていないか確認してください。
エラーが発生する理由
RedisはRESPというプロトコルを使用します。コマンドを送信する際、Redisは厳格な構造を期待します。「バルク文字列」は$文字で始まり、その後に文字列の正確なバイト数、CRLF(\r\n)、データ本体、そしてもう一つのCRLFが続きます。
$の後の文字が数値でない場合、ERR Protocol error: invalid bulk lengthがトリガーされます。Redisは即座に接続を切断します。これは、ゴミデータによるメモリ破損やバッファオーバーフローから自身を保護するためです。
一般的なシナリオと解決策
1. TelnetやNetcatによる手動コマンド
Redisを手動でテストするのは有効ですが、コマンドをプレーンテキストとして入力すると失敗することがよくあります。RedisにはPINGのような単純なリクエスト用の「インラインコマンド」モードがありますが、複雑な操作には適切なRESP形式が必要です。
間違いの例:
$ telnet localhost 6379
$ SET mykey
# 数値ではなく $ の後にテキストを入力した場合:
$invalid_length
-ERR Protocol error: invalid bulk length
解決策: 手動テストにはredis-cliを使用してください。どうしてもTelnetを使用する必要がある場合は、完全なRESP構造を使用します。例えば、"name"を"John"に設定するには、コマンドの各パーツに対して正確なバイト数を送信する必要があります。
# 完全なRESP形式
*3
$3
SET
$4
name
$4
John
2. 誤ったHTTPリクエスト
ウェブブラウザやセキュリティスキャナーがポート6379にアクセスすると、このエラーがログに頻繁に記録されます。HTTPリクエストはGET / HTTP/1.1で始まります。Redisはその/やヘッダーをRESPとして解析しようとし、即座に失敗します。
解決策:
REDIS_URL環境変数を確認してください。誤ってウェブサービスを指していないか確認します。- ロードバランサーのヘルスチェックを監査してください。AWS ELBやKubernetesのLiveness Probeなどのツールは、生のHTTP GETではなく、Redis互換のチェックを使用する必要があります。
3. エンコーディングとシリアライズのバグ
CやGoなどの言語のカスタムまたは古いクライアントライブラリでは、文字列の長さの計算を誤ることがあります。これは、UTF-8の絵文字やベトナム語などのマルチバイト文字でよく発生します。
ライブラリがバイト数ではなく文字数をカウントしている場合、計算が合いません。Redisはバイト数を期待しています。宣言された長さが8で、実際のペイロードが9バイトの場合、プロトコルが壊れます。
解決策:
string.lengthではなく、常にBuffer.byteLength()またはその同等のものを使用してください。- Redisクライアントを最新の安定版にアップデートしてください。
Node.jsの例:
const val = "Xin chào";
console.log(val.length); // 8 (Redisにとっては間違い!)
console.log(Buffer.byteLength(val)); // 9 (正解!)
4. 巨大なペイロード
このエラーは通常フォーマットのバグを示しますが、クライアントがあり得ないほど大きな長さの値を送信した場合にも発生する可能性があります。Redisは、ヘッダーがサーバーの処理能力を超えるデータサイズを主張している場合、リクエストの解析すら行いません。
解決策: redis.confのproto-max-bulk-len制限を確認してください。デフォルトは512MBです。より大きなファイルを保存する必要がある場合は、データをチャンクに分割するか、APPENDを使用して段階的に値を構築してください。
# CLIで現在の制限を確認する
CONFIG GET proto-max-bulk-len
修正の確認方法
クライアントが何を送信しているかを正確に把握する必要があります。ngrepを使用して、Redisサーバーに届く生のトラフィックをスニッフィングしてください。これは、不正な形式のデータを特定する最速の方法です。
受信トラフィックを監視するには、次のコマンドを実行します:
sudo ngrep -W byline -d any port 6379
$記号に注目してください。$NaN、$-5、または$の後にテキストが続く場合は、クライアントコードが壊れています。正常なリクエストは、アスタリスクとドル記号がきれいに並んで見えます。プロトコルが修正されると、エラーは止まり、クライアントは標準的な+OKレスポンスを受信するようになります。

