fromm์˜ SQS์™€ DLQ - 1. DeadLetterQueue๋ฅผ ๋„์ž…ํ•˜๊ธฐ๊นŒ์ง€

yeon
  • #AWS
  • #SQS
  • #DLQ
  • #event-driven

์•ˆ๋…•ํ•˜์„ธ์š”. ๋…ธ๋จธ์Šค ๋ฐฑ์—”๋“œํŒ€์—์„œ fromm ์„œ๋น„์Šค๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๊น€์—ฐํƒœ์ž…๋‹ˆ๋‹ค.

fromm์˜ Event Driven

fromm์˜ ์„œ๋น„์Šค๋Š” ํฌ๊ฒŒ ์•„ํ‹ฐ์ŠคํŠธ์™€ ํ”„๋ผ์ด๋น—๋ฉ”์‹œ์ง€๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” fromm ์•ฑ๊ณผ fromm ์•ฑ์˜ ์ด์šฉ๊ถŒ, ์•„ํ‹ฐ์ŠคํŠธ๋ณ„ ๊ตฟ์ฆˆ ๋“ฑ์„ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ๋Š” fromm store ๋‘ ๊ฐœ์˜ ์„œ๋น„์Šค๋กœ ๋‚˜๋‰˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ์„œ๋น„์Šค๋Š” ์ฃผ๋ฌธ, ๊ฒฐ์ œ, ํ”„๋กฌ์นœ๊ตฌ, ์•Œ๋ฆผ ๋“ฑ์˜ ์—ฌ๋Ÿฌ ๋ชจ๋“ˆ๋“ค๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ๋ชจ๋“ˆ๋กœ ๊ตฌ์„ฑ๋œ ์„œ๋น„์Šค์—์„œ ์ƒํ’ˆ์„ ๊ตฌ๋งคํ–ˆ๋Š”๋ฐ ๊ตฌ๋งค๊ณผ์ •์—์„œ ์•ฑ์— ์ด์šฉ๊ถŒ์ด ์ฆ‰์‹œ ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๋‹ค๊ณ , ํ˜น์€ ์•ฑ์—์„œ ์ฑ„ํŒ…๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋ƒˆ๋Š”๋ฐ ํ‘ธ์‹œ์•Œ๋ฆผ์ด ๊ฐ€์ง€ ์•Š์•˜๋‹ค๊ณ  ์ด์šฉ๊ถŒ ๊ตฌ๋งค๊ฐ€ ์‹คํŒจํ•˜๊ฑฐ๋‚˜ ์ฑ„ํŒ…๋ฉ”์‹œ์ง€ ์ „์†ก์ด ์‹คํŒจํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ด์™€ ๊ฐ™์€ ์‚ฌ๋ก€๋“ค์€ ์ฆ‰์‹œ ๋ฐ˜์˜๋˜์ง€๋Š” ์•Š์ง€๋งŒ ์–ธ์  ๊ฐ€ ๋ชฉํ‘œํ•œ๋Œ€๋กœ ์ƒํƒœ๊ฐ€ ๋ฐ˜์˜๋˜๋ฉด ๋˜๋Š” ๊ฒฐ๊ณผ์  ์ผ๊ด€์„ฑ(eventually consistency)๋ฅผ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ๊ฐ„ ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. fromm ์„œ๋น„์Šค์˜ ๋ฐฑ์—”๋“œ๋Š” ์ด๋ฅผ ์œ„ํ•ด event driven architecture๋ฅผ ์„ ํƒํ–ˆ๊ณ  ์ด๋ฒคํŠธ๋ฅผ ์ „๋‹ฌํ•  ๋ฉ”์‹œ์ง€ ํ๋กœ SQS๋ฅผ ํ™œ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์™œ SQS์˜€๋‚˜?

๋ฉ”์‹œ์ง€ ํ๋กœ SQS๋ฅผ ์„ ํƒํ•œ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

SQS์˜ ๋†’์€ ํŠธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ๋Ÿ‰

SQS๋Š” ํ‘œ์ค€๋Œ€๊ธฐ์—ด์„ ์‚ฌ์šฉ์‹œ ๊ฑฐ์˜ ๋ฌด์ œํ•œ์— ๊ฐ€๊นŒ์šด ์ดˆ๋‹น API ์ž‘์—…์„ ์ง€์›ํ•˜๋ฉฐ ๋™์‹œ์— ์ฒ˜๋ฆฌ๊ฐ€๋Šฅํ•œ inflight message limit์€ 120,000๊ฐœ๋กœ ํ˜„์žฌ fromm ์„œ๋น„์Šค์—์„œ ๋ฐœ์ƒํ•˜๋Š” ํŠธ๋ž˜ํ”ฝ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ์— ์ถฉ๋ถ„ํžˆ ๋†’์€ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ SQS์˜ ํ‘œ์ค€๋Œ€๊ธฐ์—ด์€ ๋ฉ”์‹œ์ง€์˜ at least once delivery๋ฅผ ๋ณด์žฅํ•˜์—ฌ ์ด๋ฒคํŠธ๊ฐ€ ์ ์ ˆํžˆ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ฉ”์‹œ์ง€์˜ ์™„๋ฒฝํ•œ ์ˆœ์„œ๋ณด์žฅ๊ณผ exactly once๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด ์ฒ˜๋ฆฌ๋Ÿ‰์„ ์กฐ๊ธˆ ํฌ๊ธฐํ•˜๊ณ  ํ‘œ์ค€๋Œ€๊ธฐ์—ด ๋Œ€์‹  FIFO Queue๋ฅผ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค๋Š” ์˜ต์…˜๋„ ๋ˆˆ์— ๋„์—ˆ์Šต๋‹ˆ๋‹ค.

์ŠคํŒŒ์ดํฌ์„ฑ ํŠธ๋ž˜ํ”ฝ์— ์ ์ ˆํžˆ ๋Œ€์‘๊ฐ€๋Šฅํ•œ Lambda์™€ ์กฐํ•ฉ

fromm ์„œ๋น„์Šค๋Š” ์•„ํ‹ฐ์ŠคํŠธ๊ฐ€ ํ”„๋ผ์ด๋น— ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์†กํ•˜๋ฉด ํŒฌ๋“ค์ด ๋‹ค์ˆ˜ ์œ ์ž…๋˜๋ฉฐ ์ˆœ๊ฐ„์ ์œผ๋กœ API call์ด ๋‹ค์ˆ˜ ์ผ์–ด๋‚˜๋Š” ์ŠคํŒŒ์ดํฌ์„ฑ ํŠธ๋ž˜ํ”ฝ์˜ ํŠน์„ฑ์„ ๋ณด์ž…๋‹ˆ๋‹ค. ๋ฏธ๋ฆฌ ์Šค์ผ€์ผ์•„์›ƒ์„ ํ•˜๊ธฐ์—๋Š” ์•„ํ‹ฐ์ŠคํŠธ๊ฐ€ ์–ธ์ œ ํ”„๋ผ์ด๋น—๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ผ์ง€๋Š” ์ „ํ˜€ ์˜ˆ์ƒํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ํŠธ๋ž˜ํ”ฝ์ด ์ ์€ ์‹œ์ ์— ๋Š˜์–ด๋‚œ ์ธ์Šคํ„ด์Šค์˜ ์œ ํœด์ž์›์œผ๋กœ ์ธํ•œ ๋น„์šฉ์„ ํฌ๊ธฐํ•˜๋˜์ง€ SQS์˜ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์˜คํ† ์Šค์ผ€์ผ๋ง๋˜๋Š” ์‹œ๊ฐ„๋™์•ˆ ๋ฉ”์‹œ์ง€๊ฐ€ ๋Šฆ๊ฒŒ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Œ์„ ๊ฐ์ˆ˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

01. ์–ธ์ œ ํŠˆ์ง€ ๋ชจ๋ฅด๋Š” ์ŠคํŒŒ์ดํฌ์„ฑ ํŠธ๋ž˜ํ”ฝ

SQS์˜ event handler๋กœ node.js๋กœ ๋งŒ๋“  Lambda๋ฅผ ํ™œ์šฉํ•˜๋ฉฐ EC2, ECS์˜ ์˜คํ† ์Šค์ผ€์ผ๋ง์— ๋น„ํ•ด ํ›จ์”ฌ ๋น ๋ฅธ ์Šค์ผ€์ผ์•„์›ƒ์„ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ JVM, .net์— ๋น„ํ•ด cold start ์ด์Šˆ์—์„œ๋„ ๋น„๊ต์  ์ž์œ ๋กœ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šด์˜์œผ๋กœ๋ถ€ํ„ฐ์˜ ์ž์œ 

๋ฌผ๋ก  Kafka๊ฐ€ SQS์— ๋น„ํ•ด ๋†’์€ ์„ฑ๋Šฅ๊ณผ ๊ฐ€์šฉ์„ฑ์„ ๋ณด์—ฌ์ฃผ๊ณ  ์—์ฝ”์‹œ์Šคํ…œ์ด ๋‹ค์–‘ํ•œ ๊ฒƒ์ด ์‚ฌ์‹ค์ด์ง€๋งŒ Kafka๋ฅผ ์žฅ์• ์—†์ด ์šด์˜ํ•˜๊ธฐ ์œ„ํ•ด์„  ๋งŽ์€ ์ง€์‹๊ณผ ๊ฒฝํ—˜์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. AWS๋ฅผ ํ†ตํ•ด ์™„์ „ํžˆ ๋งค๋‹ˆ์ง•๋˜๋Š” SQS๋ฅผ ์„ ํƒํ•จ์œผ๋กœ์จ Kafka๋ฅผ ์šด์˜ํ•˜๋‹ค ๋งˆ์ฃผ์น  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋‹ˆํ„ฐ๋ง, EBS ๋ณผ๋ฅจ์ด์Šˆ, ์ฃผํ‚คํผ ์ด์Šˆ, ๋ธŒ๋กœ์ปค ์ถ”๊ฐ€ ์ค‘ ์ˆœ๋‹จ ๋“ฑ ์ˆ˜๋งŽ์€ ๋ฌธ์ œ์—์„œ ์ž์œ ๋กœ์šธ ์ˆ˜ ์žˆ์—ˆ๊ณ  ์ด๋Ÿฐ ๋‚ฎ์€ ๋Ÿฌ๋‹์ปค๋ธŒ๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ํŒ€์›๋“ค์ด ์ˆ˜์›”ํ•˜๊ฒŒ SQS๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

SQS ์‚ฌ์šฉ์ค‘ ๋งˆ์ฃผํ•œ ๋ฌธ์ œ์ 

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  SQS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ๋งˆ์ฃผํ•œ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋กœ ํ•ธ๋“ค๋ง ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ ๊ณ„์† ์žฌ์ฒ˜๋ฆฌ ์‹œ๋„๋˜๋Š” ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€

SQS์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ฃผ์š” API๋Š” 3๊ฐ€์ง€ ์ž…๋‹ˆ๋‹ค.

  • SendMessage : ๋ฉ”์‹œ์ง€๋ฅผ SQS์— producing ํ•ฉ๋‹ˆ๋‹ค.
  • ReceiveMessage : ๋ฉ”์‹œ์ง€๋ฅผ consume ํ•˜์—ฌ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • DeleteMessage : ์ฒ˜๋ฆฌ๊ฐ€ ์™„๋ฃŒ๋œ ๋ฉ”์‹œ์ง€๋ฅผ SQS ํ์—์„œ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

SQS๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ consume ๋˜์—ˆ๋‹ค๊ณ  ์ฆ‰์‹œ ํ์—์„œ ์‚ญ์ œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ์—์„œ ์ •์ƒ์ ์œผ๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋œ ํ›„ DeleteMessage Request๊ฐ€ ์žˆ์–ด์•ผ์ง€๋งŒ ๋ฉ”์‹œ์ง€๊ฐ€ ํ์—์„œ ์‚ญ์ œ๋˜๋ฉฐ DeleteMessage Request๊ฐ€ ์—†๋‹ค๋ฉด ๋ฉ”์‹œ์ง€๋Š” SQS์— ์„ค์ •๋œ Visibility Timeout, Delay Seconds์„ ๊ฑฐ์นœ ํ›„ ๋‹ค์‹œ ์†Œ๋น„๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Lambda์—์„œ๋Š” ๋ช…์‹œ์ ์œผ๋กœ DeleteMessage๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์œผ๋ฉฐ ์ •์ƒ์ ์œผ๋กœ Lambda function์ด ์ข…๋ฃŒ๋œ ๊ฒฝ์šฐ DeleteMessage Request๋ฅผ ๋‚ ๋ ค์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ Service ์ฝ”๋“œ ๋“ฑ์—์„œ throw Error๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ Lambda๋Š” ์ •์ƒ์ ์œผ๋กœ ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ณ  DeleteMessage๋„ ๋˜์ง€ ์•Š์•„ ์ผ์ •์‹œ๊ฐ„ ํ›„ ๋ฉ”์‹œ์ง€๋Š” ๊ณ„์†ํ•ด์„œ ์žฌ์ฒ˜๋ฆฌ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์žฌ์ฒ˜๋ฆฌ๋ฅผ ์‹œ๋„ํ•ด ๋ฉ”์‹œ์ง€๊ฐ€ ๋‹ค์‹œ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค๋ฉด ๋‹คํ–‰์ด์ง€๋งŒ ์ˆ˜์ฐจ๋ก€ ์žฌ์‹œ๋„ ํ›„์—๋„ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ๋ฉ”์‹œ์ง€๋Š” ๋Œ€๊ฐœ ์จ๋“œํŒŒํ‹ฐ API ๋ฌธ์ œ ํ˜น์€ ์ž˜๋ชป๋œ ๋ฐฐํฌ๋กœ ์ธํ•œ ์ฝ”๋“œ๋ฌธ์ œ ๋“ฑ์œผ๋กœ ๊ณ„์†ํ•ด์„œ ๋ฉ”์‹œ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฐ ์ƒํ™ฉ์ด ์ง€์†๋œ๋‹ค๋ฉด SQS์˜ ๋™์‹œ์— ์ฒ˜๋ฆฌ๊ฐ€๋Šฅํ•œ ๋ฉ”์‹œ์ง€ ์ˆ˜ limit์œผ๋กœ ์ธํ•ด ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•  ๋ฉ”์‹œ์ง€๊ฐ€ ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Error๋กœ ์ธํ•œ ์•Œ๋žŒ์„ ๊ฑธ์–ด๋’€๋‹ค๋ฉด ๋ฌดํ•œํžˆ ์šธ๋ฆฌ๋Š” ์•Œ๋žŒ์€ ๋ค์ž…๋‹ˆ๋‹ค๐Ÿ˜ญ

02. ๊ณ„์† ์šธ๋ฆฌ๋Š” ์Šฌ๋ž™์•Œ๋žŒ ์‚ด๋ ค์ค˜...

ํ™•์ธํ•˜๊ธฐ ์–ด๋ ค์šด ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€ ๋ ˆ์ฝ”๋“œ

SQS์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ํ์— ๋“ค์–ด์™€ Delay Seconds ๋™์•ˆ ํ˜น์€ ReceiveMessage Request๋ฅผ ํ†ตํ•ด Visibility Timeout ๋™์•ˆ์€ invisible ์ƒํƒœ๋กœ AWS console ์—์„œ ๋ฉ”์‹œ์ง€์˜ ๋ ˆ์ฝ”๋“œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งŒ์•ฝ ๋ฉ”์‹œ์ง€๊ฐ€ ์ง€์†์ ์œผ๋กœ ์‹คํŒจ๋ฅผ ํ•ด ์žฌ์‹œ๋„๊ฐ€ ์ผ์–ด๋‚˜๊ณ  ์žˆ๊ณ  ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ๊ทธ๋กœ ์›์ธ์„ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค๋ฉด ๋ ˆ์ฝ”๋“œ ๋‚ด์šฉ์„ ์ง์ ‘ ํ™•์ธํ•ด ์ž˜๋ชป๋œ ๊ฐ’์ด ์žˆ๋Š”์ง€ ์›์ธ์„ ์ฐพ์•„๋ณด๊ณ  ์‹ถ์„ ๋•Œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ์–ธ์ œ invisible ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณผ ์ˆ˜ ์žˆ๋Š”์ง€, ๋ณผ ์ˆ˜ ์žˆ๋Š” ๋ฉ”์‹œ์ง€๊ฐ€ ์žˆ๋‹ค ํ•˜๋”๋ผ๋„ ์ •์ƒ์ ์œผ๋กœ ์†Œ๋น„๋˜๋Š” ๋ฉ”์‹œ์ง€์ธ์ง€ ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€์ธ์ง€ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์–ด์„œ ๋ฉ”์‹œ์ง€์˜ ๋ ˆ์ฝ”๋“œ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

DLQ(DeadLetterQueue) ๋„์ž…

SQS๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์„ค์ •ํ•œ ํšŸ์ˆ˜๋งŒํผ ๋ฉ”์‹œ์ง€ ์†Œ๋น„๋ฅผ ์‹œ๋„ ํ›„ ๊ณ„์†ํ•ด์„œ ์‹คํŒจํ•˜๋ฉด ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋ฅผ ๋ชจ์•„๋†“์„ ์ˆ˜ ์žˆ๋Š” DLQ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. SQS DLQ๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์•ž์„œ ๋งˆ์ฃผํ•œ SQS๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ๋ฌธ์ œ์ ๋“ค์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • DLQ์— ์‹คํŒจํ•œ ๋ฉ”์‹œ์ง€๋“ค์ด ๋ชจ์—ฌ์žˆ๊ณ  ์ด ๋ฉ”์‹œ์ง€๋“ค์€ ํ•ญ์ƒ visibleํ•œ ์ƒํƒœ์ด๋ฏ€๋กœ AWS console์—์„œ ๋ฉ”์‹œ์ง€๋ฅผ receiveํ•ด ๋ ˆ์ฝ”๋“œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ปจ์Šˆ๋จธ์—์„œ ์‹คํŒจํ–ˆ์„ ๋•Œ ์•Œ๋žŒ์„ ๋ณด๋‚ด๊ธฐ๋ณด๋‹จ DLQ๋กœ ์ „์†ก๋  ๋•Œ ์•Œ๋žŒ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์„ ํ†ตํ•ด ๊ณ„์†๋˜๋Š” ์•Œ๋žŒ์„ ๋ฐ›๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ 1ํšŒ๋งŒ ์•Œ๋žŒ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋‚ด๋ถ€ ์ฝ”๋“œ, ์ธํ”„๋ผ, ์„œ๋“œํŒŒํ‹ฐ API ๋“ฑ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋œ๋‹ค๋ฉด ํ•ด๊ฒฐ๋œ ํ›„ DLQ์˜ ๋ฉ”์‹œ์ง€๋ฅผ Origin Queue๋กœ Redriveํ•ด ๋‹ค์‹œ ์ •์ƒ์ ์œผ๋กœ ์†Œ๋น„์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ ์žฅ์ ๋“ค ๋•Œ๋ฌธ์— ์ €ํฌ ํŒ€์—์„œ๋Š” ์ฆ‰์‹œ DLQ๋ฅผ ๋„์ž…ํ•ด ๊ธฐ์กด์˜ ๋ฌธ์ œ์ ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.

DLQ ๊ตฌ์„ฑํ•˜๊ธฐ

๊ฐ„๋‹จํ•œ ์†Œ์Šค์ฝ”๋“œ ์˜ˆ์‹œ๋ฅผ ํ†ตํ•ด ์–ด๋–ป๊ฒŒ DLQ๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

DLQ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์€ AWS console์„ ํ†ตํ•˜๊ฑฐ๋‚˜ AWS CLI, CloudFormation ๋“ฑ ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ์ง€๋งŒ ์˜ˆ์‹œ์—์„œ๋Š” Lambda๋ฅผ ํ”„๋กœ๋น„์ ธ๋‹ ํ•  ๋•Œ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” serverless framework๋ฅผ ํ†ตํ•ด SQS Queue, DLQ, Lambda Handler๋ฅผ ๊ตฌ์„ฑํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Lambda Handler Source Code

lambda.ts

export const handler = async event => {
  const app = await NestFactory.create(AppModule);
  
  const helloFrommService = app.get(HelloFrommService);

  try {
    await helloFrommService.executeTestData(JSON.parse(event.Records[0].body));
  } catch (e) {
    // logging, alerting, etc...
    throw e;
  }
}

Lambda ํ•ธ๋“ค๋Ÿฌ๋Š” DLQ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๋•Œ์˜ ์†Œ์Šค์ฝ”๋“œ์™€ ํฌ๊ฒŒ ๋‹ค๋ฅด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹ค๋งŒ ์ง€์ •๋œ ํšŸ์ˆ˜๋งŒํผ ๋ฉ”์‹œ์ง€๊ฐ€ ์žฌ์‹œ๋„ ๋œ ํ›„ DLQ๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณด๋‚ด์งˆ ๋•Œ์—๋งŒ ์•Œ๋žŒ์„ ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด catch ๋ธ”๋ก ์•ˆ์—์„œ if (*event*.Records[0].attributes.ApproximateReceiveCount >= maxReceiveCount){ ...alert } ๋ฅผ ํ†ตํ•ด ์•Œ๋žŒ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

serverless YAML config

serverless.yml

service: hello-fromm

provider:
  name: aws
  runtime: nodejs18.x
  region: ap-northeast-2
  memorySize: 1024
  timeout: 60
  tracing:
    lambda: true

functions:
  HelloFromm:
    handler: src/lambda.handler
    events:
      - sqs:
          arn:
            Fn::GetAtt:
              - HelloFrommQueue
              - Arn

resources:
  Resources:
    HelloFrommQueue:
      Type: AWS::SQS::Queue
      Properties:
        QueueName: Hello-Fromm-Queue
        VisibilityTimeout: 60
        MessageRetentionPeriod: 2000 # should be less than or equal to HelloFrommDeadLetterQueue's MessageRetentionPeriod
        RedrivePolicy:
          deadLetterTargetArn:
            Fn::GetAtt:
              - HelloFrommDeadLetterQeueue
              - Arn
          maxReceiveCount: 5
    HelloFrommDeadLetterQeueue:
        Type: AWS::SQS::Queue
        Properties:
            QueueName: Hello-Fromm-DeadLetterQueue
            MessageRetentionPeriod: 1209600 # 14 * 24 * 60 * 60 = 14 days, available range : 60 ~ 1209600

์œ„์™€ ๊ฐ™์€ serverless.yml config file์„ ํ†ตํ•ด lambda, SQS Queue, DLQ ๋ฅผ ๋ชจ๋‘ ํ”„๋กœ๋น„์ €๋‹ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•ด์•ผํ•  ์ ์€

  • SQS Queue์™€ DLQ๋Š” ๊ฐ™์€ ํƒ€์ž…์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ‘œ์ค€๋Œ€๊ธฐ์—ด์€ DLQ๋„ ํ‘œ์ค€๋Œ€๊ธฐ์—ด์ด์–ด์•ผ ํ•˜๊ณ  FIFO ํ๋Š” DLQ๋„ FIFOํ์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • DLQ์˜ MessageRetentionPeriod๋Š” ํ•ญ์ƒ SQS Queue์˜ ๊ฐ’๋ณด๋‹ค ์ปค์•ผํ•ฉ๋‹ˆ๋‹ค. SQS Queue์—์„œ Record๋‹น ์นด์šดํŠธ๋˜๋Š” MessageRetentionPeriod๋Š” DLQ์—์„œ๋„ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š๊ณ  ์ง€์†์ ์œผ๋กœ ์นด์šดํŠธ๋ฉ๋‹ˆ๋‹ค. ์ฆ‰ DLQ์˜ MessageRetentionPeriod ๊ฐ’์ด SQS Queue์˜ MessageRetentionPeriod ๊ฐ’๊ณผ ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์œผ๋ฉด DLQ๋กœ ๋ฉ”์‹œ์ง€๊ฐ€ ์ด๋™๋˜์ž ๋งˆ์ž retentionPeriod๊ฐ€ ๋๋‚˜ ์ฆ‰์‹œ ์‚ญ์ œ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์น˜๋ฉฐ

์ง€๊ธˆ๊นŒ์ง€ fromm์„œ๋น„์Šค์— SQS์™€ DLQ๋ฅผ ๋„์ž…ํ•˜๊ฒŒ๋œ ๊ณผ์ •๊ณผ ๋ฐฉ๋ฒ•์„ ๊ฐ„๋žตํžˆ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๋ฒˆ fromm์˜ SQS์™€ DLQ - 2. Throughput์„ ํšจ๊ณผ์ ์œผ๋กœ ๋Š˜๋ฆฌ๊ธฐ ์œ„ํ•œ Partial Batch ์‚ฌ์šฉ์—์„œ๋Š” SQS์˜ throughput์„ ๋Š˜๋ฆฌ๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•๊ณผ ์ด๋ฅผ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ partial batch failure๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ๊นŒ์ง€ ๊ธ€์„ ๊ด€์‹ฌ์žˆ๊ฒŒ ์ฝ์–ด์ฃผ์‹  ๋ชจ๋“ ๋ถ„๊ป˜ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค๐Ÿ™‡โ€

๋‹น์‹ ์˜ ์˜ˆ์ˆ ์ด ์„ธ์ƒ์„ ๋ฐ”๊พผ๋‹ค.

์ €ํฌ์™€ ํ•จ๊ป˜ ์„œ๋น„์Šค์˜ ํ’ˆ์งˆ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ๊ณ ๋ฏผํ•˜๊ณ  ํ•จ๊ป˜ ์„ฑ์žฅํ•ด๋‚˜๊ฐˆ ๊ฐœ๋ฐœ์ž๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. ๊ด€์‹ฌ์žˆ์œผ์‹ ๋ถ„๋“ค์€ ์–ธ์ œ๋“ ์ง€ ์ง€์›๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค๐Ÿ˜€

๋…ธ๋จธ์Šค ์ง€์›ํ•˜๊ธฐ

์ฐธ๊ณ ์ž๋ฃŒ

Serverless Framework Documentation

Amazon SQS Dead-Letter Queues

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

Art Changes Life

๋…ธ๋จธ์Šค์™€ ํ•จ๊ป˜ ์—”ํ„ฐํ…Œํฌ ์‚ฐ์—…์„ ํ˜์‹ ํ•ด๋‚˜๊ฐˆ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ฑ„์šฉ ์ค‘์ธ ๊ณต๊ณ  ๋ณด๊ธฐ