์ ๋ก ์ฝ๋ผ, ์ ๋ก ๋งฅ์ฃผ ๊ทธ๋ฆฌ๊ณ ์ ๋ก ETL : DynamoDB์ OpenSearch Zero-ETL ๋ฐ์ดํฐ ๋ณํ์ ํ ๋ฒ์
- 2024๋ 6์ 18์ผ
- 3๋ถ ๋ถ๋
์ต์ข ์์ ์ผ: 2024๋ 6์ 18์ผ
์ ๋ก ์ฝ๋ผ, ์ ๋ก ๋งฅ์ฃผ ๊ทธ๋ฆฌ๊ณ ์ ๋ก ETL: DynamoDB์ OpenSearch Zero-ETL๋ก ๋ฐ์ดํฐ ๋ณํ์ ํ ๋ฒ์

Written by Hyejin Jeon
์๋ ํ์ธ์, ์ค๋ง์ผ์คํฌ์ ์ ํ์ง์ ๋๋ค.
AWS์ Zero-ETL ๊ธฐ๋ฅ์ด 2023๋ 11์ ์ ์ ์ถ์๋์์ต๋๋ค. ์ ๋ก ์ฝ๋ผ, ์ ๋ก ๋งฅ์ฃผ์ ์ด์ด๊ฒฐ๊ตญ Zero-ETL๋ ์ถ์๋์๋ค์..
์ค๋์ Zero-ETL ๊ธฐ๋ฅ์ด ๋ฌด์์ธ์ง ์ดํด๋ณด๊ณ , ์ผ๋ง๋ ํธ๋ฆฌํ๊ณ ๊ฐ๋จํ๊ฒ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๋์ง ์ง์ ์ค์ต์ผ๋ก ์์๋ณด๊ฒ ์ต๋๋ค.
Zero-ETL์ด๋

์๋ฅผ ๋ค์ด, ๊ณ ๊ฐ ์ฃผ๋ฌธ ๋ฐ์ดํฐ๋ฅผ Aurora MySQL ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ ์์ต๋๋ค.
์ด ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ์ฌ ํ๋งค ๋ํฅ์ ํ์ ํ๊ณ , ์ฌ๊ณ ๊ด๋ฆฌ๋ ๋ง์ผํ ์ ๋ต์ ์ธ์ฐ๊ธฐ ์ํด ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค ์๋น์ค์ธ Amazon Redshift๋ก ๋ฐ์ดํฐ๋ฅผ ์ฎ๊ฒจ์ผ ํ๋๋ฐ์,
๊ธฐ์กด์๋ DMS, Glue์ ๊ฐ์ ์๋น์ค๋ฅผ ์ฐ๋ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํ๊ณ ๋ฐ์ดํฐ ํ์์ ๋ณํํ๊ณ Redshift์ ๋ก๋ํด์ผ ํ์ต๋๋ค.
Zero-ETL์ ์ด๋ฌํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ถํ์ง ์๊ฑฐ๋ ์ต์ํํ๋ ํ๋ก์ธ์ค์ ๋๋ค.
AWS๊ฐ ๋ฐ์ดํฐ ๋ณํ ๋ฐ ๋ก๋๋ฅผ ์๋์ผ๋ก ๊ด๋ฆฌํ์ฌ ๋ณ๋์ ETL ๊ณผ์ ์ด ํ์ํ์ง ์๊ณ ๊ทธ๋งํผ ๋ฐ์ดํฐ๋ฅผ ๊ฑฐ์ ์ค์๊ฐ์ผ๋ก Redshift๋ก ์ด๋ํ ์ ์์ต๋๋ค.
Zero-ETL์ ์ฌ์ฉํ๋ ๋น์ฉ์ ๋ฌด๋ฃ์ด๊ณ , ๋ฐ์ดํฐ ํํฐ๋ง์ด๋ผ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋ฉด ํ์ํ ํ ์ด๋ธ๋ง ๋ถ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด๋ณด๋ค ํจ์ฌ ๋น์ฉ์ ์ ๊ฐํ ์ ์์ต๋๋ค.
DynamoDB์ OpenSearch์ Zero-ETL
Aurora์ Redshift๋ฟ๋ง ์๋๋ผ DynamoDB์ Amazon OpenSearch ๊ฐ์ Zero-ETL๋ ๊ฐ๋ฅํฉ๋๋ค.
DynamoDB๋ ์์ ๊ด๋ฆฌํ NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค ์๋น์ค๋ก ์ฃผ๋ก ์ค์๊ฐ ํธ๋์ญ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
๊ฐ๊ฒฉ ๋๋น ์ฑ๋ฅ์ด ์ข์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ด์ง๋ง ๋ฐ์ดํฐ ๊ฒ์ ์ฟผ๋ฆฌ๋ฅผ ์ ๊ณตํ์ง๋ ์์์ ์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด OpenSearch ์๋น์ค์ ์ฐ๋ํ์ฌ ์ฌ์ฉํ๋๋ฐ์,
OpenSearch๋ Elasticsearch์ ํธํ๋๋ ๊ฒ์ ๋ฐ ๋ถ์ ์์ง์ผ๋ก ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ค์๊ฐ ๋ก๊ทธ ๋ถ์, ๋ชจ๋ํฐ๋ง, ์น์ฌ์ดํธ ๊ฒ์์ด ๊ฐ๋ฅํฉ๋๋ค.

๊ธฐ์กด์๋ DynamoDB ํ ์ด๋ธ์ ๋ณ๊ฒฝ ์ฌํญ์ OpenSearch๋ก ์คํธ๋ฆฌ๋ฐํ๊ธฐ ์ํด AWS Lambda์ ๋ก์ง์ ์ง์ ์ฝ๋ฉํ์ฌ ๋ฐ์ดํฐ ํ์ดํ๋ผ์ธ์ ์ค์ ํด์ผ ํ์ต๋๋ค.
ํ์ฌ๋ OpenSearch Ingestion ํ์ดํ๋ผ์ธ์ ํตํด ์๋ํ๋ ๋ฐ์ดํฐ ๋๊ธฐํ ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋ ์๋น์ค๋ฅผ ์ฐ๋ํด์ DynamoDB์ ์คํธ๋ฆผ ๋ฐ์ดํฐ๋ฅผ OpenSearch๋ก ์ค์๊ฐ ์ ์กํด ๋ณด๊ฒ ์ต๋๋ค.
Zero-ETL ํ์ดํ๋ผ์ธ ๊ตฌ์ถ ์ค์ต
1. ์ ์ ์กฐ๊ฑด
1. S3 ๋ฒํท ์์ฑ
2. OpenSearch ๋๋ฉ์ธ ์์ฑ - ๋งํฌย ๋ฅผ ์ฐธ๊ณ ํ์ฌ DynamoDB์ ์ฐ๋ํ OpenSearch ๋๋ฉ์ธ์ ์์ฑํฉ๋๋ค.

3. ๋ค์๊ณผ ๊ฐ์ IAM ์ญํ ์ ์์ฑํฉ๋๋ค.
2. DynamoDB ํ ์ด๋ธ ์์ฑ
1. DynamoDB ํ ์ด๋ธ์ ์์ฑํฉ๋๋ค. ํน์ ์์ ๋ณต๊ตฌ(PITR) ๋ฐ DynamoDB ์คํธ๋ฆผ์ ํ์ฑํํฉ๋๋ค.
2. ํ์ด์ฌ์ ์ฌ์ฉํด ProductCatalog ํ ์ด๋ธ์ ํ ์คํธ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํฉ๋๋ค. (์๋ ํ์ด์ฌ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ๋ ค๋ฉด boto3๋ฅผ ์ค์นํ๊ณ AWS CLI ์๊ฒฉ์ฆ๋ช ์ด ์ค์ ๋์ด์ผ ํฉ๋๋ค.)
import boto 3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('productCatalog')
def batch_write(items):
with table.batch_writer() as batch:
for item in items:
batch.put_item(Item=item)
items = [
{
"Id": 101,
"๋์๋ช
": "To Kill a Mockingbird",
"๋์๋ฒํธ": "978-0061120084",
"์ ์": "Harper Lee",
"๊ฐ๊ฒฉ": 12000
},
{
"Id": 102,
"๋์๋ช
": "1984",
"๋์๋ฒํธ": "978-0451524935",
"์ ์": "George Orwell",
"๊ฐ๊ฒฉ": 15000
},
{
"Id": 103,
"๋์๋ช
": "The Great Gatsby",
"๋์๋ฒํธ": "978-0743273565",
"์ ์": "F. Scott Fitzgerald",
"๊ฐ๊ฒฉ": 20000
}
]
batch_write(items)3. Zero-ETL ํ์ดํ๋ผ์ธ ์์ฑ
1. DynamoDB - [ํตํฉ] - ProductCatalog ํ ์ด๋ธ ์ ํ - [์์ฑ]์ ํด๋ฆญํฉ๋๋ค.
![DynamoDB - [ํตํฉ] - ProductCatalog ํ
์ด๋ธ ์ ํ - [์์ฑ]](https://static.wixstatic.com/media/3aac70_f0ae5d035eee439c953946abaa34a17a~mv2.png/v1/fill/w_49,h_16,al_c,q_85,usm_0.66_1.00_0.01,blur_2,enc_avif,quality_auto/3aac70_f0ae5d035eee439c953946abaa34a17a~mv2.png)
2. ์ ์ผ ์ค์ํ ๋ถ๋ถ์ ์ด ํ์ดํ๋ผ์ธ ๊ตฌ์ฑ ํ ํ๋ฆฟ ์์ฑ์ ๋๋ค.
๋ชจ๋ ํ์ดํ๋ผ์ธ ์ค์ ์ ์ด ํ๋์ ํ ํ๋ฆฟ์ ํตํด ์ด๋ฃจ์ด์ง๋๋ฐ์, ๋ฆฌ์์ค ARN ๋ฑ์ ํ์๊ฐ์ ์ ๋ ฅํ๊ณ [ํ์ดํ๋ผ์ธ ๊ฒ์ฆ]์ ํตํด์ ๊ตฌ์ฑ์ด ์ ํจํ์ง ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์์ต๋๋ค.

์๋๋ ์์ฑํด์ผ ํ๋ ํ์๊ฐ๊ณผ ๊ทธ์ ๋ํ ์ค๋ช ์ ๋๋ค. (๋ํ ์ผํ ์ค์ ์ ์ฃผ์์ REQUIRED๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.)
version: "2"
dynamodb-pipeline:
source:
dynamodb:
acknowledgments: true
tables:
# DynamoDB ํ
์ด๋ธ ARN ์
๋ ฅ
- table_arn: "<<arn:aws:dynamodb:us-east-1:123456789012:table/MyTable>>"
stream:
start_position: "LATEST"
export:
# ์์ฑํ S3 ๋ฒํท๋ช
s3_bucket: "<<my-bucket>>"
# S3 ๋ฒํท์ ๋ฆฌ์
s3_region: "<<us-east-1>>"
s3_prefix: "ddb-to-opensearch-export/"
aws:
# ์์ฑํ IAM ์ญํ (dynamodb, s3 ์ก์ธ์ค ๊ถํ)
sts_role_arn: "<<arn:aws:iam::123456789012:role/Example-Role>>"
# AWS ๊ณ์ ๋ฆฌ์
region: "<<us-east-1>>"
sink:
- opensearch:
# OpenSearch ๋๋ฉ์ธ ์๋ํฌ์ธํธ(IPv4)
hosts: [ "<<https://search-mydomain-1a2a3a4a5a6a7a8a9a0a9a8a7a.us-east-1.es.amazonaws.com>>" ]
index: "table-index"
index_type: custom
document_id: "${getMetadata(\"primary_key\")}"
action: "${getMetadata(\"opensearch_action\")}"
document_version: "${getMetadata(\"document_version\")}"
document_version_type: "external"
aws:
# IAM ์ญํ (๋๋ฉ์ธ์ ๋ํ ์ก์ธ์ค ๊ถํ)
sts_role_arn: "<<arn:aws:iam::123456789012:role/Example-Role>>"
# ์์ฑํ ๋๋ฉ์ธ ๋ฆฌ์
region: "<<us-east-1>>"
serverless: false
# S3 DLQ๋ฅผ ํ์ฑํํ์ฌ ์คํจํ ์์ฒญ์ ์บก์ฒ
dlq:
s3:
# S3 ๋ฒํท๋ช
bucket: "<<your-dlq-bucket-name>>"
# ๋ฒํท ๋ฆฌ์
region: "<<us-east-1>>"
# S3 ์ก์ธ์ค ๊ถํ์ด ๋ถ์ฌ๋ IAM ์ญํ
sts_role_arn: "<<arn:aws:iam::123456789012:role/Example-Role>>"3. (์ฐธ๊ณ ) ํ์ดํ๋ผ์ธ์ ์ํ๊ฐ ํ์ฑํ๋๊ณ ๋ฐ์ดํฐ ์์ง์ ์์ํ๋ฉด S3 ๋ฒํท์ ddb-to-opensearch-export ์ ๋์ฌ ํด๋๋ฅผ ์์ฑํ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.

4. OpenSearch ๋์๋ณด๋๋ฅผ ํตํด ๋ฐ์ดํฐ ์ฟผ๋ฆฌ
1. ์์ฑํ ํ์ดํ๋ผ์ธ์ OpenSearch ๋์๋ณด๋ URL๋ก ์ ์ํฉ๋๋ค.

2. OpenSearch์ ํ์ดํ๋ผ์ธ์ ๊ตฌ์ฑํ ๋ ProductCatalogย ํ ์ด๋ธ์ table-index๋ผ๋ ์ธ๋ฑ์ค๋ก ์ค์ ํ์ต๋๋ค. OpenSearch ๋์๋ณด๋์ Dev Toolย ํ๋ฉด์์ ์ด ์ธ๋ฑ์ค ํ ์ด๋ธ๋ก GET ์์ฒญ์ ๋ณด๋ด๋ฉด โGeroge Orwellโ์ด๋ผ๋ โ์ ์โ ํ๋์ ์ผ์นํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค.

๋ง๋ฌด๋ฆฌ
์ค์ต๋์์ ๋ฐ์ํ OpenSearch ์๋ฒ๋ฆฌ์ค์ ๋น์ฉ์ ๊ณ ๋ คํ๋ฉด ๋ฐ์ดํฐ ๊ท๋ชจ๊ฐ ์๋นํ ์ปค์ผ ๋น์ฉ ํจ์จ์ ์ธ ์๋ฃจ์ ์ ์ฌ์ฉํ ์ ์์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์์ต๋๋ค.
๋ค๋ง, ์ด๋ฒ ํฌ์คํ ์์๋ 2023๋ 11์์ ์ถ์๋ Zero-ETL ๊ธฐ๋ฅ์ ์ด๋ป๊ฒ ๊ตฌ์ถํ๋์ง ์์๋ณด์๊ณ , ๋ถํ์ํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ณผ์ ์์ด ๋ฐ์ดํฐ ์ธ์ฌ์ดํธ๋ฅผ ๋์ถํ ์ ์๊ธฐ ๋๋ฌธ์ ์ด ๊ธฐ๋ฅ์ ํตํด ์๋ก์ด Use case ๋ค์ด ๋ง๋ค์ด์ง ์ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
AWS์ ๋ค์ํ Zero-ETL ๊ธฐ๋ฅ์ ๋ํด ์์๋ณด์๋ ค๋ฉด ๋งํฌ๋ฅผ, DynamoDB์ OpenSearch์ ํ์ดํ๋ผ์ธ์ ๋ํ ์์ธํ ๋ด์ฉ์ ๊ณต์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด ์ฃผ์ธ์.





