透過 AWS Athena 查詢 DynamoDB
我們公司習慣將 VPC 的流量日誌放置在 S3 中,並透過 Athena 生成網路流量的報告。前陣子我接到一個需求,一樣是生成網路流量的報告,但需要串額外串聯儲存在 DynamoDB 中的資料。起初我打算寫支程式將 DynamoDB 上的資料匯入到 S3、建立 Schema 後再用 Athena 做關聯查詢。結果 AI 告訴我 Athena 本身就支援跨來源查詢,所以可以直接查詢 DynamoDB 中的資料,只是需要做一些設定。
我還真的不知道有這一招,所以開始查看文件並與 AI 討論該如何實作。
想要查詢 DynamoDB 上的資料,就需要透過 AWS Athena 的 Federated Query(聯合查詢) 功能,透過 Lambda Connector 作為橋接層,Connector 會將外部資料萃取出來後放置於 S3,最後讓 Athena 進行查詢。
整個架構如下:
flowchart TD
User([使用者送出 SQL 查詢]) --> Workgroup["Athena Workgroup<br/>(執行 SQL,結果存到 S3)"]
Workgroup --> Catalog["Athena Data Catalog<br/>(FEDERATED 類型,橋接 DynamoDB)"]
Catalog --> Lambda["Lambda Connector<br/>(由 SAR 部署,實際呼叫 DynamoDB API)"]
Lambda --> DynamoDB[("DynamoDB Tables<br/>(原始資料來源)")]
Lambda -.-> SpillBucket[("S3 Spill Bucket<br/>(溢出暫存,超過 Lambda 記憶體時使用)")]- 使用者對 Athena Workgroup 送出 SQL 查詢
- Athena 辨識出這是 Federated Catalog,呼叫對應的 Lambda Connector
- Lambda Connector 呼叫 DynamoDB API 取得資料
- 若資料量超過 Lambda 記憶體上限,多餘的資料會先溢出到 Spill S3 Bucket
- 查詢結果回傳給 Athena,最終寫入 Query Results S3 Bucket
- 使用者可從 Athena Console 或 API 取得結果
元件說明
| 元件 | 名稱 | 用途 |
|---|---|---|
| S3 Bucket | athena-dynamodb-connector-spill-bucket-* | Connector Lambda 的溢出暫存桶 |
| S3 Bucket | athena-query-results-* | Athena 查詢結果存放處 |
| CloudFormation Stack | athena-dynamodb-connector | 透過 SAR 部署 Lambda Connector |
| Lambda Function | 由 SAR Stack 建立 | 實際執行 DynamoDB 查詢的核心元件 |
| Athena Data Catalog | dynamodb-connector-catalog | FEDERATED 類型的資料目錄 |
| Glue Catalog Database | dynamodb_database | DynamoDB 表格的 schema metadata 管理 |
| Athena Workgroup | dynamodb-workgroup | 執行查詢的工作群組,指定結果輸出位置 |
使用 Terraform 部署
上述提到的元件都可以使用 Terraform 來部署。
Provider 設定
provider "aws" {
region = "us-west-2"
default_tags {
tags = {
Environment = "Test"
Owner = "Allen Chiang"
Project = "QueryDynamoDBWithAthena"
}
}
}透過 default_tags 統一幫所有資源打上標籤,方便成本管理與資源識別。
S3 Spill Bucket
resource "random_string" "spill_bucket_suffix" {
length = 4
upper = false
special = false
numeric = false
}
resource "aws_s3_bucket" "athena_dynamodb_connector_spill_bucket" {
bucket = "athena-dynamodb-connector-spill-bucket-${random_string.spill_bucket_suffix.result}"
}S3 Bucket 名稱必須全球唯一,因此用 random_string 加上後綴避免命名衝突。
Spill Bucket 是 Athena Federated Query 的必要元件:當 Lambda Connector 處理的資料量超過其記憶體限制時,多餘的資料會先溢出到這個 Bucket,Athena 再從這裡讀取合併。
部署 Athena DynamoDB Connector
data "aws_serverlessapplicationrepository_application" "athena_dynamodb_connector" {
application_id = "arn:aws:serverlessrepo:us-east-1:292517598671:applications/AthenaDynamoDBConnector"
}
resource "aws_serverlessapplicationrepository_cloudformation_stack" "athena_dynamodb_connector" {
name = "athena-dynamodb-connector"
application_id = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.application_id
semantic_version = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.semantic_version
capabilities = data.aws_serverlessapplicationrepository_application.athena_dynamodb_connector.required_capabilities
parameters = {
AthenaCatalogName = "dynamodb-connector-catalog"
SpillBucket = aws_s3_bucket.athena_dynamodb_connector_spill_bucket.bucket
}
}AWS 在 Serverless Application Repository(SAR)上提供了官方的 AthenaDynamoDBConnector。這裡用 data source 取得最新版本資訊,再透過 CloudFormation Stack 部署。
AthenaCatalogName:指定 Connector 對應的 Athena Data Catalog 名稱,必須與後面建立的 Catalog 同名,且只能使用小寫SpillBucket:指定溢出資料的暫存 Bucketcapabilities:CloudFormation Stack 需要CAPABILITY_IAM和CAPABILITY_RESOURCE_POLICY才能建立 IAM Role 和資源策略
若想要在 Console 中手動部署 DynamoDB Connector,步驟如下:
- 進入 Serverless Application Repository → Available applications
- 勾選
Show apps that create custom IAM roles or resource policies - 搜尋
AthenaDynamoDBConnector並選擇 - 填入
AthenaCatalogName和SpillBucket等參數 - 勾選同意建立對應的 IAM Role 與 Policy,並點擊 Deploy
Athena Data Catalog(Lambda)
resource "aws_athena_data_catalog" "dynamodb" {
depends_on = [aws_serverlessapplicationrepository_cloudformation_stack.athena_dynamodb_connector]
name = "dynamodb-connector-catalog"
description = "Athena data source for querying DynamoDB via federated query"
type = "LAMBDA"
parameters = {
function = "arn:aws:lambda:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:function:dynamodb-connector-catalog"
}
}建立一個 LAMBDA 類型的 Athena Data Catalog。
type = "LAMBDA"告訴 Athena 這個 Catalog 要透過 Lambda Connector 存取外部資料來源name必須與 CloudFormation Stack 中的AthenaCatalogName相同depends_on確保 Lambda Connector 先部署完成才建立 Catalog- Data Catalog 名稱不可使用保留字:
awsdatacatalog、hive、jmx、system
Query Results Bucket 與 Workgroup
resource "aws_s3_bucket" "athena_query_results" {
bucket = "athena-query-results-${random_string.spill_bucket_suffix.result}"
}
resource "aws_athena_workgroup" "dynamodb" {
name = "dynamodb-workgroup"
configuration {
result_configuration {
output_location = "s3://${aws_s3_bucket.athena_query_results.bucket}/results/"
}
}
}Athena Workgroup 是執行查詢的邏輯單位,可以控制查詢的輸出位置、掃描資料量上限等設定。這裡指定查詢結果存到專用的 S3 Bucket。
最後我們使用 Terraform 部署資源:
terraform init
terraform plan
terraform apply部署完成後,AWS 上會建立好所有元件,我們就可以開始使用 Athena 查詢 DynamoDB 了。
基本查詢
在 Athena Console 選擇 dynamodb-workgroup Workgroup,查詢時需同時指定 Federated Catalog、Database 和 Table:
SELECT *
FROM "dynamodb-connector-catalog"."default"."my_table"
LIMIT 100;功能限制
使用 AthenaDynamoDBConnector 時需注意以下限制:
- 不支援寫入操作:
INSERT INTO、UPDATE、DELETE均不支援,僅能執行SELECT - 欄位大小寫:若搭配 Lake Formation 使用,只能識別全小寫的 Table 和 Column 名稱
費用考量
這個架構會產生以下費用:
- Athena 查詢費用:每次查詢依掃描的資料量計費
- Lambda 執行費用:每次查詢都會觸發 Lambda Connector
- S3 儲存與請求費用:Spill Bucket 和 Query Results Bucket 的存取費用
- DynamoDB 讀取費用:Scan 操作會消耗大量 RCU,對 Provisioned Throughput 表格影響尤其顯著
對於正式環境,建議:
- 設定 Athena Workgroup 的
bytes_scanned_cutoff_per_query限制單次查詢掃描量上限 - 定期清理 Spill Bucket 和 Query Results Bucket 中的舊資料
- 如果 DynamoDB 的資料量很大,請評估是否需要將 DynamoDB 資料匯出到 S3 + Glue,改用 Athena 直接查 Parquet,成本會更低
小結
透過 Athena Federated Query + AthenaDynamoDBConnector,可以用熟悉的 SQL 語法查詢 DynamoDB,適合以下場景:
- 臨時性的資料探索與分析
- 跨 DynamoDB 表格的聯合查詢
- 搭配 Glue 其他資料來源做跨系統 JOIN
- 快速驗證資料內容,不需建立額外的 ETL Pipeline