Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

ํ—ค์ด ํ•˜๋ธŒ๋ฅด!

๋น„ํ–‰๊ธฐ ์กฐ์ข…์„ ์ข‹์•„ํ•˜์‹œ๋‚˜์š”? ๋‚˜๋Š” ๊ทธ๊ฒƒ์„ ์ข‹์•„ํ•˜์ง€๋งŒ ์ž๊ฐ€ ๊ฒฉ๋ฆฌ ์ค‘์— ์ž˜ ์•Œ๋ ค์ง„ ๋ฆฌ์†Œ์Šค์ธ Aviasales์—์„œ ํ•ญ๊ณต๊ถŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์•„ํ–ˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ Amazon Kinesis์˜ ์ž‘์—…์„ ๋ถ„์„ํ•˜๊ณ , ์‹ค์‹œ๊ฐ„ ๋ถ„์„ ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ˜ ์ŠคํŠธ๋ฆฌ๋ฐ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๊ณ , Amazon DynamoDB NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์Šคํ† ๋ฆฌ์ง€๋กœ ์„ค์น˜ํ•˜๊ณ , ํฅ๋ฏธ๋กœ์šด ํ‹ฐ์ผ“์— ๋Œ€ํ•œ SMS ์•Œ๋ฆผ์„ ์„ค์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  ์„ธ๋ถ€ ์‚ฌํ•ญ์€ ์ปท ์•„๋ž˜์— ์žˆ์Šต๋‹ˆ๋‹ค! ๊ฐ€๋‹ค!

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

์†Œ๊ฐœ

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ ํ•ญ๋ชฉ์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ•ญ๊ณต์„ธ์ผ์ฆˆ API. ์ด์— ๋Œ€ํ•œ ์•ก์„ธ์Šค๋Š” ์ œํ•œ ์—†์ด ๋ฌด๋ฃŒ๋กœ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด API ํ† ํฐ์„ ๋ฐ›์œผ๋ ค๋ฉด "๊ฐœ๋ฐœ์ž" ์„น์…˜์— ๋“ฑ๋กํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ๋ฌธ์„œ์˜ ์ฃผ์š” ๋ชฉ์ ์€ AWS์—์„œ์˜ ์ •๋ณด ์ŠคํŠธ๋ฆฌ๋ฐ ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ผ๋ฐ˜์ ์ธ ์ดํ•ด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋œ API์—์„œ ๋ฐ˜ํ™˜๋œ ๋ฐ์ดํ„ฐ๋Š” ์—„๋ฐ€ํžˆ ๋งํ•˜๋ฉด ์ตœ์‹ ์ด ์•„๋‹ˆ๋ฉฐ ์บ์‹œ์—์„œ ์ „์†ก๋œ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•ฉ๋‹ˆ๋‹ค. ์ง€๋‚œ 48์‹œ๊ฐ„ ๋™์•ˆ Aviasales.ru ๋ฐ Jetradar.com ์‚ฌ์ดํŠธ ์‚ฌ์šฉ์ž์˜ ๊ฒ€์ƒ‰์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ˜•์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

API๋ฅผ ํ†ตํ•ด ์ˆ˜์‹ ๋œ ์ƒ์‚ฐ ๋จธ์‹ ์— ์„ค์น˜๋œ Kinesis-agent๋Š” Kinesis Data Analytics๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๊ณ  ์›ํ•˜๋Š” ์ŠคํŠธ๋ฆผ์œผ๋กœ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. ์ด ์ŠคํŠธ๋ฆผ์˜ ์›์‹œ ๋ฒ„์ „์€ ์ €์žฅ์†Œ์— ์ง์ ‘ ๊ธฐ๋ก๋ฉ๋‹ˆ๋‹ค. DynamoDB์— ๋ฐฐํฌ๋œ ์›์‹œ ๋ฐ์ดํ„ฐ ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด AWS Quick Sight์™€ ๊ฐ™์€ BI ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ๋” ์‹ฌ์ธต์ ์ธ ํ‹ฐ์ผ“ ๋ถ„์„์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์ „์ฒด ์ธํ”„๋ผ๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๋‘ ๊ฐ€์ง€ ์˜ต์…˜์„ ๊ณ ๋ คํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ์ˆ˜๋™ - AWS Management Console์„ ํ†ตํ•ด;
  • Terraform ์ฝ”๋“œ์˜ ์ธํ”„๋ผ๋Š” ๊ฒŒ์œผ๋ฅธ ์ž๋™ํ™”๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ๋œ ์‹œ์Šคํ…œ์˜ ์•„ํ‚คํ…์ฒ˜

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์‚ฌ์šฉ๋œ ๊ตฌ์„ฑ ์š”์†Œ:

  • ํ•ญ๊ณต์„ธ์ผ์ฆˆ 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๊ฐœ์˜ ์ƒค๋“œ์ด๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด์ œ ์ด๋ฆ„์ด ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์–ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํŠน์ˆ˜ ์ŠคํŠธ๋ฆผ:

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

์ƒ์‚ฐ์ž ์„ค์ •

์ž‘์—…์„ ๋ถ„์„ํ•˜๋ ค๋ฉด ์ผ๋ฐ˜ EC2 ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ์ดํ„ฐ ์ƒ์‚ฐ์ž๋กœ ์‚ฌ์šฉํ•˜๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ•๋ ฅํ•˜๊ณ  ๊ฐ’๋น„์‹ผ ๊ฐ€์ƒ ๋จธ์‹ ์ผ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ŠคํŒŸ t2.micro๊ฐ€ ๊ดœ์ฐฎ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ค‘์š” ์ฐธ๊ณ  ์‚ฌํ•ญ: ์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋ฏธ์ง€(Amazon Linux AMI 2018.03.0)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฉฐ Kinesis ์—์ด์ „ํŠธ๋ฅผ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ •์ด ๋” ์ ์Šต๋‹ˆ๋‹ค.

EC2 ์„œ๋น„์Šค๋กœ ์ด๋™ํ•˜์—ฌ ์ƒˆ ๊ฐ€์ƒ ๋จธ์‹ ์„ ์ƒ์„ฑํ•˜๊ณ  ํ”„๋ฆฌ ํ‹ฐ์–ด์— ํฌํ•จ๋œ t2.micro ์œ ํ˜•์˜ ์›ํ•˜๋Š” AMI๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๊ฐ€์ƒ ๋จธ์‹ ์ด Kinesis ์„œ๋น„์Šค์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ ค๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์ด ๋ถ€์—ฌ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฐ€์žฅ ์ข‹์€ ๋ฐฉ๋ฒ•์€ IAM ์—ญํ• ์„ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ 3๋‹จ๊ณ„: ์ธ์Šคํ„ด์Šค ์„ธ๋ถ€ ์ •๋ณด ๊ตฌ์„ฑ ํ™”๋ฉด์—์„œ ๋‹ค์Œ์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ƒˆ IAM ์—ญํ•  ์ƒ์„ฑ:

EC2์— ๋Œ€ํ•œ IAM ์—ญํ•  ์ƒ์„ฑ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์—ด๋ฆฌ๋Š” ์ฐฝ์—์„œ EC2์— ๋Œ€ํ•œ ์ƒˆ ์—ญํ• ์„ ์ƒ์„ฑ ์ค‘์ž„์„ ์„ ํƒํ•˜๊ณ  ๊ถŒํ•œ ์„น์…˜์œผ๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
ํ›ˆ๋ จ ์˜ˆ์ œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฆฌ์†Œ์Šค ๊ถŒํ•œ์„ ์„ธ๋ถ€์ ์œผ๋กœ ๊ตฌ์„ฑํ•˜๋Š” ๋ณต์žกํ•œ ๊ณผ์ •์„ ๋ชจ๋‘ ์‚ดํŽด๋ณผ ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ Amazon์—์„œ ์‚ฌ์ „ ๊ตฌ์„ฑ๋œ ์ •์ฑ…์ธ AmazonKinesisFullAccess ๋ฐ CloudWatchFullAccess๋ฅผ ์„ ํƒํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ์—ญํ• ์— ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„์„ ์ง€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค(์˜ˆ: EC2-KinesisStreams-FullAccess). ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด ์ƒˆ ์—ญํ• ์„ ์ƒ์„ฑํ•œ ํ›„์—๋Š” ์ƒ์„ฑ๋œ ๊ฐ€์ƒ ๋จธ์‹  ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด ํ™”๋ฉด์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๊ณ  ๋‹ค์Œ ์ฐฝ์œผ๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.

ํ•˜๋“œ ๋“œ๋ผ์ด๋ธŒ ์„ค์ •๊ณผ ํƒœ๊ทธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๋‘˜ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํƒœ๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ ์ตœ์†Œํ•œ ์ธ์Šคํ„ด์Šค์— ์ด๋ฆ„์„ ์ง€์ •ํ•˜๊ณ  ํ™˜๊ฒฝ์„ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค).

์ด์ œ 6๋‹จ๊ณ„: ๋ณด์•ˆ ๊ทธ๋ฃน ๊ตฌ์„ฑ ํƒญ์— ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ƒˆ ๋ณด์•ˆ ๊ทธ๋ฃน์„ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ๋ณด์•ˆ ๊ทธ๋ฃน์„ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด SSH(ํฌํŠธ 22)๋ฅผ ํ†ตํ•ด ์ธ์Šคํ„ด์Šค์— ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์Šค -> ๋‚ด IP๋ฅผ ์„ ํƒํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์‹คํ–‰ ์ƒํƒœ๋กœ ์ „ํ™˜๋˜์ž๋งˆ์ž 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

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๊ทธ๋ฆฌ๊ณ  Agent ๋กœ๊ทธ์™€ Airlines_tickets ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์˜ ๋ชจ๋‹ˆํ„ฐ๋ง ํƒญ์—์„œ ์ž‘์—… ๊ฒฐ๊ณผ๋ฅผ ์‚ดํŽด๋ด…๋‹ˆ๋‹ค.

tail -f /var/log/aws-kinesis-agent/aws-kinesis-agent.log

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๋ณด์‹œ๋‹ค์‹œํ”ผ ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•˜๊ณ  Kinesis ์—์ด์ „ํŠธ๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ด์ œ ์†Œ๋น„์ž๋ฅผ ๊ตฌ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Kinesis Data Analytics ์„ค์ •

์ „์ฒด ์‹œ์Šคํ…œ์˜ ์ค‘์‹ฌ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๋„˜์–ด๊ฐ€์„œ Kinesis Data Analytics์—์„œ kinesis_analytics_airlines_app์ด๋ผ๋Š” ์ƒˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Kinesis Data Analytics๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด SQL ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Kinesis Streams์—์„œ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ถ„์„์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Kinesis Streams์™€ ๋‹ฌ๋ฆฌ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์™„์ „ ์ž๋™ ์กฐ์ • ์„œ๋น„์Šค์ž…๋‹ˆ๋‹ค.

  1. ์†Œ์Šค ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ƒˆ๋กœ์šด ์ŠคํŠธ๋ฆผ(์ถœ๋ ฅ ์ŠคํŠธ๋ฆผ)์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜๊ฐ€ ํฌํ•จ๋œ ์ŠคํŠธ๋ฆผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค(์˜ค๋ฅ˜ ์ŠคํŠธ๋ฆผ).
  3. ์ž…๋ ฅ ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑํ‘œ๋ฅผ ์ž๋™์œผ๋กœ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ˆ˜๋™์œผ๋กœ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ์Œ).

์ž‘์—… ์‹œ๊ฐ„๋‹น 0.11๋‹ฌ๋Ÿฌ๋ผ๋Š” ์ €๋ ดํ•œ ์„œ๋น„์Šค๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ์ฃผ์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜์‹œ๊ณ  ์ž‘์—…์ด ๋๋‚˜๋ฉด ์‚ญ์ œํ•˜์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋ฐ์ดํ„ฐ ์†Œ์Šค์— ์—ฐ๊ฒฐํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์—ฐ๊ฒฐํ•  ์ŠคํŠธ๋ฆผ(airline_tickets)์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๋‹ค์Œ์œผ๋กœ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ŠคํŠธ๋ฆผ์—์„œ ์ฝ๊ณ  ์ŠคํŠธ๋ฆผ์— ์“ธ ์ˆ˜ ์žˆ๋„๋ก ์ƒˆ IAM ์—ญํ• ์„ ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ์•ก์„ธ์Šค ๊ถŒํ•œ ๋ธ”๋ก์—์„œ ์•„๋ฌด๊ฒƒ๋„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด์ œ ์ŠคํŠธ๋ฆผ์—์„œ ๋ฐ์ดํ„ฐ ์Šคํ‚ค๋งˆ ๊ฒ€์ƒ‰์„ ์š”์ฒญํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ ค๋ฉด "์Šคํ‚ค๋งˆ ๊ฒ€์ƒ‰" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์„ธ์š”. ๊ฒฐ๊ณผ์ ์œผ๋กœ IAM ์—ญํ• ์ด ์—…๋ฐ์ดํŠธ๋˜๊ณ (์ƒˆ ์—ญํ• ์ด ์ƒ์„ฑ๋จ) ์ŠคํŠธ๋ฆผ์— ์ด๋ฏธ ๋„์ฐฉํ•œ ๋ฐ์ดํ„ฐ์—์„œ ์Šคํ‚ค๋งˆ ๊ฐ์ง€๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด์ œ SQL ํŽธ์ง‘๊ธฐ๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹œ์ž‘ํ•  ๊ฒƒ์ธ์ง€ ๋ฌป๋Š” ์ฐฝ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ํ•  ํ•ญ๋ชฉ์„ ์„ ํƒํ•˜์„ธ์š”.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
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 ์ŠคํŠธ๋ฆผ์— ๋ฐฐ์น˜๋ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๋Œ€์ƒ ๋ธ”๋ก์—์„œ Special_stream ์ŠคํŠธ๋ฆผ์„ ์„ ํƒํ•˜๊ณ  ์ธ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ŠคํŠธ๋ฆผ ์ด๋ฆ„ DESTINATION_SQL_STREAM ๋“œ๋กญ๋‹ค์šด ๋ชฉ๋ก์—์„œ ๋‹ค์Œ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๋ชจ๋“  ์กฐ์ž‘์˜ ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ์œ ์‚ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

SNS ์ฃผ์ œ ์ƒ์„ฑ ๋ฐ ๊ตฌ๋…

๋‹จ์ˆœ ์•Œ๋ฆผ ์„œ๋น„์Šค๋กœ ์ด๋™ํ•˜์—ฌ ๊ฑฐ๊ธฐ์— Airlines๋ผ๋Š” ์ด๋ฆ„์˜ ์ƒˆ ์ฃผ์ œ๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด ์ฃผ์ œ๋ฅผ ๊ตฌ๋…ํ•˜๊ณ  SMS ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ํœด๋Œ€ํฐ ๋ฒˆํ˜ธ๋ฅผ ์ง€์ •ํ•˜์„ธ์š”.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

DynamoDB์—์„œ ํ…Œ์ด๋ธ” ์ƒ์„ฑ

Airlines_tickets ์ŠคํŠธ๋ฆผ์˜ ์›์‹œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด DynamoDB์— ๋™์ผํ•œ ์ด๋ฆ„์˜ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Record_id๋ฅผ ๊ธฐ๋ณธ ํ‚ค๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

๋žŒ๋‹ค ํ•จ์ˆ˜ ์ˆ˜์ง‘๊ธฐ ๋งŒ๋“ค๊ธฐ

Airlines_tickets ์ŠคํŠธ๋ฆผ์„ ํด๋งํ•˜๊ณ  ๊ฑฐ๊ธฐ์—์„œ ์ƒˆ ๋ ˆ์ฝ”๋“œ๊ฐ€ ๋ฐœ๊ฒฌ๋˜๋ฉด ์ด๋Ÿฌํ•œ ๋ ˆ์ฝ”๋“œ๋ฅผ DynamoDB ํ…Œ์ด๋ธ”์— ์‚ฝ์ž…ํ•˜๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” Collector๋ผ๋Š” ๋žŒ๋‹ค ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ ๊ธฐ๋ณธ ๊ถŒํ•œ ์™ธ์—๋„ ์ด ๋žŒ๋‹ค์—๋Š” Kinesis ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์— ๋Œ€ํ•œ ์ฝ๊ธฐ ์•ก์„ธ์Šค ๊ถŒํ•œ๊ณผ DynamoDB์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์•ก์„ธ์Šค ๊ถŒํ•œ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ˆ˜์ง‘๊ธฐ ๋žŒ๋‹ค ํ•จ์ˆ˜์— ๋Œ€ํ•œ IAM ์—ญํ•  ์ƒ์„ฑ
๋จผ์ € Lambda-TicketsProcessingRole์ด๋ผ๋Š” ๋žŒ๋‹ค์— ๋Œ€ํ•œ ์ƒˆ IAM ์—ญํ• ์„ ์ƒ์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
ํ…Œ์ŠคํŠธ ์˜ˆ์˜ ๊ฒฝ์šฐ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์‚ฌ์ „ ๊ตฌ์„ฑ๋œ AmazonKinesisReadOnlyAccess ๋ฐ AmazonDynamoDBFullAccess ์ •์ฑ…์ด ๋งค์šฐ ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

์ด ๋žŒ๋‹ค๋Š” ์ƒˆ ํ•ญ๋ชฉ์ด Airlines_stream์— ์ž…๋ ฅ๋  ๋•Œ Kinesis์˜ ํŠธ๋ฆฌ๊ฑฐ์— ์˜ํ•ด ์‹œ์ž‘๋˜์–ด์•ผ ํ•˜๋ฏ€๋กœ ์ƒˆ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๋‚จ์€ ๊ฒƒ์€ ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๊ณ  ๋žŒ๋‹ค๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ๋ฟ์ž…๋‹ˆ๋‹ค.

"""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 ๋žŒ๋‹ค์— ์ด ์—ญํ• ์„ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

์ด ๋žŒ๋‹ค๋Š” ์ƒˆ ๋ ˆ์ฝ”๋“œ๊ฐ€ Special_stream์— ์ž…๋ ฅ๋˜๋Š” ํŠธ๋ฆฌ๊ฑฐ์—์„œ ์ž‘๋™ํ•ด์•ผ ํ•˜๋ฏ€๋กœ Collector ๋žŒ๋‹ค์—์„œ์™€ ๋™์ผํ•œ ๋ฐฉ์‹์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ๋žŒ๋‹ค๋ฅผ ๋” ์‰ฝ๊ฒŒ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ์ƒˆ๋กœ์šด ํ™˜๊ฒฝ ๋ณ€์ˆ˜์ธ TOPIC_ARN์„ ๋„์ž…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— Airlines ์ฃผ์ œ์˜ ANR(Amazon Recourse Names)์„ ๋ฐฐ์น˜ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๊ทธ๋ฆฌ๊ณ  ๋žŒ๋‹ค ์ฝ”๋“œ๋ฅผ ์‚ฝ์ž…ํ•˜๋ฉด ์ „ํ˜€ ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

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 ์ฝ”๋“œ์—์„œ ๋ฐฐํฌ

ํ•„์š”ํ•œ ์ค€๋น„

ํ…Œ๋ผ ํผ ์ฝ”๋“œ์—์„œ ์ธํ”„๋ผ๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์œ„ํ•œ ๋งค์šฐ ํŽธ๋ฆฌํ•œ ์˜คํ”ˆ ์†Œ์Šค ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋ฐฐ์šฐ๊ธฐ ์‰ฌ์šด ์ž์ฒด ๊ตฌ๋ฌธ์ด ์žˆ์œผ๋ฉฐ ๋ฐฐํฌ ๋ฐฉ๋ฒ•๊ณผ ๋‚ด์šฉ์— ๋Œ€ํ•œ ๋งŽ์€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Atom ํŽธ์ง‘๊ธฐ ๋˜๋Š” Visual Studio Code์—๋Š” Terraform ์ž‘์—…์„ ๋” ์‰ฝ๊ฒŒ ํ•ด์ฃผ๋Š” ํŽธ๋ฆฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฐํฌํŒ์„ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ. ๋ชจ๋“  Terraform ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋ถ„์„์€ ์ด ๊ธฐ์‚ฌ์˜ ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋ฏ€๋กœ ์ฃผ์š” ์‚ฌํ•ญ์œผ๋กœ๋งŒ ์ œํ•œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹ฌ๋ฆฌ๋Š” ๋ฐฉ๋ฒ•

ํ”„๋กœ์ ํŠธ์˜ ์ „์ฒด ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋‚ด ์ €์žฅ์†Œ์—. ์ €์žฅ์†Œ๋ฅผ ์šฐ๋ฆฌ ์ž์‹ ์—๊ฒŒ ๋ณต์ œํ•ฉ๋‹ˆ๋‹ค. ์‹œ์ž‘ํ•˜๊ธฐ ์ „์— AWS CLI๊ฐ€ ์„ค์น˜ ๋ฐ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. Terraform์€ ~/.aws/credentials ํŒŒ์ผ์—์„œ ์ž๊ฒฉ ์ฆ๋ช…์„ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ข‹์€ ๋ฐฉ๋ฒ•์€ ์ „์ฒด ์ธํ”„๋ผ๋ฅผ ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๊ณ„ํš ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ํ˜„์žฌ ํด๋ผ์šฐ๋“œ์—์„œ Terraform์ด ์ƒ์„ฑํ•˜๊ณ  ์žˆ๋Š” ํ•ญ๋ชฉ์„ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

terraform.exe plan

์•Œ๋ฆผ์„ ๋ณด๋‚ผ ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ผ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ์ด ๋‹จ๊ณ„์—์„œ๋Š” ์ž…๋ ฅํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
ํ”„๋กœ๊ทธ๋žจ ์šด์˜ ๊ณ„ํš์„ ๋ถ„์„ํ•œ ํ›„ ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

terraform.exe apply

์ด ๋ช…๋ น์„ ๋ณด๋‚ธ ํ›„ ๋‹ค์‹œ ์ „ํ™”๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ผ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ํ‘œ์‹œ๋˜๋ฉฐ, ์‹ค์ œ ์ž‘์—… ์ˆ˜ํ–‰์— ๋Œ€ํ•œ ์งˆ๋ฌธ์ด ํ‘œ์‹œ๋˜๋ฉด "์˜ˆ"๋ฅผ ๋ˆ„๋ฅด์‹ญ์‹œ์˜ค. ์ด๋ฅผ ํ†ตํ•ด ์ „์ฒด ์ธํ”„๋ผ๋ฅผ ์„ค์ •ํ•˜๊ณ , EC2์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ตฌ์„ฑ์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋žŒ๋‹ค ๊ธฐ๋Šฅ์„ ๋ฐฐํฌํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Terraform ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ๋ฆฌ์†Œ์Šค๊ฐ€ ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋œ ํ›„์—๋Š” Kinesis Analytics ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ธ๋ถ€ ์ •๋ณด๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค(์•ˆํƒ€๊น๊ฒŒ๋„ ์ฝ”๋“œ์—์„œ ์ง์ ‘ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค).

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค:

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
๊ทธ๋Ÿฐ ๋‹ค์Œ ๋“œ๋กญ๋‹ค์šด ๋ชฉ๋ก์—์„œ ์„ ํƒํ•˜์—ฌ ์ธ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ŠคํŠธ๋ฆผ ์ด๋ฆ„์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ด์ œ ๋ชจ๋“  ๊ฒƒ์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ…Œ์ŠคํŠธ

์ˆ˜๋™์œผ๋กœ ๋˜๋Š” Terraform ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ์‹œ์Šคํ…œ์„ ๋ฐฐํฌํ•œ ๋ฐฉ๋ฒ•์— ๊ด€๊ณ„์—†์ด ๋™์ผํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

Kinesis ์—์ด์ „ํŠธ๊ฐ€ ์„ค์น˜๋œ EC2 ๊ฐ€์ƒ ๋จธ์‹ ์— SSH๋ฅผ ํ†ตํ•ด ๋กœ๊ทธ์ธํ•˜๊ณ  api_caller.py ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

sudo ./api_caller.py TOKEN

๋‹น์‹ ์ด ํ•ด์•ผ ํ•  ์ผ์€ ๋‹น์‹ ์˜ ์ „ํ™”๋ฒˆํ˜ธ๋กœ SMS๊ฐ€ ์˜ค๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ ๋ฟ์ž…๋‹ˆ๋‹ค:

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
SMS - ๊ฑฐ์˜ 1๋ถ„ ์•ˆ์— ๋ฉ”์‹œ์ง€๊ฐ€ ์ „ํ™”๋กœ ๋„์ฐฉํ•ฉ๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ
์ดํ›„์˜ ๋ณด๋‹ค ์ž์„ธํ•œ ๋ถ„์„์„ ์œ„ํ•ด ๋ ˆ์ฝ”๋“œ๊ฐ€ DynamoDB ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋˜์—ˆ๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Airlines_tickets ํ…Œ์ด๋ธ”์—๋Š” ๋Œ€๋žต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฐ์ดํ„ฐ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

Amazon Kinesis ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค ๋‹จ์ˆœ์„ฑ๊ณผ Aviasales API ํ†ตํ•ฉ

๊ฒฐ๋ก 

์ž‘์—… ๊ณผ์ •์—์„œ Amazon Kinesis๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜จ๋ผ์ธ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์ด ๊ตฌ์ถ•๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Kinesis Data Streams ๋ฐ SQL ๋ช…๋ น์„ ์‚ฌ์šฉํ•œ ์‹ค์‹œ๊ฐ„ ๋ถ„์„ Kinesis Analytics์™€ ํ•จ๊ป˜ Kinesis ์—์ด์ „ํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์˜ต์…˜์€ ๋ฌผ๋ก  Amazon Kinesis์™€ ๋‹ค๋ฅธ AWS ์„œ๋น„์Šค์˜ ์ƒํ˜ธ ์ž‘์šฉ๋„ ๊ณ ๋ ค๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์œ„ ์‹œ์Šคํ…œ์„ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋ฐฐํฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์†Œ ๊ธด ์ˆ˜๋™ ๋ฐฉ๋ฒ•๊ณผ Terraform ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•œ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋ชจ๋“  ํ”„๋กœ์ ํŠธ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ๋‚ด GitHub ์ €์žฅ์†Œ์—, ์ต์ˆ™ํ•ด์ง€๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ธฐ์‚ฌ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ฒŒ ๋œ ๊ฒƒ์„ ๊ธฐ์˜๊ฒŒ ์ƒ๊ฐํ•˜๋ฉฐ ๊ท€ํ•˜์˜ ์˜๊ฒฌ์„ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๊ฑด์„ค์ ์ธ ๋น„ํŒ์„ ๋ฐ”๋ž๋‹ˆ๋‹ค.

๋‚œ ๋‹น์‹ ์—๊ฒŒ ์„ฑ๊ณต์„ ๊ธฐ์›ํ•ฉ๋‹ˆ๋‹ค!

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€