Amazon AthenaでCTASが失敗したときの対応方法

# 概要
Amazon AthenaにおいてCTASでデータ作成をしているのですが、CTASが失敗したときに何が起き得るか、どうすればよいか、というトラブルシュートの話を整頓しました。


# CTASとは
Athenaで2018年に利用できるようになった仕組みです。
Parquet形式への変換を、パーティションも考慮し簡単に作成することができます。

参考記事：[Amazon Athena が待望のCTAS（CREATE TABLE AS）をサポートしました！](https://dev.classmethod.jp/articles/amazon-athena-support-ctas/)

# どういう運用をしているか

- パーティションが100個を超えるテーブルのデータ作成
- CTASにおけるパーティションは100個が上限なので、何回かに分けてCTASをする必要がある

今回のケースにおいては、こうしたデータ作成を月に1回行っています。

# エラーが起きるとどういう状態になるか
2通りに分かれます

エラーの種類自体は様々ですが、エラーメッセージにかかわらず「成功しなかった」時点でこれらの確認は必要となろうかと思います。

## 1レコードも入らない
ファイル作成自体が失敗しているケースです。
この場合、単純に再実行をすればよいので楽ですね。

## 中途半端にINSERTされる
運用を始めて数ヵ月して観測しました。
エラーメッセージを見るとそういうケースがありそうな記述はあるのですが、それまでエラーになっても「1レコードも入らない」しか体験したことがなかったので、このケースの対応も考えることとなりました。

この手の運用のチェックとして「xxxレコード以上入ったらOK」という方法だけを取ってしまうと、チェックがすり抜けることとなります。もちろん、そのような事故が起きた訳ではありませんが「ほんの少しだけ欠損する」というケースがあるため「なんだ入ってるじゃん、このまま行こう」などと誘惑に負けてはなりません。ステータスが失敗になっている以上、失敗なのでやり直すべきです。



# 対応方法
2021.04時点では、AthenaのCTASを利用すると、作成されたParquetファイル名の頭に「YYYYMMDD_HHMMSS」といった作成日時（っぽいもの）が入ります。また、当然s3に作成されたファイルのタイムスタンプがあります。
これらを利用して、対象ファイルを削除していきます。


## 基本方針
エラーメッセージを見ると

```
If a data manifest file was generated at 's3://xxxxxxxxxxx/result/xxxxxxxxxx.csv', 
you may need to manually clean the data from locations specified in the manifest. 
Athena will not delete data in your account.
```
とあるので、この通りにやれば良いは良いはずです。
ただAWS側から「手動で消してね」と言われている以上、こちらの責任として諸々確認をしたい気持ちになります。

## 対象データを実際に確認する
CTASをしようとしてエラーになったテーブルのデータの状況を確認します。
今回のケースでは月次の作業となるため、YYYY-MM に注目して影響調査をしています。

### 対象パーティションが明確な場合
以下の通り直接そのパーティションにlsとgrepをします。
（もちろん、grepなしで事前にlsをしていますが記事上は割愛）

```
aws s3 ls s3://valuesccg-example-bucket/athena/data/tablename/partitionkey=aaaa/ |grep 2021-03

2021-03-02 10:52    124711   s3://valuesccg-example-bucket/athena/data/tablename/partitionkey=aaaa/20210302_105142_00026_3pshx_032aa1ba-db43-45a1-8733-18ebd2fde5a8
2021-03-02 10:52    118498   s3://valuesccg-example-bucket/athena/data/tablename/partitionkey=aaaa/20210302_105142_00026_3pshx_11e4b164-e334-4c4d-8bcd-6140a0aac2d8
2021-03-02 10:52    114402   s3://valuesccg-example-bucket/athena/data/tablename/partitionkey=aaaa/20210302_105142_00026_3pshx_1a83aa8a-facb-49aa-a54c-2b816e9e6626
...
```

この時「エラーになったのにデータが作成されている！」という状況であれば、消す必要があります。


### 対象パーティションが不明確な場合
こっちをやれば前述のものを兼ねるのでこっちだけやれば良い説はありますが、たとえば3個のCTASのうち1個だけ失敗、というケースにおいては他2つの結果は返ってきてしまうので、両方やるとリカバリのミスを減らせると思います。

```
aws s3 ls s3://valuesccg-example-bucket/athena/data/tablename/ --recursive |grep 2021-03

※結果割愛
```


## 対象ファイルを消す

さて、実際に消していくのですが、マニフェストファイル（xxxxx-manifest.csv）の中身は、対象ファイル名が羅列されています。
単純な方法として、マニフェストファイルの頭に aws s3 rm をつけたり、ファイル自体を読み込んで aws s3 rm をしていくスクリプトを書く形になるかと思います。
しかし、これが1000個とか10000個になってくると、結構時間がかかります。

そこで、上記の確認をそのまま削除条件にしてしまえばよいわけで、以下の通りのコマンドで消しに行きます。ファイル名に日時があるので、簡単に対象を指定することができます。

```
#aws s3 rm s3://valuesccg-example-bucket/athena/data/tablename/partitionkey=aaaa/ --exclude "*" --include "*20210302_*" --recursive --dryrun
```

もちろん --dryrun をつけて、事前に対象ファイルを確認しましょう。

そして、--dryrunをして確認したファイルの数と、マニフェストのレコード数が一致していたら、より安心して消しにいくことができます（より確実にするには、整形してソートをしてdiffをとるとよいと思います）。



# 雑感
知った当初は（たまたまか）エラーが少なかったこともあり便利でCTASを多用していたのですが、こうしたエラーの確率に振り回されてしまうほか、スキャンが発生するため結構お金もかかります。デメリットというかトレードオフというか。

というわけで今後はCTASを用いない方法へと切り替えていこうかなと考えています。