Amazon Athena のManaging query processing capacityを試してみた

# 背景・目的
4/28に、Amazon Athenaで[Managing query processing capacity](https://aws.amazon.com/about-aws/whats-new/2023/04/amazon-athena-provisioned-capacity/)が発表されましたので、仕様の整理と、簡単に試してみたいと思います。

# まとめ
- プロビジョンドキャパシティを利用することで、事前にキャパシティを確保し、クエリのパフォーマンスを制御が可能
- アカウントとリージョンごとに合計で最大1000DPUまで割り当てが可能。一つのキャパシティでは24 DPU 〜 100DPUまで割り当て可能
- 複数のクエリを処理するDPUは、下記を目安にする。

|Concurrent queries |DPUs required |
|:--|:--|
|10 | 40 |
|20 | 96 |
|30 以上| 240|


# 概要
## Managing query processing capacityとは
- プロビジョンドキャパシティを使用すると、ミッションクリティカルなクエリに専用のコンピューティングを割り当て、クエリの同時実行数やコストなどのワークロードのパフォーマンス特性を制御できる。
- ワークロードの例
    - 多数のクエリを同時に実行しながら、クエリのキューイングが最小限または、全く無いようにする場合
    - 専用のコンピューティングリソースを必要とする優先度が高いワークロードがある場合

### DPU について
キャパシティは、データ処理ユニット（DPU）で測定される。DPUはAthenaが使用するコンピューティングリソースとメモリリソースを指す。1つのリソースは、4vCPUと、16GBメモリを提供する。
このDPUの数により同時に実行できるクエリ数が決まる。（例えば、256 DPUの予約は、128DPUの予約よりも約2倍の数の同時クエリを許可できる。）

- アカウントとリージョンごとに、最大1,000の合計DPUで、最大100のキャパシティ予約を作成可能。
- リクエストできる最小DPUは、24DPU

### 制約事項
主な制約事項を記載します。既に記載しているものは省略しています。詳細は、[Considerations and limitations
](https://docs.aws.amazon.com/athena/latest/ug/capacity-management.html#capacity-management-considerations-limitations)をご確認ください。

- Athenaのエンジンバージョンは3が必要
- キャパシティリクエストは保証されない。完了するまでに最大30分かかる場合がある。
- 最低請求期間は8時間
- 全てのDPUが使用中の場合、送信されたクエリはキューに入れられる。このようなクエリは拒否されず、オンデマンドキャパシティにはならない。

## Determining capacity requirements
キャパシティーの予約を作成する前に、必要なキャパシティーを見積もり、正しい数の DPU を割り当てることができる。 
また、予約が使用された後、予約のキャパシティーが不足または超過していないかどうかを確認する必要がある場合がある。 

### Estimating required capacity
容量要件を見積もるときは、特定のクエリに必要な容量と、一般的に必要な容量の 2 つの観点を考慮すると役立つとのこと。

#### Estimating per-query capacity requirements
クエリに必要な DPU の数を決定するには、下記のガイドラインを使用できます。
- DDL クエリは 4 DPU を消費する。
- 通常、DML クエリは 4 ～ 124 DPU を消費する。

Athena は、クエリが送信されたときに、DML クエリに必要な DPU の数を決定する。 この数は、下記により決まる。
- データ サイズ
- ストレージ形式
- クエリの構築
- その他の要因 

一般に、Athena は、最小で最も効率的な DPU 数を選択しようとする。 Athena は、クエリが正常に完了するにはより多くの計算能力が必要であると判断した場合、クエリに割り当てられる DPU の数を増やす。

#### Estimating workload specific capacity requirements
複数のクエリを同時に実行するために必要な容量を判断するには、次の表の一般的なガイドラインを考慮する。

|Concurrent queries |DPUs required |
|:--|:--|
|10 | 40 |
|20 | 96 |
|30 以上| 240|


- 経験則として、10 個の同時クエリを実行するには、少なくとも 40 個の DPU から始めるとのこと。
20 個の同時クエリの場合は 96 を使用し、30 個以上の同時クエリの場合は 240 DPU の使用を計画するとのこと。
- 実際に必要な DPU の数は、目標と分析パターンによって異なる。たとえば、クエリをキューに入れずにすぐに開始する場合は、ピーク時の同時クエリ需要を特定し、それに応じて DPU の数をプロビジョニングする。
- 固定予算内でクエリを実行することが目標の場合は、AWS 料金計算ツールを使用して、必要な DPU の数を決定できる。
- データ サイズ、ストレージ形式、およびクエリの記述方法が、クエリに必要な DPU に影響する。
    - クエリのパフォーマンスを向上させるために、データを圧縮または分割したり、列形式に変換したりできる。 詳細については、「[Athena でのパフォーマンス チューニング](https://docs.aws.amazon.com/athena/latest/ug/performance-tuning.html)」を参照のこと。

:::note warn
ピーク需要よりも少ない数の DPU をプロビジョニングできるが、ピーク需要が発生するとキューイングが発生する可能性がある。 キューイングが発生すると、Athena はクエリをキューに保持し、容量が利用可能になったときにそれらを実行する。
::: 

### Signs that more capacity is required
:::note warn
Insufficient capacity エラー メッセージとクエリ キューイングは、割り当てられた容量が不十分であることを示している。
:::

容量不足のエラー メッセージでクエリが失敗する場合は、容量予約の DPU カウントがクエリ ワークロードに対して低すぎる可能性がある。 たとえば、24 DPU の予約があり、24 を超える DPU を必要とするクエリを実行すると、クエリは失敗する。
このクエリ エラーを監視するには、Athena の CloudWatch Events を使用できる。 

多くのクエリがキューに入れられている場合、容量が他のクエリによって完全に使用されていることを意味する。 キューイングを減らすには、下記のいずれかを実行するとのこと。

- DPU を予約に追加して、クエリの同時実行数を増やす。
- 予約からワークグループを削除して、他のクエリのために容量を解放する。

過度のクエリ キューイングをチェックするには、キャパシティー予約のワークグループに 「Athena query queue time」CloudWatch メトリクスを使用する。 値が優先しきい値を超えている場合は、DPU をキャパシティー予約に追加できる。

### Checking for idle capacity
アイドル容量を確認するには、予約内の DPU の数を減らすか、そのワークロードを増やして、結果を観察する。

1. 下記のいずれかを実行する
    - 予約内の DPU の数を減らす (使用可能なリソースを減らす)
    - 予約にワークグループを追加する (ワークロードを増やす)
1. CloudWatch を使用して、クエリのキュー時間を測定する
1. 待機時間が想定レベルを超えて増加した場合は、下記のいずれかを実行する。
    - キャパシティー予約に DPU を追加する
    - ワークグループを削除
1. 変更するたびに、パフォーマンスとクエリのキュー時間を確認する
1. ワークロードや DPU 数を調整し続けて、目的のバランスを達成する。

:::note info
希望の時間外にキャパシティーを維持したくない場合は、予約をキャンセルして、後で別の予約を作成できる。 ただし、最近別の予約からキャパシティーをキャンセルした場合でも、新しいキャパシティーのリクエストは保証されず、新しい予約の作成には時間がかかる。
:::

### Tools for assessing capacity requirements and cost
AWS の次のサービスと機能を使用して、Athena の使用状況とコストを測定できる。

#### CloudWatch metrics
クエリ関連のメトリクスをワークグループ レベルで Amazon CloudWatch に発行するように Athena を設定可能。 ワークグループのメトリクスを有効にすると、ワークグループのクエリのメトリクスがワークグループの詳細ページの Athena コンソールに表示される。

#### CloudWatch usage metrics
CloudWatch の使用状況メトリクスを使用して、現在のサービスの使用状況を CloudWatch のグラフとダッシュボードに表示することで、アカウントがリソースをどのように使用しているかを可視化できる。 Athena の場合、使用状況のメトリクスは Athena の AWS サービス クォータに対応する。 使用量がサービス クォータに近づいたときに警告するアラームを構成できる。

#### CloudWatch Events and Amazon EventBridge
CloudWatch で Athena を使用して、クエリの状態に関するリアルタイムの通知を受け取ることができる。送信したクエリの状態が変化すると、Athena は、クエリの状態遷移に関する情報を含むイベントを CloudWatch Events に発行する。 関心のあるイベントの単純なルールを作成し、イベントがルールに一致したときに自動化されたアクションを実行できる。

### Managing reservations
キャパシティー予約ページでキャパシティー予約を表示および管理できる。 DPU の追加または削減、ワークグループ割り当ての変更、予約のタグ付けまたはキャンセルなどの管理タスクを実行できる。

#### Understanding Active DPUs and Target DPUs
Athena コンソールのキャパシティー予約のリストで、予約には 2 つの DPU（アクティブ DPU とターゲット DPU） 値が表示される。
- アクティブな DPU
    - クエリを実行するために予約で使用できる DPU の数。 
    - たとえば、100 DPU を要求し、要求が満たされると、Active DPU には 100 が表示される。
- ターゲット DPU
    - 予約が移動中の DPU の数。 
    - 予約の作成中、または DPU 数の増減が保留中の場合、ターゲット DPU はアクティブ DPU とは異なる値を表示する。

下記に例を記載する。
- たとえば、24 DPU の予約を作成するリクエストを送信した後、予約ステータスは保留中、アクティブ DPU は 0、ターゲット DPU は 24 になる。
- 100 DPU の予約があり、予約を編集して 20 DPU の増加をリクエストした場合、ステータスは更新保留中、アクティブ DPU は 100、ターゲット DPU は 120 になる。
- 100 DPU の予約があり、予約を編集して 20 DPU の削減をリクエストした場合、ステータスは更新保留中になり、アクティブ DPU は 100 になり、ターゲット DPU は 80 になる。

# 実践
## Creating capacity reservations
[Creating capacity reservations](https://docs.aws.amazon.com/athena/latest/ug/capacity-management-creating-capacity-reservations.html)を元に試してみます。

1. Athenaのナビゲーションペインで、「管理＞キャパシティ予約」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/99ec2bbc-e7bf-9b1d-5bb1-d4309ac8a9c7.png)

1. 「キャパシティ予約を作成」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/3f54f3a4-af43-6989-896f-497e54b6bedf.png)

1. キャパシティ予約の名前と、DPUを指定（ここでは、同時クエリ数10を想定し40 DPUとしました。）し、「レビュー」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/52ab2fb9-a4ea-ce00-5774-63a25650ad78.png)

1. ポップアップが表示されるので、「送信」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/cde1bc32-914e-f78c-3d2a-9c719caff9d8.png)

1. 作成直後は、下記のように表示されます。
    - ステータス：保留中
    - Active DPU: 0
    - ターゲットDPU： 40
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/a61cbf3e-db48-1e12-eec6-3ac4c87a86c9.png)

1. しばらくすると、下記のように変わりました。（試したときは、3分程度）
    - ステータス：アクティブ
    - Active DPU: 40
    - ターゲットDPU： 40
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/25a826b6-2942-2afe-75af-d5886e662c79.png)


## ワークグループを追加
1. キャパシティ予約画面で、作成したキャパシティ予約名をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/9a0d269e-180f-ae73-34f6-5e5ffe236ac5.png)

1. 当該キャパシティ予約で、「ワークグループを追加」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/5ad99223-3ee0-7496-c6c3-2116ce34819c.png)

1. チェックボックスにチェックを入れて、「ワークグループを追加」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c7a91444-d764-6fbf-be44-33340dcd7be5.png)

1. ワークグループが追加されました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/3d8976eb-3838-f374-420c-4a94bb172d3e.png)

## 実行確認（１）
プロビジョンドキャパシティの効果を確認するため、定期的にクエリを実行し、Athena query queue timeを確認します。

### Lambdaのプログラムを作成
1. Lambda関数を作成します。
タイムアウト時間を10分に変更します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/89e30380-c349-7d5e-e2ad-cb86ba33ef7f.png)
1.LambdaのIAMポリシーに、Athenaの実行結果を格納するための権限を追加します。
    ```
    {
        "Effect": "Allow",
        "Action": [
            "s3:GetObject",
            "s3:PutObject",
            "s3:ListBucket"
        ],
        "Resource": [
            "arn:aws:s3:::{Athenaの結果バケット}",
            "arn:aws:s3:::{Athenaの結果バケット}/*"
        ]
    }
    ```
1. Athenaの結果を格納するS3バケットのポリシーを修正します。
    ```
    {
        "Effect": "Allow",
        "Principal": {
            "AWS": "arn:aws:iam::アカウント:role/service-role/{LambdaのIAMロール}"
        },
        "Action": [
            "s3:ListBucket",
            "s3:GetObject",
            "s3:GetObjectAcl"
        ],
        "Resource": [
            "arn:aws:s3:::{Athenaの結果バケット}",
            "arn:aws:s3:::{Athenaの結果バケット}/*"
        ]
    }
    ```
1. （オプション）Glueデータカタログについて、顧客管理のCMKで暗号化している場合はキーポリシーを修正します。
1. コードを作成します。起動の都度、クエリを20回実行します。結果の確認等は省略しています。
    ```
    
    import json
    import boto3
    import time
    
    # Function to query using Athena
    def query_athena(query):
        client = boto3.client('athena')
        
        for i in range(20):
            custom_query = query + " where value={0}".format(i)
            response = client.start_query_execution(
                QueryString=custom_query,
                ResultConfiguration={
                    'OutputLocation': 's3://XXXXX/athena/'
                },
                WorkGroup="primary"
            )  
    
    def lambda_handler(event, context):
        
        # call query_athena function
        query_athena("SELECT * FROM crossaccount_access_db.test_table ")
    
        
        # TODO implement
        return {
            'statusCode': 200,
            'body': json.dumps('Hello from Lambda!')
        }
    
    ```
1. トリガー（EventBridge）を作成し、3分おきに実行するよう設定します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e55e710f-6e3e-1258-905a-dce900a174e4.png)

### キューイングの確認
1. CloudWatch Metricsで、AthenaのQueryQueueTimeを確認します。おおよそ600ms〜900msの時間がかかっていました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ba43aabb-8931-3531-f987-45ef15da63a2.png)

## 実行確認（２）
DPUを96に設定し、同時実行クエリ数10→20をさばけるプロビジョンドキャパシティを用意します。

### Athenaのキャパシティ設定を変更

1. Athenaのキャパシティ予約画面で作成します。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/e84433f8-b973-ff51-f9c9-85b9591c5757.png)


1. キャパシティ予約から、「Workgroupsを削除」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/8b467a51-1517-763e-b684-e024934700ad.png)

1. ポップアップが表示されるので、「削除」をクリックします。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/284100db-dd9e-b89a-64e6-6997b07779f2.png)

1. 作成したDPU96のキャパシティで、Workgroupsを紐付けます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/6ec684e3-bfbb-ecc8-1502-a95ff052cfd1.png)

### キューイングの確認
1. CloudWatch Metricsで、AthenaのQueryQueueTimeを確認します。おおよそ300ms程度まで削減されました。キャパシティの変更は、効果がありました。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/da5a04e3-a42a-4f2f-4144-d44430523d99.png)

# 考察
プロビジョンドキャパシティを使用することで、クエリのスループットや性能を制御できます。
今回は、一度に20クエリを実行しキャパシティを増量することで挙動が確認できました。今後は、クエリ単体の性能が向上するか確認したいと思います。

# 参考
https://aws.amazon.com/about-aws/whats-new/2023/04/amazon-athena-provisioned-capacity/

https://docs.aws.amazon.com/athena/latest/ug/capacity-management.html