LoginSignup
5
4

More than 5 years have passed since last update.

WebSocketをLoadBalancer経由で使う時にsocket-io-sticky-sessionを使うと、keep-aliveを有効にしているとSession ID unknownになることがある

Posted at

はじめに

npmの socket-io-sticky-session (以降、sio-sticky)が、stickyを有効にしたAWSのALBなどのLoadBalancerの後ろにいて、
LoadBalancerからKeep-Alive接続される場合、X-Forwarded-Forなどのヘッダによって正しいWorkerに割り振られないことがある。

という話です。

説明

症状

sio-stickyX-Forwarded-ForなどのHTTPヘッダをみてNode.jsの Webサーバ/WebSocketサーバ などにStickyに接続を振り分けてくれます。これは、SocketIOのpollingやwebsocketで使われるsidというSessionIDを持つリクエストを同じプロセスのNode.jsに振り分ける時に大変重宝します(sidは異なるプロセスのNode.jsで共有されないので)。

しかし、以下のような構成の場合、
ブラウザがALBのCookieをちゃんと送っていても、Stickyが上手く行かずにエラー(BadRequest: Session ID unknown)になることがあります。

20170829_WebSocket400エラー問題の説明.png

原因

原因は、 ALB と sio-sticky の間の keep-alive 接続だと思われます。

sio-sticky は 新規のTCP接続があった時に、配下のWorker(Node.js)にその接続を渡すので、keep-aliveされたあとの2回目以降のHTTPリクエストのヘッダなどを見たりしません。
また、ALBはどのターゲットにリクエストを送るかは制御していますが、どのkeep-aliveされた接続にどのHTTPリクエストを流すかは気にしてはいないので、基本的に運任せになります。

下の図で説明しますと、

20170829_WebSocket400エラー問題の説明.png

  • ① Browser1 と Browser2 は、異なるWorker(Node.js)に振り分けられていたとする
  • ② Browser2からのリクエストがしばらくなくても、ALBとWorkerの間のTCP接続は維持される(keep-alive)
  • ③ Browser1からALBにリクエストがある場合、この別のWorkerとkeep-aliveされた接続にリクエストが流されることがある。異なるworkerにリクエストが行くと、Session ID unknownと怒られてしまう。

というイメージです。

検証

sio-stickyのkeep-alive時の動作についての検証は下記を見てください。
https://github.com/mokemokechicken/socket-io-sticky-session/blob/feature/for_test_keep-alive/NOTE-keep-alive.md

ちなみに、ALBからsio-stickyへの接続は通常の設定ではkeep-aliveされますし、今回の現象も確認することができます。

さいごに

sio-stickyのような仕組みだとTCP接続時に振り分けるので辛いのでしょうね。
keep-aliveを無効にするのも非効率ですし、sio-stickyなどを使わずに1つのNode.jsを直接ALBにぶら下げるのがBetterなのかなぁ、と思います。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4