ํค์ด ํ๋ธ๋ฅด!
๋นํ๊ธฐ ์กฐ์ข ์ ์ข์ํ์๋์? ๋๋ ๊ทธ๊ฒ์ ์ข์ํ์ง๋ง ์๊ฐ ๊ฒฉ๋ฆฌ ์ค์ ์ ์๋ ค์ง ๋ฆฌ์์ค์ธ Aviasales์์ ํญ๊ณต๊ถ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๋ ๊ฒ๋ ์ข์ํ์ต๋๋ค.
์ค๋์ Amazon Kinesis์ ์์ ์ ๋ถ์ํ๊ณ , ์ค์๊ฐ ๋ถ์ ๊ธฐ๋ฅ์ ๊ฐ์ถ ์คํธ๋ฆฌ๋ฐ ์์คํ ์ ๊ตฌ์ถํ๊ณ , Amazon DynamoDB NoSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์คํ ๋ฆฌ์ง๋ก ์ค์นํ๊ณ , ํฅ๋ฏธ๋ก์ด ํฐ์ผ์ ๋ํ SMS ์๋ฆผ์ ์ค์ ํด ๋ณด๊ฒ ์ต๋๋ค.
๋ชจ๋ ์ธ๋ถ ์ฌํญ์ ์ปท ์๋์ ์์ต๋๋ค! ๊ฐ๋ค!
์๊ฐ
์๋ฅผ ๋ค์ด ๋ค์ ํญ๋ชฉ์ ์ก์ธ์คํด์ผ ํฉ๋๋ค.
์ด ๋ฌธ์์ ์ฃผ์ ๋ชฉ์ ์ AWS์์์ ์ ๋ณด ์คํธ๋ฆฌ๋ฐ ์ฌ์ฉ์ ๋ํ ์ผ๋ฐ์ ์ธ ์ดํด๋ฅผ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค. ์ฌ์ฉ๋ API์์ ๋ฐํ๋ ๋ฐ์ดํฐ๋ ์๋ฐํ ๋งํ๋ฉด ์ต์ ์ด ์๋๋ฉฐ ์บ์์์ ์ ์ก๋๋ค๋ ์ ์ ๊ณ ๋ คํฉ๋๋ค. ์ง๋ 48์๊ฐ ๋์ Aviasales.ru ๋ฐ Jetradar.com ์ฌ์ดํธ ์ฌ์ฉ์์ ๊ฒ์์ ๊ธฐ๋ฐ์ผ๋ก ํ์ฑ๋์์ต๋๋ค.
API๋ฅผ ํตํด ์์ ๋ ์์ฐ ๋จธ์ ์ ์ค์น๋ Kinesis-agent๋ Kinesis Data Analytics๋ฅผ ํตํด ์๋์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋ฌธ ๋ถ์ํ๊ณ ์ํ๋ ์คํธ๋ฆผ์ผ๋ก ์ ์กํฉ๋๋ค. ์ด ์คํธ๋ฆผ์ ์์ ๋ฒ์ ์ ์ ์ฅ์์ ์ง์ ๊ธฐ๋ก๋ฉ๋๋ค. DynamoDB์ ๋ฐฐํฌ๋ ์์ ๋ฐ์ดํฐ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ๋ฉด AWS Quick Sight์ ๊ฐ์ BI ๋๊ตฌ๋ฅผ ํตํด ๋ ์ฌ์ธต์ ์ธ ํฐ์ผ ๋ถ์์ด ๊ฐ๋ฅํฉ๋๋ค.
์ ์ฒด ์ธํ๋ผ๋ฅผ ๋ฐฐํฌํ๊ธฐ ์ํ ๋ ๊ฐ์ง ์ต์ ์ ๊ณ ๋ คํด ๋ณด๊ฒ ์ต๋๋ค.
- ์๋ - AWS Management Console์ ํตํด;
- Terraform ์ฝ๋์ ์ธํ๋ผ๋ ๊ฒ์ผ๋ฅธ ์๋ํ๋ฅผ ์ํ ๊ฒ์ ๋๋ค.
๊ฐ๋ฐ๋ ์์คํ ์ ์ํคํ ์ฒ
์ฌ์ฉ๋ ๊ตฌ์ฑ ์์:
ํญ๊ณต์ธ์ผ์ฆ API โ ์ด API์์ ๋ฐํ๋ ๋ฐ์ดํฐ๋ ๋ชจ๋ ํ์ ์์ ์ ์ฌ์ฉ๋ฉ๋๋ค.EC2 ์์ฐ์ ์ธ์คํด์ค โ ์ ๋ ฅ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ด ์์ฑ๋ ํด๋ผ์ฐ๋์ ์ผ๋ฐ ๊ฐ์ ๋จธ์ :ํค๋ค์์ค ์์ด์ ํธ ๋ฐ์ดํฐ๋ฅผ ์์งํ์ฌ Kinesis(Kinesis Data Streams ๋๋ Kinesis Firehose)๋ก ๋ณด๋ด๋ ์ฌ์ด ๋ฐฉ๋ฒ์ ์ ๊ณตํ๋ ๋จธ์ ์ ๋ก์ปฌ๋ก ์ค์น๋ Java ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ์์ด์ ํธ๋ ์ง์ ๋ ๋๋ ํฐ๋ฆฌ์ ํ์ผ ์งํฉ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํ๊ณ ์ ๋ฐ์ดํฐ๋ฅผ Kinesis๋ก ๋ณด๋ ๋๋ค.API ํธ์ถ์ ์คํฌ๋ฆฝํธ โ API์ ์์ฒญํ๊ณ Kinesis ์์ด์ ํธ๊ฐ ๋ชจ๋ํฐ๋งํ๋ ํด๋์ ์๋ต์ ์ ์ฅํ๋ Python ์คํฌ๋ฆฝํธ์ ๋๋ค.
Kinesis ๋ฐ์ดํฐ ์คํธ๋ฆผ โ ๊ด๋ฒ์ํ ํ์ฅ ๊ธฐ๋ฅ์ ๊ฐ์ถ ์ค์๊ฐ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ ์๋น์คํค๋ค์์ค ๋ถ์ ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ ๋ถ์์ ์ค์๊ฐ์ผ๋ก ๋จ์ํํ๋ ์๋ฒ๋ฆฌ์ค ์๋น์ค์ ๋๋ค. Amazon Kinesis Data Analytics๋ ์ ํ๋ฆฌ์ผ์ด์ ๋ฆฌ์์ค๋ฅผ ๊ตฌ์ฑํ๊ณ ๋ชจ๋ ์์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋๋ก ์๋์ผ๋ก ํ์ฅํฉ๋๋ค.AWS ๋๋ค โ ์๋ฒ๋ฅผ ๋ฐฑ์ ํ๊ฑฐ๋ ์ค์ ํ์ง ์๊ณ ๋ ์ฝ๋๋ฅผ ์คํํ ์ ์๋ ์๋น์ค์ ๋๋ค. ๋ชจ๋ ์ปดํจํ ์ฑ๋ฅ์ ๊ฐ ํธ์ถ์ ๋ํด ์๋์ผ๋ก ํ์ฅ๋ฉ๋๋ค.์๋ง์กด DynamoDB - ์ด๋ค ๊ท๋ชจ์์๋ ์คํ ์ 10๋ฐ๋ฆฌ์ด ๋ฏธ๋ง์ ๋๊ธฐ ์๊ฐ์ ์ ๊ณตํ๋ ํค-๊ฐ ์ ๋ฐ ๋ฌธ์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๋ค. DynamoDB๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฒ๋ฅผ ํ๋ก๋น์ ๋, ํจ์น ๋๋ ๊ด๋ฆฌํ ํ์๊ฐ ์์ต๋๋ค. DynamoDB๋ ์๋์ผ๋ก ํ ์ด๋ธ์ ํ์ฅํ์ฌ ์ฌ์ฉ ๊ฐ๋ฅํ ๋ฆฌ์์ค์ ์์ ์กฐ์ ํ๊ณ ๋์ ์ฑ๋ฅ์ ์ ์งํฉ๋๋ค. ์์คํ ๊ด๋ฆฌ๊ฐ ํ์ํ์ง ์์ต๋๋ค.์๋ง์กด SNS - ๊ฒ์์-๊ตฌ๋ ์(Pub/Sub) ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ์์ ๊ด๋ฆฌํ ์๋น์ค๋ก, ์ด๋ฅผ ํตํด ๋ง์ดํฌ๋ก์๋น์ค, ๋ถ์ฐ ์์คํ ๋ฐ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฒฉ๋ฆฌํ ์ ์์ต๋๋ค. SNS๋ ๋ชจ๋ฐ์ผ ํธ์ ์๋ฆผ, SMS ๋ฉ์์ง, ์ด๋ฉ์ผ์ ํตํด ์ต์ข ์ฌ์ฉ์์๊ฒ ์ ๋ณด๋ฅผ ๋ณด๋ด๋ ๋ฐ ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
์ด๊ธฐ ๊ต์ก
๋ฐ์ดํฐ ํ๋ฆ์ ์๋ฎฌ๋ ์ดํธํ๊ธฐ ์ํด Aviasales API์์ ๋ฐํ๋ ํญ๊ณต๊ถ ์ ๋ณด๋ฅผ ์ฌ์ฉํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค. ์์
๊ทธ๋ผ ๋ฑ๋กํ๊ณ ํ ํฐ์ ๋ฐ์๋ด ์๋ค.
์์ฒญ ์์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
http://api.travelpayouts.com/v2/prices/month-matrix?currency=rub&origin=LED&destination=HKT&show_to_affiliates=true&token=TOKEN_API
์์ฒญ์ ํ ํฐ์ ์ง์ ํ์ฌ API์์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ ์์ ๋ฐฉ๋ฒ์ด ์๋ํ์ง๋ง ํค๋๋ฅผ ํตํด ์ก์ธ์ค ํ ํฐ์ ์ ๋ฌํ๋ ๊ฒ์ ์ ํธํ๋ฏ๋ก api_caller.py ์คํฌ๋ฆฝํธ์์ ์ด ๋ฐฉ๋ฒ์ ์ฌ์ฉํ๊ฒ ์ต๋๋ค.
๋ต๋ณ ์์:
{{
"success":true,
"data":[{
"show_to_affiliates":true,
"trip_class":0,
"origin":"LED",
"destination":"HKT",
"depart_date":"2015-10-01",
"return_date":"",
"number_of_changes":1,
"value":29127,
"found_at":"2015-09-24T00:06:12+04:00",
"distance":8015,
"actual":true
}]
}
์์ ์์ API ์๋ต์ ์ํธํํ
๋ฅด๋ถ๋ฅดํฌ์์ ํธํฌ(Phuk)๊น์ง์ ํฐ์ผ์ ๋ณด์ฌ์ค๋๋ค. ์, ๊ฟ์ด๊ตฐ์...
์ ๋ ์นด์ ์ถ์ ์ด๊ณ ํธ์ผ์ ์ด์ "๊ฟ์ผ ๋ฟ"์ด๋ฏ๋ก ์ํธ ํํ
๋ฅด๋ถ๋ฅดํฌ์์ ์นด์๊น์ง์ ํฐ์ผ์ ์ฐพ์ ๋ณด๊ฒ ์ต๋๋ค.
์ด๋ฏธ AWS ๊ณ์ ์ด ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. Kinesis ๋ฐ SMS๋ฅผ ํตํ ์๋ฆผ ์ ์ก์ ์ฐ๊ฐ ์๊ธ์ ํฌํจ๋์ง ์๋๋ค๋ ์ฌ์ค์ ์ฆ์ ํน๋ณํ ๊ด์ฌ์ ๊ธฐ์ธ์ด๊ณ ์ถ์ต๋๋ค.
ํ๋ฆฌ ํฐ์ด(๋ฌด๋ฃ ์ฌ์ฉ) . ๊ทธ๋ฌ๋ ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ๋ช ๋ฌ๋ฌ๋ฅผ ์ผ๋์ ๋๊ณ ์ ์๋ ์์คํ ์ ๊ตฌ์ถํ๊ณ ํ์ฉํ๋ ๊ฒ์ด ๊ฐ๋ฅํฉ๋๋ค. ๋ฌผ๋ก , ๋ ์ด์ ํ์ํ์ง ์์ ๋ชจ๋ ๋ฆฌ์์ค๋ฅผ ์ญ์ ํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
๋คํํ ์๋ณ ๋ฌด๋ฃ ํ๋๋ฅผ ์ถฉ์กฑํ๋ฉด DynamoDb ๋ฐ Lambda ํจ์๊ฐ ๋ฌด๋ฃ๋ก ์ ๊ณต๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด DynamoDB์ ๊ฒฝ์ฐ ์คํ ๋ฆฌ์ง 25GB, WCU/RCU 25๊ฐ, ์ฟผ๋ฆฌ 100์ต ๊ฐ์ ๋๋ค. ๋งค์ ๋ฐฑ๋ง ๊ฑด์ ๋๋ค ํจ์ ํธ์ถ์ด ๊ฐ๋ฅํฉ๋๋ค.
์๋ ์์คํ ๋ฐฐํฌ
Kinesis Data Streams ์ค์
Kinesis Data Streams ์๋น์ค๋ก ์ด๋ํ์ฌ ๊ฐ๊ฐ ์ค๋ ํ๋์ฉ, ๋ ๊ฐ์ ์๋ก์ด ์คํธ๋ฆผ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
์ค๋๋ ๋ฌด์์
๋๊น?
์ค๋๋ Amazon Kinesis ์คํธ๋ฆผ์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์ ์ก ๋จ์์
๋๋ค. ํ ์ธ๊ทธ๋จผํธ๋ 1MB/s์ ์๋๋ก ์
๋ ฅ ๋ฐ์ดํฐ ์ ์ก์ ์ ๊ณตํ๊ณ 2MB/s์ ์๋๋ก ์ถ๋ ฅ ๋ฐ์ดํฐ ์ ์ก์ ์ ๊ณตํฉ๋๋ค. ํ๋์ ์ธ๊ทธ๋จผํธ๋ ์ด๋น ์ต๋ 1000๊ฐ์ PUT ํญ๋ชฉ์ ์ง์ํฉ๋๋ค. ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ฑํ ๋ ํ์ํ ์ธ๊ทธ๋จผํธ ์๋ฅผ ์ง์ ํด์ผ ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ ๊ฐ์ ์ธ๊ทธ๋จผํธ๊ฐ ์๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ์์ฑํ ์ ์์ต๋๋ค. ์ด ๋ฐ์ดํฐ ์คํธ๋ฆผ์ 2MB/s์ ์
๋ ฅ ๋ฐ์ดํฐ ์ ์ก๊ณผ 4MB/s์ ์ถ๋ ฅ ๋ฐ์ดํฐ ์ ์ก์ ์ ๊ณตํ๋ฉฐ ์ด๋น ์ต๋ 2000๊ฐ์ PUT ๋ ์ฝ๋๋ฅผ ์ง์ํฉ๋๋ค.
์คํธ๋ฆผ์ ์ค๋๊ฐ ๋ง์์๋ก ์ฒ๋ฆฌ๋์ด ๋์ด๋ฉ๋๋ค. ์์น์ ์ผ๋ก ์ด๋ ์ค๋๋ฅผ ์ถ๊ฐํ์ฌ ํ๋ฆ์ ํ์ฅํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ํ์ง๋ง ์ค๋๊ฐ ๋ง์์๋ก ๊ฐ๊ฒฉ์ด ๋์์ง๋๋ค. ๊ฐ ์ค๋์ ๋น์ฉ์ ์๊ฐ๋น 1,5์ผํธ์ด๋ฉฐ, PUT ํ์ด๋ก๋ ๋จ์ ๋ฐฑ๋ง ๊ฐ๋น 1.4์ผํธ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค.
์ด๋ฆ์ผ๋ก ์ ์คํธ๋ฆผ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ํญ๊ณต๊ถ, 1๊ฐ์ ์ค๋์ด๋ฉด ์ถฉ๋ถํฉ๋๋ค.
์ด์ ์ด๋ฆ์ด ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. ํน์ ์คํธ๋ฆผ:
์์ฐ์ ์ค์
์์ ์ ๋ถ์ํ๋ ค๋ฉด ์ผ๋ฐ EC2 ์ธ์คํด์ค๋ฅผ ๋ฐ์ดํฐ ์์ฐ์๋ก ์ฌ์ฉํ๋ฉด ์ถฉ๋ถํฉ๋๋ค. ๊ฐ๋ ฅํ๊ณ ๊ฐ๋น์ผ ๊ฐ์ ๋จธ์ ์ผ ํ์๋ ์์ต๋๋ค. ์คํ t2.micro๊ฐ ๊ด์ฐฎ์ ๊ฒ์ ๋๋ค.
์ค์ ์ฐธ๊ณ ์ฌํญ: ์๋ฅผ ๋ค์ด ์ด๋ฏธ์ง(Amazon Linux AMI 2018.03.0)๋ฅผ ์ฌ์ฉํด์ผ ํ๋ฉฐ Kinesis ์์ด์ ํธ๋ฅผ ๋น ๋ฅด๊ฒ ์์ํ๊ธฐ ์ํ ์ค์ ์ด ๋ ์ ์ต๋๋ค.
EC2 ์๋น์ค๋ก ์ด๋ํ์ฌ ์ ๊ฐ์ ๋จธ์ ์ ์์ฑํ๊ณ ํ๋ฆฌ ํฐ์ด์ ํฌํจ๋ t2.micro ์ ํ์ ์ํ๋ AMI๋ฅผ ์ ํํฉ๋๋ค.
์๋ก ์์ฑ๋ ๊ฐ์ ๋จธ์ ์ด Kinesis ์๋น์ค์ ์ํธ ์์ฉํ ์ ์์ผ๋ ค๋ฉด ๊ทธ๋ ๊ฒ ํ ์ ์๋ ๊ถํ์ด ๋ถ์ฌ๋์ด์ผ ํฉ๋๋ค. ์ด๋ฅผ ์ํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ IAM ์ญํ ์ ํ ๋นํ๋ ๊ฒ์
๋๋ค. ๋ฐ๋ผ์ 3๋จ๊ณ: ์ธ์คํด์ค ์ธ๋ถ ์ ๋ณด ๊ตฌ์ฑ ํ๋ฉด์์ ๋ค์์ ์ ํํด์ผ ํฉ๋๋ค. ์ IAM ์ญํ ์์ฑ:
EC2์ ๋ํ IAM ์ญํ ์์ฑ
์ด๋ฆฌ๋ ์ฐฝ์์ EC2์ ๋ํ ์ ์ญํ ์ ์์ฑ ์ค์์ ์ ํํ๊ณ ๊ถํ ์น์
์ผ๋ก ์ด๋ํฉ๋๋ค.
ํ๋ จ ์์ ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฆฌ์์ค ๊ถํ์ ์ธ๋ถ์ ์ผ๋ก ๊ตฌ์ฑํ๋ ๋ณต์กํ ๊ณผ์ ์ ๋ชจ๋ ์ดํด๋ณผ ํ์๊ฐ ์์ผ๋ฏ๋ก Amazon์์ ์ฌ์ ๊ตฌ์ฑ๋ ์ ์ฑ
์ธ AmazonKinesisFullAccess ๋ฐ CloudWatchFullAccess๋ฅผ ์ ํํ๊ฒ ์ต๋๋ค.
์ด ์ญํ ์ ์๋ฏธ ์๋ ์ด๋ฆ์ ์ง์ ํด ๋ณด๊ฒ ์ต๋๋ค(์: EC2-KinesisStreams-FullAccess). ๊ฒฐ๊ณผ๋ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.
์ด ์ ์ญํ ์ ์์ฑํ ํ์๋ ์์ฑ๋ ๊ฐ์ ๋จธ์ ์ธ์คํด์ค์ ์ฐ๊ฒฐํ๋ ๊ฒ์ ์์ง ๋ง์ธ์.
์ด ํ๋ฉด์์๋ ์๋ฌด๊ฒ๋ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ค์ ์ฐฝ์ผ๋ก ๋์ด๊ฐ๋๋ค.
ํ๋ ๋๋ผ์ด๋ธ ์ค์ ๊ณผ ํ๊ทธ๋ฅผ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋ ์ ์์ต๋๋ค(ํ๊ทธ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ง๋ง ์ต์ํ ์ธ์คํด์ค์ ์ด๋ฆ์ ์ง์ ํ๊ณ ํ๊ฒฝ์ ํ์ํ๋ ๊ฒ์ด ์ข์ต๋๋ค).
์ด์ 6๋จ๊ณ: ๋ณด์ ๊ทธ๋ฃน ๊ตฌ์ฑ ํญ์ ์์ต๋๋ค. ์ฌ๊ธฐ์ ์ ๋ณด์ ๊ทธ๋ฃน์ ์์ฑํ๊ฑฐ๋ ๊ธฐ์กด ๋ณด์ ๊ทธ๋ฃน์ ์ง์ ํด์ผ ํฉ๋๋ค. ์ด๋ฅผ ํตํด SSH(ํฌํธ 22)๋ฅผ ํตํด ์ธ์คํด์ค์ ์ฐ๊ฒฐํ ์ ์์ต๋๋ค. ์์ค -> ๋ด IP๋ฅผ ์ ํํ๋ฉด ์ธ์คํด์ค๋ฅผ ์์ํ ์ ์์ต๋๋ค.
์คํ ์ํ๋ก ์ ํ๋์๋ง์ SSH๋ฅผ ํตํด ์ฐ๊ฒฐ์ ์๋ํ ์ ์์ต๋๋ค.
Kinesis ์์ด์ ํธ๋ก ์์ ํ๋ ค๋ฉด ๋จธ์ ์ ์ฑ๊ณต์ ์ผ๋ก ์ฐ๊ฒฐํ ํ ํฐ๋ฏธ๋์ ๋ค์ ๋ช ๋ น์ ์ ๋ ฅํด์ผ ํฉ๋๋ค.
sudo yum -y update
sudo yum install -y python36 python36-pip
sudo /usr/bin/pip-3.6 install --upgrade pip
sudo yum install -y aws-kinesis-agent
API ์๋ต์ ์ ์ฅํ ํด๋๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
sudo mkdir /var/log/airline_tickets
์์ด์ ํธ๋ฅผ ์์ํ๊ธฐ ์ ์ ํด๋น ๊ตฌ์ฑ์ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค.
sudo vim /etc/aws-kinesis/agent.json
Agent.json ํ์ผ์ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ์์ผ ํฉ๋๋ค.
{
"cloudwatch.emitMetrics": true,
"kinesis.endpoint": "",
"firehose.endpoint": "",
"flows": [
{
"filePattern": "/var/log/airline_tickets/*log",
"kinesisStream": "airline_tickets",
"partitionKeyOption": "RANDOM",
"dataProcessingOptions": [
{
"optionName": "CSVTOJSON",
"customFieldNames": ["cost","trip_class","show_to_affiliates",
"return_date","origin","number_of_changes","gate","found_at",
"duration","distance","destination","depart_date","actual","record_id"]
}
]
}
]
}
๊ตฌ์ฑ ํ์ผ์์ ๋ณผ ์ ์๋ฏ์ด ์์ด์ ํธ๋ /var/log/airline_tickets/ ๋๋ ํฐ๋ฆฌ์์ .log ํ์ฅ์๋ฅผ ๊ฐ์ง ํ์ผ์ ๋ชจ๋ํฐ๋งํ๊ณ ๊ตฌ๋ฌธ ๋ถ์ํ ํ Airline_tickets ์คํธ๋ฆผ์ผ๋ก ์ ์กํฉ๋๋ค.
์๋น์ค๋ฅผ ๋ค์ ์์ํ๊ณ ์๋น์ค๊ฐ ์คํ๋๊ณ ์๋์ง ํ์ธํฉ๋๋ค.
sudo service aws-kinesis-agent restart
์ด์ API์์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ Python ์คํฌ๋ฆฝํธ๋ฅผ ๋ค์ด๋ก๋ํด ๋ณด๊ฒ ์ต๋๋ค.
REPO_PATH=https://raw.githubusercontent.com/igorgorbenko/aviasales_kinesis/master/producer
wget $REPO_PATH/api_caller.py -P /home/ec2-user/
wget $REPO_PATH/requirements.txt -P /home/ec2-user/
sudo chmod a+x /home/ec2-user/api_caller.py
sudo /usr/local/bin/pip3 install -r /home/ec2-user/requirements.txt
api_caller.py ์คํฌ๋ฆฝํธ๋ Aviasales์์ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ Kinesis ์์ด์ ํธ๊ฐ ๊ฒ์ํ๋ ๋๋ ํฐ๋ฆฌ์ ์์ ๋ ์๋ต์ ์ ์ฅํฉ๋๋ค. ์ด ์คํฌ๋ฆฝํธ์ ๊ตฌํ์ ๋งค์ฐ ํ์ค์ ์ด๋ฉฐ TicketsApi ํด๋์ค๊ฐ ์์ผ๋ฉฐ ์ด๋ฅผ ํตํด API๋ฅผ ๋น๋๊ธฐ์์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ํ ํฐ๊ณผ ์์ฒญ ๋งค๊ฐ๋ณ์๊ฐ ํฌํจ๋ ํค๋๋ฅผ ์ด ํด๋์ค์ ์ ๋ฌํฉ๋๋ค.
class TicketsApi:
"""Api caller class."""
def __init__(self, headers):
"""Init method."""
self.base_url = BASE_URL
self.headers = headers
async def get_data(self, data):
"""Get the data from API query."""
response_json = {}
async with ClientSession(headers=self.headers) as session:
try:
response = await session.get(self.base_url, data=data)
response.raise_for_status()
LOGGER.info('Response status %s: %s',
self.base_url, response.status)
response_json = await response.json()
except HTTPError as http_err:
LOGGER.error('Oops! HTTP error occurred: %s', str(http_err))
except Exception as err:
LOGGER.error('Oops! An error ocurred: %s', str(err))
return response_json
def prepare_request(api_token):
"""Return the headers and query fot the API request."""
headers = {'X-Access-Token': api_token,
'Accept-Encoding': 'gzip'}
data = FormData()
data.add_field('currency', CURRENCY)
data.add_field('origin', ORIGIN)
data.add_field('destination', DESTINATION)
data.add_field('show_to_affiliates', SHOW_TO_AFFILIATES)
data.add_field('trip_duration', TRIP_DURATION)
return headers, data
async def main():
"""Get run the code."""
if len(sys.argv) != 2:
print('Usage: api_caller.py <your_api_token>')
sys.exit(1)
return
api_token = sys.argv[1]
headers, data = prepare_request(api_token)
api = TicketsApi(headers)
response = await api.get_data(data)
if response.get('success', None):
LOGGER.info('API has returned %s items', len(response['data']))
try:
count_rows = log_maker(response)
LOGGER.info('%s rows have been saved into %s',
count_rows,
TARGET_FILE)
except Exception as e:
LOGGER.error('Oops! Request result was not saved to file. %s',
str(e))
else:
LOGGER.error('Oops! API request was unsuccessful %s!', response)
์์ด์ ํธ์ ์ฌ๋ฐ๋ฅธ ์ค์ ๊ณผ ๊ธฐ๋ฅ์ ํ ์คํธํ๊ธฐ ์ํด api_caller.py ์คํฌ๋ฆฝํธ๋ฅผ ํ ์คํธํด ๋ณด๊ฒ ์ต๋๋ค.
sudo ./api_caller.py TOKEN
๊ทธ๋ฆฌ๊ณ Agent ๋ก๊ทธ์ Airlines_tickets ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋ชจ๋ํฐ๋ง ํญ์์ ์์
๊ฒฐ๊ณผ๋ฅผ ์ดํด๋ด
๋๋ค.
tail -f /var/log/aws-kinesis-agent/aws-kinesis-agent.log
๋ณด์๋ค์ํผ ๋ชจ๋ ๊ฒ์ด ์๋ํ๊ณ Kinesis ์์ด์ ํธ๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์คํธ๋ฆผ์ผ๋ก ๋ณด๋
๋๋ค. ์ด์ ์๋น์๋ฅผ ๊ตฌ์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
Kinesis Data Analytics ์ค์
์ ์ฒด ์์คํ ์ ์ค์ฌ ๊ตฌ์ฑ ์์๋ก ๋์ด๊ฐ์ Kinesis Data Analytics์์ kinesis_analytics_airlines_app์ด๋ผ๋ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
Kinesis Data Analytics๋ฅผ ์ฌ์ฉํ๋ฉด SQL ์ธ์ด๋ฅผ ์ฌ์ฉํ์ฌ Kinesis Streams์์ ์ค์๊ฐ ๋ฐ์ดํฐ ๋ถ์์ ์ํํ ์ ์์ต๋๋ค. Kinesis Streams์ ๋ฌ๋ฆฌ ๋ค์๊ณผ ๊ฐ์ ์์ ์๋ ์กฐ์ ์๋น์ค์
๋๋ค.
- ์์ค ๋ฐ์ดํฐ์ ๋ํ ์์ฒญ์ ๊ธฐ๋ฐ์ผ๋ก ์๋ก์ด ์คํธ๋ฆผ(์ถ๋ ฅ ์คํธ๋ฆผ)์ ์์ฑํ ์ ์์ต๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๋ ๋์ ๋ฐ์ํ ์ค๋ฅ๊ฐ ํฌํจ๋ ์คํธ๋ฆผ์ ์ ๊ณตํฉ๋๋ค(์ค๋ฅ ์คํธ๋ฆผ).
- ์ ๋ ฅ ๋ฐ์ดํฐ ๊ตฌ์ฑํ๋ฅผ ์๋์ผ๋ก ๊ฒฐ์ ํ ์ ์์ต๋๋ค(ํ์ํ ๊ฒฝ์ฐ ์๋์ผ๋ก ์ฌ์ ์ํ ์ ์์).
์์ ์๊ฐ๋น 0.11๋ฌ๋ฌ๋ผ๋ ์ ๋ ดํ ์๋น์ค๊ฐ ์๋๋ฏ๋ก ์ฃผ์ํด์ ์ฌ์ฉํ์๊ณ ์์ ์ด ๋๋๋ฉด ์ญ์ ํ์๊ธฐ ๋ฐ๋๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์ดํฐ ์์ค์ ์ฐ๊ฒฐํด ๋ณด๊ฒ ์ต๋๋ค.
์ฐ๊ฒฐํ ์คํธ๋ฆผ(airline_tickets)์ ์ ํํฉ๋๋ค.
๋ค์์ผ๋ก, ์ ํ๋ฆฌ์ผ์ด์
์ด ์คํธ๋ฆผ์์ ์ฝ๊ณ ์คํธ๋ฆผ์ ์ธ ์ ์๋๋ก ์ IAM ์ญํ ์ ์ฐ๊ฒฐํด์ผ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด ์ก์ธ์ค ๊ถํ ๋ธ๋ก์์ ์๋ฌด๊ฒ๋ ๋ณ๊ฒฝํ์ง ์๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค.
์ด์ ์คํธ๋ฆผ์์ ๋ฐ์ดํฐ ์คํค๋ง ๊ฒ์์ ์์ฒญํด ๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฅผ ์ํํ๋ ค๋ฉด "์คํค๋ง ๊ฒ์" ๋ฒํผ์ ํด๋ฆญํ์ธ์. ๊ฒฐ๊ณผ์ ์ผ๋ก IAM ์ญํ ์ด ์
๋ฐ์ดํธ๋๊ณ (์ ์ญํ ์ด ์์ฑ๋จ) ์คํธ๋ฆผ์ ์ด๋ฏธ ๋์ฐฉํ ๋ฐ์ดํฐ์์ ์คํค๋ง ๊ฐ์ง๊ฐ ์์๋ฉ๋๋ค.
์ด์ SQL ํธ์ง๊ธฐ๋ก ์ด๋ํด์ผ ํฉ๋๋ค. ์ด ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์
์ ์์ํ ๊ฒ์ธ์ง ๋ฌป๋ ์ฐฝ์ด ๋ํ๋ฉ๋๋ค. ์คํํ ํญ๋ชฉ์ ์ ํํ์ธ์.
SQL ํธ์ง๊ธฐ ์ฐฝ์ ๋ค์๊ณผ ๊ฐ์ ๊ฐ๋จํ ์ฟผ๋ฆฌ๋ฅผ ์ฝ์
ํ๊ณ SQL ์ ์ฅ ๋ฐ ์คํ์ ํด๋ฆญํฉ๋๋ค.
CREATE OR REPLACE STREAM "DESTINATION_SQL_STREAM" ("cost" DOUBLE, "gate" VARCHAR(16));
CREATE OR REPLACE PUMP "STREAM_PUMP" AS INSERT INTO "DESTINATION_SQL_STREAM"
SELECT STREAM "cost", "gate"
FROM "SOURCE_SQL_STREAM_001"
WHERE "cost" < 5000
and "gate" = 'Aeroflot';
๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ INSERT ๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ ์ฝ๋๋ฅผ ์ถ๊ฐํ๊ณ SELECT ๋ฌธ์ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฟผ๋ฆฌํ๋ ํ ์ด๋ธ ์์ ์ ์ํํฉ๋๋ค. Amazon Kinesis Data Analytics์์๋ ์คํธ๋ฆผ(STREAM) ๋ฐ ํํ(PUMP), ์ฆ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธ๋ฆผ์์ ๋ค๋ฅธ ์คํธ๋ฆผ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ๋ ์ง์์ ์ธ ์ฝ์ ์์ฒญ์ ์ฌ์ฉํฉ๋๋ค.
์์ ์ ์๋ SQL ์ฟผ๋ฆฌ๋ XNUMX๋ฃจ๋ธ ๋ฏธ๋ง์ ๋น์ฉ์ผ๋ก Aeroflot ํฐ์ผ์ ๊ฒ์ํฉ๋๋ค. ์ด๋ฌํ ์กฐ๊ฑด์ ์ถฉ์กฑํ๋ ๋ชจ๋ ๋ ์ฝ๋๋ DESTINATION_SQL_STREAM ์คํธ๋ฆผ์ ๋ฐฐ์น๋ฉ๋๋ค.
๋์ ๋ธ๋ก์์ Special_stream ์คํธ๋ฆผ์ ์ ํํ๊ณ ์ธ์ ํ๋ฆฌ์ผ์ด์
์คํธ๋ฆผ ์ด๋ฆ DESTINATION_SQL_STREAM ๋๋กญ๋ค์ด ๋ชฉ๋ก์์ ๋ค์์ ์ ํํฉ๋๋ค.
๋ชจ๋ ์กฐ์์ ๊ฒฐ๊ณผ๋ ์๋ ๊ทธ๋ฆผ๊ณผ ์ ์ฌํด์ผ ํฉ๋๋ค.
SNS ์ฃผ์ ์์ฑ ๋ฐ ๊ตฌ๋
๋จ์ ์๋ฆผ ์๋น์ค๋ก ์ด๋ํ์ฌ ๊ฑฐ๊ธฐ์ Airlines๋ผ๋ ์ด๋ฆ์ ์ ์ฃผ์ ๋ฅผ ๋ง๋ญ๋๋ค.
์ด ์ฃผ์ ๋ฅผ ๊ตฌ๋
ํ๊ณ SMS ์๋ฆผ์ ๋ณด๋ผ ํด๋ํฐ ๋ฒํธ๋ฅผ ์ง์ ํ์ธ์.
DynamoDB์์ ํ ์ด๋ธ ์์ฑ
Airlines_tickets ์คํธ๋ฆผ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ธฐ ์ํด DynamoDB์ ๋์ผํ ์ด๋ฆ์ ํ ์ด๋ธ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค. Record_id๋ฅผ ๊ธฐ๋ณธ ํค๋ก ์ฌ์ฉํฉ๋๋ค.
๋๋ค ํจ์ ์์ง๊ธฐ ๋ง๋ค๊ธฐ
Airlines_tickets ์คํธ๋ฆผ์ ํด๋งํ๊ณ ๊ฑฐ๊ธฐ์์ ์ ๋ ์ฝ๋๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ์ด๋ฌํ ๋ ์ฝ๋๋ฅผ DynamoDB ํ ์ด๋ธ์ ์ฝ์ ํ๋ ์์ ์ ์ํํ๋ Collector๋ผ๋ ๋๋ค ํจ์๋ฅผ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค. ๋ถ๋ช ํ ๊ธฐ๋ณธ ๊ถํ ์ธ์๋ ์ด ๋๋ค์๋ Kinesis ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๋ํ ์ฝ๊ธฐ ์ก์ธ์ค ๊ถํ๊ณผ DynamoDB์ ๋ํ ์ฐ๊ธฐ ์ก์ธ์ค ๊ถํ์ด ์์ด์ผ ํฉ๋๋ค.
์์ง๊ธฐ ๋๋ค ํจ์์ ๋ํ IAM ์ญํ ์์ฑ
๋จผ์ Lambda-TicketsProcessingRole์ด๋ผ๋ ๋๋ค์ ๋ํ ์ IAM ์ญํ ์ ์์ฑํด ๋ณด๊ฒ ์ต๋๋ค.
ํ
์คํธ ์์ ๊ฒฝ์ฐ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ์ฌ์ ๊ตฌ์ฑ๋ AmazonKinesisReadOnlyAccess ๋ฐ AmazonDynamoDBFullAccess ์ ์ฑ
์ด ๋งค์ฐ ์ ํฉํฉ๋๋ค.
์ด ๋๋ค๋ ์ ํญ๋ชฉ์ด Airlines_stream์ ์
๋ ฅ๋ ๋ Kinesis์ ํธ๋ฆฌ๊ฑฐ์ ์ํด ์์๋์ด์ผ ํ๋ฏ๋ก ์ ํธ๋ฆฌ๊ฑฐ๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.
๋จ์ ๊ฒ์ ์ฝ๋๋ฅผ ์ฝ์
ํ๊ณ ๋๋ค๋ฅผ ์ ์ฅํ๋ ๊ฒ๋ฟ์
๋๋ค.
"""Parsing the stream and inserting into the DynamoDB table."""
import base64
import json
import boto3
from decimal import Decimal
DYNAMO_DB = boto3.resource('dynamodb')
TABLE_NAME = 'airline_tickets'
class TicketsParser:
"""Parsing info from the Stream."""
def __init__(self, table_name, records):
"""Init method."""
self.table = DYNAMO_DB.Table(table_name)
self.json_data = TicketsParser.get_json_data(records)
@staticmethod
def get_json_data(records):
"""Return deserialized data from the stream."""
decoded_record_data = ([base64.b64decode(record['kinesis']['data'])
for record in records])
json_data = ([json.loads(decoded_record)
for decoded_record in decoded_record_data])
return json_data
@staticmethod
def get_item_from_json(json_item):
"""Pre-process the json data."""
new_item = {
'record_id': json_item.get('record_id'),
'cost': Decimal(json_item.get('cost')),
'trip_class': json_item.get('trip_class'),
'show_to_affiliates': json_item.get('show_to_affiliates'),
'origin': json_item.get('origin'),
'number_of_changes': int(json_item.get('number_of_changes')),
'gate': json_item.get('gate'),
'found_at': json_item.get('found_at'),
'duration': int(json_item.get('duration')),
'distance': int(json_item.get('distance')),
'destination': json_item.get('destination'),
'depart_date': json_item.get('depart_date'),
'actual': json_item.get('actual')
}
return new_item
def run(self):
"""Batch insert into the table."""
with self.table.batch_writer() as batch_writer:
for item in self.json_data:
dynamodb_item = TicketsParser.get_item_from_json(item)
batch_writer.put_item(dynamodb_item)
print('Has been added ', len(self.json_data), 'items')
def lambda_handler(event, context):
"""Parse the stream and insert into the DynamoDB table."""
print('Got event:', event)
parser = TicketsParser(TABLE_NAME, event['Records'])
parser.run()
๋๋ค ํจ์ ์๋ฆฌ๋ฏธ ๋ง๋ค๊ธฐ
๋ ๋ฒ์งธ ์คํธ๋ฆผ(special_stream)์ ๋ชจ๋ํฐ๋งํ๊ณ SNS์ ์๋ฆผ์ ๋ณด๋ด๋ ๋ ๋ฒ์งธ ๋๋ค ํจ์๋ ๋น์ทํ ๋ฐฉ์์ผ๋ก ์์ฑ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ด ๋๋ค์๋ Kinesis์์ ์ฝ๊ณ ํน์ SNS ์ฃผ์ ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ผ ์ ์๋ ์ก์ธ์ค ๊ถํ์ด ์์ด์ผ ํฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ฉ์์ง๋ SNS ์๋น์ค์์ ์ด ์ฃผ์ ์ ๋ชจ๋ ๊ตฌ๋ ์(์ด๋ฉ์ผ, SMS ๋ฑ)์๊ฒ ์ ์ก๋ฉ๋๋ค.
IAM ์ญํ ์์ฑ
๋จผ์ ์ด ๋๋ค์ ๋ํ IAM ์ญํ Lambda-KinesisAlarm์ ์์ฑํ ๋ค์ ์์ฑ ์ค์ธ Alarm_notifier ๋๋ค์ ์ด ์ญํ ์ ํ ๋นํฉ๋๋ค.
์ด ๋๋ค๋ ์ ๋ ์ฝ๋๊ฐ Special_stream์ ์
๋ ฅ๋๋ ํธ๋ฆฌ๊ฑฐ์์ ์๋ํด์ผ ํ๋ฏ๋ก Collector ๋๋ค์์์ ๋์ผํ ๋ฐฉ์์ผ๋ก ํธ๋ฆฌ๊ฑฐ๋ฅผ ๊ตฌ์ฑํด์ผ ํฉ๋๋ค.
์ด ๋๋ค๋ฅผ ๋ ์ฝ๊ฒ ๊ตฌ์ฑํ ์ ์๋๋ก ์๋ก์ด ํ๊ฒฝ ๋ณ์์ธ TOPIC_ARN์ ๋์ ํ๊ฒ ์ต๋๋ค. ์ฌ๊ธฐ์ Airlines ์ฃผ์ ์ ANR(Amazon Recourse Names)์ ๋ฐฐ์นํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋๋ค ์ฝ๋๋ฅผ ์ฝ์
ํ๋ฉด ์ ํ ๋ณต์กํ์ง ์์ต๋๋ค.
import boto3
import base64
import os
SNS_CLIENT = boto3.client('sns')
TOPIC_ARN = os.environ['TOPIC_ARN']
def lambda_handler(event, context):
try:
SNS_CLIENT.publish(TopicArn=TOPIC_ARN,
Message='Hi! I have found an interesting stuff!',
Subject='Airline tickets alarm')
print('Alarm message has been successfully delivered')
except Exception as err:
print('Delivery failure', str(err))
์ฌ๊ธฐ๊น์ง๊ฐ ์๋ ์์คํ ๊ตฌ์ฑ์ด ์๋ฃ๋ ๊ฒ ๊ฐ์ต๋๋ค. ๋จ์ ๊ฒ์ ๋ชจ๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅด๊ฒ ๊ตฌ์ฑ๋์๋์ง ํ ์คํธํ๊ณ ํ์ธํ๋ ๊ฒ์ ๋๋ค.
Terraform ์ฝ๋์์ ๋ฐฐํฌ
ํ์ํ ์ค๋น
๋ฐฐํฌํ์ ๋ค์ด๋ก๋ํ ์ ์์ต๋๋ค.
๋ฌ๋ฆฌ๋ ๋ฐฉ๋ฒ
ํ๋ก์ ํธ์ ์ ์ฒด ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์ข์ ๋ฐฉ๋ฒ์ ์ ์ฒด ์ธํ๋ผ๋ฅผ ๋ฐฐํฌํ๊ธฐ ์ ์ ๊ณํ ๋ช ๋ น์ ์คํํ์ฌ ํ์ฌ ํด๋ผ์ฐ๋์์ Terraform์ด ์์ฑํ๊ณ ์๋ ํญ๋ชฉ์ ํ์ธํ๋ ๊ฒ์ ๋๋ค.
terraform.exe plan
์๋ฆผ์ ๋ณด๋ผ ์ ํ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋ผ๋ ๋ฉ์์ง๊ฐ ํ์๋ฉ๋๋ค. ์ด ๋จ๊ณ์์๋ ์ ๋ ฅํ ํ์๊ฐ ์์ต๋๋ค.
ํ๋ก๊ทธ๋จ ์ด์ ๊ณํ์ ๋ถ์ํ ํ ๋ฆฌ์์ค ์์ฑ์ ์์ํ ์ ์์ต๋๋ค.
terraform.exe apply
์ด ๋ช ๋ น์ ๋ณด๋ธ ํ ๋ค์ ์ ํ๋ฒํธ๋ฅผ ์ ๋ ฅํ๋ผ๋ ๋ฉ์์ง๊ฐ ํ์๋๋ฉฐ, ์ค์ ์์ ์ํ์ ๋ํ ์ง๋ฌธ์ด ํ์๋๋ฉด "์"๋ฅผ ๋๋ฅด์ญ์์ค. ์ด๋ฅผ ํตํด ์ ์ฒด ์ธํ๋ผ๋ฅผ ์ค์ ํ๊ณ , EC2์ ํ์ํ ๋ชจ๋ ๊ตฌ์ฑ์ ์ํํ๊ณ , ๋๋ค ๊ธฐ๋ฅ์ ๋ฐฐํฌํ๋ ๋ฑ์ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
Terraform ์ฝ๋๋ฅผ ํตํด ๋ชจ๋ ๋ฆฌ์์ค๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์์ฑ๋ ํ์๋ Kinesis Analytics ์ ํ๋ฆฌ์ผ์ด์ ์ ์ธ๋ถ ์ ๋ณด๋ก ์ด๋ํด์ผ ํฉ๋๋ค(์ํ๊น๊ฒ๋ ์ฝ๋์์ ์ง์ ์ด ์์ ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ์ฐพ์ง ๋ชปํ์ต๋๋ค).
์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํฉ๋๋ค:
๊ทธ๋ฐ ๋ค์ ๋๋กญ๋ค์ด ๋ชฉ๋ก์์ ์ ํํ์ฌ ์ธ์ ํ๋ฆฌ์ผ์ด์
์คํธ๋ฆผ ์ด๋ฆ์ ๋ช
์์ ์ผ๋ก ์ค์ ํด์ผ ํฉ๋๋ค.
์ด์ ๋ชจ๋ ๊ฒ์ด ์ค๋น๋์์ต๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ํ ์คํธ
์๋์ผ๋ก ๋๋ Terraform ์ฝ๋๋ฅผ ํตํด ์์คํ ์ ๋ฐฐํฌํ ๋ฐฉ๋ฒ์ ๊ด๊ณ์์ด ๋์ผํ๊ฒ ์๋ํฉ๋๋ค.
Kinesis ์์ด์ ํธ๊ฐ ์ค์น๋ EC2 ๊ฐ์ ๋จธ์ ์ SSH๋ฅผ ํตํด ๋ก๊ทธ์ธํ๊ณ api_caller.py ์คํฌ๋ฆฝํธ๋ฅผ ์คํํฉ๋๋ค.
sudo ./api_caller.py TOKEN
๋น์ ์ด ํด์ผ ํ ์ผ์ ๋น์ ์ ์ ํ๋ฒํธ๋ก SMS๊ฐ ์ค๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ๊ฒ ๋ฟ์ ๋๋ค:
SMS - ๊ฑฐ์ 1๋ถ ์์ ๋ฉ์์ง๊ฐ ์ ํ๋ก ๋์ฐฉํฉ๋๋ค.
์ดํ์ ๋ณด๋ค ์์ธํ ๋ถ์์ ์ํด ๋ ์ฝ๋๊ฐ DynamoDB ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋์๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํด์ผ ํฉ๋๋ค. Airlines_tickets ํ
์ด๋ธ์๋ ๋๋ต ๋ค์๊ณผ ๊ฐ์ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋์ด ์์ต๋๋ค.
๊ฒฐ๋ก
์์ ๊ณผ์ ์์ Amazon Kinesis๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์จ๋ผ์ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์์คํ ์ด ๊ตฌ์ถ๋์์ต๋๋ค. Kinesis Data Streams ๋ฐ SQL ๋ช ๋ น์ ์ฌ์ฉํ ์ค์๊ฐ ๋ถ์ Kinesis Analytics์ ํจ๊ป Kinesis ์์ด์ ํธ๋ฅผ ์ฌ์ฉํ๋ ์ต์ ์ ๋ฌผ๋ก Amazon Kinesis์ ๋ค๋ฅธ AWS ์๋น์ค์ ์ํธ ์์ฉ๋ ๊ณ ๋ ค๋์์ต๋๋ค.
์ฐ๋ฆฌ๋ ์ ์์คํ ์ ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๋ฐฐํฌํ์ต๋๋ค. ๋ค์ ๊ธด ์๋ ๋ฐฉ๋ฒ๊ณผ Terraform ์ฝ๋๋ฅผ ์ฌ์ฉํ ๋น ๋ฅธ ๋ฐฉ๋ฒ์ ๋๋ค.
๋ชจ๋ ํ๋ก์ ํธ ์์ค ์ฝ๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค
๊ธฐ์ฌ์ ๋ํด ๋ ผ์ํ๊ฒ ๋ ๊ฒ์ ๊ธฐ์๊ฒ ์๊ฐํ๋ฉฐ ๊ทํ์ ์๊ฒฌ์ ๊ธฐ๋ํฉ๋๋ค. ๊ฑด์ค์ ์ธ ๋นํ์ ๋ฐ๋๋๋ค.
๋ ๋น์ ์๊ฒ ์ฑ๊ณต์ ๊ธฐ์ํฉ๋๋ค!
์ถ์ฒ : habr.com