7.1 ์™œ ํ•„์š”ํ•œ๊ฐ€

์šฐ๋ฆฌ๋Š” ACID์˜ ๋ชจ๋“  ์†์„ฑ, ๋ชฉ์  ๋ฐ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•ด ์ž์„ธํžˆ ๋…ผ์˜ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ณด์‹œ๋‹ค์‹œํ”ผ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ACID ๋ณด์žฅ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋ฉฐ ๋” ๋‚˜์€ ์„ฑ๋Šฅ์„ ์œ„ํ•ด ํฌ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ACID๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ํ”„๋กœ์ ํŠธ์—์„œ ์„ ํƒ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธก์—์„œ ํ•„์š”ํ•œ ACID ๊ธฐ๋Šฅ ์ค‘ ์ผ๋ถ€๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹œ์Šคํ…œ์ด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๋˜๋Š” ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ๋ถ„์‚ฐ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ์„ค๊ณ„๋œ ๊ฒฝ์šฐ ํ•œ ์„œ๋น„์Šค์˜ ์ •์ƒ์ ์ธ ๋กœ์ปฌ ํŠธ๋žœ์žญ์…˜์€ ์ด์ œ ๋ถ„์‚ฐ ํŠธ๋žœ์žญ์…˜์ด ๋˜๋ฉฐ ๋ฌผ๋ก  ACID ํŠน์„ฑ์„ ์žƒ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ ๊ฐœ๋ณ„ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๋Š” ACID๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ํฌ๊ณ  ๋ณต์žกํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ์ž๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ฒ ์ €ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์‹ถ์ง€ ์•Š์œผ๋ฉฐ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋ณธ ๊ธฐ์ˆ ๋งŒ ๋‹ค๋ฃจ๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค. ๋ถ„์‚ฐ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ๋ฉด ACID ๋ณด์žฅ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ธก์—์„œ ACID๋ฅผ ์™„์ „ํžˆ ๊ตฌํ˜„ํ•˜๋ ค๊ณ  ํ•  ์ด์œ ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๊ธฐ์„ฑ ์†”๋ฃจ์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ชจ๋“ ๋ฉด์—์„œ ๋” ์‰ฝ๊ณ  ์ €๋ ดํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ACID๊ฐ€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค).

ํ•˜์ง€๋งŒ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ ์ธก์—์„œ ํŠธ๋žœ์žญ์…˜์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๊ธฐ์ˆ ์„ ๋ณด์—ฌ ๋“œ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ์ด๋Ÿฌํ•œ ๊ธฐ์ˆ ์„ ์•Œ๋ฉด ๋‹ค์–‘ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํŠธ๋žœ์žญ์…˜์ด ๋ฐ˜๋“œ์‹œ ํฌํ•จ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋„ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋” ๋‚˜์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๊ทธ๋ ‡๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค).

7.2 ๊ฑฐ๋ž˜ ์• ํ˜ธ๊ฐ€๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ๋„๊ตฌ

๋‚™๊ด€์  ๋ฐ ๋น„๊ด€์  ์ฐจ๋‹จ. ์ด๋Š” ๋™์‹œ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ๋Š” ์ผ๋ถ€ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ์ž ๊ธˆ์ž…๋‹ˆ๋‹ค.

๋‚™์ฒœ์ฃผ์˜์ž๋™์‹œ ์•ก์„ธ์Šค ๊ฐ€๋Šฅ์„ฑ์ด ๊ทธ๋‹ค์ง€ ํฌ์ง€ ์•Š๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฏ€๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๋ผ์ธ์„ ์ฝ๊ณ  ํ•ด๋‹น ๋ฒ„์ „ ๋ฒˆํ˜ธ๋ฅผ ๊ธฐ์–ตํ•ฉ๋‹ˆ๋‹ค(๋˜๋Š” ํƒ€์ž„์Šคํƒฌํ”„ ๋˜๋Š” ์ฒดํฌ์„ฌ/ํ•ด์‹œ - ๋ฐ์ดํ„ฐ ๊ตฌ์„ฑํ‘œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ๋ฒ„์ „์— ๋Œ€ํ•œ ์—ด์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ). ๋˜๋Š” ํƒ€์ž„์Šคํƒฌํ”„), ์ด ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์“ฐ๊ธฐ ์ „์— ์ด ๋ฐ์ดํ„ฐ์˜ ๋ฒ„์ „์ด ๋ณ€๊ฒฝ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋ฒ„์ „์ด ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ์ƒ์„ฑ๋œ ์ถฉ๋Œ์„ ์–ด๋–ป๊ฒŒ๋“  ํ•ด๊ฒฐํ•˜๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธ("์ปค๋ฐ‹")ํ•˜๊ฑฐ๋‚˜ ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑ("๋กค๋ฐฑ")ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์˜ ๋‹จ์ ์€ "time-of-check to time-of-use"๋ผ๋Š” ๊ธด ์ด๋ฆ„(TOCTOU๋กœ ์ถ•์•ฝ๋จ)์ด ์žˆ๋Š” ๋ฒ„๊ทธ์— ์œ ๋ฆฌํ•œ ์กฐ๊ฑด์„ ์ƒ์„ฑํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ƒํƒœ๋Š” ํ™•์ธ๊ณผ ์“ฐ๊ธฐ ์‚ฌ์ด์˜ ๊ธฐ๊ฐ„์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚™๊ด€์  ์ž ๊ธˆ์— ๋Œ€ํ•œ ๊ฒฝํ—˜์ด ์—†์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ๋‚™๊ด€์  ์ž ๊ธˆ๊ณผ ๊ฐ™์€ ๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฐœ๋ฐœ์ž์˜ ์ผ์ƒ ์ƒํ™œ์—์„œ HTTP ํ”„๋กœํ† ์ฝœ์ด๋ผ๋Š” ๊ธฐ์ˆ ์„ ๋ฐœ๊ฒฌํ–ˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ HTTP GET ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์—๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ If-Match ํ—ค๋”์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ํ›„์† PUT ์š”์ฒญ์— ๋Œ€ํ•œ ETag ํ—ค๋”๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(MAY). GET ๋ฐ HEAD ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ ์„œ๋ฒ„๋Š” ์•Œ๊ณ  ์žˆ๋Š” ETag ์ค‘ ํ•˜๋‚˜์™€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋‹ค์‹œ ๋ณด๋ƒ…๋‹ˆ๋‹ค. PUT ๋ฐ ๊ธฐํƒ€ ์•ˆ์ „ํ•˜์ง€ ์•Š์€ ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ ์ด ๊ฒฝ์šฐ์—๋„ ๋ฆฌ์†Œ์Šค๋งŒ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ETag์˜ ์ž‘๋™ ๋ฐฉ์‹์„ ๋ชจ๋ฅด๋Š” ๊ฒฝ์šฐ RSS ๋ฐ ๊ธฐํƒ€ ํ”ผ๋“œ๋ฅผ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜๋Š” "feedparser" ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ข‹์€ ์˜ˆ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.


>>> import feedparser 
>>> d = feedparser.parse('http://feedparser.org/docs/examples/atom10.xml') 
>>> d.etag 
'"6c132-941-ad7e3080"' 
>>> d2 = feedparser.parse('http://feedparser.org/docs/examples/atom10.xml', etag=d.etag) 
>>> d2.feed 
{} 
>>> d2.debug_message 
'The feed has not changed since you last checked, so the server sent no data.  This is a feature, not a bug!' 

๋ฐ˜๋ฉด์— ๋น„๊ด€์ฃผ์˜์ž๋Š” ๊ฑฐ๋ž˜๊ฐ€ ์ข…์ข… ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์—์„œ "๋งŒ๋‚œ๋‹ค"๋Š” ์‚ฌ์‹ค์—์„œ ์‹œ์ž‘ํ•˜์—ฌ ๊ทธ์˜ ์‚ถ์„ ๋‹จ์ˆœํ™”ํ•˜๊ณ  ๋ถˆํ•„์š”ํ•œ ๊ฒฝ์Ÿ ์กฐ๊ฑด์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค . ์ž ๊ธˆ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ตฌํ˜„ํ•˜๋ ค๋ฉด ์„ธ์…˜์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜(ํ’€์—์„œ ์—ฐ๊ฒฐ์„ ๊ฐ€์ ธ์˜ค๋Š” ๋Œ€์‹  - ์ด ๊ฒฝ์šฐ ๋‚™๊ด€์  ์ž ๊ธˆ์œผ๋กœ ์ž‘์—…ํ•ด์•ผ ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Œ) ํŠธ๋žœ์žญ์…˜์— ID๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. , ์—ฐ๊ฒฐ์— ๊ด€๊ณ„์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๊ด€์  ์ž ๊ธˆ์˜ ๋‹จ์ ์€ ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋Š๋ ค์ง€์ง€๋งŒ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•ด ์นจ์ฐฉํ•˜๊ณ  ์ง„์ •ํ•œ ๊ฒฉ๋ฆฌ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์ถ”๊ฐ€์ ์ธ ์œ„ํ—˜์€ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์„œ๋กœ ์ž ๊ธด ๋ฆฌ์†Œ์Šค๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฐ€๋Šฅํ•œ ๊ต์ฐฉ ์ƒํƒœ์— ๋„์‚ฌ๋ฆฌ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํŠธ๋žœ์žญ์…˜์—๋Š” ๋ฆฌ์†Œ์Šค A์™€ B๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ํ”„๋กœ์„ธ์Šค 1์€ ๋ฆฌ์†Œ์Šค A๋ฅผ ์ ์œ ํ–ˆ๊ณ  ํ”„๋กœ์„ธ์Šค 2๋Š” ๋ฆฌ์†Œ์Šค B๋ฅผ ์ ์œ ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‘ ํ”„๋กœ์„ธ์Šค ์ค‘ ์–ด๋Š ๊ฒƒ๋„ ์‹คํ–‰์„ ๊ณ„์†ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์œผ๋ฏ€๋กœ Wikipedia๋ฅผ ๋จผ์ € ์ฝ์œผ์‹ญ์‹œ์˜ค. ๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ ์ž ๊ธˆ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐœ๋…์„ ๋” ์ž์„ธํžˆ ์•Œ๊ณ  ์‹ถ๋‹ค๋ฉด "Dinning Philosophers Problem"("์‹์‚ฌํ•˜๋Š” ์ฒ ํ•™์ž ๋ฌธ์ œ")์— ๋จธ๋ฆฌ๋ฅผ ์ˆ™์ด๋„๋ก ์ดˆ๋Œ€ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋™์ผํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๋‘ ์ž ๊ธˆ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ข‹์€ ์˜ˆ์ž…๋‹ˆ๋‹ค.

์ž ๊ธˆ ๊ตฌํ˜„์— ๋Œ€ํ•ด. ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š์ง€๋งŒ ๋ถ„์‚ฐ ์‹œ์Šคํ…œ์šฉ ์ž ๊ธˆ ๊ด€๋ฆฌ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(์˜ˆ: ZooKeeper, Redis, etcd, Consul).

7.3 ์—ฐ์‚ฐ์˜ ๋ฉฑ๋“ฑ์„ฑ

Idempotent ์ฝ”๋“œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋ฉฐ ํŠธ๋žœ์žญ์…˜์„ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๊ฐœ๋ฐœ์ž๊ฐ€ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. Idempotency๋Š” ํ•ด๋‹น ์ž‘์—…์„ ๊ฐœ์ฒด์— ๋‹ค์‹œ ์ ์šฉํ•  ๋•Œ ๋™์ผํ•œ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ž‘์—…์˜ ์†์„ฑ์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜์—ˆ์Šต๋‹ˆ๋‹ค - ๊ฒฐ๊ณผ๋ฅผ ์ œ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค. 1~5์ดˆ ํ›„์— ๋‹ค์‹œ ํ˜ธ์ถœํ•˜๋ฉด ๋™์ผํ•œ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค. ์„ธ ๋ฒˆ์งธ ์‹œ์Šคํ…œ์˜ ๋ฐ์ดํ„ฐ๋Š” ํ•จ์ˆ˜์— ์˜์กดํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ง€๋งŒ ํ•จ์ˆ˜์— ์˜์กดํ•˜๋Š” ๋ชจ๋“  ๊ฒƒ์€ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ฉฑ๋“ฑ์„ฑ์€ ์—ฌ๋Ÿฌ ๊ฐ€์ง€๋กœ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ์ค‘ ํ•˜๋‚˜๋Š” ์ฝ”๋“œ ์ž‘์„ฑ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๊ถŒ์žฅ ์‚ฌํ•ญ์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. ์ตœ๊ณ ์˜ ๊ธฐ๋Šฅ์€ ํ•œ ๊ฐ€์ง€ ์ผ์„ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์‹ญ๋‹ˆ๊นŒ? ๊ทธ๋ฆฌ๊ณ  ์ด ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ์ ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด ๋‘ ๊ฐ€์ง€ ๊ทœ์น™์„ ์ค€์ˆ˜ํ•˜๋ฉด ํ•จ์ˆ˜๊ฐ€ ๋ฉฑ๋“ฑ์„ฑ์ด ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์ด๋ฏธ ๋†’์•„์ง‘๋‹ˆ๋‹ค. ํ˜ผ๋™์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋ฉฑ๋“ฑ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋“œ์‹œ "์ˆœ์ˆ˜"("ํ•จ์ˆ˜ ์ˆœ์ˆ˜์„ฑ"์ด๋ผ๋Š” ์˜๋ฏธ์—์„œ)๋Š” ์•„๋‹˜์„ ๋ถ„๋ช…ํžˆ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์ˆœ์ˆ˜ ํ•จ์ˆ˜๋Š” ์–ด๋–ค ์‹์œผ๋กœ๋“  ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ์ž…๋ ฅ์—์„œ ๋ฐ›์€ ๋ฐ์ดํ„ฐ์—์„œ๋งŒ ์ž‘๋™ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ ๋ฐ์ดํ„ฐ์™€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋Šฅ์ด ์ˆœ์ˆ˜ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ˆœ์ˆ˜ํ•œ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.


def square(num: int) -> int: 
	return num * num 

๊ทธ๋Ÿฌ๋‚˜ ์ด ํ•จ์ˆ˜๋Š” ์ˆœ์ˆ˜ํ•˜์ง€ ์•Š๊ณ  ๋ฉฑ๋“ฑ์ ์ž…๋‹ˆ๋‹ค(์ด ๋ถ€๋ถ„์—์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๊ฒฐ๋ก ์„ ๋‚ด๋ฆฌ์ง€ ๋งˆ์‹ญ์‹œ์˜ค).


def insert_data(insert_query: str, db_connection: DbConnectionType) -> int: 
  db_connection.execute(insert_query) 
  return True 

๋งŽ์€ ๋‹จ์–ด ๋Œ€์‹  ๋ฉฑ๋“ฑ ํ”„๋กœ๊ทธ๋žจ์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šฐ๋„๋ก ๊ฐ•์š”๋ฐ›์€ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณด์‹œ๋‹ค์‹œํ”ผ ์ €๋Š” AWS๋กœ ๋งŽ์€ ์ž‘์—…์„ ํ•˜๊ณ  ์žˆ์œผ๋ฉฐ AWS Lambda๋ผ๋Š” ์„œ๋น„์Šค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. Lambda๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์„œ๋ฒ„๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๊ณ  ์ผ์ •์— ๋”ฐ๋ผ ๋˜๋Š” ์ผ๋ถ€ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ์‹คํ–‰ํ•  ์ฝ”๋“œ๋ฅผ ๋กœ๋“œํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฒคํŠธ๋Š” ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค๊ฐ€ ์ „๋‹ฌํ•˜๋Š” ๋ฉ”์‹œ์ง€์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AWS์—์„œ ์ด ๋ธŒ๋กœ์ปค๋Š” AWS SNS์ž…๋‹ˆ๋‹ค. AWS์™€ ํ•จ๊ป˜ ์ผํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ์ด ์ ์€ ๋ถ„๋ช…ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ฑ„๋„("์ฃผ์ œ")์„ ํ†ตํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋Š” ๋ธŒ๋กœ์ปค๊ฐ€ ์žˆ๊ณ  ์ด๋Ÿฌํ•œ ์ฑ„๋„์„ ๊ตฌ๋…ํ•˜๋Š” ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค๊ฐ€ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์–ด๋–ป๊ฒŒ๋“  ๋ฐ˜์‘ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” SNS๊ฐ€ "์ ์–ด๋„ ํ•œ ๋ฒˆ์€" ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌํ•œ๋‹ค๋Š” ์ ์ด๋‹ค("์ตœ์†Œ 1ํšŒ ์ „๋‹ฌ"). ๋ฌด์Šจ ๋œป์ด์—์š”? ์กฐ๋งŒ๊ฐ„ Lambda ์ฝ”๋“œ๊ฐ€ ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์€ ์ •๋ง๋กœ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๊ฐ€ ๋ฉฑ๋“ฑ์ ์ด์–ด์•ผ ํ•˜๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ณ„์ •์—์„œ ๋ˆ์ด ์ธ์ถœ๋  ๋•Œ ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ๊ฐ™์€ ๊ธˆ์•ก์„ ๋‘ ๋ฒˆ ์ธ์ถœํ•  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์ด๊ฒƒ์ด ์‹ค์ œ๋กœ 2๋ฒˆ์˜ ๋…๋ฆฝ์ ์ธ ์‹œ๊ฐ„์ธ์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ด๋“ค์€ ํ•˜๋‚˜์˜ ๋ฐ˜๋ณต์ด ์•„๋‹ˆ๋ผ 2๊ฐœ์˜ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ž…๋‹ˆ๋‹ค.

๋ณ€๊ฒฝ์„ ์œ„ํ•ด API์— ๋Œ€ํ•œ ์š”์ฒญ ๋นˆ๋„๋ฅผ ์ œํ•œ("์†๋„ ์ œํ•œ")ํ•˜๋Š” ๋˜ ๋‹ค๋ฅธ ์˜ˆ๋ฅผ ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค. Lambda๋Š” ํŠน์ • user_id๊ฐ€ ์žˆ๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜๋ฉฐ ํ•ด๋‹น ID๋ฅผ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž๊ฐ€ ์ผ๋ถ€ API์— ๋Œ€ํ•œ ๊ฐ€๋Šฅํ•œ ์š”์ฒญ ์ˆ˜๋ฅผ ์†Œ์ง„ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ ๊ฐ’์„ AWS์—์„œ DynamoDB์— ์ €์žฅํ•˜๊ณ  ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ 1์”ฉ ๋Š˜๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด Lambda ํ•จ์ˆ˜๊ฐ€ ๋™์ผํ•œ ์ด๋ฒคํŠธ์— ์˜ํ•ด ๋‘ ๋ฒˆ ํ˜ธ์ถœ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? ๊ทธ๋Ÿฐ๋ฐ lambda_handler() ํ•จ์ˆ˜์˜ ์ธ์ˆ˜์— ์ฃผ์˜๋ฅผ ๊ธฐ์šธ์˜€์Šต๋‹ˆ๊นŒ? ๋‘ ๋ฒˆ์งธ ์ธ์ˆ˜์ธ AWS Lambda์˜ ์ปจํ…์ŠคํŠธ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋ฉฐ ๊ฐ ๊ณ ์œ  ํ˜ธ์ถœ์— ๋Œ€ํ•ด ์ƒ์„ฑ๋˜๋Š” request_id๋ฅผ ๋น„๋กฏํ•œ ๋‹ค์–‘ํ•œ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ์ด์ œ ํ…Œ์ด๋ธ”์— ์ˆ˜ํ–‰๋œ ํ˜ธ์ถœ ์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๋Œ€์‹  request_id ๋ชฉ๋ก์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค Lambda๊ฐ€ ์ฃผ์–ด์ง„ ์š”์ฒญ์ด ์ด๋ฏธ ์ฒ˜๋ฆฌ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

import json
import os
from typing import Any, Dict

from aws_lambda_powertools.utilities.typing import LambdaContext  # needed only for argument type annotation
import boto3

limit = os.getenv('LIMIT')

def handler_name(event: Dict[str: Any], context: LambdaContext):

	request_id = context.aws_request_id

	# We find user_id in incoming event
	user_id = event["user_id"]

	# Our table for DynamoDB
	table = boto3.resource('dynamodb').Table('my_table')

	# Doing update
	table.update_item(
    	Key={'pkey': user_id},
    	UpdateExpression='ADD requests :request_id',
    	ConditionExpression='attribute_not_exists (requests) OR (size(requests) < :limit AND NOT contains(requests, :request_id))',
    	ExpressionAttributeValues={
        	':request_id': {'S': request_id},
        	':requests': {'SS': [request_id]},
        	':limit': {'N': limit}
    	}
	)

	# TODO: write further logic

	return {
    	"statusCode": 200,
    	"headers": {
        	"Content-Type": "application/json"
    	},
    	"body": json.dumps({
        	"status ": "success"
    	})
	}

๋‚ด ์˜ˆ๋Š” ์‹ค์ œ๋กœ ์ธํ„ฐ๋„ท์—์„œ ๊ฐ€์ ธ์˜จ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ ์กฐ๊ธˆ ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋ฏ€๋กœ ์›๋ณธ ์†Œ์Šค์— ๋Œ€ํ•œ ๋งํฌ๋ฅผ ๋‚จ๊ฒจ ๋‘˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ณ ์œ ํ•œ ํŠธ๋žœ์žญ์…˜ ID์™€ ๊ฐ™์€ ๊ฒƒ์„ ๊ณต์œ  ๋ฐ์ดํ„ฐ๋ฅผ ์ž ๊ทธ๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์•ž์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์‹ญ๋‹ˆ๊นŒ? ์ด์ œ ์ž‘์—…์„ ๋ฉฑ๋“ฑ์„ฑ์œผ๋กœ ๋งŒ๋“œ๋Š” ๋ฐ์—๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ID๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.