どの区間が遅いのか、そしてあのマイナスは何か
目標
注文1500件の区間タイムスタンプから区間ごとの遅延を計算し、ホストの時計オフセットで補正して、時計の誤差と本当の欠陥を分けたうえで、区間別のパーセンタイルと、全体のテールを作る区間を別々に数えて、どこを直すべきかまで絞り込みます。
なぜ重要なのか
「遅いです」という報告には、直す場所がありません。経路に物差しを当てて区間に分けて初めて、直すチームが決まります。分けたあとには、2つの落とし穴が待っています。1つ目は、負の数です。両端が別のマシンの区間には、2つのマシンの時計の誤差がそのまま混ざっていて、本当の回線時間より時計の差が大きければ、値が負の数になります。これを測定の故障とみなして捨ててしまうと、あとで相手と話し合う根拠を失い、逆に、まるごと時計のせいとひとまとめにすると、その中に混ざった本当の1件を見逃します。2つ目は、パーセンタイルです。区間別のp99が最も大きい区間と、全体の遅延のテールを作る区間は、同じではありません。前者は区間ごとに互いに異なる注文を見ており、後者は1つの注文の中で何が大きかったかを見ています。この2つを混ぜると、見当違いの場所にお金を使います。
ステップ
python3で/root/lat/dataに、spans.jsonl・offsets.json・spec.json・budget.jsonを作成してください。- データの形を数えて、
/root/lat/shape.jsonに書いてください。 - 補正していない区間遅延を計算して、
/root/lat/raw_stats.jsonと/root/lat/raw_negative.csvに書いてください。 - オフセットで補正して、
/root/lat/clock_split.csv・/root/lat/defects.csv・/root/lat/adjust_summary.jsonに、原因を分けて書いてください。 - 区間別のパーセンタイルを
/root/lat/percentile.csvに書いてください。 - 全体の遅延のテールを取り出して、
/root/lat/tail.csvと/root/lat/tail.jsonに書いてください。 - バジェット2セットの超過件数を、
/root/lat/budget_over.csvと/root/lat/budget_summary.jsonに書いてください。 - 分単位の推移を
/root/lat/trend.csvに、絞り込んだ結論を/root/lat/report.jsonに書いてください。
参考
- 時刻と遅延は、マイクロ秒の整数で扱います。浮動小数点数を使うと、最後の桁が揺らいで、パーセンタイルがずれます。
- 補正時刻は、記録された時刻からその時刻を刻んだマシンのオフセットを引いた値です。ゲートウェイの時刻はその注文を扱ったホストが、取引所の受付時刻は
exch-1が刻みます。誰が刻んだかは、spec.jsonのeventsにあります。 - パーセンタイルの定義は、
spec.jsonのpercentileにあります。線形補間で、位置はp*(n-1)/100を0から数え、補間値はhalf upで丸めます。平均は、整数の割り算で切り捨てます。statistics.quantilesのデフォルトは、この定義と違うので、そのまま使わないでください。 - ステップ5から8までの対象は、
spec.jsonのeligibleが決める注文です。6つの時刻がすべてあり、補正した区間遅延5つがすべて0以上の注文です。 - 分バケットは、補正された受信時刻を60秒で割った商です。記録された時刻で割ると、ホストごとに境界がずれます。
- よくある間違い1: ある区間がまるごと負の数だからと、すべて時計のせいとひとまとめにしてしまいます。補正のあとも残るものがないか、必ず確認してください。
- よくある間違い2: 区間別のp99が最も大きい区間を、そのままテールの原因として書いてしまいます。ステップ6が、2つの答えが違うことを示します。
- データファイルは、ステップ1が作ります。生成スクリプトは
/root/lat/mkdata.py、計算の補助は/root/lat/lib.pyに置きます。採点ツールは、データを標準形に変換してフィンガープリントを突き合わせるので、データを手で直すと、すべてのステップが行き詰まります。 - 公開ドキュメント: RFC 5905、statistics、time、FIX Standards。注文1500件とオフセットの報告は、このラボの合成データです。
区間タイムスタンプとオフセットの報告を作る
python3で/root/lat/dataに、spans.jsonl・offsets.json・spec.json・budget.jsonを作成してください。乱数を使わない生成スクリプトを、そのまま使ってください。
顧客のデータをそのまま持ってこられないので、同じ形の合成データを作ります。乱数を使わなければ、誰が何回回しても同じデータが出て、お互いの判定を突き合わせられます。パーセンタイルの定義とバジェットをデータの横に書いておくことが、このラボの核心の習慣です。
データの形を数える
/root/lat/shape.jsonに、orders・segments・hosts・complete_orders・incomplete_orders・missing_by_field・segment_nを書いてください。
区間ごとに数えられる注文の数が違います。時刻が1か所なくても、その時刻を使う区間2つが計算されないからです。segment_nは、区間ごとに両端の時刻がどちらもある注文の数で、complete_ordersは、6つの時刻がすべてある注文の数です。2つを混ぜないでください。
補正していない区間遅延と負の数を探す
/root/lat/raw_stats.jsonに、区間ごとにn・negative・min_us・max_usを書き、/root/lat/raw_negative.csvに、1行目にsegment,host,negative_orders,min_us,max_usを置いて、負の数が出た区間とホストの組だけを書いてください。
区間遅延は、後ろの時刻から前の時刻を引いた値で、ここではまだ補正しません。負の数が出る理由は2つです。両端が別のマシンなので時計の差が混ざったか、同じマシンの中で時刻が逆に刻まれたか。まだ分けずに、どこに集中しているかだけを数えてください。負の数がない組は、書きません。
オフセットで補正して、時計の誤差と本当の欠陥を分ける
/root/lat/clock_split.csvに、1行目にsegment,host,raw_negative,adjusted_negative,causeを、/root/lat/defects.csvに、1行目にorder_id,host,segment,raw_us,adjusted_usを置き、/root/lat/adjust_summary.jsonにraw_negative・explained_by_clock・real_defects・roundtrip_offset_free_orders・eligible_ordersを書いてください。
補正時刻は、記録された時刻から、その時刻を刻んだマシンのオフセットを引いた値です。補正のあと、負の数が1つも残らなければ시계오차、すべて残れば진짜결함、一部だけ残れば섞임です(韓国語の3つの語は、順に「時計の誤差」「本当の欠陥」「混在」を意味します)。roundtrip_offset_free_ordersは、回線送信からack受信までの値が、補正の前と後で同じ注文の数です。同じマシンが両端を刻んだので、何件になるはずかを先に考えてみてください。
区間別のパーセンタイルを出す
/root/lat/percentile.csvに、1行目にsegment,n,p50_us,p95_us,p99_us,max_us,mean_usを置いて、区間5行とtotal1行を書いてください。対象は、spec.jsonのeligibleが決める注文です。
パーセンタイルの定義は、spec.jsonにあります。並べ替えたあと、位置をp*(n-1)/100で取って0から数え、位置が整数でなければ、隣り合う2つの値の間を補間して、half upで丸めます。すべて整数演算でできます。totalは、受信からack受信までで、この値は両端が同じマシンなので、補正が不要です。平均は、整数の割り算で切り捨てます。
全体のテールを作る区間を数える
/root/lat/tail.csvに、1行目にsegment,tail_ordersを置いて、区間5行をすべて書き、/root/lat/tail.jsonにthreshold_us・tail_orders・top_p99_segment・top_tail_segment・sameを書いてください。
テールの注文は、補正したtotal遅延が、totalのp99以上の注文です。注文ごとに最も大きな区間を1つ選んで数えますが、値が同じなら、データが決めた区間の順序で前のものを選びます。top_p99_segmentは、ステップ5の区間別のp99が最も大きい区間で、top_tail_segmentは、ここで最も多く選ばれた区間です。2つが違えば、sameは偽です。選ばれた注文が1つもない区間も、0と書きます。
バジェット2セットの超過件数を比べる
/root/lat/budget_over.csvに、1行目にbudget,segment,over_ordersを置いて、バジェットごとに区間5行ずつ書き、/root/lat/budget_summary.jsonにeligible_ordersと、バジェットごとにover_orders・over_ppm・worst_segmentを書いてください。
区間の値が上限を超えれば超過です。同じなら超過ではありません。over_ordersは、1つの区間でも超えた注文の数で、区間別の超過件数の合計ではありません。1つの注文が2つの区間を超えても、1回だけ数えます。over_ppmは百万分率なので、整数の割り算で出してください。worst_segmentは、区間別の超過件数が最も多い区間で、同じなら、データが決めた順序で前のものです。
いつから悪化したかと、排除した仮説を書く
/root/lat/trend.csvに、1行目にminute,segment,n,p99_usを置いて、分バケットごとに区間別のp99を書き、/root/lat/report.jsonにworst_segment・degraded_minutes・onset_minute・end_minute・supported・ruled_outを書いてください。
分バケットは、補正された受信時刻を60秒で割った商です。ある分の区間のp99が、その区間全体のp50の10倍以上なら、その分は劣化した分で、劣化した分が最も多い区間が、最も悪い区間です。4つの仮説の判定規則は、spec.jsonのhypothesesに書かれています。規則どおりに計算して、支持されるものと排除されるものを分け、2つの一覧とも、識別子を昇順で書いてください。