とある行ログをLogstashでJSONに変換してGzip圧縮後にS3にPUTし、Athenaで検索できるようにしていた。
LogstashのS3 outputプラグインはrestoreオプションをTrue (デフォルト) にしておくと、再起動時に前回途中まで処理したログをPUTしておいてくれる。
しかし、これに何かの原因で失敗すると、S3には不完全なログファイルがPUTされることがある。
そしてこれはGzip的には破損したファイルとなる可能性がある。
検索中に破損したファイルに遭遇すると、Athenaはエラーを出す。
HIVE_CURSOR_ERROR: Unexpected end of input stream
しかし、どのファイルが破損しているのかは教えてくれない。
なので、Athenaで検索をかけたい場合、restoreオプションは誠に遺憾ながらFalseにしておくのが良いのではないかと思う。
リストアされないのでログに欠落が出る可能性があるが、とはいえファイルが破損すると検索できないというトレードオフ。
この場合、例えば (今回みたいに) 1時間でローテートする設定にしておくと、最長1時間分のログが欠落する。
1時間「だけ」と考えるか、「も」と考えるかが問題だ。
まぁお金の節約のためにもパーティションとローテーションは適切に設定しておくしかない、ってそれはいつだってそう。
今回はしかたがないので、ローカルでgunzip
して破損したログファイルを特定する羽目になった。
How
エラーが出たパーティション下のデータ量を調べる
aws s3 ls log-bucket/log/yearmonth=201707/ --recursive --human --sum
何とかローカルに入りきりそうだったので
aws s3 sync s3://log-bucket/log/yearmonth=201707/ .
適当なスクリプトを作ってエラーチェック
#! /bin/bash
for f in $(ls *.gz); do
gunzip $f
if [ $? = 0 ]; then
rm $(basename $f .gz)
else
echo $f
fi
done
どれかのファイルでUnexpected end of stream
が出たりすると思う。
破損ファイルを特定したらリダイレクトで解凍できるところまで解凍する
gunzip < ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt.gz > ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt
JSON行の途中で終わってたりすると思うので、編集
vim ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt
再度圧縮
gzip ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt
アップロードしなおし
aws s3 cp ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt.gz s3://log-bucket/log/yearmonth=201707/ls.s3.1d8fc54c-4ce8-4b29-98be-f323641ae011.2017-07-10T18.00.part225.txt.gz
これで完了。yearmonth=201707
パーティションが検索できるようになった。
解凍後のファイルサイズが大きすぎて編集できない場合は、諦めてDELETEするか、「きっと最終行だけがおかしいに違いない」と運を天に任せてシェルで最終行だけ削除してみるとか、何か便利なアレとかコレとか使ってファイルを修復する。
ローカルに入りきらないよ
1個ずつダウンロードして確かめるとか……
いや、ファイル1個がローカルに入りきらないんですよ
そんな巨大な単一ログファイルをAthenaで検索するのはちょっとイケてない気がします。
ファイル分割してパーティション切ったほうがお得だと思います。