【AWS】Athenaで1日の使用量の閾値を超えたらSlackに通知する流れ

# 概要
AWS Athenaを利用して、S3にあるELBのアクセスログを調査するとき、スキャンするデータ量が多すぎると予期しないコストが発生してしまうかもしれません。
Athenaでは、クエリごとのデータ制限と1日の閾値を設定できるので、その方法を紹介いたします。

## 準備手順
Athenaの準備手順は以下を参考にしてください。

https://dev.classmethod.jp/articles/application-load-balancer-athena-202306/


基本的には、S3、ELBのアクセス設定に問題がなければ、
ワークグループを作成し、その中にデータベースを作成、これで準備OKです。
あとはクエリ実行するだけです。

## アラート設定方法

Athenaは、「実行したクエリでスキャンされたデータに対してのみ支払う」という課金体系です。
「USD 5.00 per TB of data scanned」
とあります。

ただし、「クエリごとに最小 10 MB が課金されます」とあるので、10MB未満は10MBとして扱われるよう。

https://aws.amazon.com/jp/athena/pricing/


閾値については、ワークグループごとに
①クエリデータ使用状況コントロールごとに管理
②ワークグループデータの使用状況アラート
の２つの観点で設定ができます。

それぞれ、ワークグループの編集画面から設定ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/5557d648-0349-534b-80aa-65da112084da.png)

「①クエリデータ使用状況コントロールごとに管理」については、
1クエリにおける「スキャンされたデータ」の制限値です。
例えば1GBとしておけば、1クエリで1GB以上をスキャンすると「スキャンしたバイト数が制限を超えました」というメッセージがコンソール上に表示され、クエリがキャンセルされるようになっています。

「②ワークグループデータの使用状況アラート」については、
1分、1時間、1日などの単位で、使用した合計量の閾値です。
例えば1日の利用閾値を5GBとしておけば、5GB以上を合計でスキャンしているとアラートが出るようになります。

このアラートは、SNSトピックにプッシュされるものです（コンソール上に表示されるものではない）。
SNSトピックのサブスクリプションの設定からEメール向けに発信することも可能ですし、Lambdaに向けて発信することでSlack通知を行うことも可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2710373/e9462654-1416-518a-482c-3462333484e2.png)

メールの場合は、上記「プロトコル」で「Eメール」を選択し、メールアドレスを入力するだけです。
Slackの指定チャンネルに飛ばしたい場合は、以下の設定を行います。

## Slackの指定チャンネルに飛ばす方法
1. SlackのIncoming Webhookから該当のSlackチャンネルを指定し、「Incoming Webhookインテグレーションの追加」をクリック
2. Lambda関数を作成。以下のコードを貼り付ける。ランタイムはPython3.12。Roleは適切な権限のものを指定
3. SNSトピック作成、そのサブスクリプションでプロトコルをAWS Lambdaにして、上記で作成したものを指定
4. Athenaの「ワークグループデータの使用状況アラート」で上記で作成したSNSトピックを指定

```py
#!/usr/bin/python3.12
import urllib3
import json

http = urllib3.PoolManager()

def handler(event, context):
    url = "https://hooks.slack.com/services/xxxxxxxxx"
    sns_message = event['Records'][0]['Sns']['Message']
    
    message = {
        "text": sns_message
    }
    
    response = http.request(
        "POST",
        url,
        body=json.dumps(message).encode('utf-8'),
        headers={'Content-Type': 'application/json'}
    )
    
    return {
        'statusCode': response.status,
        'body': response.data.decode('utf-8')
    }
```

これにより、指定のSlackチャンネルへ通知を飛ばすことができました。
結果は以下のような形です。

> {"AlarmName":"AWS_Athena_Workgroup_sample-alb_xxxxxxxx","AlarmDescription":null,"AWSAccountId":"01234567890","AlarmConfigurationUpdatedTimestamp":"2024-11-05T06:12:13.083+0000","NewStateValue":"ALARM","NewStateReason":"Threshold Crossed: 1 out of the last 1 datapoints [5732139.0 (05/11/24 06:46:00)] was greater than the threshold (1024.0) (minimum 1 datapoint for OK -> ALARM transition).","StateChangeTime":"2024-11-05T06:47:56.757+0000","Region":"Asia Pacific (Tokyo)","AlarmArn":"arn:aws:cloudwatch:ap-northeast-1:01234567890:alarm:AWS_Athena_Workgroup_sample-alb_xxxxxxxx","OldStateValue":"OK","OKActions":[],"AlarmActions":["arn:aws:sns:ap-northeast-1:01234567890:sample-athena"],"InsufficientDataActions":[],"Trigger":{"MetricName":"ProcessedBytes","Namespace":"AWS/Athena","StatisticType":"Statistic","Statistic":"SUM","Unit":null,"Dimensions":[{"value":"sample-alb","name":"WorkGroup"}],"Period":60,"EvaluationPeriods":1,"DatapointsToAlarm":1,"ComparisonOperator":"GreaterThanThreshold","Threshold":1024.0,"TreatMissingData":"notBreaching","EvaluateLowSampleCountPercentile":""}}