TT Lab
はじめる
学ぶ 学習パス コース

EAI 中間層をつくる

番号ひとつで四チームのログをつなぐ

TT Labで続きを見る

一言でいうと

障害対応の会議の最初の質問は、いつも同じです。「その取引は、どこまで行きましたか」。この質問に数分で答えるには、すべての区間が同じ番号(GUID)をログに残し、そのログを1つの形式・1つのタイムゾーンでつなぎ合わせられなければなりません。番号が区間ごとに違ったり、時刻がばらばらだったりすると、答えは数時間がかりの推測になります。

なぜ必要なのか

振込1件が、チャネル(MCI) → ハブ(EAI) → 勘定系(CORE) → 必要なら外部連携ゲートウェイ(FEP)を通ります。顧客が「お金が引かれたのに、振込失敗と表示された」と電話してくると、4つのチームがそれぞれのログを調べます。MCIはkey=value、ハブはパイプ区切り、勘定系はJSON、FEPは固定桁です。勘定系はUTCで書き、ほかは韓国時間です。さらに最悪の場合、ハブが勘定系を呼び出すときに番号を新しく採番していました。チャネルのログの番号で勘定系のログを検索しても、何も出てきません。「こちらにはその取引が見えない」が4回繰り返され、結局、時刻と金額で似た行を探して手でつなぎます。

モジュール1でGUIDを「最初に作ったシステムが1回だけ発行し、すべての区間がそのまま載せる」と定めた理由が、ここにあります。このモジュールは、その約束が守られたログで何ができるか、そして約束を破る中継をどう直すかを扱います。

どう動くのか

正規化。形式の違うログを、同じ列(guid、hop、時刻、イベント、応答コード)に変えます。元のログの形式を変えるよう4つのチームに求めるより、読む側で1回合わせるほうが早いのです。ただし、新しく作るシステムは最初から構造化ログ(JSON 1行、決まったキー)で書きます。正規表現なしで読めます。

タイムゾーン。ログの時刻には、必ずタイムゾーンが付いていなければなりません。2026-09-23T00:02:08.268ZのZはUTCという意味で、韓国時間(UTC+9)では09:02:08.268です。タイムゾーンのない時刻(2026-09-23 09:02:08)は、「どのタイムゾーンか知っている人にしか読めない」時刻です。1つのシステムだけがUTCだと知らずにつなぐと、勘定系がハブより9時間先に処理したように見えます。

時系列でつなぐ。1つのGUIDの行を時系列に並べると、取引の経路が出てきます。最初のイベントからの経過時間を付ければ、どの区間で時間を使ったかが見えます。ただし、異なるサーバーの時計は少しずつずれるため(それぞれNTPで合わせても数ミリ秒)、ミリ秒単位の区間をまたぐ順序は、参考程度にしか見られません。同じサーバー内の2つのイベントの差(勘定系のRECV → APPLY)は信頼できます。

消えた取引。ハブが「送った(OUT)」と書いたのに、勘定系に「受け取った(RECV)」がなければ、その取引は両者の間で消えたことになります。ネットワークの断絶かもしれず、勘定系の前段で捨てられたのかもしれません。こうした取引に、ハブはE901で答えたはずで(モジュール4)、モジュール8の照会で確定する必要があります。GUIDでつないで初めて、この一覧を機械的に取り出せます。

遅い取引の分解。全体の時間が3秒を超えた取引を、区間ごとに分けます。勘定系の内部でかかった時間(RECV→APPLY)、外部機関でかかった時間(REQ→RSP)です。平均ではなく個々の取引を分解してこそ、「勘定系が遅い日」と「特定の機関が遅い日」が分かれます。

伝播ルール。中継は、受け取ったGUIDをそのまま次の区間に載せます。電文の区間ではヘッダーのGUIDの位置、HTTPの区間ではヘッダー(このコースはX-GUID)と本文です。そして標準もあります。W3C Trace Contextは、HTTPでトレースコンテキストを渡すtraceparentヘッダーを定めています。形は버전-trace-id-parent-id-flags(プレースホルダーはバージョンです)で、バージョン00では、trace-idは16バイト(小文字16進数32文字)、parent-idは8バイト(16文字)であり、どちらもすべて0なら無効です。trace-idは取引全体で1つ、parent-idは呼び出しごとに新しく作ります。そのため、1つの取引の中の複数の呼び出しを、親子として描けます。LH-STDのGUIDをtrace-idと同じ形に定めておいたおかげで(モジュール1)、GUIDをそのままtrace-idに載せれば、電文の区間とHTTPの区間のトレースが途切れずにつながります。

ログの必須列。区間イベント1行には、最低限、時刻(タイムゾーン付き)、GUID、区間名、イベント、応答コードが必要です。金額・口座番号のような個人情報は、入れないかマスクします。トレースには番号1つで十分です。

現場での姿

最もよくあるのは、中継がGUIDを新しく採番してしまう事故です。誰かが「自分たちのシステムの取引番号ルール」を守ろうとして、受け取った番号を捨てて自分の番号を付けました。善意でしたが、トレースはその区間で途切れます。自分の番号がどうしても必要なら追加で書き、受け取ったGUIDはそのまま渡します。2つ目は、タイムゾーンのないログです。サーバー1台のタイムゾーン設定が変わった日からログが9時間ずつずれ、誰も気づきません。3つ目は、ログにGUIDを残さないエラー経路です。正常系にはGUIDを出力するのに、例外処理ブロックのログ1行では抜けています。本当に必要なのは、その行なのにです。

次のラボですること

ある営業日の4つの区間のログ(MCI・EAI・CORE・FEP、形式4つ、タイムゾーン2つ)を1つの形式に正規化し、韓国時間に揃えます。GUID1つの経路を描くtrace.py、勘定系に届かなかった取引の一覧、遅い取引の区間分解を作ります。最後に、GUIDを新しく採番する中継(relay_buggy.py)を直し、受け取ったGUIDをそのまま載せて構造化ログを残すようにし、HTTPの区間にtraceparentを載せます。