はじめに
クラウドを使った株式の定量実習や自作ツール開発をしていると、購読する銘柄が増えてくる場面があります。処理能力を上げようと、複数の WebSocket 接続を立ち上げてロードバランサーでトラフィックを分散させたところ、気づかないうちにデータの不具合が起きていた…… という経験はありませんか?
実習内で行った圧力テストによると、特別な対策を施していない環境では、時系列の乱れ・データの欠損・同じデータの重複配信が7~12%程度の確率で発生します。 プログラム自体がエラーで落ちるわけではないので見逃しやすいのですが、バックテストの結果がおかしくなったり、板指標の計算が狂ったりする原因になります。後から原因を探すのにとても時間がかかるのが厄介なポイントです。
ロードバランシングで発生する、見えにくいデータトラブル
スループットや可用性を高める目的で、WebSocket の接続を複数用意して負荷分散をかけると、思いがけない落とし穴に遭遇することがあります。
「接続さえ繋がっていれば、ロードバランサーが全部正しくデータを届けてくれる」と思いがちですが、実際はそうとは限りません。
バックエンドの各インスタンスのセッションの寿命は完全には揃っていないため、セッションアフィニティの設定が不十分だと、同じ銘柄の相場データが複数のサーバーにバラバラに送られてしまうことが起きます。その結果、受け取る Tick データの時間順番がバラバラになってしまいます。
また、インスタンスの再均衡やアップデートのタイミングで WebSocket 接続が強制的に切れて再接続される際、切り替わった瞬間の相場スナップショットが消えてしまうケースもよくあります。
さらにロードバランサーの再試行処理によって同じパケットが何度も届く「重複メッセージ」の問題もあります。重複除去の処理を書いていないと、同じ相場データを何度も計算してしまい、バックテストのサンプルが歪んでしまいます。
これらのトラブルは目立ったエラーログを吐かないことが多いので、バックテストを回して初めて不具合に気づくことが多いです。
「接続数を増やせば性能が上がる」は誤解?
相場データの量が増えてくると、とりあえず WebSocket 接続をたくさん作って負荷を分散しよう、と考える方が多いです。 ですが株式リアルタイム相場は時系列順番が重要なストリームデータで、普通のステートレスな HTTP リクエストとは性質が違います。
単純に接続だけ増やしても、セッションの管理や欠損データの補完の仕組みがなければ、処理能力は比例して上がりません。むしろ先ほど紹介したデータの乱れや欠損のリスクを大きくしてしまいます。
クラウド環境では過剰な WebSocket 接続は、ファイルディスクリプタ・メモリ・ネットワークのリソースをどんどん消費します。リソースだけ消費して期待した性能が得られない、という残念な状況に陥りがちです。 ボトルネックは接続の数そのものではなく、ロードバランサーと相場ストリームの相性・調整ロジックにあることが多いです。
データの完全性を守るために必要な仕組み
複数接続+ロードバランシングの環境で株式リアルタイム相場の品質を保つには、ロードバランサーの標準機能だけに頼ってはいけません。データストリーム側に複数の仕組みを組み合わせる必要があります。
- セッションを意識したトラフィック制御 購読している銘柄の情報をロードバランサーが判別できるようにし、同じ銘柄のデータはできるだけ同じバックエンドにまとめます。セッションが移り変わった時用のデータ補完処理も忘れずに。
- パケットごとの識別情報 各相場データにシーケンス番号と高精度なタイムスタンプを付けます。受信側では番号から重複を消し、タイムスタンプからデータの抜けや順番の狂いを検知します。
- セッション切り替え時の欠損補完 WebSocket が切断・再接続したとき、新しいデータが届くのを待つだけではダメです。スナップショット API を叩いて、接続が切れていた間に抜けた相場データを埋める処理を入れます。
- 受信側のバッファキューとフィルタ処理 メモリ上のキューにいったんデータを溜めて、時系列の並び替えや異常パケットの除去を行ってから、指標計算・保存・バックテストのモジュールに渡します。
今回の実習では AllTick API を相場データソースとして動作確認を行いました。返ってくるパケットにシーケンス番号と高精度タイムスタンプが含まれているので、上記の補完・検証ロジックを実装しやすいです。
仕組みを整えると何が変わるの?
上記の一連の仕組みをきちんと実装すると、次のような変化が見られます。
・時系列の乱れや気づきにくいデータ欠損が減り、バックテスト用データの信頼度が上がります。汚れたデータを後から手作業で直す手間が減ります。 ・無闇に WebSocket 接続を増やさなくてよくなり、クラウドのリソース消費が適正に抑えられます。 ・シーケンス番号やタイムスタンプを活用した監視を入れることで、不具合が起きたときに早期に検知できるようになります。
大切なポイントとして、データの完全性は API 単体、あるいはロードバランサー単体だけでは実現できません。 トラフィックの振り分け、パケットの識別、欠損データの補完、受信側のフィルタリング、これら全部を組み合わせて初めて安定します。
コメント欄で情報交換しましょう
自作定量ツールや実習で、複数 WebSocket+ロードバランシングを使っていて、時系列の乱れ・データ欠損・重複メッセージに困ったことはありますか? こんな対策をした、こんな罠にハマった、など経験談をぜひコメントに残してください。