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

Loki — ログを索引しないログストア

二時間分を復旧して入れたのに画面には何も出なかった

TT Labで続きを見る

目標

過去のタイムスタンプで入れた行が、受け付けられるのに見えない現象を、Pod内の本物のLokiで再現し、その境界を決める設定をサーバーで直接確認したうえで、フラッシュで復活させます。

なぜ重要なのか

Lokiの書き込みと読み取りは、別々の道を通ります。入ってきた行はインジェスターの開いているチャンクにたまり、チャンクが閉じて初めてストレージに上がります。クエリはストレージに尋ね、最近の区間ならインジェスターにも尋ねますが、その「最近」の範囲がquery_ingesters_within(デフォルト3時間)です。そのため、復旧作業であとから流し込んだ過去のデータは、2つの道の間の隙間に落ちます。ストレージにはまだなく、インジェスターにはあるのに、誰も尋ねません。この構造を知らないと、「pushが嘘をついている」と結論づけて、見当違いの場所を直すことになります。

ステップ

  1. /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行で書いてください(プレースホルダーは整数です)。
  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ステータスコードと整数です)。
  3. 新しいストリーム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行で書いてください(プレースホルダーは設定名と、デフォルト値そのままです)。
  4. フラッシュの前後を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=です。
  5. サーバーの/configで、開いているチャンクが閉じる条件を決める3つの設定を見つけて、/root/lk-chunks/chunkparams.tsvに、ヘッダーなしで3行、タブで区切った2つの欄<설정이름><탭><값>(プレースホルダーは設定名、タブ、値です)で書いてください。順序はchunk_idle_period、chunk_target_size、max_chunk_ageで、値はサーバーが出力したままです。
  6. フラッシュが終わった今、インデックスにどのストリームがあるかを、series APIで確認して、/root/lk-chunks/06-series.txtに2行で書いてください。streams=<정수>とapps=<app 라벨 값들을 쉼표로, 사전순>です(プレースホルダーは整数と、appラベルの値をカンマでつないだ辞書順の並びです)。照会区間は、基準時刻から過去7時間を指定してください。ステップ8で作るreviveストリームは数えません(このステップではまだありません)。
  7. /root/lk-chunks/runbook.txtに4行を書いてください。各行は1.から4.で始まり、各行には、実際に入力できる確認コマンドか確認する値が1つずつ入っている必要があります。テーマは、「過去の区間のログが空に見える」という報告を受けたときの、点検の順序です。4行を合わせて、空白を除いた文字数が120文字以上である必要があります。
  8. 本文にrevive-checkという語が入った行を1つ、ラベル{"app":"revive"}で、基準時刻から6時間前に入れ、クエリで見えるようにしたあと、その行の本文を/root/lk-chunks/08-revive.txtに1行で書いてください。本文の残りの内容は自由です。

参考

最近のデータは、入れた直後から見える

/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つ段階が残っています。