FIX 接続はセッション層で決まる── シーケンス番号と再送をどう扱うか
インフラ

FIX 接続はセッション層で決まる── シーケンス番号と再送をどう扱うか

FTL編集部

FIX での接続を新しく引くとき、議論の中心になりがちなのは注文メッセージの項目です。どの値を送るか、相手の仕様書のどこに合わせるか。ところが実際に接続が通らない、あるいは通った後に止まる原因は、そのほとんどがセッション層にあります。注文の項目が 1 つ違っていれば拒否メッセージが返ってきますが、シーケンス番号の扱いを誤ると、対向との状態がずれたまま復旧できなくなります。

本稿では、FIX のセッション層で実務上問題になる箇所を、シーケンス番号・再送・接続検証の 3 点に絞って整理します。プロトコルのバージョンの選び方にも触れます。参照した一次資料は末尾に挙げています。

どのバージョンで繋ぐか

バージョンの選択は、多くの場合こちらの都合では決まりません。対向が指定してきます。FIX Trading Community は現在、拡張パック方式で更新される「FIX Latest」の利用を強く推奨していますが、レガシー実装のために FIX 4.2 と FIX 4.4 も引き続きサポート対象としています。拡張パックは後方互換で、旧バージョンの実装に対しても適用できるとされています。

実務では、証券会社や取引所との接続で 4.2 や 4.4 を指定されることが今も珍しくありません。バージョンが古いこと自体は問題ではなく、問題になるのはバージョンと方言の混在です。同じ 4.4 でも、対向ごとに使う項目や必須の扱いが違います。「FIX 4.4 対応」と書かれていても、そのまま繋がるわけではありません。

したがって、設計の出発点はバージョン番号ではなく、対向が出す接続仕様書です。どの項目を必須とし、どの値を許容するかは、そこにしか書かれていません。複数の対向を相手にするなら、方言の差を吸収する層を最初から用意しておくほうが、後から条件分岐を足し込むより整理された形に収まります。

セッション層のメッセージは 7 つ

FIX 4.4 の管理用メッセージは、以下の 7 種類です。MsgType(35) の値で区別します。

  • A Logon ── セッションの開始
  • 0 Heartbeat ── 生存確認
  • 1 Test Request ── 応答がないときの確認要求
  • 2 Resend Request ── 抜けたメッセージの再送要求
  • 3 Reject ── セッション層での拒否
  • 4 Sequence Reset ── シーケンス番号の調整
  • 5 Logout ── セッションの終了

この 7 つだけで、接続の確立・維持・復旧・終了がすべて行われます。業務メッセージがどれだけ増えても、セッション層はこの範囲です。逆に言えば、ここを正しく実装できていない接続は、業務メッセージが正しくても安定しません。

シーケンス番号がずれると復旧できない

FIX のセッションは、双方が独立に連番を持ちます。送信側は 1 から順に番号を振り、受信側は次に来るはずの番号を覚えています。届いた番号が期待より大きければ、その間のメッセージが抜けたことになり、再送を要求します。

厄介なのは、この番号が接続をまたいで保持される点です。TCP の接続が切れても、番号は続きます。翌日の接続時に前日の続きから始まるのか、1 に戻すのかは、対向との取り決めです。ここが食い違うと、Logon の直後に不整合が起きます。

実装として最も事故が多いのが、番号の永続化です。プロセスが再起動したときに、どこまで送ったかを覚えていなければ、再開できません。メモリ上にしか持っていない実装は、開発中は問題なく動き、本番で最初の再起動時に破綻します。ファイルなりデータベースなりに書き、書いてから送る順序にしておく必要があります。逆順にすると、送った後に落ちた分が失われます。

もう一つ、番号を安易に戻さないことです。不整合が起きたときに番号をリセットすれば当座はつながりますが、その間のメッセージが本当に処理されたのかは分からないままです。注文が絡む接続では、これは「約定したかどうか不明な注文がある」状態に相当します。リセットは運用手順として、対向と合意したうえで行うものであり、実装が自動で行ってよい操作ではありません。

シーケンス番号の抜けを検知してから復旧するまでの流れを示した図。送信側が 7 から 11 を送り、受信側で 9 と 10 が欠けたため再送要求を出し、業務メッセージの再送とシーケンスリセットで埋める
11 が届いた時点で抜けが分かり、再送要求から復旧が始まる

再送で何を送るか

再送要求を受けたとき、送り返すのは 2 種類です。業務上意味のあるメッセージは、元の内容を再送します。このとき重複であることを示す指標を立てます。一方、心拍のようなセッション層のメッセージを再送しても意味がないため、番号だけを進める形で埋めます。

ここで判断が要るのが、古い業務メッセージをそのまま再送してよいかです。数時間前の注文を今そのまま流せば、意図しない発注になりかねません。時間が経過したメッセージは再送せず番号だけ埋める、という扱いにするのが一般的ですが、その閾値は対向との取り決めに属します。実装側で勝手に決めてよい部分ではありません。

受信側では、重複指標が立ったメッセージを受け取ったときの処理を決めておきます。既に処理済みの注文が再び届くことは正常な動作なので、業務処理は冪等に作る必要があります。同じ注文 ID で二重に発注しない、同じ約定を二重に計上しない。これはセッション層ではなく業務層の責務ですが、セッション層の仕様を知らないと必要性に気づけません。

接続検証に何を含めるか

接続の検証は、業務メッセージの往復だけでは足りません。実際に本番で起きるのは、正常系ではなく異常系だからです。最低限、次の項目は対向との検証で通しておきます。

心拍と応答なし。心拍の間隔は Logon で合意します。相手からの送信が途絶えたときに確認要求を出し、それにも応答がなければ切断する。この一連が動くことを確認します。間隔の設定だけして、途絶時の動作を試していない実装は珍しくありません。

切断と再接続。接続を強制的に切り、番号を保ったまま再開できることを確認します。ここで前述の永続化が効いてきます。

抜けと再送。意図的に番号を飛ばし、再送要求が出ること、再送に対して正しく応答できることを双方向で確認します。自分が要求する側と要求される側、両方を試す必要があります。

拒否。不正なメッセージを送ったときに拒否が返ること、拒否を受け取ったときに処理が止まらないことを確認します。

これらは対向が用意する検証環境で行うのが通常です。検証環境の利用可否と期間は、開発の日程に直結します。実装が終わってから検証枠を取ろうとして数週間待つ、という事態は避けたいところです。

エンジンを作るか、使うか

セッション層は仕様が明確なので、自作しようと思えばできます。ただし、上に挙げた異常系をすべて実装し、検証を通すとなると、相応の工数がかかります。既存の FIX エンジンを使うのが一般的な判断です。

エンジンを使う場合でも、設定の意味は理解しておく必要があります。番号の保存先、日次でのリセット有無、再送の扱い、心拍の間隔。これらは設定項目として並んでいますが、値の意味は対向との取り決めから決まります。既定値のまま繋いで、後から食い違いが判明するのが最も手戻りの大きい進め方です。

まとめ

FIX 接続の成否は、注文メッセージの項目より手前、セッション層の作りで決まります。番号は接続をまたいで続き、永続化しなければ再起動で破綻する。リセットは自動化してよい操作ではない。再送では古い業務メッセージの扱いを取り決めておく。受信側の業務処理は冪等にする。検証は異常系まで含めて枠を確保する。この 5 点を最初に押さえておけば、接続後に長く止まる事態はかなり避けられます。

金融テクノロジー総合研究所では、FIX 接続の設計・実装・接続検証の支援を受託しています。既存接続の点検や、複数対向をまとめる基盤の設計からご相談いただけます。FIX 対応の詳細もあわせてご覧ください。ご相談はお問い合わせよりご連絡ください。

参考資料

記事一覧に戻る