zgrep が8分帰ってこない。
しかも今日はこれが3回目です。同じアーカイブ、違う検索語。1回目に8分かかるのは仕方ないとして、なぜ3回目も8分なのでしょうか。
圧縮は容量問題をきれいに解決します。ところが解決した翌日から、別の問題が始まります。小さくしたぶんだけ、読むのが遅くなった — その代償を、私たちは「保管したのだから仕方ない」と受け入れています。
以下、圧縮したログと付き合う4つの場面を並べます。zgrepの遅さ・クラウドに預けたログ・バックアップからの1ファイル復元・保管中の破損検出。どれも回避策はありますが、4つとも同じ1つの前提で詰まります。
先に結論: UwView Pro なら、ログを約1/9のサイズで保管したまま展開せずに開いて検索でき、2回目以降は行番号付きで約0.02〜0.07秒で開き直せます(47.73GBのテキストでの実測。圧縮率・速度は内容と環境により異なります。詳細は記事末尾)
1. 3回目の zgrep も、1回目と同じだけ待たされる
状況
半年前のログを app-2026-03.log.gz として保管しています。障害の再発調査で、ここから特定のリクエストIDを探すことになりました。
zgrep 'req-8f21ac' app-2026-03.log.gz
8分後、ヒットが3行返ります。前後の文脈が見たいので -C 20 を付けて打ち直します。また8分。 別のIDでも探したくなります。また8分。
なぜ起きるか
展開した結果が、毎回捨てられているからです。
第4回では「圧縮すると途中の位置へ飛べなくなる」という構造の話をしました。ここで問題にしたいのは、その一段あと——同じアーカイブを繰り返し読むときのコストです。
zgrep は実体として「gzip -dc の出力を grep に流す」ラッパーです。検索のたびに全展開が走り、展開されたデータは grep が判定したあと捨てられます。次の検索は、まったく同じ展開をゼロからやり直します。
ここで律速要因が入れ替わります。生テキストの grep はディスクI/Oが律速ですが、圧縮ファイルでは読むバイト数が減る代わりに展開のCPU処理が律速になります。gzip の展開はおおむね数百MB/s、grep は工夫された実装ならGB/s級で走るので、ボトルネックは展開側に移る。ディスクを速くしても、この待ち時間は縮みません。
そして調査は本質的に繰り返しです。語を変え、文脈を広げ、別の切り口で確かめる。その反復回数だけ、展開コストが線形に積み上がります。
汎用ツールでの対処と限界
まず並列化と、展開の速い形式への移行です。
# 分割済みアーカイブを並列に展開して検索する
ls app-2026-03.*.gz | xargs -P 8 -I{} sh -c 'zcat {} | grep -H "req-8f21ac" || true'
# zstd に置き換えると展開が速い(gzipより一桁速いことが多い)
zstd -dc app-2026-03.log.zst | grep 'req-8f21ac'
# 一度だけ展開して、以降は生ファイルで作業する
zcat app-2026-03.log.gz > /tmp/work.log # 8分。以降の検索は速い
grep -C 20 'req-8f21ac' /tmp/work.log
zstd への移行は素直な改善です。3本目も正しい判断で、3回検索するなら展開1回+高速検索3回のほうが確実に速い。
限界は3つ。ひとつめ、展開先の空きが要ることです。1/9で保管していたのなら、展開には9倍の空きが必要になります。容量が苦しいから圧縮したのに、読むために元のサイズを要求される——第4回の「展開先の空きがない」がそのまま再来します。
ふたつめ、/tmp/work.log は原本ではないことです。障害報告書に書く行番号は展開物の行番号になります。再展開すれば同じになるはずですが、それを保証するのは自分の注意力だけです。
みっつめ、消す前提の一時ファイルが、消えずに残ることです。「まだ調査中だから」と置いたまま数日が過ぎ、ディスク使用率のアラートで思い出す。圧縮保管の効果を、一時展開が食い潰します。
2. クラウドに預けたエビデンスログを、取り出さずに確認したい
状況
保管義務のあるログをオブジェクトストレージに上げています。容量が大きいので、安い保管クラス(低頻度アクセス層やアーカイブ層)に置いてあります。
問い合わせが来ました。「この日のこのIDのログ、ありますか」。あるかどうかを知りたいだけです。ところがアーカイブ層のオブジェクトは、まず復元をリクエストして、数時間待って、それから読むことになります。
なぜ起きるか
クラウドストレージが「置く」と「読む」を別々に課金し、安さと取り出しやすさが反比例するからです。
保管クラスを下げるほど保管の単価は下がりますが、取り出しには待ち時間と取り出し料金が発生します。「安く置く」を選んだ時点で、「気軽に確認する」を手放しているという設計です。
ここで圧縮が効きます。テキストログはよく縮むので、上げる前に圧縮すれば保管量が大きく減ります。実測の一例として、48GBのログが5.3GB(約1/9)になったケースがあります(内容と設定により異なります)。保管量が減れば保管の課金もおおむねその比率で下がるので、圧縮はクラウド課金に対しては素直に効く手です。
ところが取り出し側では逆に働きます。中身を確認するにはオブジェクト全体を取り出して展開する必要があり、「1行だけ確認したい」に対してファイル全体の取り出しを要求されます。 部分取得(レンジリクエスト)自体はストレージ側の機能として使えますが、圧縮ファイルの途中バイトを取ってきても、そこから展開はできません。
汎用ツールでの対処と限界
素朴には、必要なぶんだけ取ってくる工夫をします。
# 生テキストなら、バイト範囲だけ取得できる
aws s3api get-object --bucket logs --key 2026-03/app.log --range bytes=0-1048576 head.log
# 圧縮ファイルでも、先頭側なら部分展開で覗ける
aws s3 cp s3://logs/2026-03/app.log.gz - | gzip -dc 2>/dev/null | head -100
# チャンク分割して上げておけば、必要なチャンクだけ取れる
split -b 1G app.log chunk_ && gzip chunk_* && aws s3 sync . s3://logs/2026-03/
3本目の「分割してから圧縮」は実務的な折衷案で、実際によく採られます。
限界は3つ。ひとつめ、分割は原本を壊すことです。chunk_ac.gz の1,203行目は原本の何行目か。1本のログという単位が失われ、行番号を人間が計算することになります。
ふたつめ、どのチャンクに入っているかは、取ってみるまで分からないことです。時刻順なら当たりは付きますが、IDで探す場合は総当たりです。「取り出しを減らすために分割したのに、探すために全チャンクを取り出す」という本末転倒が起きます。
みっつめ、ローカルに落とした瞬間、それはクラウドに預けたログではなくなることです。管理・削除・アクセス制御を、こんどは手元でやることになります。エビデンスとして預けていたはずのものが、確認のたびに複製されて散らばります。
3. バックアップから「1ファイルだけ復元して中身を見る」
状況
「去年の11月のバッチログ、まだありますか」と聞かれました。バックアップにはあります。tarで固めた、月ごとの数百GBのアーカイブの中に。
欲しいのはその中の1ファイル、それも中身を数行確認したいだけです。復元ジョブを流すと、リストア先の空き容量を確認してくださいと言われます。
なぜ起きるか
バックアップは「全部を戻す」ために最適化されていて、「1つを覗く」ためには最適化されていないからです。
tarはテープアーカイブの略で、その名のとおりシーケンシャルアクセスを前提にしています。個別ファイルの取り出しは指定できますが、その位置に着くまでアーカイブを順に読みます。.tar.gz のように全体を圧縮していれば、目的のファイルの手前を全部展開することになります。数百GBのアーカイブの後ろにあるファイルは、実質的に全読みです。
増分バックアップならさらに面倒で、直近のフルバックアップと増分を順に適用します。1ファイルを見るために、複数のアーカイブを跨いだ再構成が要ります。
そして、確認は一度で終わりません。復元して開いて「思っていたのと違うファイルだった」、隣の日付を見たい、もう一度復元ジョブ。この往復が1回あたり数十分から数時間かかります。
汎用ツールでの対処と限界
tarには個別取り出しのオプションがあります。
tar -tzf backup-2025-11.tar.gz | grep batch # 中身の一覧を見る(全展開が走る)
tar -xzf backup-2025-11.tar.gz path/to/batch.log # 1ファイルだけ取り出す(手前まで展開)
# 圧縮していない tar なら、インデックスを作っておける
tar -tvf backup.tar > backup.index # オフセット込みで一覧を保存
dd if=backup.tar bs=512 skip=$OFFSET count=$BLOCKS of=batch.log
最後の方法は実際に効きます。非圧縮tarはブロック境界が計算できるので、位置さえ分かれば直接抜けます。
限界は3つ。ひとつめ、非圧縮でしか使えないことです。容量のためにバックアップを圧縮しているのなら、そもそも選べません。「小さくして読めなくする」か「大きいまま読める」の二択が、ここでも顔を出します。
ふたつめ、取り出せても、それは巨大な1ファイルであることです。復元した batch.log が40GBなら、こんどはそれを開く問題に戻ります。復元は入り口にすぎません。
みっつめ、道具の粒度が粗すぎることです。バックアップシステムが提供する最小単位はファイルであって、行ではありません。ところが実務で確認したいのは、たいてい行です。
4. 保管中に壊れていないことを、どうやって知るか
状況
3年前のログをNASから読み出しました。gzip -dc が途中でエラーを出して止まります。ファイルは壊れています。
いつ壊れたのかは分かりません。書いたときからおかしかったのか、保管中にビットが化けたのか、コピーの途中で切れたのか。そして最悪なのは、壊れていることに今日まで気づかなかったことです。
なぜ起きるか
保管したファイルを、誰も読み返さないからです。
保管ログの大半は、置かれたまま一度も読まれません。読まれないということは、壊れていても検出されないということです。ディスクの静かなデータ破損(サイレントデータコラプション)は低確率ですが、数年×数十TBという規模では無視できる確率ではなくなります。
圧縮していると影響が拡大します。生テキストなら1バイト化けても1文字が読めなくなるだけですが、圧縮ファイルは前の内容に依存して復号するので、1箇所の破損がそれ以降を全部読めなくします。容量のために圧縮したことが、破損時の被害を大きくします。
もうひとつ、破損と改ざんは技術的には見分けがつきません。監査やインシデント対応で必要なのは「壊れていない」の確認ではなく「保管したときと同じである」の確認です。これは事後には作れません。保管時点で記録しておかなければ、あとから証明する手段がない。
汎用ツールでの対処と限界
やるべきことは単純です。保管時にハッシュを取り、定期的に検証します。
sha256sum app-2026-03.log.gz > app-2026-03.log.gz.sha256 # 保管時に記録
sha256sum -c app-2026-03.log.gz.sha256 # 定期検証
find /archive -name '*.sha256' -exec sha256sum -c {} + # まとめて検証
gzip -t app-2026-03.log.gz # gzip内蔵のCRC32で整合性だけ確認
par2 create -r5 app-2026-03.log.gz # 5%の冗長データで軽微な破損なら復旧できる
par2 まで用意すれば、検出だけでなく修復もある程度できます。ZFSやBtrfsのようなチェックサム付きファイルシステムを使う手もあります。
限界は3つ。ひとつめ、検証そのものが全読みであることです。数十TBを毎月検証すれば、そのI/Oと時間を誰かが負担します。「壊れていないことを確かめる」ためだけに、保管量ぶんの読み込みが定期的に発生します。
ふたつめ、運用が続かないことです。.sha256 を横に置く方式は、ファイルを移動・コピーするたびに一緒に運ぶ必要があります。別ファイルとして管理するものは、必ずいつかはぐれます。
みっつめ、検証と閲覧が別の作業になっていることです。「検証する日」と「読む日」が分かれている限り、3年ぶりに開いた日に初めて壊れていたと知る構図は改善されません。理想は開くたびに自動で検証されることですが、そのためにはアーカイブ形式そのものがチェックサムを内包している必要があります。
4つに共通していたもの
| 場面 | 圧縮で得たもの | 圧縮で失ったもの | 詰まる場所 |
|---|---|---|---|
| zgrepの繰り返し | 保管容量 | 検索のたびの展開結果 | 展開がCPU律速になり、反復回数だけ線形に積む |
| クラウド保管 | 保管課金 | 部分取得の自由度 | 1行の確認にオブジェクト全体の取り出しが要る |
| バックアップ復元 | アーカイブ容量 | 個別ファイルへの直接アクセス | 圧縮tarは手前を全展開、復元先に元サイズの空きが要る |
| 破損の検出 | 保管容量 | 破損の局所性 | 1箇所の破損が以降を全滅させ、検証は別作業のまま |
2列目と3列目を見比べると、取引の中身がはっきりします。私たちは容量を買うために、アクセス性を売っています。 しかもこの取引には明示的な合意がありません。gzip を打った時点で自動的に成立してしまいます。
止まる場所を集めると、要求されているのは3つです。
- 展開せずに、圧縮したまま読む・探す — 展開という中間ステップがあるから、繰り返しコストが積み、展開先の空きが要り、原本でない一時ファイルが生まれます。中間ステップが不要なら、3つとも消えます。
- 圧縮したまま、位置で飛ぶ — 「1行だけ確認したい」に応えるには、圧縮形式の側がランダムアクセスを持っている必要があります。分割は、これを人力で近似した回避策です。
- 完全性の確認を、閲覧と同じ動作に含める — アーカイブ自体がチェックサムを内包し、開くときに検証されるなら、「検証する日」を運用でつくる必要がなくなります。
3つとも、圧縮形式を「保管のための形式」ではなく「閲覧のための形式」として設計すれば同時に満たせる性質のものです。逆に、gzip や tar が満たさないのは当然でもあります。読むためではなく、送るため・置くために作られた形式だからです。
冒頭の「3回目の zgrep も8分」に戻ります。あれは zgrep が遅いのではありません。8分かけて作ったものを毎回捨てているのが遅いのです。取っておければ、2回目からは別の話になります。
使っている道具
私が開発している UwView(無料)は、巨大なテキストを開いた瞬間から全体を表示・スクロール・検索できるビューアです。索引はバックグラウンドで作られ、完成すると行番号が付きます(他のビューアの多くは索引が終わるまで先頭しか見えません)。分割せず、原本を1本のまま・無改変のまま扱えます。第3章で復元した40GBの batch.log を、そのまま開いて確認する——という使い方がここに当たります。
そのうえで、この記事の4つに効くのが UwView Pro の圧縮キャッシュです。索引と圧縮を .uwvz として保存するので、ログを約1/9のサイズで保管して、展開せずそのまま開けます(48GB→5.3GB・実測の一例。圧縮率は内容により異なります)。第1章の「展開結果を毎回捨てる」が構造的に起きません。
- 2回目以降は行番号付きで瞬時: 47.73GBのテキストで、2回目以降のオープンは実測0.02〜0.07秒でした(環境により異なります)。第1章の「同じアーカイブを1日に3回開く」が、待ち時間の問題ではなくなります。
- 圧縮キャッシュ経由の検索: 同じ実測条件で、文字列検索は約9倍になりました(2回目以降・圧縮キャッシュ経由)。読むバイト数が減り、かつ展開のやり直しがないぶんです。
- チェックサム付き: アーカイブがチェックサムを内包しているので、保管中の破損を検出できます。第4章の「別ファイルのハッシュがはぐれる」問題が起きません。
- 多段階検索(ドリルダウン): 圧縮したまま、検索結果をさらに別の語で絞り込めます。タブに
語(件数)が並ぶので、段ごとの件数が残ります。→ 多段階検索の記事
正直に書いておくと、UwView は .gz や .tar.gz を直接開く道具ではありません。効くのは、一度展開した原本を UwView で開き、以降は .uwvz の側で保管・閲覧する運用にした場合です。つまり既存の gzip アーカイブを置き換える提案であって、gzip アーカイブを速く読む提案ではありません。既存の保管資産をそのまま活かしたいなら、第1章で挙げた zstd への移行のほうが素直です。クラウドの保管クラスや取り出し料金そのものにも何もしません(第2章)。できるのは、上げるファイルを小さくしておくところまでです。なお無料版で使えるのは1段検索・±1文脈・結果の保存までで、多段階検索・シーケンシャル検索・可変の±N・索引と圧縮の保存は Pro の機能です。
ストレージを専有している巨大ログを圧縮して保管し、さらに高速に検索したいなら UwView Pro をどうぞ。永続索引・圧縮キャッシュ検索・約1/9保管で、開き直しも検索も一段速くなります(全OS対応・買い切り/月額プランあり)。
リンク
- 第1回: 巨大ファイルに沈む4つの定番ツールと、その先: https://uvp.y42u.net/blog/uwview-ps01-huge-file-tool-limits/
- 第2回: ログの因果を遡る4つの技法: https://uvp.y42u.net/blog/uwview-ps02-log-causality-tracing/
- 第3回: 文字コード4つの罠と切り分け手順: https://uvp.y42u.net/blog/uwview-ps03-japanese-encoding-traps/
- 第4回: 消す・残す・圧縮するの判断基準: https://uvp.y42u.net/blog/uwview-ps04-log-retention-decision/
- 第5回: 開発ログとの正しい付き合い方4選: https://uvp.y42u.net/blog/uwview-ps05-debug-log-practices/
- 第6回: 認証ログ数千万行から痕跡を拾う4手順: https://uvp.y42u.net/blog/uwview-ps06-intrusion-triage-auth-logs/
- 第7回: タイムスタンプを武器にする4つの読み方: https://uvp.y42u.net/blog/uwview-ps07-timestamp-driven-triage/
- 多段階検索(ドリルダウン)— 9万件を2回の絞り込みで54件に: https://uvp.y42u.net/blog/uvp-drilldown-search/
- 48GBファイルは「開ける」だけでは調査できない: https://uvp.y42u.net/blog/uwview-emeditor-48gb-comparison/
- ソースコード(GitHub): https://github.com/amru195704/UwView
開発者より: アプリ・Kindle本・オープンソースの一覧は GitHub: amru195704 にまとめています。
お願い
本記事の情報は参考目的で掲載しており、正確性・完全性を保証するものではありません。圧縮率・展開速度・検索速度は、ログの内容・圧縮アルゴリズムとレベル・CPU・ストレージにより大きく異なります。記載した実測値は特定の1環境での測定例であり、同じ結果を保証するものではありません。クラウドストレージの保管クラス・取り出し方式・課金体系は提供事業者と時期により変わるため、ご自身の契約内容をご確認ください。コマンド例は環境(GNU/BSD、シェル、tar・gzip・zstdの実装とバージョン、クラウドCLIのバージョン等)により調整が必要です。誤記・不正確な情報がございましたら、コメント欄よりご指摘いただければ、確認のうえ修正いたします。
