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

ログから原因を見つける

収集側に届いた行が、送った行より少なかった

TT Labで続きを見る

目標

収集器が受け取った行と送信側のカウンターを突き合わせて欠落を数え、重複を畳み、到着遅延の分布を求め、締め切り時刻での集計の過少集計と、再起動が作った錯覚を、数字で明らかにします。

なぜ重要なのか

ログが空いているとき、「届かなかった」と「何も起きなかった」は結論が正反対なのに、ファイルだけを見ても区別できません。2つを分けるのは、送信側が付けた単調増加の番号だけです。ところが、その番号も、プロセスが再起動すると1から再スタートするので、ブート識別子と一緒に結び付けなければ、再起動の前後が重複に見え、再起動後の欠落は隠されます。受け取った順序が起きた順序ではないことも、同じ重さで重要です。締め切り時刻に集計すると、まだ届いていない行が抜け、数日後に同じクエリが別の数字を出します。

ステップ

  1. /root/gap/gen_gap.pyを作成して実行し、/root/gap/raw/の下にcollector.ndjsonとsender_state.jsonを作ってください。
  2. /root/gap/tally.jsonに、受け取った行と送った行を突き合わせて数えた結果を書いてください。
  3. /root/gap/missing.jsonに、欠けた番号を区間にまとめて書いてください。
  4. /root/gap/dedup.ndjsonに、重複を畳んだ結果を書いてください。
  5. /root/gap/delay.jsonに、到着遅延の分布を書いてください。
  6. /root/gap/cutoff.jsonに、締め切り時刻での集計の過少集計を書いてください。
  7. /root/gap/reboot.jsonに、再起動が集計に与えた影響を書いてください。
  8. /root/gap/gap_report.mdに、4つの節で報告書を残してください。

参考

受け取ったものと送ったものを一緒に手に入れる

/root/gap/gen_gap.pyを作成して実行し、/root/gap/raw/collector.ndjson(2311行、重複61を含む)と、/root/gap/raw/sender_state.json(ストリーム4つ、送信行数の合計2400)を作ってください。

収集器のファイルは、到着順(observed_ts)に積み上がります。送信側のカウンターがないと、何が欠けたのか永遠にわからないので、2つを一緒に作ります。1つのホストは途中で再起動して、(host, boot_id)の組み合わせがホスト数より1つ多くなる必要があります。

受け取った行と送った行を突き合わせる

/root/gap/tally.jsonに、lines_in_file・unique_records・duplicate_lines・sent_total・missing_total・loss_rateを書いてください。

ファイルの行数は、出来事の数ではありません。同じ行が2度来たものを先に畳んで初めて「受け取ったもの」が出て、それを送信側のカウンターから引いて初めて「届かなかったもの」が出ます。同じ行かどうかは、(host, boot_id, seq)で見ます。

欠けた番号を区間にまとめる

/root/gap/missing.jsonに、ストリームごとに、欠けた番号を連続した区間にまとめて、host・boot_id・first・last・countで書いてください。(host, boot_id, first)の昇順です。

散らばった1件ずつの損失と、50件が1つの塊として欠けたものは、原因が違います。そのため、個数だけを数えず、区間にまとめます。ストリームごとに、送信側が知らせてくれたfirst_seqからlast_seqまでを走査しながら、受け取れなかった番号が続く間、区間を伸ばしていきます。

再送が作った重複を畳む

/root/gap/dedup.ndjsonに、重複を畳んだレコードを、host・boot_id・seq・event_ts・observed_ts・msgで、(host, boot_id, seq)の昇順で書いてください。同じ行が何度も来ていたら、最初に届いたものを残します。

at-least-onceの収集器で同じ行が2度来るのは、故障ではなく設計です。必要なのは「何を同じ行と見なすか」の定義です。内容のフィンガープリントで畳むと、本当にまったく同じ2つの出来事まで1つになってしまうので、番号があるときは番号を使います。

到着遅延の分布を求める

/root/gap/delay.jsonに、count・p50_sec・p95_sec・max_sec・over_60s・worst(host・boot_id・seq・delay_sec)を書いてください。遅延は、observed_tsからevent_tsを引いた値を、秒単位の整数に切り捨てたものです。

受け取った順序は、起きた順序ではありません。2つの時刻を別々に残しておく理由がこれで、2つの差が、収集経路の健康状態です。平均は役に立ちません。大半が数秒で、一部が数分なら、平均は両方とも説明できません。

締め切り時刻に集計していたら、どれだけ見逃したか

/root/gap/cutoff.jsonに、cutoff_ts・event_before_cutoff・observed_before_cutoff・late_arrivals・undercount_rateを書いてください。締め切り時刻は2026-05-20T03:20:00Zで、比較は未満です。

同じクエリを真夜中の直後と3日後に実行すると、数字が違います。バグではなく、遅れて届いたのです。出来事の時刻が締め切り前なのに、到着が締め切り後のレコードが、そのとき数えられなかったもので、その比率が、締め切り猶予をどれだけ置くべきかを教えてくれます。

再起動が欠落と重複を入れ替える

/root/gap/reboot.jsonに、hosts_with_multiple_boots・boots_by_host・false_duplicates・missing_with_boot・missing_without_bootを書いてください。

プロセスが再び立ち上がると、番号は1から再スタートします。ブート識別子を除いて数えると、再起動の前後の同じ番号が重複に見え、再起動後に欠けた番号は、再起動前の記録に隠れて、欠落ではないように見えます。2つの数字を並べて出し、その差を示してください。

何を依頼するかを文章に残す

/root/gap/gap_report.mdに、## 무엇이 얼마나 빠졌나、## 중복과 늦은 도착、## 왜 숫자가 달라지나、## 무엇을 요청할 것인가(韓国語の見出しは、順に「何がどれだけ欠けたか」「重複と遅れて届いた行」「なぜ数字が変わるのか」「何を依頼するか」という意味です)の4つの節で書いてください。欠落件数・重複行数・遅延p95・締め切り前に受け取れなかった件数・boot_idを無視したときの欠落件数を、数字で含める必要があります。

この報告書の最後の節が、実際には最も価値があります。次の束から何を付けてもらうよう依頼するかが、次の調査の難易度を決めるからです。送信番号とブート識別子、出来事の時刻と観測時刻を、すべて求める理由を、前の数字で裏づけてください。