TECHSCORE BLOG

クラウドCRMを提供するシナジーマーケティングのエンジニアブログです。

巨大なファイルを安全に参照したい

Synergy! プロダクト開発業務において、開発と保守・運用は、同じメンバーが対応しています。分かれている会社もあると思いますが、弊社ではサブシステム単位で担当グループが決まっており、開発しながら保守・運用を行っています。
問い合わせや障害調査などで、ログファイルを参照することがあると思いますが、先日、ログファイルを参照中に共用環境の負荷があがってしまい、「どなたか、ログファイル参照している方はやめて下さい」とアナウンスされました。その時は、ある時間帯のログを調査しようと less コマンドでファイルを参照して検索していましたが、すぐにキャンセルしてゴメンナサイをしました。
これを機に、安全に参照する方法を自分のなかで確立しておこうと思いました。

検証用のログファイルを作成

なんでもいいので、可読である文字列の巨大ファイルを作成しようと思います。
実際にはあまりないと思いますが、1 年分の巨大ログファイルのようなものを作成します。
ランダムな文字列を生成しつつ、ところどころに検索対象の 2023-01-01 〜 2023-12-31 までの日時を忍ばせます。
これで、約 6GB のファイルの出来上がりです。

for i in `seq 0 364`; do 
    date '+%Y-%m-%d' --date "$i day 2023-01-01" >> log.txt
    head -c 12m /dev/urandom | base64 >> log.txt
done

色んなコマンドで参照・検索してみる

ログファイルが 1 年分として、とりあえず、2023-10-01 あたりを知りたい、という想定とします。
検索しながら、負荷状況をチェックしていこうと思います。
作業したのは、私のローカルマシンなので、共用環境とは異なります。
CPU 負荷やメモリ使用量などはあくまでも参考程度とさせてください。

grep コマンド
# 対象文字列を含む後方 10,000 行を参照します。これである程度のログは参照できるはず
grep -A10000 '2023-10-01' log.txt | less

CPU は 50% 近く消費しました。時間にして 15sec ほどで表示されました。
メモリはほとんど消費しません。

less コマンド
# less でファイルを参照しながら、`/2023-10-01` で検索
less log.txt

ファイルを開くだけだと、CPU も メモリもほとんど消費しません。
検索すると、CPU は 100% 消費状態で数分間続きましたが、結局は検索できず、キャンセルしました。
less の検索はかなり CPU を消費します。
less しか使用していないので、メモリの使用量はほぼ無く 0.1% 使用程度でした。
more コマンドでも同様の結果でした。

# cat でファイルを開き、less でファイルを参照しながら、`/2023-10-01` で検索
cat log.txt | less

less と同様、検索中、CPU は 100% 消費状態で数分間続きましたが、結局は検索できず、キャンセルしました。
cat を利用しているので、メモリの使用量も多く、50% 超使用されていました。

view コマンド

# view でファイルを開いて、`/2023-10-01` で検索 
view log.txt

ファイルを開くまでに、CPU 60% 超消費、2 分程度かかりました。メモリも 50% 超使用。
開いてから、検索してみると、CPU 70% 超消費。メモリも 50% 超使用。1 分程度で検索はできました。

巨大なまま扱うのは躊躇してしまう

色々と試しましたが、一番負荷が低いのが、grep ということが分かりました。
ただ、どの手法も、リソースをかなり消費するので、共用環境で利用するには躊躇してしまいます。
利用状況によっては、監視によるアラートなどが発砲してしまう可能性がありますし、最悪のケースだと、共用環境がダウンしてしまう可能性もありますので、慎重にならざるを得ないと思いました。
巨大なまま扱うのはとても難しいので、分割案を考えてみます。

案1.ファイル分割

ファイルを物理的に分割してみます。
共用環境に自由に書き込める領域と、十分な容量がある場合、もしくはファイルを外部に持ち出すことが可能な場合を想定しています。
全体の行数をカウントしてみてたところ、80,000,000 行ありましたので、80 分割してみようと思います。
下記コマンドで、x00, x01, x02・・・x80 といったファイルが作成されます。

# 1 ファイルあたり、1,000,000 行のファイルが生成される
split -l 1000000 -d log.txt

split してる間は、CPU は 20% 程度消費。1 分程度でファイルが生成されました。
次に、目当てのファイルを探します。
2023-10-01 なので、後半であろうと想定して、x54 あたりを参照。

# 年月日行を grep してみる
$ grep '2023-' x54
2023-09-03
2023-09-04
2023-09-05
2023-09-06
2023-09-07

この grep は一瞬で表示されました。CPU メモリともにほぼ消費されません。
less x54 でファイルを参照しながら検索すると、時間がかかり、CPU も 40% 程消費されるので、grep 検索のほうがよいといえます。
この要領で、2023-10-01 の含まれるファイルを探します。x60 が対象ファイル、ということが判明しました。
あとは、このファイルの 2023-10-01 以降の任意の行を grep で抽出して調査することができると思います。
必要であれば、さらに分割すると扱いやすくなると思います。

案2.ファイルを部分的に抽出

共用環境で、作業領域が無い場合や容量に制限がある場合などは、上記の方法は使えません。
巨大ファイルから、部分的に抽出する方法を試してみようと思います。
先ほどの検証から、60,000,000 行 〜 61,000,000 行 の間に存在することがわかっているので、行を指定して抽出します。

sed -n 60000000,61000000p log.txt | less

CPU は 40% 程消費しますが、10 秒程度で表示されました。
そこから、2023-10-01 を検索することができました。
今回は、案1の検証から、行番号がある程度わかっていたのですが、わからない場合は、sed の行番号指定を少しずつずらしながら、該当の行が出てくるまで繰り返さざるを得ないと思います。

結論

共用環境に作業領域があり容量が十分ある場合、もしくはファイルの持ち出しが可能な場合は、ファイルを物理的に分割するのが、安全だと思います。
そうではない場合でも、sed で部分抽出するほうが、巨大なファイルをそのまま参照するよりは十分安全であると思いました。
今回は、テキストファイルで検証してみましたが、実際のログファイルは圧縮されていたりするので、もう一工夫が必要かもしれません。
時間に制限があり、他の手法は思いつかなかったので試せてませんが、こんな方法があるよ、など、アドバイスがございましたら、コメントいただけると嬉しいです。

田渕 陽子(タブチ ヨウコ)
陸上部だったわけではないですが、走るのが好き、唯一続いている趣味です。


シナジーマーケティング株式会社では一緒に働く仲間を募集しています。