二時間分を復旧して入れたのに画面には何も出なかった
目標
過去のタイムスタンプで入れた行が、受け付けられるのに見えない現象を、Pod内の本物のLokiで再現し、その境界を決める設定をサーバーで直接確認したうえで、フラッシュで復活させます。
なぜ重要なのか
Lokiの書き込みと読み取りは、別々の道を通ります。入ってきた行はインジェスターの開いているチャンクにたまり、チャンクが閉じて初めてストレージに上がります。クエリはストレージに尋ね、最近の区間ならインジェスターにも尋ねますが、その「最近」の範囲がquery_ingesters_within(デフォルト3時間)です。そのため、復旧作業であとから流し込んだ過去のデータは、2つの道の間の隙間に落ちます。ストレージにはまだなく、インジェスターにはあるのに、誰も尋ねません。この構造を知らないと、「pushが嘘をついている」と結論づけて、見当違いの場所を直すことになります。
ステップ
/root/lk-chunksでLokiを起動し、date +%sを/root/lk-chunks/anchor.txtに書いたあと、python3 /opt/lab/d5/gen.py chunks "$(cat anchor.txt)"でデータを入れてください。このデータは、基準時刻から30分以内にあります。{app="fresh"}を1時間の区間でクエリして行数を数え、ストレージのディレクトリ/tmp/lokidata/chunksの下のファイル数も数えて、/root/lk-chunks/01-boot.txtにlines=<정수>とchunk_files=<정수>の2行で書いてください(プレースホルダーは整数です)。python3 /opt/lab/d5/gen.py chunks-old "$(cat anchor.txt)"で、基準時刻から5時間前のデータを入れてください。そして、その時刻の前後1時間の区間で{app="aged"}をクエリして行数を数え、/root/lk-chunks/02-aged.txtに2行で書いてください。push_code=<HTTP 상태 코드>とlines=<정수>です(プレースホルダーはHTTPステータスコードと整数です)。- 新しいストリーム4つに1行ずつ入れて、見えるかを確認してください。基準時刻から1・2・4・5時間前で、ラベルは
{"app":"b1h"}・b2h・b4h・b5hです。結果を/root/lk-chunks/boundary.tsvに、ヘッダーなしで4行、タブで区切った2つの欄<시간><탭><yes|no>(プレースホルダーは時間とタブです)で書きます(時間は1・2・4・5)。そして、この境界を決める設定を、サーバーの/configで見つけて、/root/lk-chunks/03-param.txtにparam=<설정 이름>とvalue=<기본값 그대로>の2行で書いてください(プレースホルダーは設定名と、デフォルト値そのままです)。 - フラッシュの前後を1つのファイルに記録してください。まず
{app="aged"}の行数と/tmp/lokidata/chunksのファイル数を測り、curl -XPOST http://localhost:3100/flushを呼んだあと、同じ2つの数字をもう一度測ります。/root/lk-chunks/04-flush.txtに4行で書いてください。aged_before=、chunks_before=、aged_after=、chunks_after=です。 - サーバーの
/configで、開いているチャンクが閉じる条件を決める3つの設定を見つけて、/root/lk-chunks/chunkparams.tsvに、ヘッダーなしで3行、タブで区切った2つの欄<설정이름><탭><값>(プレースホルダーは設定名、タブ、値です)で書いてください。順序はchunk_idle_period、chunk_target_size、max_chunk_ageで、値はサーバーが出力したままです。 - フラッシュが終わった今、インデックスにどのストリームがあるかを、series APIで確認して、
/root/lk-chunks/06-series.txtに2行で書いてください。streams=<정수>とapps=<app 라벨 값들을 쉼표로, 사전순>です(プレースホルダーは整数と、appラベルの値をカンマでつないだ辞書順の並びです)。照会区間は、基準時刻から過去7時間を指定してください。ステップ8で作るreviveストリームは数えません(このステップではまだありません)。 /root/lk-chunks/runbook.txtに4行を書いてください。各行は1.から4.で始まり、各行には、実際に入力できる確認コマンドか確認する値が1つずつ入っている必要があります。テーマは、「過去の区間のログが空に見える」という報告を受けたときの、点検の順序です。4行を合わせて、空白を除いた文字数が120文字以上である必要があります。- 本文に
revive-checkという語が入った行を1つ、ラベル{"app":"revive"}で、基準時刻から6時間前に入れ、クエリで見えるようにしたあと、その行の本文を/root/lk-chunks/08-revive.txtに1行で書いてください。本文の残りの内容は自由です。
参考
- 作業ディレクトリは
/root/lk-chunksです。Lokiはステップ1で自分で起動します。 - データ生成器は
/opt/lab/d5/gen.pyで、chunksとchunks-oldの2つのデータを書き込みます。採点ツールはこのファイルを読みません。 - このラボの設定は
reject_old_samples: falseなので、古いタイムスタンプも受け付けられます。運用のデフォルトではオンになっていて、古すぎるデータは受け付けの段階で拒否されます。 - ストレージはローカルファイルシステム(
/tmp/lokidata)です。運用のオブジェクトストレージとはパスが違うだけで、原理は同じです。 - よくある間違い: フラッシュの直後にすぐ数えてしまいます。非同期なので数秒かかります。ファイル数が増えるまで、上限を設けたループで待ってください。
- よくある間違い: series APIに
start・endを指定しません。デフォルトの区間が短く、過去のストリームが抜けます。 - Lokiのアーキテクチャ・設定ドキュメント・HTTP API・リクエスト検証とレート制限
最近のデータは、入れた直後から見える
/root/lk-chunksでLokiを起動し、date +%sを/root/lk-chunks/anchor.txtに書いたあと、python3 /opt/lab/d5/gen.py chunks "$(cat anchor.txt)"でデータを入れてください。このデータは、基準時刻から30分以内にあります。{app="fresh"}を1時間の区間でクエリして行数を数え、ストレージのディレクトリ/tmp/lokidata/chunksの下のファイル数も数えて、/root/lk-chunks/01-boot.txtにlines=<정수>とchunk_files=<정수>の2行で書いてください(プレースホルダーは整数です)。
設定ファイルのpath_prefixとstorage_config.filesystem.directoryが、ストレージの場所を決めます。ファイル数はfind /tmp/lokidata/chunks -type f | wc -lで数えます。入れたばかりなのにそのディレクトリが空なのが不思議なら、それがこのラボの出発点です。
5時間前のデータは、204を受け取っても見えない
python3 /opt/lab/d5/gen.py chunks-old "$(cat anchor.txt)"で、基準時刻から5時間前のデータを入れてください。そして、その時刻の前後1時間の区間で{app="aged"}をクエリして行数を数え、/root/lk-chunks/02-aged.txtに2行で書いてください。push_code=<HTTP 상태 코드>とlines=<정수>です(プレースホルダーはHTTPステータスコードと整数です)。
ジェネレーターは、失敗すると0以外の値で終了します。ステータスコードを直接見たければ、curl -o /dev/null -w '%{http_code}'で1行を手で入れてみてください。クエリの区間は、5時間前を中心に置く必要があります。直近1時間で尋ねれば、当然0です。
境界がどこかを実測し、設定で確認する
新しいストリーム4つに1行ずつ入れて、見えるかを確認してください。基準時刻から1・2・4・5時間前で、ラベルは{"app":"b1h"}・b2h・b4h・b5hです。結果を/root/lk-chunks/boundary.tsvに、ヘッダーなしで4行、タブで区切った2つの欄<시간><탭><yes|no>(プレースホルダーは時間とタブです)で書きます(時間は1・2・4・5)。そして、この境界を決める設定を、サーバーの/configで見つけて、/root/lk-chunks/03-param.txtにparam=<설정 이름>とvalue=<기본값 그대로>の2行で書いてください(プレースホルダーは設定名と、デフォルト値そのままです)。
curl -s localhost:3100/configが、現在動いている設定をまるごと出力します。querier:ブロックを見てください。値は、サーバーが出力した文字列のまま書きます(例: 1h0m0sのような形)。各行をクエリするときは、その時刻の前後に十分な区間を指定してください。
強制的にフラッシュすると、同じクエリが答える
フラッシュの前後を1つのファイルに記録してください。まず{app="aged"}の行数と/tmp/lokidata/chunksのファイル数を測り、curl -XPOST http://localhost:3100/flushを呼んだあと、同じ2つの数字をもう一度測ります。/root/lk-chunks/04-flush.txtに4行で書いてください。aged_before=、chunks_before=、aged_after=、chunks_after=です。
フラッシュは非同期です。ファイルが実際にできるまで数秒かかるので、固定のsleepの代わりに、ファイル数が増えるまで短く回るループを使ってください(上限を設けることを忘れないでください)。クエリの区間は、ステップ2と同じにしないと、2つの数字を比べられません。
チャンクはいつ閉じるか: 3つのつまみを探す
サーバーの/configで、開いているチャンクが閉じる条件を決める3つの設定を見つけて、/root/lk-chunks/chunkparams.tsvに、ヘッダーなしで3行、タブで区切った2つの欄<설정이름><탭><값>(プレースホルダーは設定名、タブ、値です)で書いてください。順序はchunk_idle_period、chunk_target_size、max_chunk_ageで、値はサーバーが出力したままです。
ingester:ブロックにあります。/configの出力が長ければ、grep -nで行番号を先に探し、sed -nでその近くだけを見てください。同じ名前が別のブロックにも出ることがあるので、どのブロックの値かを確認する必要があります。
インデックスには何が残ったか
フラッシュが終わった今、インデックスにどのストリームがあるかを、series APIで確認して、/root/lk-chunks/06-series.txtに2行で書いてください。streams=<정수>とapps=<app 라벨 값들을 쉼표로, 사전순>です(プレースホルダーは整数と、appラベルの値をカンマでつないだ辞書順の並びです)。照会区間は、基準時刻から過去7時間を指定してください。ステップ8で作るreviveストリームは数えません(このステップではまだありません)。
/loki/api/v1/seriesに、match[]={app=~".+"}とstart・endを指定します。区間を指定しないと、デフォルトは直近数時間なので、過去のストリームが抜けます。それ自体が、このラボが述べる罠と同じ種類のものです。
応用①: 同じ報告を受けたときの点検の順序
/root/lk-chunks/runbook.txtに4行を書いてください。各行は1.から4.で始まり、各行には、実際に入力できる確認コマンドか確認する値が1つずつ入っている必要があります。テーマは、「過去の区間のログが空に見える」という報告を受けたときの、点検の順序です。4行を合わせて、空白を除いた文字数が120文字以上である必要があります。
このラボで実際に使ったものを順に思い出せば済みます。受け付けられたか、どの経路が答えるか、ストレージに下りたか、設定がどうなっているか。他の人が明け方に読んで、そのとおりにできるように、コマンドをそのまま書いてください。
応用②: 6時間前の行を1つ見えるようにする
本文にrevive-checkという語が入った行を1つ、ラベル{"app":"revive"}で、基準時刻から6時間前に入れ、クエリで見えるようにしたあと、その行の本文を/root/lk-chunks/08-revive.txtに1行で書いてください。本文の残りの内容は自由です。
前のステップで行ったことを、順にもう一度行えば済みます。入れて、ストレージに下ろして、その時刻を中心に置く区間で尋ねます。クエリが空の結果を返すなら、まだ1つ段階が残っています。