Upgrade to Pro — share decks privately, control downloads, hide ads and more …

WebSocket における Graceful Update

Toru Sasaki
December 25, 2023
240

WebSocket における Graceful Update

クライアントと常時接続している WebSocket アプリケーションの場合、通常のサーバーと同じようにデプロイするとそのタイミングで一斉に接続が切れて、再接続の波が押し寄せてしまいます。EVサービス事業部でとった対策方法についてまとめています。

Toru Sasaki

December 25, 2023
Tweet

Transcript

  1. Copyright © ENECHANGE Ltd. All Rights Reserved. | 2 自己紹介

    佐々木 徹 所属 EV充電サービス事業部 開発チーム 入社 2023年5月 経歴 • 新卒で SI 下請SE … 2年 • Webシステム受託開発会社でサーバーサイドエンジニア …8年 ◦ 大規模ブログサービス ▪ 記事検索システムのフルリプレイス ▪ 記事更新通知システムの開発 ◦ 広告代理店案件管理システム新規開発 ◦ 社内用Web会議システムのR&D GitHub tetsu040e 所有EV VW ID.4 Lite (2023年10月納車)
  2. Copyright © ENECHANGE Ltd. All Rights Reserved. | 3 今回お話しする内容

    • EV充電サービスのシステムについて • WebSocket を使ったプロダクトのデプロイ問題 • WebSocket における Graceful Update
  3. Copyright © ENECHANGE Ltd. All Rights Reserved. | 5 EV充電エネチェンジ

    日本政府の掲げた「2035年までに新車販売の100%を電動車にする」という目標を背景に、2021年11月からサービスを開始 2027年までの3万台設置へ向け鋭意成長中 基本的な機能 • 充電スポットを探す • 充電開始・終了 • 経路検索v2 • 充電スポットへのコメント投稿・閲覧 • 使えた・使えなかった報告 https://ev-charge-enechange.jp/
  4. Copyright © ENECHANGE Ltd. All Rights Reserved. | 6 システム構成

    AWS データベース フロント サーバー 充電器管理 サーバー アプリユーザー (スポットを探すなど) アプリ・ゲストユーザー (アプリ・Web から充電) 充電カードユーザー (カードをかざして充電 ) 外部システム 充電器ステータスなどを同期 OCPP HTTPS HTTP HTTPSなど
  5. Copyright © ENECHANGE Ltd. All Rights Reserved. | 7 OCPP

    (Open Charge Point Protocol) • EV用充電スタンドと中央管理システム(充電器管理サーバー)との通信に使用されるプロ トコル • JSON over WebSocket で充電操作や電力データの連携を行う ◦ StartTransaction ◦ StopTransaction ◦ StatusNotification ◦ MeterValue ◦ …など => 充電器1台ごとに充電器管理サーバーと WebSocket で接続している WebSocket JSON JSON
  6. Copyright © ENECHANGE Ltd. All Rights Reserved. | 9 EV充電サービスで悩まされてた課題

    • 4月 ◦ 充電器管理サーバーダウン (8時間) ◦ 充電器管理サーバーダウン (8時間) ◦ 充電器の利用ステータス更新が途絶える (1時間) • 6月 ◦ DB ダウン (5時間) => いずれの障害も、多くの充電器で充電開始できないという致命的な障害 => デプロイによる充電器からの再接続が集中してサーバーが耐えられなかった
  7. Copyright © ENECHANGE Ltd. All Rights Reserved. | 10 デプロイによって

    WebSocket 切断・再接続が集中する問題 デプロイ前 デプロイ後の再接続 デプロイによる切断 • 常時 WebSocket で接続しているサーバーで単純にデプロイをすると、一斉に切断されてしまう • 切断を検知して即時再接続するクライアントだと、再接続アクセスがスパイクしてサーバーがパン クしてしまうことがある
  8. Copyright © ENECHANGE Ltd. All Rights Reserved. | 11 解決策は明白

    再接続が集中しない Graceful な仕組みを導入する
  9. Copyright © ENECHANGE Ltd. All Rights Reserved. | 13 •

    Exponential Backoff • AWS CodeDeploy の線形デプロイオプション • 独自実装 考えられるソリューション
  10. Copyright © ENECHANGE Ltd. All Rights Reserved. | 14 Exponential

    Backoff • リトライ(再接続)間隔を指数関数的に後退させていくアルゴリズム ◦ 例: 1秒後に再接続、NGなら2秒後に再接続、4秒後、8秒後... • ジッターと組み合わせて実装すればサーバーへの再接続が集中しにくくなる • クライアント側での実装が必要 ◦ クライアント側の実装ができるのであれば、これが一番シンプルな解決策 • IoT システムの場合、クライアントである端末側のシステムアップデートが難しい場合がある ◦ ENECHANGE の EV充電サービスにおいても、充電器はメーカーから購入しているためそこ で動くソフトウェアの更新には時間とコストがかかる
  11. Copyright © ENECHANGE Ltd. All Rights Reserved. | 15 AWS

    CodeDeploy の機能を使った線形デプロイ • AWS CodeDeploy には線形デプロイのオプションがあり簡単に設定できる! ◦ CodeDeployDefault.ECSLinear10PercentEvery3Minutes • Blue 環境 (既存) から Green 環境 (新) へ設定に応じて徐々にトラフィックを置き換えてくれる • これを使えばデプロイ時の再接続が集中しなくて Graceful になるのでは => しかし、実際はそうならない...
  12. Copyright © ENECHANGE Ltd. All Rights Reserved. | 16 Green環境立ち上げ

    AWS CodeDeploy の線形デプロイと WebSocket • トラフィックを置き換えてくれるのは新規接続のみ • WebSocket で接続済みのものはそのまま Blue 環境と繋がったまま • 結局 Blue 環境が破棄されるタイミングで一斉切断 -> 再接続が集中するのは変わらない トラフィックを置き換え 各端末 Blue環境 コンテナ コンテナ Green環境 コンテナ コンテナ Blue環境 コンテナ コンテナ 各端末 ALB Green環境 コンテナ コンテナ Blue環境破棄 各端末 Blue環境 Green環境 コンテナ コンテナ 既存のWebSocket接続 ALB ALB
  13. Copyright © ENECHANGE Ltd. All Rights Reserved. | 17 少しずつ切断用の

    エンドポイントを叩く Graceful Update の独自実装 Graceful Update の仕組みを自前で実装する • WebSocket サーバーに任意の端末との接続を切るための内部向けエンドポイントを作成 • トラフィックの置き換えが完了したタイミングを EventBridge で検知 • Lambda を起動し、 10〜15分かけて少しずつ充電器と接続を切っていく • 切断された端末から順に Green 環境へ再接続される 各端末 Blue環境 コンテナ コンテナ CodeDeploy EventBridge Lambda トラフィック置き換え トラフィック置き換え完了 のイベント WebSocket切断用の 関数起動 Green環境 コンテナ コンテナ ALB
  14. Copyright © ENECHANGE Ltd. All Rights Reserved. | 18 Graceful

    Update の独自実装 トラフィックのシフトが完了したイベントを検知 { "detail": { "deploymentGroup": ["xxxxxx"], "state": ["SUCCESS"] }, "detail-type": ["CodeDeploy Instance State-change Notification"], "source": ["aws.codedeploy"] } 参照: https://docs.aws.amazon.com/codedeploy/latest/userguide/monitoring-cloudwatch-events.html 待機時間の間に Lambda で少しずつ切断用エンドポイントを叩く const waitingTimePerDevice = 100; // 実際は待機時間と端末数から適切な待ち時間を算出する for (const device of devices) { const url = `http://ws.example.com/foo/${device.id}/close` await http.post(url).catch((err) => { console.log(err); }) console.log(`Close websocket. deviceId: ${device.id}`); await scheduler.wait(waitingTimePerDevice); } 切断処理用の Lambda 関数を実行
  15. Copyright © ENECHANGE Ltd. All Rights Reserved. | 19 まとめ

    • Exponential Backoff ◦ クライアント側での実装ハードルが容易であれば、一番ポピュラーでシンプルな選択肢 ◦ IoT 端末などがクライアントである場合、クライアント側の対応が難しいケースもある • AWS CodeDeploy ◦ 線形デプロイのオプションがあるためパッと見では簡単に対応できそう (だができない) ◦ 新規接続のトラフィックを移行してくれるものなので、常時接続している WebSocket ではう まく使いにくい • 独自実装 ◦ CodeDeploy のイベントを EventBridge で拾って Lambda を起動し、徐々に既存接続を切断 していく仕組みを自ら実装する ◦ 端末の仕様にあわせてカスタマイズ可能