Hele maika'i

趣味とか技術とかざっくばらんに書いてます。タイトルはハワイの言葉で「幸せな一歩」

Node.jsでioredisを使っている人がenvoyのredis-proxyを通すときの注意点

どうも、お久しぶりです!

コッピーです。

表題の件について、かなり沼ったのでメモがてらブログに残すことにしました。

何があったか

そもそも注意点と書いているが、何があったのかという話です。

簡潔に言ってしまうと、ioredisのインスタンス生成時に

[ioredis] Unhandled error event: ReplyError: invalid request

というエラーが出て、Redisへの接続ができませんでした。

アプリケーション構成

上記の問題が発生した際の構成を以下に示します。

f:id:hmaa_ryo:20210920004103p:plain

ここで、各コンポーネントのバージョンなどは以下の通りです。

  • node.js: 13.5.0
  • redis: 6
  • envoy: 1.18.3

なお、これについては基本的にはどのバージョンでも発生する問題だと思っています。理由については読み進めていただければ分かると思います。

問題の詳細

Invalid request のエラーが起きたといっても、なぜそれが起きたかという話ですね。

これはenvoyのissueを見ていただけると同じ問題について上がっているのですが、ioredisではredisのステータスチェックにINFOコマンドを使っており、envoyのredis-proxyがINFOコマンドに対応していないため、INFOのリクエストを処理することができず、エラーが起きるということのようです。

ioredisの詳細

ioredisではインスタンス生成時にいくつかのオプションを設定することができます。その中で enableReadyCheck というオプションがデフォルトでtrueになっており、この設定がINFOコマンドでのステータスチェックを行う設定になります。

具体的な処理内容についてはコードを読んでいただければと思いますが、ざっくりと言うとINFOコマンドを叩いて、返ってきたレスポンスから loading: 0 だったらredisのチェックに成功するという処理です。

envoyの対応コマンド

envoyで対応しているコマンドについてはこちらです。

上のissueにもあるのですが、そもそもenvoyを通す時点で、アプリケーション側はどのredisに繋がるかが分かりません。envoyから先、どのredisに繋がるかが分からないということはINFOコマンドの結果が変わってくる可能性があるということです。

それを考えたとき、envoyのredis-proxyでINFOコマンドに対応しないのは自然だと思いますし、今後も対応することは無いのでは?と思っています。

解決策

envoyを通す以上、INFOコマンドを使うことができないため、どうしてもioredisを使いたいということであれば、インスタンス生成時に enableReadyCheck: false を渡して、INFOコマンドによるreadyのチェックを行わないようにすることで解決することができます。基本的にはenvoy側でredisへのhealthcheckはしていると思うので、ioredis側でわざわざreadyのチェックを行わなくてもあまり影響はないと思いますが、これをオフにするのが嫌だという場合にはioredisをやめて別の方法でredisへの処理を行うか、envoyを通さずにprimaryとreaderをredis側で明確に分けてあげるかだと思います。

参考文献