- ๋งค์ผ ์ต๋ 500๊ฑด์ ์ด๋ฉ์ผ ๋๋ ๋ฐ์ก ํ์
- ์ด๋ฉ์ผ๋น ํ๊ท ํฌ๊ธฐ๋ 100KB ์์
- ์ด๋ฉ์ผ ๋ฐ์ก ์ง์ฐ ์๊ฐ์ 5๋ถ ์ด๋ด
- ๋ฐ์ก ์คํจ ์ฒ๋ฆฌ: ์คํจํ ์ด๋ฉ์ผ์ ๋ํ ์๋ ์ฌ์๋ ๋ก์ง (์ต๋ 3ํ)
- ๊ตฌ๋ ๊ด๋ฆฌ: ์ฌ์ฉ์๋ณ ์ด๋ฉ์ผ ์์ ์ค์ ๋ฐ ๊ตฌ๋ ํด์ง ๊ธฐ๋ฅ
- ์คํธ ๋ฐฉ์ง: SES์ SPF๋ฅผ ํตํ ๋๋ฉ์ธ ์ธ์ฆ
- ๋ฌด์ ์ฌ ๋ง์ผํ ์ง์ A์จ๊ฐ ๊ณ ๊ฐ 200๋ช ์๊ฒ ๋ง์ถคํ ํ๋ณด ์ด๋ฉ์ผ ์ ์ก
๋ฐ์ธ์ | ๊น์ง์ | ๋ฐ๊ฐ์ | ์ด๋์ค | ์ ํ์ | ํฉ๊ท๋ฆฌ |
---|---|---|---|---|---|
eonpark | JiwonKim08 | ParkIsComing | dongjune8931 | Junghs21 | gyuuuuri |
Lambda
- 15๋ถ์ Lambda ์คํ ์๊ฐ์ ์ ์ฝ ๋ฐ์
- but, Serverless ํ๊ฒฝ์ ์ฅ์ ์ ์ฌ์ฉํ๊ณ ์ถ์
- StepFunction ๋์
StepFunction
- Map์ ์ฌ์ฉํด ๋์ผํ ์ํฌํ๋ก์ฐ(์: Lambda ํจ์ ํธ์ถ)๋ฅผ ๋ณ๋ ฌ๋ก ์คํ
- ์ ์ฒด ์คํ์๊ฐ์ ๋จ์ถ & ๋ณต์กํ ๋ฐ๋ณต ๋ก์ง์ ๊ฐ๊ฒฐํ๊ฒ ์ฒ๋ฆฌ
- ์ด๋ฉ์ผ์ด ๋์ด๋ ์๋ก ์ฒ๋ฆฌ์๋ ์์น
Email Verification(sandbox)
- SES Sandbox๋ก ์ธํด '์ผ์ผ ์ต๋ 200๊ฐ๋ผ๋ ํ๋', '์ธ์ฆ๋ ์ด๋ฉ์ผ๋ก๋ง ์ ์ก' ๋ค๋ก ์ธํด ํ๋ก์ ํธ ๋ชฉ์ ๋ฌ์ฑ์ ์ ์ฝ ๋ฐ์
- ์๋๋ฐ์ค ํด์ ํ์ฌ ๋ฌธ์ ํด๊ฒฐ
- ํ๋ก๋์ ํ๊ฒฝ์ผ๋ก ์ ํ๋์ด ์์ ์์ ์ฃผ์ ๋๋ ๋๋ฉ์ธ์ด ํ์ธ๋์๋์ง ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ชจ๋ ์์ ์์๊ฒ ์ด๋ฉ์ผ์ ๋ณด๋ผ ์ ์์
- ์ผ์ผ ์ต๋ 200๊ฐ ๋ฆฌ๋ฐ ๋ฒ์ด๋จ.
- Request production access์ ํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ด์ฉ์ ์์ฑํด์ ์ ์ฒญ
- ๋ฉ์ผ ๋ฐ์ก ๋ชฉ๋ก์ ์ด๋ป๊ฒ ์์ฑํ๊ฑฐ๋ ๋ง๋ค ๊ณํ
- ๋ฐ์ก ๋ฉ์ผ๊ณผ ์์ ๊ฑฐ๋ถ๋ฅผ ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊ณํ
- ์์ ์๊ฐ ๊ทํ๊ฐ ๋ณด๋ด๋ ์ด๋ฉ์ผ์ ์์ ๊ฑฐ๋ถํ๋ ๋ฐฉ๋ฒ
- ์ด ์์ฒญ์์ ๊ทํ๊ฐ ์ง์ ํ ์ก์ ๋ฅ ๋๋ ๋ฐ์ ํ ๋น๋
DynamoDB
- ํ์๋ค ๋ชจ๋ RDS๋ฅผ ์ฌ์ฉํด๋ณธ ๊ฒฝํ์ด ์์ผ๋ฏ๋ก ์๋ก์ด DB์ธ NoSQL์ ์ฌ์ฉํ๊ณ ์ ์ ํํจ
- ์์ ๊ด๋ฆฌํ ์๋น์ค์ด๋ฏ๋ก ์ด์ ๋ถ๋ด์ด ๋ฐ์ํ์ง ์์
- key-value ํํ์ด๋ฏ๋ก READ ์๋๊ฐ ๋น ๋ฆ
- ๋ฐ์ดํฐ ์์ด ๋์ด๋๋ฉด ์๋ฒ๋ฅผ ์ฆ์คํ๋ ์ํ์ ํ์ฅ์ ํตํด ์ฑ๋ฅ ์ ์ง ๊ฐ๋ฅ
- ์ค์ ์ด๋ฉ์ผ์ sandbox๋ฅผ ํด์ ํ์ง ์๋ ์ด์ AWS ๊ณ์ ๋น ๋ฉ์ผ 200๊ฐ๋ง์ ๋ณด๋ผ ์ ์๊ธฐ์, ์คํ ์์๋ 200๊ฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ํจ
- DynamoDB์ ์๋ ์ ์ฒด ์ ์ 200๋ช ์๊ฒ ์ด๋ฉ์ผ์ ๋ณด๋ธ๋ค๊ณ ๊ฐ์
- Lambda(1)์์ dynamoDB๋ก๋ถํฐ 10๋ช ์ ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ด
- ๊ทธ ํ Lambda(2)๋ฅผ ํธ์ถํด 10๋ช ์ ์ ์ payload์ ํ ํ๋ฆฟ ์ ๋ณด๋ฅผ SQS๋ก ์ ๋ฌ (*SQS๋ฅผ ๊ฑฐ์น๋ ์ด์ ๋ ์ด๋ฉ์ผ ๋๋ฝ์ ๋ง๊ธฐ ์ํจ)
- Lambda(3)์์ 10๋ช ์ ์ ์ payload๋ฅผ ๊ฐ์ ธ์ ํ ํ๋ฆฟ์ ์ฝ์ ํ์ฌ ์ด๋ฉ์ผ์ ์์ฑํ ํ, SES๋ก ์ด๋ฉ์ผ์ ์ ์ก
- 200๊ฐ์ ์ด๋ฉ์ผ์ ์ ์กํ๊ธฐ ์ํด ์ ๊ณผ์ ์ 20๋ฒ ๋ฐ๋ณต (10*20 = 200๊ฐ์ ์ด๋ฉ์ผ)
AWS SES(Amazon Simple Email Service)๋ ๋๋์ผ๋ก ์ด๋ฉ์ผ์ ์ ์กํ ์ ์๋ ํด๋ผ์ฐ๋ ์ด๋ฉ์ผ ์๋น์ค ๊ณต๊ธ์
- ๋น์ฉ ํจ์จ์ฑ: ์ฌ์ฉํ ๋งํผ๋ง ๋น์ฉ์ ์ง๋ถํ์ฌ ๊ฒฝ์ ์
- ์๋ ์ค์ผ์ผ๋ง: ์ด๋ฉ์ผ ๋ฐ์ก ํฌ๊ธฐ๊ฐ ์๋์ผ๋ก ์ค์ผ์ผ๋ง๋์ด ์ ์ฐํ๊ฒ ๋์
- ์์ธํ ๋ก๊ทธ์ ๋ณด๊ณ ์: ์ ์ก๋ ์ด๋ฉ์ผ์ ๋ํ ์์ธํ ๋ก๊ทธ์ ๋ณด๊ณ ์๋ฅผ ์ ๊ณตํ์ฌ, ๋ค๋ฅธ ์๋น์ค์ ๊ธฐ์ค๊ฐ์ผ๋ก ํ์ฉ ๊ฐ๋ฅ
-
๋๋ฉ์ธ ๊ตฌ๋งค: ๊ฐ๋น์์์ ๋๋ฉ์ธ์ ๊ตฌ๋งคํ์ฌ ์ฌ์ฉ
-
DKIM ์ธ์ฆ: SES์์ ์ ๊ณตํ๋ **DKIM(DomainKeys Identified Mail)**์ CNAME ๋ ์ฝ๋๋ฅผ ๊ฐ๋น์์ ๋๋ฉ์ธ DNS ์ค์ ์ ์ถ๊ฐ
๋ชฉ์ : ์ด๋ฉ์ผ ์ ์ก ์, ๋๋ฉ์ธ์ด ์ค์ ๋ก ๋ด ๊ฒ์์ ์ฆ๋ช ํ๊ณ , ์ด๋ฉ์ผ์ด ์คํธ์ผ๋ก ๋ถ๋ฅ๋๋ ๊ฒ์ ๋ฐฉ์ง
StepFunction ๋ด Lambda ๋ณ ๊ธฐ๋ฅ ๋ฐ Input/Output
Lambda(1) | Lambda(2) | Lambda(3) | |
---|---|---|---|
๋ชฉ์ | ์ ์ ๋ฆฌ์คํธ n๊ฐ์ฉ ๊ฐ์ ธ์ด | payload๋ฅผ ํ๋ก n๊ฐ์ฉ ์ ์ก | SQS์์ SES๋ก ์ด๋ฉ์ผ ์ ์ก |
Input | ์ ์ ๋ฆฌ์คํธ chunk (ํฌ๊ธฐ: n๊ฐ) (DynamoDB์์ ์ ์ ๋ฐ์ดํฐ ๋ช ๊ฐ ์ฝ์ด์ฌ ์ง) | ์ ์ ๋ฆฌ์คํธ ๋ฐ์ดํฐ (DynamoDB์์ ๊บผ๋ด์จ ์ ๋ณด) | ์ ์ payload ๋ฆฌ์คํธ n๊ฐ ๋ฐฐ์น |
Output | 1. ์ ์ ๋ฆฌ์คํธ chunk (DynamoDB์์ ๊บผ๋ด์จ ์ ๋ณด = name, email, gender, isscribing) 2. ํ ํ๋ฆฟ ์ ๋ณด | ์ ์ payload ๋ฆฌ์คํธ n๊ฐ ๋ฐฐ์น (name, email, subject, body) | ๋ฉ์ผ ์์ฑ๋ณธ (ํ ํ๋ฆฟ์ ์ ์ payload ์ฝ์ + ๊ตฌ๋ ์ทจ์๋งํฌ ์ฝ์ + S3์์ ๊ฐ์ ธ์จ ์ด๋ฏธ์ง ์ฝ์ ) |
Output
{
"result": {
"Payload": [
{
"Gender": "Male",
"SubscriptionStatus": true,
"Email": "[email protected]",
"Name": "chulsu"
},
.
. (์๋ต)
.
{
"Gender": "Female",
"SubscriptionStatus": "true",
"Email": "[email protected]",
"Name": "Karen Young"
},
],
"LastEvaluatedKey": {
"Email": "[email protected]"
}
}
- 10๊ฐ์ ์ ์ ๋ฐ์ดํฐ output์ map#1~map#10์ ํด๋น
- ๋ค๊ณ ์จ ๋ง์ง๋ง ๋ฐ์ดํฐ๋ฅผ LastEvaluatedKey ๋ก ์ ์ฅ
Input | Output |
{ "Gender": "Female", "SubscriptionStatus": "true", "Email": "[email protected]", "Name": "chulsu" } |
{ "statusCode": 200, "body": { "template": { "subject": "ํ์ํฉ๋๋ค!", "body": "<title>{{Subject}}</title> |
- Lambda(2)์ ์ ํฌ๋ฉง์ map#1๋ง์ ์๋ฏธ
- Step Functions์ Map ํน์ฑ์, ๋๋จธ์ง map#2~map#10๋ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋๊ณ ์์
โ SES์ ์ ์ฅํด ๋ ํ
ํ๋ฆฟ์ ๊ฐ์ ธ์ Lambda(3)๋ก ์ฎ๊น
โ Lambda(3)๋ก ์ด๋ ์ SQS ๊ฑฐ์นจ
- ๋ฉ์ผ ์์ฑ๋ณธ์ SES๋ก ์ ๋ฌ
-> S3์ผ๋ก๋ถํฐ ์ด๋ฏธ์ง ์ฝ์
-> ๊ตฌ๋
์ทจ์ ๋งํฌ ์ฝ์
{
"StartAt": "Lambda (1)",
"States": {
"Lambda (1)": {
"Type": "Task",
"Resource": "arn:aws:lambda:ap-northeast-2:008971651769:function:GetUserData10",
"ResultPath": "$.result",
"Next": "Map"
},
"Map": {
"Type": "Map",
"ItemsPath": "$.result.Payload",
"MaxConcurrency": 10,
"ItemProcessor": {
"ProcessorConfig": {
"Mode": "INLINE"
},
"StartAt": "Lambda(2)",
"States": {
"Lambda(2)": {
"Type": "Task",
"Resource": "arn:aws:lambda:ap-northeast-2:008971651769:function:EmailQueuer_update",
"Next": "Lambda (3)"
},
"Lambda (3)": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"OutputPath": "$.Payload",
"Parameters": {
"Payload.$": "$",
"FunctionName": "arn:aws:lambda:ap-northeast-2:008971651769:function:email_pra"
},
"Retry": [
{
"ErrorEquals": [
"Lambda.ServiceException",
"Lambda.AWSLambdaException",
"Lambda.SdkClientException",
"Lambda.TooManyRequestsException"
],
"IntervalSeconds": 1,
"MaxAttempts": 3,
"BackoffRate": 2
}
],
"End": true
}
}
},
"Next": "CheckForMoreData",
"ResultPath": "$.results_test"
},
"CheckForMoreData": {
"Type": "Choice",
"Choices": [
{
"Variable": "$.result.LastEvaluatedKey",
"IsPresent": true,
"Next": "UpdateLastEvaluatedKey"
}
],
"Default": "Finish"
},
"UpdateLastEvaluatedKey": {
"Type": "Pass",
"Parameters": {
"LastEvaluatedKey.$": "$.result.LastEvaluatedKey"
},
"ResultPath": "$.meta",
"Next": "Lambda (1)"
},
"Finish": {
"Type": "Succeed"
}
}
}
- 50๊ฐ์ ์ด๋ฉ์ผ์ ๋ณด๋ด๋๋ฐ ์ด 21์ด ๊ฑธ๋ฆผ
- ์ด๋ฅผ ํ๊ท ์ผ๋ก ๊ณ์ฐํ๋ฉด 5๋ถ ๋์ ๋ณด๋ผ ์ ์๋ ์ด๋ฉ์ผ์ ๊ฐ์๋ 750๊ฐ
- Lambda ํจ์์์ SES์ ๋ฏธ๋ฆฌ ์ฌ๋ ค๋์ ํ ํ๋ฆฟ์ ๊ฐ์ ธ์ค๋ ์ฝ๋์์ ๋๋ฌด ๋ง์ API ์์ฒญ์ผ๋ก ์ธํด Throttling์ด ๋ฐ์ โ ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฒ์์๋ง SES์์ ํ ํ๋ฆฟ์ ๊ฐ์ ธ์์ ElastiCache์ ๋ฃ์ด ์ฌ์ฉํ๋ ํ์์ผ๋ก ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ ํจ
- ์ ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ํ ์ด๋ธ
Partition key
- Email(String)
- ์ ์ ์ด๋ฉ์ผ ์ฃผ์๋ฅผ ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉ
Attributes
- Name(String)
- ์ ์ ์ด๋ฆ์ ์ ์ฅํ๊ธฐ ์ํด ์ฌ์ฉ
- Gender(String)
- ํด๋น ์ ์ ์ ์ฑ๋ณ์ ์ ์ฅ
- CreateTime(์ซ์)
- ํ์๊ฐ์ ์๊ฐ ์ ์ฅ
- SubscriptionStatus(๋ถ์ธ)
- ๊ตฌ๋ ์ํ๋ฅผ ์ ์ฅ
- ์ด๋ฉ์ผ ํ ํ๋ฆฟ๊ณผ ์ฌ์ฉํ๋ ์ด๋ฏธ์ง๋ค์ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํ ํ ์ด๋ธ
Partition key
- TemplateID(String)
- ์ด๋ฉ์ผ ํ ํ๋ฆฟ์ ๊ณ ์ ํ๊ฒ ์๋ณํ TemplateID
Attributes
- ImageURLs(List)
- ํด๋น ํ ํ๋ฆฟ์ด๋ ๋งคํํ, s3์ ์ ์ฅ๋ ํด๋น ์ด๋ฏธ์ง ์ฃผ์
- TemplateName(String)
- ์ด๋ฉ์ผ ํ ํ๋ฆฟ ์ฌ์ฉ ์ฉ๋๋ฅผ ๊ฐ๋ตํ๊ฒ ์ ์ฅํ๊ธฐ ์ํ ์ฉ๋
- ์๋น์ค ์ด์ DB๋ก ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๊ณ ๊ฐ์ ํ๊ณ , ์ด๋ฉ์ผ ๋๋ ๋ฐ์ก์ ์ํด์๋ ์ด๋ฉ์ผ ๋ณด๋ผ ์ ์ ์ ์ ๋ณด(์ด๋ฆ, ์ด๋ฉ์ผ, ์ฑ๋ณ ๋ฑ)๋ฅผ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ธ์์ผ ํจ
- ๋ค๋ฅธ ํ ์ด๋ธ๊ณผ์ join ์์ ์ด ํ์ํ์ง ์๊ธฐ ๋๋ฌธ์ ๋งค๋ฒ ์ด์ DB์ ์ ์ํ์ฌ ๋ฉ์ผ์ ๋ฐ์กํ ์ ์ ์ ๋ณด๋ฅผ ์ฝ์ด์ค๊ธฐ ๋ณด๋ค๋ ๋น ๋ฅธ Read ์์ ์ด ๊ฐ๋ฅํ DynamoDB์ ์ ์ ์ ๋ณด๋ฅผ ๋๊ณ , ๋ฉ์ผ์ ๋ฐ์กํ ๋ DynamoDB์์ ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ด
- ์ฃผ๊ธฐ์ ์ผ๋ก ์ด์ DB์์ ๋ณ๋๋ ์ ์ ์ ๋ณด๋ฅผ DynamoDB์ ์ ๋ฐ์ดํธํจ์ผ๋ก์จ ๋ฐ์ดํฐ๋ฅผ ๋์ผํ๊ฒ ์ ์งํจ
- ์ฐธ๊ณ ) ์ด์ DB๊ฐ RDS์์ MySQL DB๋ฅผ ํ์ฉํ๊ณ ์๋ค๊ณ ๊ฐ์
- ์ด๊ธฐ์๋ RDS์ ์ ์ฅ๋ ์ ์ ์ ๋ณด๋ฅผ S3๋ฅผ ๊ฑฐ์ณ DynamoDB์ ๊ฐ์ ธ์ด
- ์ ์ ์ ๋ณด๊ฐ ๋ง์ ๊ฒฝ์ฐ์ ๋๋นํด RDS์์ DynamoDB๋ก ํ๋ฒ์ ๋ฐ์ดํฐ๋ฅผ ์ฎ๊ธฐ์ง ์๊ณ , ๋ฐ์ดํฐ๋ฅผ ์ฌ๋ฌ ์์ ๋ฉ์ด๋ฆฌ๋ก ๋ถํ ํ์ฌ ๋๋์ด ์ ์ฅ
- ์ด์ DB์์ ์ ์ ์ ๋ณด๊ฐ ์ถ๊ฐ, ๋ณ๊ฒฝ๋๋ฉด์ DynamoDB์ ๋ฐ์ดํฐ์ ๋ฌ๋ผ์ง๋ฉด ์ฃผ๊ธฐ์ ์ธ polling์ ํตํด ์ด๋ฅผ ์ ๋ฐ์ดํธ ํด์ค์ผ ํจ
- ์ด๋ฉ์ผ ๋ฐ์ก์ ๊ฒฝ์ฐ, ์ค์๊ฐ ๋๊ธฐํ๊ฐ ํ์ํ์ง ์๊ณ ๋ฐ์ก ์๊ฐ์ ๊ธฐ์ค์ผ๋ก ๋๊ธฐํ๊ฐ ๋์ด ์์ผ๋ฉด ๋๊ธฐ ๋๋ฌธ์ cronjob์ ์ฃผ๊ธฐ์ ์ธ ๋๊ธฐํ๊ฐ ์ด๋ฃจ์ด์ง๋๋ก ์ค์
๋จ๊ณ
- ๋ฐฐ์น ์์
์ค์
- ์ผ์ ์๊ฐ ๊ฐ๊ฒฉ(์: ๋งค ์๊ฐ, ๋งค์ผ)์ผ๋ก ์คํ๋๋ ๋ฐฐ์น ์์ ์ ์ค์
- ๋ฐฐ์น ์์
์คํ
- EC2 ์ธ์คํด์ค์์ ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐฐ์น ์คํฌ๋ฆฝํธ๋ฅผ ์คํ
- ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ ์ถ์
- MySQL์
TIMESTAMP
ํ์ ์ ์ด์ฉํ๋ฉด ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ ๋ฐ ์์ ๋ ๋ ์๋์ผ๋กTIMESTAMP
ํ๋๊ฐ ์ ๋ฐ์ดํธ ๋จ - ์ ์ ํ
์ด๋ธ์
update_at
ํ๋๋ฅผTIMESTAMP
ํ์ ์ผ๋ก ์ค์ ํ์ฌ ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ฅผ ์ถ์ ํจ
- MySQL์
- ๋ฐ์ดํฐ ๋๊ธฐํ
- ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ DynamoDB์ ๋ฐ์ํจ. ์ดํ์๋ ์ฃผ๊ธฐ์ ์ผ๋ก 2~4๋ฒ ๊ณผ์ ์ด ์คํ๋จ