Published on

๐Ÿคฟ ์ˆจ ๊พน์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ 1 : ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ

Authors
  • avatar
    Name
    Woojin Son
    Twitter

๐Ÿคฟ ์ˆจ ๊พน์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ 1 : ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ

๐Ÿ”Ž 1. Intro

์ƒˆ๋กœ์šด ์‹œ๋ฆฌ์ฆˆ๋กœ ๋Œ์•„์™”์Šต๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž ์†์šฐ์ง„ ์ž…๋‹ˆ๋‹ค. ๋ˆˆ ๋– ๋ณด๋‹ˆ 6์›”์ด ๋์ด ๋ณด์ž…๋‹ˆ๋‹ค. 2025๋…„์ด ์–ธ์ œ ์–ด๋–ป๊ฒŒ ์ง€๋‚˜๊ฐ€๋Š” ์ง€ ์กฐ์ฐจ๋„ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋„ค์š”.

์•„๋งˆ ์ด ๊ธ€์ด ์˜ฌ๋ผ๊ฐˆ ๋•Œ ์ฏค์—๋Š” 7์›”์ผ๊ฒ๋‹ˆ๋‹ค. 6์›” ๊นŒ์ง€๋งŒ ํ•ด๋„ ๊ทธ๋ ‡๊ฒŒ ๋ฅ์ง„ ์•Š์•˜๋Š”๋ฐ 7์›”์ด ๋˜๋‹ˆ ํ™•์‹คํžˆ ๋ฅ๋„ค์š”

์ด๋ฒˆ์—๋Š” '์ˆจ ๊พน ์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ' ๋ผ๋Š” ์‹œ๋ฆฌ์ฆˆ๋ฅผ ์—ฐ์žฌํ•ด๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค. ์ •๋ง ๊ฐ€๋ณ๊ฒŒ ์“ด๋‹ค๋ฉด ๊ฐ€๋ณ๊ฒŒ๋„ ์“ธ ์ˆ˜ ์žˆ๋Š” ์ฃผ์ œ์ง€๋งŒ, ์–ด๋””๊นŒ์ง€ ์“ธ ์ˆ˜ ์žˆ๋Š”์ง€ ํ•œ๋ฒˆ ๊นŠ๊ฒŒ ํŒŒ ๋ณด๋Š” ๊ฒŒ ์ข‹๊ฒ ๋‹จ ์ƒ๊ฐ์ด ๋“ค์—ˆ์ฃ .

์ตœ๊ทผ ๋“ค์–ด์„œ ๋™๊ธฐ, ๋น„๋™๊ธฐ์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๊ณ ๋ฏผ๋“ค์„ ํ•˜๋‹ค๊ฐ€ ์ œ๋Œ€๋กœ ํ•œ๋ฒˆ ๋”ฅ๋‹ค์ด๋ธŒ ํ•ด๋ณด์ž๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์ปคํ”ผํ•œ์ž” ํ•˜๋ฉด์„œ ์ฝ์–ด์ฃผ์„ธ์š”. ์‹œ์ž‘ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

โ˜•๏ธ 2. ๋™๊ธฐ VS ๋น„๋™๊ธฐ

๋™๊ธฐ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด์„œ๋Š” ์œ ๋ช…ํ•œ ์˜ˆ์ œ๊ฐ€ ๋“ฑ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ปคํ”ผ์ˆ ์˜ˆ์ œ์ฃ .

+------------------------------+
|         โ˜• ๋™๊ธฐ ์ปคํ”ผ์ˆ        |
+------------------------------+
| ์ค„์„œ์„œ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์†๋‹˜๋“ค       |
|                              |
|  {\___/}                     |
|  ( โ€ข ใ…โ€ข)  "์ปคํ”ผ ์ฃผ์„ธ์š”..."  |
|    โ†“                         |
|  [๐Ÿ‘จโ€๐Ÿณ] โ˜• ๋งŒ๋“œ๋Š” ์ค‘...        |
|    โ†“                         |
|  {\___/}                     |
|  ( โ€ข ใ…โ€ข)  "๊ณ ๋งˆ์›Œ์š”!"       |
+------------------------------+

์˜ค๋žœ๋งŒ์— ์นด๊ณต์„ ํ•˜๋ ค๊ณ  ์ปคํ”ผ์ˆ์— ๋“ค๋ ธ์Šต๋‹ˆ๋‹ค. ๊ฐ„ํŒ ๋ถ€ํ„ฐ ๋ญ”๊ฐ€ ๊ดด๋ž„ํ•œ '๋™๊ธฐ ์ปคํ”ผ์ˆ' ์ด์ฃ .

์‚ฌ๋žŒ๋“ค์ด ์ค„์„ ๊ธธ๊ฒŒ ์„œ์žˆ์Šต๋‹ˆ๋‹ค. ์ฃผ๋ฌธํ•œ ์ปคํ”ผ๋ฅผ ๋ฐ›์•„์„œ ๊ฐ์ž ์ž๋ฆฌ๋กœ ์ด๋™ํ•˜๊ณ  ์žˆ๋„ค์š”. ์šฐ๋ฆฌ๋„ ๋ฐ›์œผ๋Ÿฌ ๊ฐ€๋ณผ๊นŒ์š”?

์†๋‹˜! 100,000,000์› ์ž…๋‹ˆ๋‹ค.

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

+-----------------------------------+
|          โ˜• ๋น„๋™๊ธฐ ์ปคํ”ผ์ˆ          |
+-----------------------------------+
|  {\___/}                          |
|  ( โ€ข ใ…โ€ข) "์ฃผ๋ฌธํ• ๊ฒŒ์š”!"           |
|     โ†’ [๐ŸŽซ] "42๋ฒˆ ์†๋‹˜์ž…๋‹ˆ๋‹ค"     |
|                                   |
|  {\___/}                          |
|  ( โ€ข ใ…โ€ข) (๋†€๋Ÿฌ๊ฐ)                |
|                                   |
|  [๐Ÿ‘จโ€๐Ÿณ] โ˜• ์ปคํ”ผ ๋งŒ๋“œ๋Š” ์ค‘...        |
|                                   |
|  [๐Ÿ””] "42๋ฒˆ ์ปคํ”ผ ๋‚˜์™”์Šต๋‹ˆ๋‹ค!"    |
|     โ†“                             |
|  {\___/}                          |
|  ( โ€ข ใ…โ€ข) "์™”๋‹ค!" โ˜•               |
+-----------------------------------+

๋™๊ธฐ ์ปคํ”ผ์ˆ์—์„œ ๋„ˆ๋ฌด ์˜ค๋ž˜ ์ค„์„ ์„œ๋‹ค๋ณด๋‹ˆ ๋‹ค๋ฆฌ๊ฐ€ ์•„ํŒŒ์กŒ์Šต๋‹ˆ๋‹ค. ์ปคํ”ผ๋ฅผ ์ฃผ๋ฌธํ•ด๋†“๊ณ  ๋ญ”๊ฐ€ ๋”ด ์ผ์„ ํ•˜๊ณ  ์‹ถ์–ด์กŒ์–ด์š”.

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

์†๋‹˜ 100,000,000 ์›์ž…๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ์ง„๋™ ๋ฒจ ์šธ๋ฆฌ๋ฉด ์ฐพ์œผ๋Ÿฌ ์˜ค์„ธ์š”!

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

๋˜ ํ•œ๊ฐ€์ง€ ์ฃผ๋ชฉํ•  ์ ์€, ๋™๊ธฐ ์ปคํ”ผ์ˆ์—์„œ๋Š” ์—ฌ๋Ÿฌ ์ค„์„ ํ†ตํ•ด ๋Œ€๊ธฐ ์ค„์„ ๋งŒ๋“ค์—ˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ ์ปคํ”ผ์ˆ์—์„œ๋Š” ๊ตณ์ด ๊ทธ๋ ‡๊ฒŒ๊นŒ์ง€ ์ค„์„ ์„œ์ง„ ์•Š์•˜์ฃ ? ๋™๊ธฐ ์ปคํ”ผ์ˆ์—์„œ ์†๋‹˜๋“ค์˜ ํšŒ์ „๋ฅ ์„ ๋†’ํžˆ๋ ค๋ฉด, ๋‘˜ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ปคํ”ผ๋ฅผ ์•„์ฃผ ๋น ๋ฅด๊ฒŒ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ปคํ”ผ ์ฃผ๋ฌธ ์ค„์„ ๋Š˜๋ ค์•ผ์ฃ . ์ „์ž๋Š” ์Œ ์žํŒ๊ธฐ๋ผ๋ฉด ๊ฐ€๋Šฅ ํ•  ์ง€๋„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค๋งŒ, ์‚ฌ๋žŒ์„ ์“ฐ๋Š” ์ž…์žฅ์—์„œ๋Š” ๊ฒฐ๊ตญ ๊ทธ ์‚ฌ๋žŒ์˜ ํผํฌ๋จผ์Šค์— ๋งก๊ฒจ์•ผ ํ•˜์ฃ .

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

๊ณ ๊ฐ                                     ์žํŒ๊ธฐ
{\___/}   โ”€โ”€ ๋ฒ„ํŠผ ๋ˆ„๋ฆ„ โ”€โ”€โ–ถ         [์ปคํ”ผ ์ œ์กฐ ์ค‘... (5์ดˆ)]
( โ€ข ใ…โ€ข)                               โ”‚
                                       โ–ผ
                              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                              โ”‚   ์ปคํ”ผ ์™„์„ฑ ๋ฐ ๋ฐฐ์ถœ   โ”‚
                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                       โ”‚
                         โ—€โ”€โ”€โ”€ ์ปคํ”ผ ๋ฐฐ์ถœ ์™„๋ฃŒ ํ›„ ๋ฐ›์Œ โ”€โ”€โ”€โ–ถ
                                       โ”‚
{\___/}                                โ”‚
( โ€ข ใ…โ€ข)   โ”€โ”€ ์ปคํ”ผ ์ˆ˜๋ น โ”€โ”€โ–ถ

์žํŒ๊ธฐ ์ปคํ”ผ ํ•˜๋‹ˆ๊นŒ ์ƒ๊ฐ๋‚œ๊ฑด๋ฐ, ์ด ๊ธ€์„ ์ฝ๊ณ  ๊ณ„์‹œ๋Š” ๋…์ž๋ถ„๋“ค ์ค‘ ์žํŒ๊ธฐ ์„ธ๋Œ€๊ฐ€ ์•„๋‹Œ ๋ถ„์ด ๊ณ„์‹ค ์ง€ ๋ชจ๋ฅด๊ฒ ๋„ค์š”.

97๋…„์ƒ์ธ ์ €๋Š” ์žํŒ๊ธฐ์˜ ์ถ”์–ต์„ ๊ธฐ์–ต ํ•  ์ˆ˜ ์žˆ๋Š” ์„ธ๋Œ€์— ์†ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€๋” ์žํŒ๊ธฐ์— ์šฐ์œ ๊ฐ€ ์žˆ์œผ๋ฉด ๊ผญ ๋ฝ‘์•„ ๋จน์—ˆ์—ˆ์ฃ .

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

์ด์ฒ˜๋Ÿผ ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ๋Š” ๋กœ์ง์˜ ๋™์ž‘ ๋ฐฉํ–ฅ์„ฑ์— ๋”ฐ๋ผ ๋‚˜๋‰  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. '์ปคํ”ผ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์†๋‹˜์—๊ฒŒ ํŒ๋งคํ•œ๋‹ค.' ๋ผ๋Š” ๋ชฉ์ ์€ ๊ณต์œ ํ•˜์ง€๋งŒ, ๊ฐ ๋กœ์ง ๋ณ„๋กœ ๊ด€์‹ฌ์‚ฌ๊ฐ€ ์กฐ๊ธˆ ์”ฉ ๋‹ค๋ฅด์ฃ .

๐Ÿค” 3. ์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜์š”?

๋™๊ธฐ์™€ ๋น„๋™๊ธฐ๋Š” ํ•„์š”ํ•œ ์ƒํ™ฉ์— ๋”ฐ๋ผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์ž…๋‹ˆ๋‹ค.

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

๐ŸŸ ์ปคํ”ผ์ˆ ์˜ˆ์ œ ๋ณด๋‹จ ๋ถ•์–ด๋นต์ง‘ ์˜ˆ์ œ๊ฐ€ ์ข€ ๋” ๋‚ซ์ง€ ์•Š๋‚˜ ๋ผ๋Š” ์ƒ๊ฐ์ด ์ž ์‹œ ๋“œ๋„ค์š”. ๋ถ•์–ด๋นต ์ง‘์ด ๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ๋น„์œ ํ•  ์ˆ˜ ์žˆ๋Š” ์ „ํ˜•์ ์ธ ํ˜„์‹ค ์˜ˆ์‹œ์ง€ ์•Š๋‚˜ ์‹ถ์–ด์š” ใ…‹ใ…‹

??? : ์‚ฌ์žฅ๋‹˜ ์ฃผ๋ฌธ์ด์š”!
์‚ฌ์žฅ๋‹˜ : ์•„๋‹ˆ ์ง€๊ธˆ ์ค„ ์•ˆ๋ณด์—ฌ์š”? ์•„์ง ์•ž ์†๋‹˜ ๋ชป๋ฐ›์•˜์ž–์•„์š”!

๋ฌผ๋ก  ๊ฐ€๊ฒŒ ๋ฐ”์ด ๊ฐ€๊ฒŒ์ง€๋งŒ...์‚ฌ์žฅ๋‹˜์ด ์—ฐ๋ฅœ์ด ์žˆ์œผ์‹œ๋ฉด ์ด๋Ÿฐ ํŒจํ„ด๋„ ์žˆ์„ ์ˆ˜ ์žˆ์ฃ .

์‚ฌ์žฅ๋‹˜ : ์†๋‹˜ ๋ช‡๊ฐœ ์ฃผ๋ฌธํ•˜์…จ์ฃ ?

ํ˜„์‹ค ์„ธ๊ณ„์—์„œ ์ปดํ“จํ„ฐ ์„ธ๊ณ„๋กœ ํ•œ๋ฒˆ ๊ฐ€๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋กœ์ง์˜ ์„ฑ๊ฒฉ์— ๋”ฐ๋ผ ์šฐ๋ฆฌ๋Š” ๋‘ ๊ฐ€์ง€ ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์ฃ . ํ•œ๋ฒˆ ์ž์„ธํžˆ ์ •๋ฆฌ ํ•ด ๋ณผ๊นŒ์š”?

๊ตฌ๋ถ„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ์ ํ•ฉํ•œ ์˜ˆ์‹œ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ์ ํ•ฉํ•œ ์˜ˆ์‹œ
์ฒ˜๋ฆฌ ์ˆœ์„œ์‚ฌ์šฉ์ž ์ธ์ฆ ์ฒ˜๋ฆฌ (ํ† ํฐ ๋ฐœ๊ธ‰ ํ›„๋งŒ ๋‹ค์Œ ๋‹จ๊ณ„ ์ง„ํ–‰ ๊ฐ€๋Šฅ)์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ํ›„ ์ธ๋„ค์ผ ์ƒ์„ฑ (์ธ๋„ค์ผ์€ ๋Šฆ๊ฒŒ ์ƒ์„ฑ๋ผ๋„ ๋ฌด๋ฐฉํ•จ)
ํŠธ๋žœ์žญ์…˜๊ฒฐ์ œ ์š”์ฒญ ๋ฐ ์Šน์ธ (๋ชจ๋“  ๋‹จ๊ณ„๊ฐ€ ์„ฑ๊ณตํ•ด์•ผ ์ตœ์ข… ์Šน์ธ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)๊ฒฐ์ œ ์„ฑ๊ณต ํ›„ ์•Œ๋ฆผ ์ „์†ก (์•Œ๋ฆผ์€ ์‹คํŒจํ•ด๋„ ๊ฒฐ์ œ์—๋Š” ์˜ํ–ฅ ์—†์Œ)
๋ฐ์ดํ„ฐ ์ •ํ•ฉ์„ฑ์ฃผ๋ฌธ ์ƒ์„ฑ ํ›„ ์žฌ๊ณ  ์ฐจ๊ฐ (์ •ํ™•ํ•œ ์ˆœ์„œ๋กœ ์ฒ˜๋ฆฌ ํ•„์š”)์‚ฌ์šฉ์ž ํ–‰๋™ ๋กœ๊ทธ ์ €์žฅ (์ผ๋‹จ ์ˆ˜์ง‘๋งŒ ํ•˜๊ณ  ๋‚˜์ค‘์— ๋ฐฐ์น˜๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)
์‘๋‹ต ์˜์กด์„ฑAPI ์ฒด์ธ ํ˜ธ์ถœ (์˜ˆ: A โ†’ B โ†’ C ์ˆœ์œผ๋กœ ํ˜ธ์ถœํ•˜๋ฉฐ ์•ž๋‹จ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ค์Œ๋‹จ ์ž…๋ ฅ์— ์‚ฌ์šฉ๋จ)์ด๋ฉ”์ผ ๋ฐœ์†ก (์‘๋‹ต ์—†์ด๋„ ๋ณ„๋„ ํ์— ์ €์žฅ ํ›„ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ)
UI ์ƒํ˜ธ์ž‘์šฉ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ๋กœ๊ทธ์ธ ์™„๋ฃŒ ํ›„ ์ด๋™ (๋ฐ˜๋“œ์‹œ ์™„๋ฃŒ๋ผ์•ผ ์ด๋™ ๊ฐ€๋Šฅ)๊ฒ€์ƒ‰์–ด ์ž๋™์™„์„ฑ ์š”์ฒญ (๊ฒฐ๊ณผ ๋Šฆ๊ฒŒ ์™€๋„ ์ž…๋ ฅ์€ ๊ณ„์† ๋ฐ›์„ ์ˆ˜ ์žˆ์Œ)
์‹œ์Šคํ…œ ๋ถ€ํ•˜์‚ฌ์šฉ์ž ๊ณ„์ขŒ ์ด์ฒด ์ฒ˜๋ฆฌ (ํ•˜๋‚˜์˜ ์ฒ˜๋ฆฌ๊ฐ€ ๋๋‚˜์•ผ ๋‹ค์Œ ์‚ฌ์šฉ์ž๊ฐ€ ์ด์ฒด ๊ฐ€๋Šฅ)์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ์ˆ˜์‹  (WebSocket, SSE ๋“ฑ์œผ๋กœ ๋น„๋™๊ธฐ ์ „๋‹ฌ)

์šฐ๋ฆฌ๊ฐ€ ํ”„๋กœ๋•ํŠธ๋ฅผ ์„ฑ๊ณต ์‹œํ‚ค๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์€ ์ •๋ง ๋‹ค์–‘ํ•ฉ๋‹ˆ๋‹ค. ๋กœ๊ทธ์ธ ๋ถ€ํ„ฐ ์กฐํšŒ, ๊ฒฐ์ œ ๋“ฑ์˜ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด, ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ ์‚ฌ์ด์— ๊ณ ๋ฏผ์ด ๋“ค์–ด๊ฐ€์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ธฐ์ฃ .

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

๐Ÿ–ฅ๏ธ 4. ๋ฐฑ์—”๋“œ ์—”์ง€๋‹ˆ์–ด๋ง์—์„œ์˜ ๋™๊ธฐ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ

๋ฐฑ์—”๋“œ์˜ ์„ธ๊ณ„๋กœ ํ•œ๋ฒˆ ๋“ค์–ด์™€๋ณผ๊นŒ์š”? ์šฐ๋ฆฌ๊ฐ€ ํ˜„์žฌ ์ผ๋ฐ˜์ ์ธ Spring MVC ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœ ํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ์„ธ์…˜์—์„œ๋Š” ๋ฐฑ์—”๋“œ ์—”์ง€๋‹ˆ์–ด๋ง ์—…๋ฌด๋ฅผ ๋งก๊ณ  ์žˆ๋Š” ๊ด€์ ์—์„œ์˜ ๋™๊ธฐ, ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด ๋‹ค๋ค„ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

โณ 4.1 ๋™๊ธฐ + ๋ธ”๋กœํ‚น : ์ผ๋ฐ˜์ ์ธ ๋ฐฑ์—”๋“œ ์š”์ฒญ-์‘๋‹ต ์ฒ˜๋ฆฌ ํŒจํ„ด

์ตœ๋Œ€ํ•œ ์ฝ”๋“œ๋Š” ์ œ์™ธํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์˜ ์ฃผ์ œ๊ฐ€ Spring ๊ฐ€์ด๋“œ ๋ณด๋‹จ ๋™๊ธฐ์™€ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋‹ˆ๊นŒ์š”.

ํ•˜์ง€๋งŒ ๊ธ€์„ ์“ฐ๋‹ค๋ณด๋ฉด ์ฝ”๋“œ๊ฐ€ ๋ณธ์˜ ์•„๋‹ˆ๊ฒŒ ์ž์ฃผ ๋“ฑ์žฅํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค...์ ๋‹นํžˆ ๋„˜๊ฒจ๊ฐ€๋ฉฐ ์ฝ์–ด์ฃผ์„ธ์š”.

Spring MVC ๋Š” ์ „ํ†ต์ ์ธ Servlet ๊ธฐ๋ฐ˜์˜ ๋™๊ธฐ์  ์š”์ฒญ-์‘๋‹ต ์ฒ˜๋ฆฌ ๋ชจ๋ธ์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. Apache Tomcat ๊ณผ ๊ฐ™์€ Servlet ์ปจํ…Œ์ด๋„ˆ๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ 1๊ฑด ๋‹น ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜์ฃ .

[Client] โ†’ [DispatcherServlet] โ†’ [Controller] โ†’ [Service] โ†’ [RestTemplate ํ˜ธ์ถœ โ†’ ์™ธ๋ถ€ API ์‘๋‹ต ๋Œ€๊ธฐ] โ†’ ์‘๋‹ต ๋ฐ˜ํ™˜

์œ„์˜ ํŒจํ„ด์€ ๊ฒฐ์ œ ์ „๋ฌธ ์—ฐ๋™๊ณผ ๊ฐ™์€ ๋กœ์ง ๊ฐœ๋ฐœ์—์„œ ์ž์ฃผ ์“ฐ์ž…๋‹ˆ๋‹ค. ๊ผญ ๊ฒฐ์ œ ์ „๋ฌธ์ด ์•„๋‹ˆ๋”๋ผ๋„ ๋‚ ์”จ ์ •๋ณด, ์ฃผ์†Œ ๊ฒ€์ƒ‰ ๋“ฑ๊ณผ ๊ฐ™์€ ์™ธ๋ถ€ API ๋ฌด์—‡์ด๋“  ์—ฐ๋™ํ•  ๋•Œ ์ •๋ง ์ž์ฃผ ์“ฐ์ด๋Š” ๊ตญ๋ฃฐ ํŒจํ„ด์ด์ฃ .

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

๊ทธ๋Ÿผ ์™œ ์‘๋‹ต์„ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ์„๊นŒ์š”? ๊ธฐ๋ณธ์ ์œผ๋กœ Spring MVC ๋Š” ๋™๊ธฐ + ๋ธ”๋กœํ‚น ๋ชจ๋ธ์„ ๋”ฐ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๐Ÿšซ๐Ÿ”“ 4.2 ๋ธ”๋กœํ‚น, ๋…ผ๋ธ”๋กœํ‚น

๋ธ”๋กœํ‚น์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๋‚˜์™”๋„ค์š”. ์ด ์ฏค์—์„œ ๋…ผ ๋ธ”๋กœํ‚น๊ณผ ๋ธ”๋กœํ‚น์— ๋Œ€ํ•ด ์กฐ๊ธˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ธ”๋กœํ‚น(Blocking) ๊ณผ ๋…ผ ๋ธ”๋กœํ‚น (Non-Blocking) ์€ ํ”„๋กœ๊ทธ๋žจ์ด I/O ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์— ๋Œ€ํ•œ ๊ฐœ๋…์ž…๋‹ˆ๋‹ค.
๋ธ”๋กœํ‚น ๋ฐฉ์‹์—์„œ๋Š” I/O ์ž‘์—… (ํŒŒ์ผ ์ฝ๊ธฐ, ์™ธ๋ถ€ API ์š”์ฒญ) ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ํ•ด๋‹น ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ ๊นŒ์ง€ ํ”„๋กœ๊ทธ๋žจ์˜ ์‹คํ–‰์ด ๋ฉˆ์ถ”๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. I/O ์ž‘์—…์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „ ๊นŒ์ง€ ๋‹ค๋ฅธ ์–ด๋–ค ์ž‘์—…๋„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†์ฃ .

[Thread] โ”€โ”€โ–ถ ์ž‘์—… A ์‹œ์ž‘
            (API ์‘๋‹ต ๋Œ€๊ธฐ ์ค‘...)
            (API ์‘๋‹ต ๋Œ€๊ธฐ ์ค‘...)
            (API ์‘๋‹ต ๋„์ฐฉ!)
            โ–ถ ์ž‘์—… A ๊ฒฐ๊ณผ ์ฒ˜๋ฆฌ
            โ”€โ”€โ–ถ ์ž‘์—… B ์‹œ์ž‘

๋…ผ ๋ธ”๋กœํ‚น ๋ฐฉ์‹์—์„œ๋Š” I/O ์ž‘์—…์„ ์š”์ฒญ ํ•˜๋”๋ผ๋„ ํ”„๋กœ๊ทธ๋žจ์˜ ์‹คํ–‰์ด ๋ฉˆ์ถ”์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰์‹œ ๋‹ค์Œ ์ž‘์—…์œผ๋กœ ๋„˜์–ด๊ฐˆ ์ˆ˜ ์žˆ์ฃ .

[Thread] โ”€โ”€โ–ถ ์ž‘์—… A ์‹œ์ž‘
            โ–ถ ์š”์ฒญ๋งŒ ๋ณด๋‚ด๊ณ  ๋‹ค์Œ์œผ๋กœ ์ด๋™
            โ”€โ”€โ–ถ ์ž‘์—… B ์‹œ์ž‘
            โ–ถ ์š”์ฒญ๋งŒ ๋ณด๋‚ด๊ณ  ๋‹ค์Œ์œผ๋กœ ์ด๋™
            โ”€โ”€โ–ถ ์ž‘์—… C ์‹œ์ž‘
            โ–ถ ์š”์ฒญ๋งŒ ๋ณด๋‚ด๊ณ  ๋‹ค์Œ์œผ๋กœ ์ด๋™

๋ธ”๋กœํ‚น, ๋…ผ๋ธ”๋กœํ‚น : ์™œ ์“ฐ๋Š”๊ฑธ๊นŒ์š”?

์šฐ๋ฆฌ์˜ HTTP ์š”์ฒญ์€ ์–ด์ฉ„๋“  ์š”์ฒญ ํ•˜๋‚˜๋กœ ๋ณด๋ฉด ๋‹จ๊ฑด์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‹œ์Šคํ…œ ์ „์ฒด์ ์œผ๋กœ ๋ณด๋ฉด ์ˆ˜ ๋งŽ์€ ์š”์ฒญ๋“ค์— ๋Œ€ํ•œ ์‘๋‹ต์„ ์ค˜์•ผํ•˜๋Š” ์ปคํ”ผ์ˆ์˜ ์ž…์žฅ๊ณผ๋„ ๊ฐ™์Šต๋‹ˆ๋‹ค.

        โ˜• ๋™๊ธฐ ์ปคํ”ผ์ˆ โ€“ ํ•˜๋‚˜์”ฉ ์ฒ˜๋ฆฌ ์ค‘...

[Thread-1] โ”€โ”€โ”
             โ”‚   {\___/}  โ˜• ์ปคํ”ผ ์ œ์กฐ ์ค‘... (3์ดˆ ๋Œ€๊ธฐ)
             โ”‚   ( โ€ข ใ…โ€ข)   โ† ์š”์ฒญ 1
             โ–ผ

[Thread-2] โ”€โ”€โ”
             โ”‚   {\___/}  โ˜• ์ปคํ”ผ ์ œ์กฐ ์ค‘... (5์ดˆ ๋Œ€๊ธฐ)
             โ”‚   ( - แ—œ -)  โ† ์š”์ฒญ 2
             โ–ผ

[Thread-3] โ”€โ”€โ”
             โ”‚   {\___/}  โ˜• ์ปคํ”ผ ์ œ์กฐ ์ค‘... (2์ดˆ ๋Œ€๊ธฐ)
             โ”‚   ( ร—_ร— )  โ† ์š”์ฒญ 3
             โ–ผ

=== ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ ์—†์Œ! ===

[๋Œ€๊ธฐ ์š”์ฒญ-1]  {\___/}   โ† ์š”์ฒญ 4: ์ปคํ”ผ ์ฃผ๋ฌธ ์ค‘...
              ( โ€ข๏ธตโ€ข )   "์™œ ์ด๋ ‡๊ฒŒ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ์ง€โ€ฆ"

[๋Œ€๊ธฐ ์š”์ฒญ-2]  {\___/}   โ† ์š”์ฒญ 5: ์ปคํ”ผ ์ฃผ๋ฌธ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์‹คํŒจ
              ( โ€ขฬ€ แ—ฃ โ€ขฬ ) "์„œ๋ฒ„๊ฐ€ ํ„ฐ์กŒ์–ด!!!"

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ฐ ์š”์ฒญ์— ๋Œ€ํ•ด ์Šค๋ ˆ๋“œ๊ฐ€ ํ•˜๋‚˜ ์”ฉ ํ• ๋‹น์ด ๋˜์ฃ . ์™ธ๋ถ€ API (์—ฌ๊ธฐ์„œ๋Š” ์ปคํ”ผ ์ œ์กฐ๋ผ๊ณ  ํ•ฉ์‹œ๋‹ค.) ๋ฅผ ๊ฐ ์Šค๋ ˆ๋“œ๊ฐ€ ํ• ๋‹น๋ฐ›์•„์„œ ๋Œ€๊ธฐ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ธ๋ฐ, ๋ฌธ์ œ๋Š” ์ „ํ˜•์ ์ธ ๋™๊ธฐ + ๋ธ”๋กœํ‚น ํŒจํ„ด์—์„œ๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ์š”์ฒญ์„ ์‘๋‹ตํ•˜๋Š” ๋™์•ˆ ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ ๋Œ€๊ธฐ ์ค„์ด ์ƒ๊ธธ ์ˆ˜ ๋ฐ–์— ์—†๊ณ  ์–ด๋А์ˆœ๊ฐ„ ์„œ๋ฒ„๊ฐ€ ํ„ฐ์กŒ๋‹ค๋ผ๋Š” CS ๋ฅผ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๐ŸŒ 4.3 ๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น : ์กฐ๊ธˆ ๋” ์œ ์—ฐํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ

์ด ์ฏค์—์„œ ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ์„ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  ์šฐ๋ฆฌ์˜ ๊ตฌ์กฐ ์ƒ ๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์ œ์™ธํ•˜์ง€ ์•Š์„ ์ˆ˜๋Š” ์—†๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€์š”? ์ €ํฐ ์ง€๊ธˆ Spring MVC ๋ฅผ ์“ฐ๊ณ  ์žˆ์ž–์•„์š”?
์ด ์ƒํ™ฉ์—์„œ ๋ธ”๋กœํ‚น, ๋…ผ ๋ธ”๋กœํ‚น์„ ๋„์ž…ํ–ˆ์„ ๋•Œ ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ์„๊นŒ์š”?

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

Spring 5 ๋ถ€ํ„ฐ๋Š” WebClient ๋ผ๋Š” ๋…ผ ๋ธ”๋กœํ‚น + ๋น„๋™๊ธฐ ๊ธฐ๋ฐ˜์˜ HTTP ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. WebClient ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ํ๋ฆ„์„ ํƒ€๊ฒŒ ๋˜์ฃ .

[Client] โ†’ [DispatcherServlet] โ†’ [Controller] โ†’ [Service] โ†’ WebClient ํ˜ธ์ถœ โ†’ ๋ฆฌ์•กํ„ฐ ์ด๋ฒคํŠธ ๋ฃจํ”„ ๋“ฑ๋ก โ†’ ์‘๋‹ต ์˜ค๋ฉด ์ฝœ๋ฐฑ ์ฒ˜๋ฆฌ โ†’ ์‘๋‹ต ๋ฐ˜ํ™˜

์•„๊นŒ์™€๋Š” ์กฐ๊ธˆ ๋‹ฌ๋ผ์กŒ์Šต๋‹ˆ๋‹ค. ์ „์ฒด ํ๋ฆ„ ์ž์ฒด๋Š” ๋™๊ธฐ ์ฒ˜๋ฆฌ์ง€๋งŒ, Service ๋ ˆ์ด์–ด์—์„œ WebClient ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ณผ์ •์—์„œ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ + ๋…ผ ๋ธ”๋กœํ‚น์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ๊ธฐ์กด๊ณผ๋Š” ์–ด๋–ค ์ฐจ์ด๊ฐ€ ์žˆ์„๊นŒ์š”?

        โ˜• ๋™๊ธฐ ํ๋ฆ„ ๊ธฐ๋ฐ˜, ๋…ผ ๋ธ”๋กœํ‚น ํ™œ์šฉ ์ปคํ”ผ์ˆ (WebClient)

[Thread-1] โ”€โ”€โ”
             โ”‚   {\___/}  ๐Ÿ”” ์ง„๋™๋ฒจ ๋ฐ›๊ณ  ์ž๋ฆฌ๋กœ ์ด๋™!
             โ”‚   ( โ€ข ใ…โ€ข)   โ† ์š”์ฒญ 1: ์ฃผ๋ฌธ ์™„๋ฃŒ
             โ–ผ

[Thread-2] โ”€โ”€โ”
             โ”‚   {\___/}  ๐Ÿ”” ์ง„๋™๋ฒจ ๋ฐ›๊ณ  ์ž๋ฆฌ๋กœ ์ด๋™!
             โ”‚   ( -แ—œ- )   โ† ์š”์ฒญ 2: ์ฃผ๋ฌธ ์™„๋ฃŒ
             โ–ผ

[Thread-3] โ”€โ”€โ”
             โ”‚   {\___/}  ๐Ÿ”” ์ง„๋™๋ฒจ ๋ฐ›๊ณ  ์ž๋ฆฌ๋กœ ์ด๋™!
             โ”‚   ( โ—•โ€ฟโ—• )   โ† ์š”์ฒญ 3: ์ฃผ๋ฌธ ์™„๋ฃŒ
             โ–ผ

=== ์Šค๋ ˆ๋“œ ์—ฌ์œ ! ๋‹ค์Œ ์š”์ฒญ๋„ ๋ฐ”๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ ===

[Thread-4] โ”€โ”€โ”
             โ”‚   {\___/}  ๐Ÿ”” ์ง„๋™๋ฒจ ๋ฐ›๊ณ  ์ž๋ฆฌ๋กœ ์ด๋™!
             โ”‚   ( ยฐ แด—ยฐ )   โ† ์š”์ฒญ 4: ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋จ
             โ–ผ

โ˜• ์ปคํ”ผ๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ œ์กฐ ์ค‘...
[Reactor-thread] โ†’ ์ปคํ”ผ ์™„์„ฑ ์‹œ ์ง„๋™๋ฒจ ์šธ๋ฆผ โ†’ ์†๋‹˜ ์‘๋‹ต ์ „์†ก!

๊ธฐ์กด๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋…ผ ๋ธ”๋กœํ‚น์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— WebClient ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์‹œ์ ์—์„œ ์Šค๋ ˆ๋“œ๋Š” ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์‘๋‹ต์€ ๊ทธ ์‹œ์ ์—์„œ ๋๋‚˜๊ณ  ์ถ”ํ›„ ๋‹ค๋ฅธ ์ฑ„๋„ (์•Œ๋ฆผ, ํ‘ธ์‹œ) ๋“ฑ์„ ํ†ตํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ „๋‹ฌํ•˜๊ฒŒ ๋˜์ฃ .

์—ฌ๊ธฐ์„œ Reactor thread ๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์š”์ฒญ๋“ค์„ ์ ์žฌํ•œ ํ›„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

Reactor?

Reactor๋Š” Spring WebFlux์™€ WebClient ๋“ฑ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋น„๋™๊ธฐ ๋…ผ๋ธ”๋กœํ‚น ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ๋กœ, Reactor thread๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ Netty์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop) ๊ธฐ๋ฐ˜์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. I/O ์š”์ฒญ์„ ๋“ฑ๋ก๋งŒ ํ•ด๋‘๊ณ , ์‘๋‹ต์ด ์˜ค๋ฉด reactor-thread๊ฐ€ ์ฝœ๋ฐฑ์ฒ˜๋Ÿผ ์‹คํ–‰ ํ๋ฆ„์„ ์ด์–ด์„œ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

์œ„์˜ ์˜ˆ์‹œ์—์„œ Reactor ๋‚ด๋ถ€์—์„œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์ผ์ด ๋ฒŒ์–ด์ง‘๋‹ˆ๋‹ค.

[HTTP ์š”์ฒญ 1] โ”€โ”
               โ–ผ
      [main thread]
        โ”€โ†’ WebClient ์š”์ฒญ ์ „์†ก (๋…ผ๋ธ”๋กœํ‚น)
        โ”€โ†’ ์ž‘์—… ๋“ฑ๋กํ•˜๊ณ  ๋ฐ˜ํ™˜
๐Ÿงต reactor-thread โ”€โ–ถ ํ™•์ธ: ์‘๋‹ต ์™”๋‚˜?

โœ” ์‘๋‹ต 1 ๋„์ฐฉ!
โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰: map/filter/flatMap ๋“ฑ ์ฒ˜๋ฆฌ ์ฒด์ธ ์‹คํ–‰

โœ” ์‘๋‹ต 2 ๋„์ฐฉ!
โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰

โœ” ์‘๋‹ต 3 ๋„์ฐฉ!
โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰

์—ฌ๊ธฐ์„œ ์ฝœ๋ฐฑ์—๋Š” ์ด๋ฒคํŠธ๊ฐ€ ์™„๋ฃŒ ๋˜์—ˆ์„ ๋•Œ ์‹คํ–‰๋˜์–ด์•ผ ํ•  ์ฝ”๋“œ๋“ค์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค. ์ฃผ๋กœ์•„๋ž˜์™€ ๊ฐ™์€ ๋กœ์ง๋“ค์ด ๋“ค์–ด๊ฐ‘๋‹ˆ๋‹ค.

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

EventLoop?

์ด๋ฒคํŠธ ๋ฃจํ”„ (Event Loop) ๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ๋‚˜์™”์Šต๋‹ˆ๋‹ค. ๋˜ ์งš๊ณ  ๋„˜์–ด๊ฐ€์•ผ๊ฒ ์ฃ ?

์ด๋ฒคํŠธ ๋ฃจํ”„๋ž€ ํ•˜๋‚˜์˜ (๋˜๋Š” ์†Œ์ˆ˜์˜) ์Šค๋ ˆ๋“œ๊ฐ€ **๋“ฑ๋ก๋œ ์ž‘์—…๋“ค(I/O, ํƒ€์ด๋จธ ๋“ฑ)**์„ ํ์—์„œ ๊บผ๋‚ด ์ฐจ๋ก€๋กœ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์ด ๊ตฌ์กฐ๋Š” ๋…ผ๋ธ”๋กœํ‚น ํ™˜๊ฒฝ(์˜ˆ: Reactor, Netty, Node.js ๋“ฑ)์—์„œ ์Šค๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜์ง€ ์•Š์œผ๋ฉด์„œ๋„ ๋†’์€ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์ฃ .

์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ํ๋ฆ„์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

1๋‹จ๊ณ„ : ์ž‘์—… ๋“ฑ๋ก
[Main Thread] โ”€โ”€โ–ถ ๋“ฑ๋ก: HTTP ์š”์ฒญ, ํƒ€์ด๋จธ, ํŒŒ์ผ ์ฝ๊ธฐ ๋“ฑ
                     โ–ผ
               โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ”‚   ์ด๋ฒคํŠธ ํ     โ”‚ โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
                                                โ”‚
                                      [I/O ์™„๋ฃŒ/ํƒ€์ด๋จธ ๋งŒ๋ฃŒ ์‹œ]
                                               โ–ผ
                                 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                 โ”‚   ์ฒ˜๋ฆฌํ•  ์ž‘์—…์ด ํ์— ๋“ค์–ด์˜ด   โ”‚
                                 โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
2๋‹จ๊ณ„ : ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๊ฐ€ ํ๋ฅผ ๋Œ๋ฉฐ ์ž‘์—…์„ ์ˆ˜ํ–‰

     ๐Ÿงต ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ (reactor-thread, event-loop)

        while(true) {
            if (์ด๋ฒคํŠธ ํ์— ์ž‘์—…์ด ์žˆ๋‹ค๋ฉด) {
                ๊บผ๋‚ด์„œ ์‹คํ–‰ (์ฝœ๋ฐฑ, map, flatMap ๋“ฑ)
            }
            ๋‹ค์Œ ์ด๋ฒคํŠธ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ (non-blocking poll)
        }

3๋‹จ๊ณ„ : ์ฒ˜๋ฆฌ๋œ ๊ฒฐ๊ณผ๋Š” ์ฝœ๋ฐฑ / ์ฒด์ธ์œผ๋กœ ์ „๋‹ฌ

๐Ÿ“ฆ ์˜ˆ: WebClient ์š”์ฒญ ํ๋ฆ„

[HTTP ์š”์ฒญ ๋“ฑ๋ก]
     โ†“
[์‘๋‹ต ๋„์ฐฉ โ†’ ์ด๋ฒคํŠธ ํ์— ๋“ฑ๋ก]
     โ†“
[์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ๊บผ๋ƒ„ โ†’ map/filter ๋“ฑ ์ฒด์ธ ์‹คํ–‰]
     โ†“
[๊ฒฐ๊ณผ โ†’ ๊ตฌ๋…์ž์—๊ฒŒ ์ „๋‹ฌ (`subscribe`, `onNext` ๋“ฑ)]
WebClient ์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋ ๊นŒ์š”?

WebClient ๋‚ด๋ถ€์—์„œ ๊ทธ๋Ÿผ ์ด๋ฒคํŠธ ๋ฃจํ”„๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ• ๊นŒ์š”? ๊ทธ๋ฆผ์œผ๋กœ ์ •๋ฆฌ ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Client โ†’ WebClient.get()          โ†’ ์š”์ฒญ ์ „์†ก (non-blocking)
                                  โ†’ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์ฝœ๋ฐฑ ๋“ฑ๋ก

<=== ์‘๋‹ต ๋„์ฐฉ ===                 โ†’ ์‘๋‹ต ์ฒ˜๋ฆฌ ๋กœ์ง ์ด๋ฒคํŠธ ํ์— ๋“ฑ๋ก

[reactor-thread]:
  โ†’ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‘๋‹ต ์ž‘์—… ๊บผ๋ƒ„
  โ†’ bodyToMono().map().flatMap() ์ฒด์ธ ์‹คํ–‰
  โ†’ subscribe() ๋กœ์ง ์‹คํ–‰

์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด WebClient ์˜ ๊ฒฝ์šฐ์—” ๋งค์šฐ ์ ์€ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๋งŒ ๊ฐ€์ง€๊ณ ๋„ ๋งŽ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ข€ ๋” ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๋ฅผ ๋ณผ๊นŒ์š”?

์‹œ๋‚˜๋ฆฌ์˜ค : 1๊ฐœ์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•˜๊ณ , 5000๋ช…์˜ ์š”์ฒญ์ด ์ „๋‹ฌ๋˜์—ˆ์„ ๋•Œ
[Client 1] โ”€โ”
[Client 2] โ”€โ”ค
[Client 3] โ”€โ”ค
...         โ”ค
[Client 5000] โ”€โ–ถ WebServer

์กฐ๊ธˆ์€ ๊ทน๋‹จ์ ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š” ์˜ˆ์‹œ๋ฅผ ๋ณผ๊ฒŒ์š”. ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ํ• ๋‹น ๋˜์—ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณผ๊ฒŒ์š”. 5000๋ช…์ด ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ ์š”์ฒญ์€ I/O ๋“ฑ๋ก๋งŒ ํ•˜๊ณ  ๋ฐ”๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค. ์ดํ›„ ์ด๋ฒคํŠธ ๋ฃจํ”„์— ์ฝœ๋ฐฑ์œผ๋กœ ๋“ฑ๋ก๋˜์ฃ .

๐Ÿงต [reactor-thread-1]: ์ด๋ฒคํŠธ ๋ฃจํ”„ ์ˆœํ™˜ ์‹œ์ž‘

(1) ์‘๋‹ต ๋„์ฐฉ: Client 128 โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰
(2) ์‘๋‹ต ๋„์ฐฉ: Client 3499 โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰
(3) ์‘๋‹ต ๋„์ฐฉ: Client 2 โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰
(4) ์‘๋‹ต ๋„์ฐฉ: Client 4000 โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰
(5) ์‘๋‹ต ๋„์ฐฉ: Client 5000 โ†’ ์ฝœ๋ฐฑ ์‹คํ–‰
...

==> I/O ์‘๋‹ต์ด ์™„๋ฃŒ๋œ ์š”์ฒญ๋งŒ ํ์— ๋“ฑ๋ก

์ด๋ฒคํŠธ๋ฃจํ”„๋Š” ์ˆœํ™˜ํ•˜๋ฉฐ ๋งŒ์•ฝ ํ•ด๋‹น ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์ด ์กด์žฌํ•œ๋‹ค๋ฉด, ๊บผ๋‚ด์„œ ์ฝœ๋ฐฑ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์ฃผ์˜ํ•ด์•ผ ํ•  ์ 

๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น ํŒจํ„ด์—์„œ๋Š” ์ด๋ฒคํŠธ ๋ฃจํ”„ ์˜ค์—ผ (Event Loop Poisoning) ์„ ์กฐ์‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ •์ž‘ ์ฝœ๋ฐฑ์— ๋ธ”๋กœํ‚น ์ฝ”๋“œ๊ฐ€ ๋“ค์–ด๊ฐ€๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌ๊ฐ€ ์˜ค๋ž˜๊ฑธ๋ฆฌ๋Š” ๋ฌด๊ฑฐ์šด ์ž‘์—…์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋œ๋‹ค๋ฉด ๋Œ€๊ธฐ์ค‘์ธ ๋ชจ๋“  ์š”์ฒญ์˜ ์‘๋‹ต ์†๋„๊ฐ€ ๋А๋ ค์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ž‘์—…๋“ค์ด ์žˆ์ฃ .

๋Œ€ํ‘œ ์˜ˆ์‹œ
Thread.sleep, File.read, JDBC ๋“ฑ ๋ธ”๋กœํ‚น ์ฝ”๋“œ
์•”ํ˜ธํ™”/ํ•ด์‹ฑ, PDF ์ƒ์„ฑ ๋“ฑ CPU ์ง‘์•ฝ ์ž‘์—…
๋Œ€๊ทœ๋ชจ DB Join, ๋ณต์žกํ•œ business logic

์ด ๊ฒฝ์šฐ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ๋ถ„๋ฆฌํ•˜๊ฑฐ๋‚˜ R2DBC ๋“ฑ ๋…ผ๋ธ”๋กœํ‚น ์ฝ”๋“œ๋กœ ์ „ํ™˜ํ•˜๋Š” ๋“ฑ ๋Œ€์•ˆ์„ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์–ด๋–ค ์ƒํ™ฉ์—์„œ ๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น ํŒจํ„ด์ด ์œ ๋ฆฌํ• ๊นŒ์š”?

ํ๋ฆ„์€ ๋™๊ธฐ์ ์œผ๋กœ ํ๋ฅด๋˜, ์‘๋‹ต์„ ๋‹ค๋ฅธ ์ฑ„๋„๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ์—” ์ƒ๋‹นํžˆ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ปคํ”ผ๋ฅผ ์ฃผ๋ฌธํ•˜๊ณ  ๋‚˜์ค‘์— ํ‘ธ์‰ฌ ์•Œ๋ฆผ์œผ๋กœ '์ปคํ”ผ๊ฐ€ ๋„์ฐฉํ–ˆ์Šต๋‹ˆ๋‹ค.' ๋ผ๋Š” ์‘๋‹ต์ด ์ „๋‹ฌ๋œ๋‹ค๋ฉด, ํ›จ์”ฌ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ง์˜ ํ๋ฆ„ ์ž์ฒด๋Š” ๋™๊ธฐ์ ์œผ๋กœ ๋Œ์•„๊ฐ”๊ณ , ์‘๋‹ต๋„ ๋™๊ธฐ์ ์œผ๋กœ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ์‘๋‹ต์ด ์ž ์‹œ ๊ธฐ๋‹ค๋ฆฌ์„ธ์š”! ๋ผ๋Š” ์ฐจ์ด๊ฐ€ ์žˆ์ฃ . ์‹ค์งˆ์ ์ธ ๋ฐ์ดํ„ฐ๋Š” ์ถ”ํ›„์— ๋‹ค๋ฅธ ์ฑ„๋„๋กœ ์ „๋‹ฌ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐ˜๋“œ์‹œ ์™ธ๋ถ€ API ๋“ฑ์˜ ์‘๋‹ต์„ ๋ฐ”๋กœ ์š”์ฒญ ๋‹จ์—์„œ ๋ฐ›์•„์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” ์–ด์ฉ” ์ˆ˜๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์œผ๋ก  ๊ฒฐ์ œ ์ฒ˜๋ฆฌ์™€ ๊ฐ™์€ ๊ฒŒ ์žˆ๊ฒ ์ฃ .

์œ„์—์„œ ๊ณต์œ ๋“œ๋ ธ๋‹ค์‹œํ”ผ [๋™๊ธฐ, ๋น„๋™๊ธฐ ์— ์ ํ•ฉํ•œ ์˜ˆ์‹œ](#์–ธ์ œ ์‚ฌ์šฉํ•˜๋‚˜์š”?) ๋กœ์ง์— ๋”ฐ๋ผ ๋™๊ธฐ + ๋ธ”๋กœํ‚น ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์ˆ˜ ๋ถˆ๊ฐ€๊ฒฐ์ธ ๊ฒฝ์šฐ๋„ ๋ถ„๋ช… ์ƒ๊น๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ํ˜ธ์ถœ ํ๋ฆ„ ์ž์ฒด๋Š” ๋™๊ธฐ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜๋˜, ๋‚ด๋ถ€ ์ฒ˜๋ฆฌ์—์„œ๋Š” ๋…ผ๋ธ”๋กœํ‚น์„ ์‚ฌ์šฉํ•ด์„œ ์Šค๋ ˆ๋“œ ์ ์œ ๋ฅผ ์ตœ์†Œํ™” ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ ํ•ด ๋ณผ๊ฒŒ์š”. ์ปคํ”ผ์ˆ์—์„œ ๋ฌด์กฐ๊ฑด ์†๋‹˜์ด ์ปคํ”ผ ์ฃผ๋ฌธ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ฐ›์•„์•ผ ํ•˜๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ • ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. [๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น ์˜ˆ์‹œ](#๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น) ์—์„œ๋Š” ์†๋‹˜์ด ์•Œ๋žŒ๋ฒจ์„ ๊ฐ€์ง€๊ณ  ๊ฐ€๋Š” ์ƒํ™ฉ์ด์—ˆ๊ณ , ์ด๋ฒˆ์—๋Š” ๋ฌด์กฐ๊ฑด ์ปคํ”ผ ์š”์ฒญ์„ ๋ฐ›์•„๊ฐ€์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ • ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 โ˜• ์ปคํ”ผ์ˆ โ€“ ๊ฒฐ์ œ ์š”์ฒญ์€ ๋…ผ ๋ธ”๋กœํ‚น ์ „์†ก, ๋Œ€๊ธฐ ์ค‘ ์Šค๋ ˆ๋“œ๋Š” ์‰ฌ์—ˆ๋‹ค๊ฐ€ ๋ณต๊ท€

[Thread-1] โ”€โ”€โ”
             โ”‚   {\___/}  ๐Ÿ’ณ ๊ฒฐ์ œ ์š”์ฒญ ์ „์†ก ์™„๋ฃŒ
             โ”‚   ( โ€ข ใ…โ€ข)   "์‘๋‹ต ์˜ฌ ๋•Œ๊นŒ์ง€ ์ž๋ฆฌ์—์„œ ๊ธฐ๋‹ค๋ฆด๊ฒŒ์š”" โ† โธ๏ธ ์ž ์‹œ ์ค‘๋‹จ
             โ–ผ

โ˜• ์ปคํ”ผ ๋งŒ๋“œ๋Š” ์ค‘... (๊ฒฐ์ œ ์‹œ์Šคํ…œ ์‘๋‹ต ๋Œ€๊ธฐ)

๐Ÿ”” ๊ฒฐ์ œ ์‘๋‹ต ๋„์ฐฉ! โ†’ Thread-1 ๋‹ค์‹œ ์ค„๋กœ ๋ณต๊ท€

[Thread-1] โ”€โ”€โ–ถ {\___/}
               ( โ—•โ€ฟโ—• )   "๊ฒฐ์ œ ์™„๋ฃŒ! ์ปคํ”ผ ๋ฐ›์•˜์–ด์š”!"

๊ฒฐ์ œ ์š”์ฒญ ๋งŒํผ์€ ๋…ผ ๋ธ”๋กœํ‚น์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด, ์–ด์จŒ๋“  ์ด ๋…ผ ๋ธ”๋กœํ‚น I/O ๋ฅผ WebClient ์˜ .block() ๋“ฑ์„ ํ™œ์šฉํ•˜๋Š” ๋“ฑ์˜ ์กฐ์น˜๋ฅผ ์ทจํ•ด์„œ ๋™๊ธฐ์ ์œผ๋กœ ๊ธฐ๋‹ค๋ ค์•ผ ํ•˜์ฃ . ํ•˜์ง€๋งŒ .block() ํ˜ธ์ถœ ์ง์ „ ๊นŒ์ง€๋Š” ๋ฌผ๋ฆฌ ์Šค๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜์ง€ ์•Š๊ณ  ๋น ๋ฅด๊ฒŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

@GetMapping("/pay")
fun pay(): PaymentResponse {
    return webClient.post()
        .uri("https://payment.example.com")
        .bodyValue(paymentRequest)
        .retrieve()
        .bodyToMono(PaymentResponse::class.java)
        .block()
}

๊ฒฐ์ œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ • ํ•ด ๋ณผ๊ฒŒ์š”. Spring MVC์—์„œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Thread-1์ด ํ• ๋‹น๋ ๊ฒ๋‹ˆ๋‹ค.

WebClient๋Š” Netty๋ฅผ ํ†ตํ•ด ๋…ผ๋ธ”๋กœํ‚น I/O๋กœ HTTP ์š”์ฒญ์„ ์ „์†กํ•ฉ๋‹ˆ๋‹ค. Thread-1์ด ํ•ด๋‹น ์š”์ฒญ์„ Netty์— ๋“ฑ๋กํ•˜๊ณ  ๋น ์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•„์ง .block() ํ˜ธ์ถœ ์ „์ด๋‹ˆ ๋ฌผ๋ฆฌ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ๋Ÿ‰์€ ์—†๊ฑฐ๋‚˜ ๋งค์šฐ ์งง์Šต๋‹ˆ๋‹ค.

์‘๋‹ต์„ ๋ฐ›๊ธฐ ์œ„ํ•ด .block()์ด ํ˜ธ์ถœ๋˜๋ฉด,ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋Š” ์‘๋‹ต์ด ๋„์ฐฉํ•  ๋•Œ๊นŒ์ง€ โ€œ๋…ผ๋ฆฌ์ ์œผ๋กœโ€ ๋Œ€๊ธฐ ์ƒํƒœ์— ์ง„์ž…ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ์‹œ์ ๋ถ€ํ„ฐ๋Š” Thread-1์ด ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์ ์œ ๋˜์ฃ .

Netty์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ์‘๋‹ต์„ ์ˆ˜์‹ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด WebClient ๋‚ด๋ถ€๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , .block()์„ ํ˜ธ์ถœํ–ˆ๋˜ Thread-1์„ ๋‹ค์‹œ ๊นจ์›๋‹ˆ๋‹ค. Controller๊ฐ€ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  Thread-1์€ ๋ฐ˜ํ™˜๋˜์ฃ .

์–ด์จŒ๋“  ์ „ํ†ต์ ์ธ ๋ธ”๋กœํ‚น ๋กœ์ง (RestTemplate) ์„ ์“ฐ๋Š” ๋ฐฉ์‹์— ๋น„ํ•ด ์•„์ฃผ ์•ฝ๊ฐ„ ์Šค๋ ˆ๋“œ ์ ์œ  ์‹œ๊ฐ„์„ ์•„๋‚„ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ ํฐ ์ฐจ์ด๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์‚ฌ์‹ค ์˜๋ฏธ์žˆ๋Š” ์ตœ์ ํ™”๋ผ๊ณ  ๋ณด๊ธฐ ์–ด๋ ค์šธ ๋งŒํผ์˜ ์ฐจ์ด์ฃ . ๊ฒฐ๊ตญ ์ด ๊ตฌ์กฐ๋„ ์ „์ฒด์ ์œผ๋กœ ๋ณด๋ฉด ๋™๊ธฐ + ๋ธ”๋กœํ‚น์ด๋ž‘ ํฐ ์ฐจ์ด๊ฐ€ ์—†์œผ๋‹ˆ๊นŒ์š”. ๊ทธ๋Ÿผ ์ด ๊ตฌ์กฐ๋กœ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ํ•  ์ˆ˜๋Š” ์—†๋Š”๊ฑธ๊นŒ์š”?

์‹ฌํ™” : ์ข€ ๋” ์Šค๋ ˆ๋“œ๋ฅผ ์•„๊ปด๋ณผ๊นŒ์š”? (๊ฐ€์ƒ์Šค๋ ˆ๋“œ)

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋ธ”๋กœํ‚น์ด ๋ฐ˜๋“œ์‹œ ๋“ค์–ด๊ฐ€์•ผ๋งŒ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋„ ์ตœ์ ํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” Java 21 ์—์„œ ์ •์‹ ์ถœ์‹œ ๋œ ๊ธฐ๋Šฅ์œผ๋กœ ๊ธฐ์กด์˜ ๋ฌผ๋ฆฌ ์Šค๋ ˆ๋“œ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ€๋ณ๊ฒŒ ๋™์ž‘ํ•˜๋Š” ์Šค๋ ˆ๋“œ์ž…๋‹ˆ๋‹ค.

๋ฌผ๋ฆฌ ์Šค๋ ˆ๋“œ๋Š” OS ์ปค๋„ ๋‹จ์—์„œ ๊ด€๋ฆฌํ•˜๊ฒŒ๋ฉ๋‹ˆ๋‹ค. OS ์ปค๋„์ด ์Šค์ผ€์ค„๋ง, ๋ฌธ๋งฅ ์ „ํ™˜(context switch), ๋™๊ธฐํ™”(synchronization) ๋ฅผ ๋ชจ๋‘ ๊ด€๋ฆฌํ•˜์ฃ . ๋˜ํ•œ ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๊ณ ์ • ํฌ๊ธฐ ์Šคํƒ๊ณผ ์ปค๋„ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ (TCB) ๊ฐ€ ํ• ๋‹น๋ฉ๋‹ˆ๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ ๋งŒ์•ฝ ๋ธ”๋กœํ‚น ๋˜๋ฉด ํ•ด๋‹น OS ์Šค๋ ˆ๋“œ ์ „์ฒด๊ฐ€ ๋ฉˆ์ถ”๋ฏ€๋กœ CPU ์ž์› ํ™œ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์ฒ˜์Œ์— ์•„์ฃผ ์ž‘์€ ์Šคํƒ ํ”„๋ ˆ์ž„๋งŒ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•  ๋•Œ๋งŒ ์Šคํƒ์„ ํ™•์žฅํ•˜๋Š” ๋“ฑ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋ฅผ ์ตœ์†Œํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@GetMapping("/pay")
fun pay(): PaymentResponse {
    return webClient.post()
        .uri("/payment")
        .bodyValue(req)
        .retrieve()
        .bodyToMono(PaymentResponse::class.java)
        .block() // ๋ธ”๋กœํ‚น!!
}

๊ธฐ์กด ์Šค๋ ˆ๋“œ๋ผ๋ฉด ์ด .block() ๋™์•ˆ ๋ฌผ๋ฆฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์ ์œ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์“ฐ๋ ค๋ฉด ๋”ฐ๋กœ ์„ค์ •์„ ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

@Configuration
class VirtualThreadConfig {
    @Bean
    fun virtualThreadExecutor(): TaskExecutor =
        TaskExecutor { runnable ->
            Thread.ofVirtual().start(runnable)
        }
}

๋˜๋Š” yml ํŒŒ์ผ์— ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ค„ ์ˆ˜ ์žˆ์ฃ 

spring:
  threads:
    virtual: enabled

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ผ๋ฉด .block() ์‹œ ์Šค๋ ˆ๋“œ๊ฐ€ ์ค‘๋‹จ๋˜๊ณ  ๋‹ค๋ฅธ ์š”์ฒญ์— ํ• ๋‹นํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™๊ธฐ ์ฝ”๋“œ ์œ ์ง€ํ•˜๋ฉด์„œ๋„ ์„ฑ๋Šฅ์—์„œ ์ด์ ์„ ๋ณผ ์ˆ˜์žˆ์ฃ .

[VirtualThread-1] โ”€โ”€โ”
                    โ”‚   {\___/}  โ˜• ์ฃผ๋ฌธ ๋ณด๋ƒ„ ํ›„ ์ง„๋™๋ฒจ ๋ฐ›๊ณ  ์ž๋ฆฌ๋กœ ๊ฐ
                    โ”‚   ( โ€ข ใ…โ€ข ) "์•‰์•„์„œ ๊ธฐ๋‹ค๋ฆด๊ฒŒ์š”~"
                    โ–ผ

[VirtualThread-2] โ”€โ”€โ”
                    โ”‚   {\___/}  โ˜• ์ฃผ๋ฌธ ๋ณด๋ƒ„ ํ›„ ์ž๋ฆฌ๋กœ ๊ฐ
                    โ”‚   ( โ—•โ€ฟโ—• ) "์•‰์•„์„œ ์œ ํŠœ๋ธŒ ๋ด์•ผ์ง€"
                    โ–ผ

[VirtualThread-3] โ”€โ”€โ”
                    โ”‚   {\___/}  โ˜• ์ฃผ๋ฌธ ๋ณด๋ƒ„ ํ›„ ์ž๋ฆฌ๋กœ ๊ฐ
                    โ”‚   ( ห˜โ—กห˜ ) "ํŽธ์•ˆ~"
                    โ–ผ

=== ์ปคํ”ผ ๋‹ค ๋‚˜์˜ค๋ฉด ์ง„๋™๋ฒจ ์šธ๋ฆผ ===
โ†’ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์žฌ๊ฐœ โ†’ ์‘๋‹ต ๋ฐ˜ํ™˜
๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์กฐ์‹ฌํ•ด์•ผ ํ•  ์ ์€?

๊ฐ€์ƒ์Šค๋ ˆ๋“œ๋ฅผ ์“ฐ๋ฉด ๊ธฐ์กด์˜ ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ์ง€ ์•Š๊ณ ๋„ ํ˜„์žฌ ์ƒํ™ฉ์„ ์กฐ๊ธˆ ๋” ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด OS ์Šค๋ ˆ๋“œ์— ๋น„ํ•ด ๊ฐ€๋ฒผ์›Œ์„œ ํ›จ์”ฌ ๋งŽ์€ ์ˆซ์ž์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ , ๊ธฐ์กด ๋ธ”๋กœํ‚น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€์˜ ํ˜ธํ™˜์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

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

๋˜ํ•œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ๋กœ ์ƒ์„ฑ๋˜๋ฏ€๋กœ ThreadLocal ์žฌ์‚ฌ์šฉ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

โ“ ์—ฌ๊ธฐ์„œ ThreadLocal ์ด๋ž€?

ThreadLocal์€ โ€œ๊ฐ ์Šค๋ ˆ๋“œ๋งˆ๋‹ค ๋ณ„๋„์˜ ๊ฐ’์„ ์ €์žฅโ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋Š” Java์˜ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์ฃผ๋กœ ์š”์ฒญ๋ณ„ ์ปจํ…์ŠคํŠธ(์˜ˆ: ์‚ฌ์šฉ์ž ์ •๋ณด, ํŠธ๋žœ์žญ์…˜ ID ๋“ฑ)๋ฅผ ์Šค๋ ˆ๋“œ ์ „์—ญ์—์„œ ํŽธํ•˜๊ฒŒ ์“ฐ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

java.lang.Thread ํด๋ž˜์Šค๋Š” ๋‚ด๋ถ€์— ThreadLocal.ThreadLocalMap threadLocals๋ผ๋Š” ๋งต์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ThreadLocal<T> ๊ฐ์ฒด์— set() ์„ ํ˜ธ์ถœํ•˜๋ฉด, ํ˜„์žฌ ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ์˜ ์ด ๋งต์— ํ‚ค(ThreadLocal ๊ฐ์ฒด)โ€“๊ฐ’(์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ) ์Œ์ด ์ €์žฅ๋ฉ๋‹ˆ๋‹ค.

get()์„ ํ˜ธ์ถœํ•˜๋ฉด, ๊ฐ™์€ ์Šค๋ ˆ๋“œ์˜ ๋งต์—์„œ ๊ฐ’์„ ๊บผ๋‚ด ์˜ต๋‹ˆ๋‹ค.

๋˜ํ•œ JDK 21 ๋ถ€ํ„ฐ ์ง€์›ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ํ˜ธํ™˜์„ฑ์„ ์ž˜ ์‚ดํŽด๋ณด์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ง€๋ง‰์œผ๋กœ OS ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ๋™์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ๋“ค์— ๋Œ€ํ•ด ํ•œ๊ณ„์ ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ syncronized ์™€ ๊ฐ™์€ ๋ชจ๋‹ˆํ„ฐ ๋ฝ์€ OS ์Šค๋ ˆ๋“œ์—์„œ๋งŒ ์ž‘๋™ํ•˜์ฃ .

๐Ÿ”„ 4.4 ๋น„๋™๊ธฐ + ๋ธ”๋กœํ‚น : ์ผ๋ถ€๋งŒ ๋ธ”๋กœํ‚น์„ ๊ฑธ๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ

์ง€๊ธˆ๊นŒ์ง€ ๊ธ€์„ ์ฝ์œผ์…จ๋‹ค๋ฉด, ๋น„๋™๊ธฐ์™€ ๋ธ”๋กœํ‚น์„ ํ•จ๊ป˜ ์“ฐ๋ฉด ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚  ์ง€ ๊ณ ๋ฏผ์ด ๋˜์‹ค ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ + ๋ธ”๋กœํ‚น์„ ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ๋น„๋™๊ธฐ ํ”„๋ ˆ์ž„์›Œํฌ ์•ˆ์—์„œ ๋‚ด๋ถ€ ๋กœ์ง์€ ์—ฌ์ „ํžˆ ๋ธ”๋กœํ‚น ํ˜ธ์ถœ (RestTemplate, JDBC) ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ์ด๋Ÿฐ ์ƒํ™ฉ์ด์ฃ .

Mono.fromCallable(() -> {
    return jdbcTemplate.query(...); // โ† ๋ธ”๋กœํ‚น
})
.subscribeOn(Schedulers.boundedElastic())

Webflux ๋‚ด์—์„œ JDBC ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ๋•Œ๋กœ๋Š” ์ด๋Ÿฐ ์ƒํ™ฉ์ด ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ ์ง„์ ์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ด๋Ÿฐ ์ฝ”๋“œ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์ฃ .

์ฝ”๋“œ๊ฐ€ ์กฐ๊ธˆ ์™€๋‹ซ์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์œผ๋‹ˆ ๋‹ค์‹œ ์ปคํ”ผ์ˆ ์˜ˆ์ œ๋ฅผ ๊ฐ€์ ธ์™€๋ณผ๊นŒ์š”?

[Thread-1] โ”€โ”€โ”
             โ”‚  ๊ณ ๊ฐ1  {\___/}  "์ปคํ”ผ ์ฃผ์„ธ์š”!"
             โ”‚         ( โ€ข ใ…โ€ข)  ๐Ÿ‘‰ [๋น„๋™๊ธฐ ์ฃผ๋ฌธ ์ ‘์ˆ˜]
             โ”‚                    โ†’ [โ˜• ์ปคํ”ผ ๋งŒ๋“œ๋Š” ์ค‘... (3์ดˆ ๋ธ”๋กœํ‚น)]

[Thread-1] โ”€โ”€โ”
             โ”‚  ๊ณ ๊ฐ2  {\___/}  "์ €๋„์š”!"
             โ”‚         ( - ฯ‰ -)  ๐Ÿ‘‰ [์ฃผ๋ฌธ ๋Œ€๊ธฐ ์ค‘... โ— ์ด์ „ ์ž‘์—… ์™„๋ฃŒ ๋Œ€๊ธฐ]

[Thread-1] โ”€โ”€โ”
             โ”‚  ๊ณ ๊ฐ3  {\___/}  "ํ˜น์‹œ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋‚˜์š”?"
             โ”‚         ( โ€ข๏ธตโ€ข )  ๐Ÿ‘‰ [๋Œ€๊ธฐ ์ค‘...]

=== ์ปคํ”ผ ๋จธ์‹ ์€ ํ•˜๋‚˜์ธ๋ฐ, ์ž‘์—…์ด ๋ธ”๋กœํ‚น์ด๋ผ ๋Œ€๊ธฐํ–‰๋ ฌ ๋ฐœ์ƒ! ===

์‚ฌ์žฅ๋‹˜์ด ํ•œ๋ถ„์ด๊ณ  ์ฃผ๋ฌธ์€ ์ˆœ์„œ๋Œ€๋กœ ๋ฐ›๊ณ  ์žˆ๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งŒ๋“œ๋Š”๋ฐ ์‹œ๊ฐ„์ด ๋งŽ์ด ๊ฑธ๋ ค์„œ ์–ด์จŒ๋“  ์ค„์ด ์ƒ๊ธฐ๋Š” ๊ฒฝ์šฐ์ž…๋‹ˆ๋‹ค. ์ฃผ๋ฌธ์„ ํ‚ค์˜ค์Šคํฌ๋กœ ๋น ๋ฅด๊ฒŒ ๋ฐ›๊ณ  ์žˆ์ง€๋งŒ ๋ง‰์ƒ ์ œ์กฐ๋Š” ์‚ฌ๋žŒ์ด ํ•˜๋‚˜์”ฉ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ์ฃ . ์ง„๋™๋ฒจ์ด ๋”ฐ๋กœ ์žˆ๋Š” ์ƒํ™ฉ์€ ์•„๋‹ˆ๊ณ  ๋ฐ›๋Š” ์ค„์ด ๋”ฐ๋กœ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹œ๋ฉด ์ด ์ƒํ™ฉ์ด ์กฐ๊ธˆ ๋” ์ดํ•ด๊ฐ€ ๋˜์‹ค๊ฒ๋‹ˆ๋‹ค.

์Œ ์ž˜ ์™€๋‹ซ์ง€ ์•Š์œผ์‹ ๋‹ค๋ฉด...๋ก ํŽ˜์Šคํ‹ฐ๋ฒŒ ๋“ฑ ์ถ•์ œ ํ˜„์žฅ์—์„œ์˜ F&B ํ‘ธ๋“œํŠธ๋Ÿญ์„ ์ƒ๊ฐํ•ด๋ณด์‹œ๋ฉด ํŽธํ•ฉ๋‹ˆ๋‹ค.
์–ด๋”˜๊ฐ€์—์„œ ๋Œ€๊ธฐ๋ฅผ ํ•˜๊ธฐ ์–ด๋ ค์šด ํ˜„์žฅ์„ ์ƒ๊ฐํ•˜๋ณด์ž๊ตฌ์š”. ์ง„๋™๋ฒจ ๊ฐ™์€ ์žฅ์น˜๋ฅผ ๋‘˜ ์ˆ˜๋„ ์—†๊ตฌ์š”.

๋ญ”๊ฐ€ ์ด์ƒํ•ด๋ณด์ด์ง€๋งŒ, ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ๋ธ”๋กœํ‚น ํ˜ธ์ถœ์„ ์ œ์™ธํ•œ ๋‚˜๋จธ์ง€ ๋กœ์ง๋“ค์€ ๋…ผ ๋ธ”๋กœํ‚น์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ . ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ๋ธ”๋กœํ‚น์„ ๊ฑธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์„ ๊ฐœ์„ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ์„ ์ตœ์†Œํ™” ํ•œ ์ฑ„ ํ”„๋ ˆ์ž„์›Œํฌ๋งŒ ๋จผ์ € ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋Ÿฐ ํŒจํ„ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์•„๋ผ๋ ค๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋น„๋™๊ธฐ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์Šค๋ ˆ๋“œ ๋‚ญ๋น„๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์ฃ . ๊ฒฐ๊ตญ ๋ธ”๋กœํ‚น์€ ๋ธ”๋กœํ‚น์ด๋‹ˆ๊นŒ์š”. ๋งŒ์•ฝ ์ง€์—ฐ์ด ๊ธธ์–ด์ง„๋‹ค๋ฉด, ์ „์ฒด ํ๋ฆ„์ด ์ง€์—ฐ๋˜๊ณ  ์š”์ฒญ ์ฒ˜๋ฆฌ๋Ÿ‰์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๋น„๋™๊ธฐ์™€ ๋ธ”๋กœํ‚น์„ ํ˜ผํ•ฉํ•˜๋Š” ๊ฒฝ์šฐ stack trace ๊ฐ€ ๋’ค์—‰ํ‚ค๊ณ  ์˜ˆ์™ธ์ฒ˜๋ฆฌ ํ•˜๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ์ฆ‰ ๋ณ‘๋ชฉ ์˜ˆ์ธก์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •๋ง ํŠน์ • ์ฝ”๋“œ ๋•Œ๋ฌธ์— ๋ณ‘๋ชฉ์ด ์ƒ๊ธฐ๋Š” ์ง€ ์†๋‹จ ํ•˜๊ธฐ์—” ์›Œ๋‚™ ๋ณ€์ˆ˜๊ฐ€ ๋งŽ์ž–์•„์š”?

java.lang.RuntimeException: Payment failed
   at kr.co.demo.OrderController$callPaymentApi$1.apply(OrderController.kt:24)
   at reactor.core.publisher.MonoMap$MapSubscriber.onNext(MonoMap.java:120)
   at reactor.core.publisher.FluxFlatMap$FlatMapMain.innerNext(FluxFlatMap.java:1230)
   at reactor.core.publisher.FluxFlatMap$FlatMapInner.onNext(FluxFlatMap.java:985)
   at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1845)
   ... (Reactor ๋‚ด๋ถ€ ํ˜ธ์ถœ๋“ค ์ƒ๋žต)
   at reactor.core.publisher.Mono.block(Mono.java:1705)  โ— block() ํ˜ธ์ถœ
   at kr.co.demo.OrderController.callPaymentApi(OrderController.kt:27)
   at kr.co.demo.OrderController.processOrder(OrderController.kt:16)
   at kr.co.demo.OrderController.order(OrderController.kt:11)

WebClient ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋กœ์ง์—์„œ ์žฅ์• ๊ฐ€ ๋‚ฌ๊ณ , .block() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋ธ”๋กœํ‚น์„ ๊ฑด ์ผ€์ด์Šค์ž…๋‹ˆ๋‹ค. ์ •์ž‘ ๋กœ์ง์€ ๋‚ด๋ถ€ Reactor ์—์„œ ํ„ฐ์กŒ๋Š”๋ฐ ๋กœ๊ทธ๋Š” ์ƒ๋žต๋˜์ฃ .

์ด ๊ฒฝ์šฐ ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด boundedElastic ๋“ฑ์„ ์‚ฌ์šฉํ•ด์„œ ๋ธ”๋กœํ‚น I/O ์—๋งŒ ์Šค๋ ˆ๋“œํ’€์„ ๋”ฐ๋กœ ์œ„์ž„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ฒฐ๊ตญ ์ด ๋˜ํ•œ ์Šค๋ ˆ๋“œํ’€ ์‚ฌ์ด์ฆˆ์˜ ํ•œ๊ณ„์— ๋ถ€๋”ช์น  ์ˆ˜ ์žˆ์ฃ .

๊ทธ๋ž˜์„œ ๋น„๋™๊ธฐ + ๋ธ”๋กœํ‚น ํŒจํ„ด์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•  ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์กฐ๊ฑดํŒ๋‹จ ๊ธฐ์ค€
๋ ˆ๊ฑฐ์‹œ DB / API๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์—†์Œ๋ถˆ๊ฐ€ํ”ผํ•œ ๊ฒฝ์šฐ boundedElastic ๋˜๋Š” Dispatchers.IO๋กœ ๊ฐ์Œˆ
์ผ๋ถ€๋งŒ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์ง„ํ–‰ ์ค‘์ „ํ™˜ ๊ณผ์ •์—์„œ ์ž„์‹œ ์ „๋žต์œผ๋กœ ์‚ฌ์šฉ
์ „์ฒด ๋…ผ๋ธ”๋กœํ‚น ๊ตฌํ˜„ ๋น„์šฉ์ด ๋„ˆ๋ฌด ํผ์„ฑ๋Šฅ์ด ์ค‘์š”ํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์š”์ฒญ๋Ÿ‰์ด ์ ๋‹ค๋ฉด ํ—ˆ์šฉ ๊ฐ€๋Šฅ

๐Ÿš€ 4.5 ๋น„๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น : ์„ฑ๋Šฅ์€ ์ข‹์ง€๋งŒ ๋งŽ์€ ๋ณต์žก์„ฑ๊ณผ ์ œ์•ฝ์ด ๋Š˜์–ด๋‚˜๋Š” ํŒจํ„ด

์ด์ œ ๋งˆ์ง€๋ง‰ ๋น„๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น ๊นŒ์ง€ ์™”์Šต๋‹ˆ๋‹ค. ๋น„๋™๊ธฐ์™€ ๋…ผ ๋ธ”๋กœํ‚น์„ ํ•จ๊ป˜ ์“ฐ๋ฉด ์ƒ๋‹นํ•œ ์„ฑ๋Šฅ ๊ฐœ์„  ํšจ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒ๋ฉด ์ ์€ ์Šค๋ ˆ๋“œ๋กœ ๋งŽ์€ ์ฃผ๋ฌธ๋“ค์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ์š”.

[Thread-1] โ”€โ”€โ”
             โ”‚   ๊ณ ๊ฐ1  {\___/} "์ปคํ”ผ ์ฃผ์„ธ์š”!"
             โ”‚           ( โ€ข ใ…โ€ข) ๐Ÿ‘‰ [์ฃผ๋ฌธ์ ‘์ˆ˜ + ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์•ฝ] โ”
             โ”‚                                                  โ–ผ
             โ”‚   ๊ณ ๊ฐ2  {\___/} "์ €๋„์š”!"
             โ”‚           ( - ฯ‰ -) ๐Ÿ‘‰ [์ฃผ๋ฌธ์ ‘์ˆ˜ + ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์•ฝ] โ”
             โ”‚                                                  โ–ผ
             โ”‚   ๊ณ ๊ฐ3  {\___/} "์ €๋„ ์ฃผ์„ธ์š”!"
             โ”‚           ( ^ไบบ^) ๐Ÿ‘‰ [์ฃผ๋ฌธ์ ‘์ˆ˜ + ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ ์˜ˆ์•ฝ] โ”
             โ”‚                                                  โ–ผ
             โ”‚  (์š”์ฒญ ๊ณ„์† ๋ฐ›์Œ...)                              โ–ผ

[์ปคํ”ผ๋จธ์‹ -1] โ”€โ”€โ˜• ์ œ์ž‘ ์ค‘... (๊ณ ๊ฐ1 ์ปคํ”ผ)
[์ปคํ”ผ๋จธ์‹ -2] โ”€โ”€โ˜• ์ œ์ž‘ ์ค‘... (๊ณ ๊ฐ2 ์ปคํ”ผ)
[์ปคํ”ผ๋จธ์‹ -3] โ”€โ”€โ˜• ์ œ์ž‘ ์ค‘... (๊ณ ๊ฐ3 ์ปคํ”ผ)

๐Ÿ“ฆ ์ปคํ”ผ ๋‹ค ๋งŒ๋“ค์–ด์ง€๋ฉด, ์•Œ๋ฆผ(์ฝœ๋ฐฑ) ํ›„ ๊ณ ๊ฐ์—๊ฒŒ ์ „๋‹ฌ โ˜•

์Šค๋ ˆ๋“œ๋Š” ๊ณ„์†ํ•ด์„œ ๋ธ”๋กœํ‚น ์—†์ด ๊ณ ๊ฐ๋“ค์˜ ์ปคํ”ผ๋ฅผ ์ฃผ๋ฌธ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ปคํ”ผ ์ œ์กฐ๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ์˜ˆ์•ฝ ๋˜๊ณ , ์ œ์กฐ๊ฐ€ ์™„๋ฃŒ๋˜๋Š” ๊ฒฝ์šฐ ์ฝœ๋ฐฑ์œผ๋กœ ์•Œ๋ฆผ์ด ์ „๋‹ฌ๋˜์ฃ . ์ด ๊ฒฝ์šฐ ์ปคํ”ผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋А๋ผ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌถ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰ ํ•˜๋‚˜์˜ ๋˜๋Š” ์†Œ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋กœ ์ˆ˜๋ฐฑ ๋ช…์˜ ์ฃผ๋ฌธ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ .

์ง€๊ธˆ๊นŒ์ง€ ์†Œ๊ฐœ ํ•ด ๋“œ๋ฆฐ ํŒจํ„ด ์ค‘์— ๊ฐ€์žฅ ์„ฑ๋Šฅ์ ์œผ๋ก  ์šฐ์ˆ˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ซํ”Œ ์นดํŽ˜์˜ ๊ฒฝ์šฐ ์ด๋Ÿฐ ํŒจํ„ด์ด ์•„๋งˆ ํ•„์ˆ˜์ ์ผ ์ง€๋„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

                          ____ HOTPLACE CAFE ____
                         /                     \
                        /                       \
      [ 3F ]   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ”‚  {\___/}    {\___/}    {\___/}            โ”‚
               โ”‚  ( โ€ข ใ…โ€ข)    ( โ€ข ใ…โ€ข)    ( โ€ข ใ…โ€ข)          โ”‚
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

      [ 2F ]   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ”‚  {\___/}    {\___/}    {\___/}            โ”‚
               โ”‚  ( โ€ข ใ…โ€ข)    ( โ€ข ใ…โ€ข)    ( โ€ข ใ…โ€ข)         โ”‚
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

      [ 1F ]   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Counter & Barista โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
               โ”‚  {\___/}  ์ฃผ๋ฌธ ์ ‘์ˆ˜ โ–ถ ๐Ÿ””   {\___/}        โ”‚
               โ”‚  ( โ€ข ใ…โ€ข)                  ( โ€ข ใ…โ€ข)       โ”‚
               โ”‚   ์นด์šดํ„ฐ ์ง์›               ๋ฐ”๋ฆฌ์Šคํƒ€         โ”‚
               โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

์†๋‹˜์ด ๋ฐ”๊ธ€๋ฐ”๊ธ€ ๊ฐ€๋“ ์ฐจ ์žˆ๋Š” ์นดํŽ˜๋ฅผ ํ•œ๋ฒˆ ์ƒ๊ฐ ํ•ด๋ณผ๊นŒ์š”? ์ฃผ๋ง์— ์นดํŽ˜์—์„œ ์‹œ๊ฐ„ ๋ณด๋‚ด๊ธธ ์ข‹์•„ํ•˜์‹œ๋Š” ๋ถ„๋“ค์€ ๋นต ๊ตฝ๋Š” ๋ƒ„์ƒˆ๊ฐ€ ๋‚˜๊ฑฐ๋‚˜ ์˜ˆ์œ ์กฐํ˜•๋ฌผ๋“ค์ด ํ•จ๊ป˜ํ•˜๋Š” ์นดํŽ˜๊ฐ€ ์ƒ์ƒ์ด ๋˜์‹ค๊ฒ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ์†๋‹˜์ด ๋งŽ์•„์„œ ๊ฑด๋ฌผ์€ 2์ธต ๋˜๋Š” 3์ธต ๊นŒ์ง€ ์˜ฌ๋ผ๊ฐ€์žˆ์ฃ . ์ž๋ฆฌ๊ฐ€ ๊ฝ‰ ์ฐจ์žˆ์–ด์„œ ๋ชป ์•‰๋Š” ์‚ฌ๋žŒ์ด ๋‚˜์˜ค๊ธฐ๊นŒ์ง€ ํ•ฉ๋‹ˆ๋‹ค.

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

์•„๋‹ˆ ์ •๋ง ์ฃผ๋ฌธ์ด ๋งŽ์ด ๋ฐ€๋ฆฌ๋ฉด ๋ฐ”๋ฆฌ์Šคํƒ€ ํ•œ๋ช…์œผ๋กœ ์–ด๋ ต์ง€ ์•Š๋‚˜์š”?

๋งž์Šต๋‹ˆ๋‹ค. ๋ฐ”๋ฆฌ์Šคํƒ€๋ฅผ ์—ฌ๋Ÿฟ ๊ณ ์šฉํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์ฃ . ํ”„๋ ˆ์ž„์›Œํฌ์— ๋”ฐ๋ผ ๋‹ค๋ฅด์ง€๋งŒ, Netty ์˜ ๊ฒฝ์šฐ ์˜ต์…˜์œผ๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ํ™•์žฅ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€ ์˜ˆ์‹œ์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค์‹œํ”ผ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์€ ์„œ๋น„์Šค๋ผ๋ฉด ๋น„๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น ์„ค๊ณ„ ํŒจํ„ด์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์น˜ ์ฃผ๋ง์— ์‚ฌ๋žŒ์ด ๋ฏธ์–ดํ„ฐ์ง€๋Š” ํ•ซํ”Œ ์นดํŽ˜์ฒ˜๋Ÿผ ๋ง์ด์ฃ . ์žฅ์ ์œผ๋กœ๋Š” ๋‹น์—ฐํžˆ ์Šค๋ ˆ๋“œ ํšจ์œจ์„ ๊ทน๋Œ€ํ™” ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ ์€ ๋ฆฌ์†Œ์Šค๋กœ ๋” ๋งŽ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰๋„ ๋‹น์—ฐํžˆ ๊ฐ์†Œํ•˜์ฃ .

ํ•˜์ง€๋งŒ ๋‹จ์  ๋˜ํ•œ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ํ๋ฆ„์ด ๋ณต์žกํ•ด์ง€๋ฉด ์ฝœ๋ฐฑ ์ง€์˜ฅ์— ๋น ์งˆ ์ˆ˜ ์žˆ์ฃ .

fun serveCoffee() {
    takeOrder("์•„๋ฉ”๋ฆฌ์นด๋…ธ",
        onSuccess = { order ->
            brewCoffee(order,
                onSuccess = { brewed ->
                    packCoffee(brewed,
                        onSuccess = { packed ->
                            deliverCoffee(packed,
                                onSuccess = { delivered ->
                                    println("โœ… ๊ณ ๊ฐ์—๊ฒŒ ์ปคํ”ผ ์ „๋‹ฌ ์™„๋ฃŒ: $delivered")
                                },
                                onFailure = { e ->
                                    println("โŒ ๋ฐฐ๋‹ฌ ์‹คํŒจ: ${e.message}")
                                }
                            )
                        },
                        onFailure = { e ->
                            println("โŒ ํฌ์žฅ ์‹คํŒจ: ${e.message}")
                        }
                    )
                },
                onFailure = { e ->
                    println("โŒ ์ปคํ”ผ ์ œ์กฐ ์‹คํŒจ: ${e.message}")
                }
            )
        },
        onFailure = { e ->
            println("โŒ ์ฃผ๋ฌธ ์‹คํŒจ: ${e.message}")
        }
    )
}

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

๋˜ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณ ์ •๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— SecurityContext, MDC ๊ฐ™์€ ThreadLocal ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์ด ๊นจ์ง€๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋””๋ฒ„๊น… ํ•˜๊ธฐ ์–ด๋ ต์ฃ . stack trace ๊ฐ€ ๋Š์ผœ์„œ ์ถœ๋ ฅ ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ธฐ์กด์˜ ๋ธ”๋กœํ‚น ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์™€ ํ˜ธํ™˜์„ฑ์ด ์ œํ•œ๋ฉ๋‹ˆ๋‹ค. JPA, ๋ณด์•ˆํ•„ํ„ฐ, ๋กœ๊น…, ํŠธ๋ ˆ์ด์‹ฑ ๋“ฑ ๋„๊ตฌ๋“ค์ด ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์ฃ .

์ฝœ๋ฐฑ ์ง€์˜ฅ์—์„œ ๋ฒ—์–ด๋‚˜๋ณด์ž! : ์ฝ”๋ฃจํ‹ด

์ฝœ๋ฐฑ์ง€์˜ฅ ์ฝ”๋“œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์กฐ๊ธˆ ๋” ๋…ธ๋ ฅํ•˜๋ฉด ๊ฐœ์„ ์ด ๋  ์ˆ˜ ์žˆ์–ด์š”. ๋งŒ์•ฝ ์šฐ๋ฆฌ๊ฐ€ Kotlin ์„ ๋„์ž… ํ•œ ์ž…์žฅ์ด๋ผ๋ฉด ์ฝ”๋ฃจํ‹ด (Coroutine) ๋„์ž…์„ ๊ฒ€ํ† ํ•ด๋ณผ ์ˆ˜ ์žˆ์ฃ .

์ฝ”๋ฃจํ‹ด์€ ๊ฐ€์ƒ์Šค๋ ˆ๋“œ์™€ ๋น„์Šทํ•˜๊ฒŒ ๊ฐ€๋ฒผ์šด ์Šค๋ ˆ๋“œ๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ์‹คํ–‰ ํ๋ฆ„์„ ์ค‘๋‹จ(์ •์ง€) ํ–ˆ๋‹ค๊ฐ€ ์žฌ๊ฐœํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ˆ˜์ฒœ ~ ์ˆ˜๋งŒ ๊ฐœ์˜ ๋™์‹œ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์ฃ .

OS ์Šค๋ ˆ๋“œ์˜ ๋ฌด๊ฑฐ์›€์— ๋Œ€ํ•ด์„œ๋Š” ์ถฉ๋ถ„ํžˆ ์„ค๋ช…๋“œ๋ ธ์œผ๋‹ˆ ๋”์ด์ƒ ์ถ”๊ฐ€๋กœ ์„ค๋ช…๋“œ๋ฆฌ์ง€ ์•Š๊ฒ ์Šต๋‹ˆ๋‹ค. ์ฝ”๋ฃจํ‹ด์œผ ์•ž์„œ ์„ค๋ช…๋“œ๋ฆฐ ๊ฐ€์ƒ์Šค๋ ˆ๋“œ์™€๋Š” ๋‹ค๋ฅธ ๊ฐœ๋…์ด์—์š”.

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ํ˜ธ์ถœ ์Šคํƒ (call stack) ์„ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๋ฉฐ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ OS ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ฝ”๋ฃจํ‹ด์€ Kotlin ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ suspend fun ์„ ์ธ์ง€ํ•ด์„œ ํ˜ธ์ถœ ์Šคํƒ์„ ์ „๋ถ€ ๋ณด์กดํ•˜์ง€ ์•Š๋Š”, ์ •์ง€ ์ง€์ ๋งˆ๋‹ค ์ƒํƒœ๋งŒ ์ €์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

   [ ์ฝ” ๋ฃจ ํ‹ด ]                          [ ๊ฐ€ ์ƒ ์Šค ๋ ˆ ๋“œ ]
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  CoroutineScope   โ”‚             โ”‚   JVM Loom Scheduler    โ”‚
โ””โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”˜             โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
   โ”‚             โ”‚                       โ”‚          โ”‚
   โ†“             โ†“                       โ†“          โ†“
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ co1   โ”‚     โ”‚ co2   โ”‚              โ”‚ vth1  โ”‚  โ”‚ vth2  โ”‚
โ”‚stateโ†‘ โ”‚     โ”‚stateโ†“ โ”‚              โ”‚stackโ†‘ โ”‚  โ”‚stackโ†“ โ”‚
โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜     โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜              โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”˜
    โ†“ suspend       โ†“ resume             โ†“ block      โ†“ block
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Dispatcher (Default, IOโ€ฆ) โ”‚       โ”‚ carrier OS thread pool    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

ํ˜ธ์ถœ ์Šคํƒ์ด๋ž€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ๋Ÿฐํƒ€์ž„์ด ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ ๋งˆ๋‹ค ํ˜„์žฌ ์‹คํ–‰ ์ƒํƒœ๋ฅผ ์ €์žฅํ•ด๋‘๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ† ์Šคํƒ ์ตœ์ƒ๋‹จ (Top)
โ”‚ f3() ์˜ ํ”„๋ ˆ์ž„  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ f2() ์˜ ํ”„๋ ˆ์ž„  โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚ f1() ์˜ ํ”„๋ ˆ์ž„  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ† ์Šคํƒ ์ตœํ•˜๋‹จ (Bottom)

๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์ด๋Ÿฐ ํ˜•ํƒœ์ฃ . ํ•จ์ˆ˜๋“ค์ด ํ˜ธ์ถœ ๋œ ์ˆœ์„œ๋Œ€๋กœ ์Šคํƒ์— ์Œ“์ด์ฃ . ์Šคํƒ ๊ตฌ์กฐ๋‹ˆ๊นŒ LIFO (Last In First Out) ํ˜•ํƒœ๋กœ ํ•จ์ˆ˜๋“ค์ด ๋น ์ ธ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ๊ฐ ์Šคํƒ ํ”„๋ ˆ์ž„ (Stack Frame) ์—๋Š” ํ•จ์ˆ˜ ํ˜ธ์ถœ ์‹œ์ ์˜ ์ง€์—ญ ๋ณ€์ˆ˜, ๋งค๊ฐœ ๋ณ€์ˆ˜, ๊ทธ๋ฆฌ๊ณ  ๋ณต๊ท€ ์ฃผ์†Œ (๋ฆฌํ„ด ์œ„์น˜) ๋“ฑ์ด ์ €์žฅ๋˜์–ด์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์Šคํ…œ ์ƒ์—์„œ๋Š” ํ•จ์ˆ˜๊ฐ„์— ํ˜ธ์ถœ ๊ตฌ์กฐ๋ฅผ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๊ณ , ์ง€์—ญ๋ณ€์ˆ˜์™€ ๋งค๊ฐœ๋ณ€์ˆ˜ ๋“ฑ์˜ ๊ฐ’์ด ์œ ์ง€๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค (StackTrace) ๋ฅผ ํ†ตํ•ด ํ˜ธ์ถœ ๊ฒฝ๋กœ๋ฅผ ์•Œ ์ˆ˜ ์žˆ์ฃ .

์ฝ”๋ฃจํ‹ด์€ ์ด ํ˜ธ์ถœ ์Šคํƒ์— ํ•จ์ˆ˜์˜ ํ๋ฆ„์„ ์ €์žฅํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ suspend (์ •์ง€) ์ง€์ ๋งˆ๋‹ค ํ•„์š”ํ•œ ๋กœ์ปฌ ๋ณ€์ˆ˜์™€ ๋‹ค์Œ ์ƒํƒœ ๋ณ„ ๋ถ„๊ธฐ์ (switch-case)๊ณผ ์ฝœ๋ฐฑ ๊ตฌ์กฐ๋ฅผ ์ƒ์„ฑํ•ด ์ƒํƒœ ๊ธฐ๊ณ„ (State Machine) ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์Šคํƒ์„ ์“ฐ๋Š” ๊ฒƒ์— ๋น„ํ•ด ํ›จ์”ฌ ์ ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ฃ .

ํ˜ธ์ถœ ์Šคํƒ์—์„œ๋Š” ํ•จ์ˆ˜ ์ง„์ž…๋ถ€ํ„ฐ ๋ณต๊ท€๊นŒ์ง€ ๋ชจ๋‘” ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์— ๋น„ํ•˜๋ฉด ๊ทธ๋ƒฅ suspend ์ง€์  ๋งˆ๋‹ค ๋ณ„๋„์˜ ์ €์žฅ์šฉ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์ƒ˜์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ์ƒํƒœ ๊ธฐ๊ณ„ (State Machine) ์ด๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ •์ง€๋œ ์ง€์ ์˜ ๋กœ์ปฌ ๋ณ€์ˆ˜์™€ ๋‹ค์Œ ์‹คํ–‰ ์œ„์น˜ ์ •๋ณด๋ฅผ ๋‹ด์€ Continuation ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. ์ถ”ํ›„ Continuation.resumeWith(...) ํ˜ธ์ถœ๋กœ ๋กœ์ปฌ ๋ณ€์ˆ˜์™€ ์‹คํ–‰ ์œ„์น˜๊ฐ€ ๋ณต์›๋˜๊ณ , ํ•จ์ˆ˜๊ฐ€ ์ด์–ด์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

ํ˜ธ์ถœ ์Šคํƒ์€ ๋งŒ์•ฝ ํ•จ์ˆ˜์˜ ํ˜ธ์ถœ ๊ฐ„์— ์žฌ๊ท€๊ฐ€ ์ƒ๊ธฐ๊ณ , ์ด ์žฌ๊ท€๊ฐ€ ๊นŠ์–ด์ง€๋ฉด ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ (Stack Overflow) ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋ฃจํ‹ด์˜ ๊ฒฝ์šฐ๋Š” ์ƒํƒœ ์ „ํ™˜๋งŒ ๊ณ„์†ํ•ด์„œ ์ด๋ค„์ง€๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ์–ด๋”˜๊ฐ€์— ์Œ“์ด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ฏ€๋กœ ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

[์ „ํ†ต ์Šคํƒ ๊ธฐ๋ฐ˜ ํ˜ธ์ถœ]             [์ฝ”๋ฃจํ‹ด์˜ ์ƒํƒœ ๊ธฐ๊ณ„]
โ”Œโ”€โ”€โ”€โ”€โ”                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚f1()โ”‚โ”€โ”€โ”€ํ˜ธ์ถœโ”€โ”€โ”€โ–ถ f2()            โ”‚State=0    โ”‚
โ””โ”€โ”€โ”€โ”€โ”˜      โ””โ”€โ”€โ”€โ”€โ”˜                โ”‚locals {...} โ”‚
  โ†‘                              โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  โ”‚pop                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”Œโ”€โ”€โ”€โ”€โ”โ”€โ”€โ”€ํ˜ธ์ถœโ”€โ”€โ”€โ–ถ f3()            โ”‚State=1    โ”‚
โ”‚f1()โ”‚      โ””โ”€โ”€โ”€โ”€โ”˜                โ”‚locals {...} โ”‚
โ””โ”€โ”€โ”€โ”€โ”˜                           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

๋ฌผ๋ก  ์ฝ”๋ฃจํ‹ด์„ ์“ฐ๋Š” ๋งŒํผ ์ฝ”๋ฃจํ‹ด ๋””๋ฒ„๊ฑฐ๋ฅผ ๋”ฐ๋กœ ์จ์•ผ ํ•œ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ์ฃ . ํ˜ธ์ถœ ์Šคํƒ์€ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์‚ดํŽด๋ณด๋ฉด ํ๋ฆ„์ด ์ง๊ด€์ ์œผ๋กœ ๋ณด์ด์ง€๋งŒ ์ฝ”๋ฃจํ‹ด์€ ๊ทธ๋ ‡์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ๋Œ€๋žต์ ์ธ ์„ค๋ช…์€ ์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๊ณ  ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ํ•œ๋ฒˆ ์‚ดํŽด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ตฌ์„ฑ ์š”์†Œ์„ค๋ช…
CoroutineScope์ฝ”๋ฃจํ‹ด์˜ ์ƒ๋ช… ์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ปจํ…์ŠคํŠธ. scope.cancel()๋กœ ํ•œ๊บผ๋ฒˆ์— ์ทจ์†Œ ๊ฐ€๋Šฅ.
launch / async์ฝ”๋ฃจํ‹ด ๋นŒ๋”. launch๋Š” Job ๋ฐ˜ํ™˜, async๋Š” Deferred<T> ๋ฐ˜ํ™˜(๊ฒฐ๊ณผ๊ฐ’ ํ•„์š”ํ•  ๋•Œ).
Dispatcher์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•  ์Šค๋ ˆ๋“œ ํ’€. ๋Œ€ํ‘œ์ ์œผ๋กœ Dispatchers.Default, IO, Main ๋“ฑ์ด ์žˆ์Œ.
suspend fun์ •์ง€ ์ง€์ ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜. ๋‚ด๋ถ€์— ๋‹ค๋ฅธ suspend ํ˜ธ์ถœ, ๋…ผ๋ธ”๋กœํ‚น API ํ˜ธ์ถœ์ด ๊ฐ€๋Šฅ.
Job์ฝ”๋ฃจํ‹ด ์‹คํ–‰ ๋‹จ์œ„. ์™„๋ฃŒ, ์ทจ์†Œ ์ƒํƒœ๋ฅผ ์ฒดํฌํ•˜๊ฑฐ๋‚˜ ์ œ์–ด ๊ฐ€๋Šฅ.
Deferred<T>Job + ๊ฒฐ๊ณผ๊ฐ’์„ ๊ฐ€์ง. await()๋กœ ๊ฒฐ๊ณผ ํš๋“.

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ•˜๋‚˜ ๋ณผ๊นŒ์š”?

import kotlinx.coroutines.*

fun main() = runBlocking {               // โ‘  ์ตœ์ƒ์œ„ Scope
    val job = launch(Dispatchers.IO) {    // โ‘ก IO ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์‹คํ–‰
        val data = fetchData()            // โ‘ข ๋…ผ๋ธ”๋กœํ‚น์œผ๋กœ ํ˜ธ์ถœ
        println("Fetched: $data")
    }
    delay(100)                            // โ‘ฃ ๋‹ค๋ฅธ ์ž‘์—…
    job.cancelAndJoin()                   // โ‘ค ํ•„์š” ์‹œ ์ฝ”๋ฃจํ‹ด ์ทจ์†Œ
}

suspend fun fetchData(): String {
    delay(500)  // ์‹ค์ œ๋กœ๋Š” ๋„คํŠธ์›Œํฌ/๋””์Šคํฌ I/O ๊ฐ™์€ suspend ํ•จ์ˆ˜
    return "Hello, Coroutine"
}

์ฝ”ํ‹€๋ฆฐ์œผ๋กœ ๋…ผ๋ธ”๋กœํ‚น REST API ํ˜ธ์ถœ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค. runBlocking์ด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๋ธ”๋กœํ‚นํ•˜๋ฉฐ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. launch(Dispatchers.IO)๋กœ I/O ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์ฝ”๋ฃจํ‹ด์„ ์‹œ์ž‘ํ•˜๊ณ , fetchData() ๋‚ด๋ถ€์˜ delay๋Š” ๋…ผ๋ธ”๋กœํ‚น์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ฒฝ์šฐ (์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๋˜์ง€) job.cancelAndJoin()์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ์‚ฌ์ „ ์„ค๋ช…์€ ์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๊ณ , ์ € ์ฝœ๋ฐฑ์ง€์˜ฅ ์ฝ”๋“œ๋ฅผ ํ•œ๋ฒˆ ๊ฑท์–ด ๋‚ด ๋ณผ๊นŒ์š”?

๋จผ์ € ์ฝœ๋ฐฑ ๊ธฐ๋ฐ˜ ํ•จ์ˆ˜๋ฅผ ์ฝ”๋ฃจํ‹ด ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

suspend fun takeOrder(menu: String): String {
    // ์‹ค์ œ ๋น„๋™๊ธฐ ๋กœ์ง์„ ์ฝ”๋ฃจํ‹ด์œผ๋กœ ๊ฐ์‹ผ๋‹ค๊ณ  ๊ฐ€์ •
    //Do Something
    if (menu.isBlank()) throw IllegalArgumentException("๋ฉ”๋‰ด๊ฐ€ ๋น„์–ด์žˆ์–ด์š”")
    return "Order($menu)"
}

suspend fun brewCoffee(order: String): String {
    //Do Something
    if (order.contains("fail")) throw RuntimeException("์ปคํ”ผ ์ œ์กฐ ์‹คํŒจ")
    return "Brewed($order)"
}

suspend fun packCoffee(brewed: String): String {
    //Do Something
    return "Packed($brewed)"
}

suspend fun deliverCoffee(packed: String): String {
    //Do Something
    return "Delivered($packed)"
}

์ดํ›„ ์ฝœ๋ฐฑ ์ง€์˜ฅ์— ๋ฌถ์—ฌ์žˆ๋˜ serveCoffee ํ•จ์ˆ˜๋ฅผ ์ˆœ์ฐจ์ ์ธ ์ฝ”๋ฃจํ‹ด ํ•จ์ˆ˜ ํ˜ธ์ถœ๋กœ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ ํ•จ์ˆ˜๋“ค์ด ์™ธ๋ถ€๋กœ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋กœ๋„๋ก ์ฒ˜๋ฆฌํ–ˆ์œผ๋‹ˆ try/catch ๋˜ํ•œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ฃ .

suspend fun serveCoffee() {
    try {
        val order = takeOrder("์•„๋ฉ”๋ฆฌ์นด๋…ธ")
        val brewed = brewCoffee(order)
        val packed = packCoffee(brewed)
        val delivered = deliverCoffee(packed)

        println("โœ… ๊ณ ๊ฐ์—๊ฒŒ ์ปคํ”ผ ์ „๋‹ฌ ์™„๋ฃŒ: $delivered")
    } catch (e: Exception) {
        println("โŒ ์ฒ˜๋ฆฌ ์‹คํŒจ: ${e.message}")
    }
}

์ด์ฒ˜๋Ÿผ ์ฝ”๋ฃจํ‹ด์„ ์‚ฌ์šฉํ•˜๋ฉด, ๋น„๋™๊ธฐ I/O ๋ฅผ ๋งˆ์น˜ ๋™๊ธฐ์‹ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋ฃจํ‹ด์„ ์“ธ ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ?
๋””๋ฒ„๊น…์ด ์–ด๋ ต๋‹ค

์•ž์„œ ์„ค๋ช… ๋“œ๋ ธ๋‹ค์‹œํ”ผ ๋””๋ฒ„๊น…์ด ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์Šคํƒ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ฏ€๋กœ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๋ฅผ ํ†ตํ•œ ํ˜ธ์ถœ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ต์ฃ . ์ฆ‰ IDE ๋นจ์„ ๋งŽ์ด ํƒ‘๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ฒฐ๊ตญ ์ด๊ฒƒ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ผ๋ฐ˜ ์ž๋ฐ” ๋ธ”๋กœํ‚น I/O(์˜ˆ: Thread.sleep(), Files.readAllBytes() ๋“ฑ)๋ฅผ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœํ•˜๋ฉด, ๊ทธ ์ฝ”๋ฃจํ‹ด์ด ๋Œ์•„๊ฐ€๋˜ ์Šค๋ ˆ๋“œ ์ „์ฒด๊ฐ€ ๋ธ”๋กœํ‚น๋˜์–ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ์ ์œผ๋กœ, ๊ฐ™์€ ๋””์ŠคํŒจ์ฒ˜(Dispatcher.IO ๋“ฑ)์— ๋ฌถ์ธ ๋‹ค๋ฅธ ์ฝ”๋ฃจํ‹ด๋“ค๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์ฃ .

// ์ž˜๋ชป๋œ ์˜ˆ: Dispatchers.Default์— ๋ธ”๋กœํ‚น ํ˜ธ์ถœ
launch(Dispatchers.Default) {
    // ์‹ค์ œ๋กœ๋Š” I/O๋ผ๋ฉด withContext(Dispatchers.IO)๋กœ ์˜ฎ๊ฒจ์•ผ ํ•˜์ง€๋งŒ...
    Thread.sleep(1000)        // โŒ ์Šค๋ ˆ๋“œ ์ „์ฒด๋ฅผ 1์ดˆ ๋™์•ˆ ๋ธ”๋กœํ‚น
    println("์ž‘์—… ์™„๋ฃŒ")
}

์œ„ ์ฝ”๋“œ๋Š” Dispatchers.Default ํ’€(์ผ๋ฐ˜ CPU ์—ฐ์‚ฐ์šฉ ์Šค๋ ˆ๋“œ)์— ๋“ค์–ด๊ฐ„ ์ฝ”๋ฃจํ‹ด ํ•˜๋‚˜๊ฐ€ 1์ดˆ๊ฐ„ ๋ฌถ์ด๋ฉด์„œ, ๊ทธ ์Šค๋ ˆ๋“œ์—์„œ ๋Œ๋˜ ๋‹ค๋ฅธ CPU ์ฝ”์–ด ์‚ฌ์šฉ ์ฝ”๋ฃจํ‹ด๋„ ๋Œ€๊ธฐํ•ด์•ผ ํ•˜๋Š” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

launch(Dispatchers.IO) {      // โ‘  ๋ธ”๋กœํ‚น ํ˜ธ์ถœ ์ „์šฉ ํ’€๋กœ ๋ถ„๋ฆฌ
    // ๋ธ”๋กœํ‚น I/O๋Š” IO ๋””์ŠคํŒจ์ฒ˜์—์„œ๋งŒ!
    val data = Files.readAllBytes(path)
    withContext(Dispatchers.Default) {
        // CPU ์—ฐ์‚ฐ์ด ํ•„์š”ํ•˜๋ฉด ๋‹ค์‹œ Default๋กœ ์ „ํ™˜
        process(data)
    }
}

์ด ๊ฒฝ์šฐ์—” ๋ฐ˜๋“œ์‹œ Dispatchers.IO (I/O ์ „์šฉ ๋ธ”๋กœํ‚น ์Šค๋ ˆ๋“œ ํ’€) ๋กœ ๋ถ„๋ฆฌ์‹œํ‚ค๊ณ  withContext ๋ฅผ ํ†ตํ•ด ์ƒํ™ฉ์— ๋”ฐ๋ผ ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์ „ํ™˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ธ”๋กœํ‚น์„ ์ • ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ ˆ๋Œ€๋กœ Dispatcher.Default ๋‚˜ Main ์— ๋„ฃ์–ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ ์ ์šฉ์ด ๋ณต์žกํ•˜๋‹ค๋Š” ์ด์Šˆ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ฝ”๋ฃจํ‹ด์€ ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๋กœ ๋ฌถ์ธ ์Šค์ฝ”ํ”„ (CoroutineScope) ๋‹จ์œ„๋กœ ์ทจ์†Œ์™€ ์˜ˆ์™ธ ์ „ํŒŒ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์Šค์ฝ”ํ”„ ๋ฐ–์—์„œ ์ƒ์„ฑ๋œ ์ฝ”๋ฃจํ‹ด (GlobalScope) ๋Š” ์ด ๊ด€๊ณ„์—์„œ ๋ฒ—์–ด๋‚˜ ์˜ˆ์ธก์ด ์–ด๋ ค์›Œ์ง€์ฃ .

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

fun CoroutineScope.loadAll(ids: List<String>) = supervisorScope {
    ids.map { id ->
        // supervisorScope ๋‚ด์—์„œ launch ํ•˜๋ฉด,
        // ๊ฐœ๋ณ„ ์‹คํŒจ๊ฐ€ ๋‹ค๋ฅธ ์ž์‹์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        launch {
            fetchAndStore(id)
        }
    }.joinAll()   // ๋ชจ๋“  ์ž์‹ ์ฝ”๋ฃจํ‹ด ์™„๋ฃŒ ๋Œ€๊ธฐ
}

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์ƒํ•˜๊ด€๊ณ„์— ๋”ฐ๋ผ supervisorScope ๋ฅผ ํ†ตํ•ด ํ•˜์œ„ ๋˜๋Š” ์ƒ์œ„์˜ ์—๋Ÿฌ๋ฅผ ๊ฒฉ๋ฆฌ์‹œ์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. CoroutineScope ๋Š” ํ™”๋ฉด ์ „ํ™˜ ํ˜น์€ HTTP ์š”์ฒญ ๋‹จ์œ„ ๋“ฑ ํฐ ๋‹จ์œ„๋กœ ๋ฌถ์–ด์•ผํ•˜์ฃ .

์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ๊นŒ๋‹ค๋กญ๋‹ค

๋‹ค์Œ์œผ๋กœ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๊ฐ€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์ž์ฒด๋Š” try / catch ๋“ฑ์„ ํ†ตํ•ด ์žกํžˆ๊ธฐ๋Š” ํ•˜๊ฒ ์ง€๋งŒ, ์˜ˆ์™ธ๊ฐ€ ์ „ํŒŒ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์–ธ๊ธ‰๋˜๋Š” ๋ชจ๋“  ์˜ˆ์ œ๋“ค์˜ ๊ณตํ†ต์ ์ธ ์ด์Šˆ๋Š” ํ• ๋‹น ๋œ job ์ด ๋‹ค ๊ฐ™์ด ์ทจ์†Œ๊ฐ€ ๋˜์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๊ทธ๋Ÿฌ์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ๋“ค์ž…๋‹ˆ๋‹ค.

suspend fun main() = coroutineScope {
    val job1 = async {
        delay(100)
        println("โœ… job1 ์™„๋ฃŒ")
        "job1"
    }

    val job2 = async {
        delay(200)
        throw RuntimeException("โŒ job2 ์‹คํŒจ!")
    }

    try {
        // job2 ์˜ˆ์™ธ๊ฐ€ ์—ฌ๊ธฐ์„œ throw ๋จ
        val result1 = job1.await()
        val result2 = job2.await()
        println("๊ฒฐ๊ณผ: $result1, $result2")
    } catch (e: Exception) {
        println("์˜ˆ์™ธ ๋ฐœ์ƒ: ${e.message}")
    }
}

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

suspend fun serve() = supervisorScope {
    launch {
        throw RuntimeException("โ˜ ๏ธ ์„œ๋ธŒ ์ž‘์—… ์‹คํŒจ")
    }

    launch {
        delay(1000)
        println("โœ… ๋‹ค๋ฅธ ์ž‘์—… ์ •์ƒ ์ง„ํ–‰")
    }
}

supervisorScope ์—์„œ๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ž์‹์ด ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ž์‹ ํ•˜๋‚˜์˜ ์‹คํŒจ๊ฐ€ ๋‹ค๋ฅธ ์ž์‹์—๊ฒŒ ์ „ํŒŒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ƒํ™ฉ์— ๋”ฐ๋ผ์„œ serve() ํ•จ์ˆ˜ ์ „์ฒด์— ๋Œ€ํ•ด์„œ๋Š” ์‹คํŒจ๊ฐ€ ๋ˆ„๋ฝ๋˜๋Š” ์ผ€์ด์Šค๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์ฃ . ์ด ๊ฒฝ์šฐ์—” ์ˆ˜๋™์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ์บ์น˜ํ•˜๊ฑฐ๋‚˜ propagate ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

fun main() = runBlocking {
    launch {
        throw RuntimeException("๐Ÿ”ฅ ์ด ์˜ˆ์™ธ๋Š” ์žกํžˆ์ง€ ์•Š์•„์š”!")
    }

    delay(1000)
    println("โœ… ์—ฌ์ „ํžˆ ์‚ด์•„์žˆ์Œ")
}

๋งˆ์ง€๋ง‰์œผ๋กœ launch ๋‚ด์—์„œ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋Š” ์ž๋™์œผ๋กœ ์˜ˆ์™ธ๊ฐ€ ์ „ํŒŒ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ž์‹์ด ์ฃฝ์–ด๋„ ๋ถ€๋ชจ๋Š” ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š์ฃ . ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด CoroutineExceptionHandler ๋ฅผ ๋”ฐ๋กœ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์™ธ ๊ณ ๋ คํ•ด์•ผ ํ•  ์ 

๋˜ํ•œ suspend ํ•จ์ˆ˜ ํ˜ธ์ถœ๋งˆ๋‹ค ๋งŒ๋“ค์–ด์ง€๋Š” Continuation ๊ฐ์ฒด์™€ ์ƒํƒœ ๋ถ„๊ธฐ ๋กœ์ง์ด ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ๋ฏธ์•ฝํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•œ๋‘๊ฐœ๋ผ๋ฉด ์ƒ๊ด€ ์—†์ง€๋งŒ ์ˆ˜๋ฐฑ๋งŒ ๊ฐœ ์ด์ƒ์˜ ์ฝ”๋ฃจํ‹ด์„ ๋„์šฐ๊ฒŒ ๋˜๋ฉด GC์— ๋ถ€๋‹ด์ด ๊ฐˆ ์ˆ˜ ์žˆ์ฃ .

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

๐Ÿ˜Š ์ฝ”๋ฃจํ‹ด์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋Š” ์—ฌ๊ธฐ๊นŒ์ง€ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋”ฅ๋‹ค์ด๋ธŒ ์‹œ๋ฆฌ์ฆˆ์—์„œ ๋˜ ๋‹ค๋ค„์•ผ ํ•˜๋‹ˆ๊นŒ์š”. ์ฝ”๋ฃจํ‹ด ์ฃผ์ œ๋กœ๋งŒ ์•„๋งˆ ์ง€๊ธˆ ๊ธ€ ๋งŒํผ ๋ถ„๋Ÿ‰์ด ๋‚˜์˜ฌ๊ฒ๋‹ˆ๋‹ค ํ•˜ํ•˜...

๐ŸŽจ 5. ์กฐ๊ธˆ ๋” ๋“ค์–ด๊ฐ€๊ธฐ : ํ”„๋ก ํŠธ์—”๋“œ ์—”์ง€๋‹ˆ์–ด๋ง์—์„œ์˜ ๋™๊ธฐ, ๋น„๋™๊ธฐ ๊ทธ๋ฆฌ๊ณ  ๋ธ”๋กœํ‚น, ๋…ผ ๋ธ”๋กœํ‚น

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฑ์—”๋“œ์—์„œ์˜ ๋™๊ธฐ, ๋น„๋™๊ธฐ ๊ทธ๋ฆฌ๊ณ  ๋ธ”๋กœํ‚น, ๋…ผ ๋ธ”๋กœํ‚น์— ๋Œ€ํ•ด ๋‹ค๋ค„ ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿผ ํ”„๋ก ํŠธ์—”๋“œ์—์„œ๋Š” ์ด ๊ฐœ๋…๋“ค์ด ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์„๊นŒ์š”?

ํ”„๋ก ํŠธ์—”๋“œ๋Š” ๋‹จ์ผ ์Šค๋ ˆ๋“œ UI ์Šค๋ ˆ๋“œ ์œ„์—์„œ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์ด ๋„ค ๊ฐ€์ง€ ์กฐํ•ฉ์ด ๊ณง๋ฐ”๋กœ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜(UX)์œผ๋กœ ์ง๊ฒฐ๋ฉ๋‹ˆ๋‹ค. React ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋„ ๊ฒฐ๊ตญ ๋น„๋™๊ธฐยท๋…ผ๋ธ”๋กœํ‚น ํ๋ฆ„์„ ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•จ์ž„์„ ์ดํ•ดํ•˜์‹œ๋ฉด ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

โ›”๏ธ 5.1 ๋™๊ธฐ + ๋ธ”๋กœํ‚น

ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์ƒํ™ฉ์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ์ง์ ‘ DOM ์„ ์ˆ˜์ž‘์—… ํ•˜๋Š” ๊ฒฝ์šฐ

    // ๋™๊ธฐ XMLHttpRequest โ†’ ๋„คํŠธ์›Œํฌ ๋Œ€๊ธฐ ์ค‘ UI ์™„์ „ ๋ฉˆ์ถค
    const xhr = new XMLHttpRequest()
    xhr.open('GET', '/api/data', false)
    xhr.send()
    document.getElementById('list').innerHTML = render(xhr.response)
    
  • ๋ฌด๊ฑฐ์šด ์—ฐ์‚ฐ์„ ๋ฐ”๋กœ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒฝ์šฐ

    // ๋ฐฐ์—ด์ด ์ˆ˜์‹ญ๋งŒ ๊ฑด์ผ ๋•Œ
    const result = largeArray.map(fancyCompute)
    document.body.textContent = result.join(',')
    

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

๐Ÿ› ๏ธ 5.2 ๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น

function Counter() {
  const [count, setCount] = useState(0);
  // ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ๋ฐ”๋กœ ๋ Œ๋”๋ง
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

React ๋“ฑ์—์„œ ๋‹จ์ˆœ ์ƒํƒœ๋ณ€ํ™”์˜ ๊ฒฝ์šฐ ์ด๋Ÿฐ ์ผ€์ด์Šค์— ์†ํ•ฉ๋‹ˆ๋‹ค. 16ms ์ฆ‰ ํ”„๋ ˆ์ž„ ๋‹จ์œ„ ์•ˆ์— ์—ฐ์‚ฐ์ด ๋๋‚˜๋ฉด ์ƒ๊ด€์€ ์—†์ง€๋งŒ, ์—ฐ์‚ฐ๋Ÿ‰์ด ๊ฐ‘์ž๊ธฐ ์ปค์ง€๋ฉด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์ฃ . ์ด ๊ฒฝ์šฐ๋Š” Web Worker ๋„์ž…์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”Œ 5.3 ๋น„๋™๊ธฐ + ๋ธ”๋กœํ‚น

useEffect(() => {
  fetchData().then((data) => {
    // ์ƒํƒœ ์—…๋ฐ์ดํŠธ ์ „, ๋ณต์žก ๊ณ„์‚ฐ์œผ๋กœ ๋ Œ๋”๋ง ๋ธ”๋กœํ‚น
    const processed = expensiveTransform(data)
    setList(processed)
  })
}, [])

useEffect ์™€ ๊ฐ™์ด ์ƒํƒœ์— ๋”ฐ๋ผ DOM ์„ ๋ฆฌ๋กœ๋“œ ์‹œํ‚ค๋Š” ๋“ฑ UI ์— ์˜ํ–ฅ์„ ๋ผ์น  ์ˆ˜ ์žˆ๋Š” Hook ๊ณผ fetcher ๋ฅผ ํ•จ๊ป˜ ์“ธ ๋•Œ ๋ฐ˜๋“œ์‹œ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค. ๋งŒ์•ฝ ํŒจ์นญ์ด ์˜ค๋ž˜๊ฑธ๋ฆฌ๊ฑฐ๋‚˜, ํŒจ์นญ ๊ฒฐ๊ณผ์— ๋Œ€ํ•œ ์—ฐ์‚ฐ์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋ฉด ํ”„๋ ˆ์ž„ ๋“œ๋ž์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŒŸ 5.4 ๋น„๋™๊ธฐ + ๋…ผ ๋ธ”๋กœํ‚น

fetch('/api/large')
  .then((r) => r.json())
  .then((data) => {
    const worker = new Worker('worker.js')
    worker.postMessage(data)
    worker.onmessage = (e) => renderList(e.data)
  })
const [list, setList] = useState([]);
const [isPending, startTransition] = useTransition();

useEffect(() => {
  fetchData().then(data => {
    startTransition(() => {
      setList(expensiveTransform(data));
    });
  });
}, []);

return isPending
  ? <Spinner />
  : <ItemList items={list} />;

๋งŒ์•ฝ ํŒจ์นญ์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๊ฑฐ๋‚˜ ์—ฐ์‚ฐ์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ Web Worker ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ useTransition ์„ ์‚ฌ์šฉํ•ด์„œ ๋ฐฑ๊ทธ๋ผ์šด๋“œ๋กœ ์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋„คํŠธ์›Œํฌ I/O ์™€ CPU ์—ฐ์‚ฐ ๋ชจ๋‘ ๋ฉ”์ธ์Šค๋ ˆ๋“œ์—์„œ ๋ถ„์‚ฐ ์ฒ˜๋ฆฌ๋˜๊ณ  UX ๊ฐ€ ์ข€ ๋” ๋ถ€๋“œ๋Ÿฌ์›Œ์ง€๋Š” ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ 6. Outro

์ง€๊ธˆ๊นŒ์ง€ ๋™๊ธฐ, ๋น„๋™๊ธฐ ๊ทธ๋ฆฌ๊ณ  ๋ธ”๋กœํ‚น, ๋…ผ ๋ธ”๋กœํ‚น์ด๋ผ๋Š” ์ฃผ์ œ๋กœ ๋‹ค์–‘ํ•œ ์ผ€์ด์Šค๋ฅผ ์‚ดํŽด ๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด ์—”์ง€๋‹ˆ์–ด๋ง์—์„œ ๋ถ„์•ผ์™€ ์ƒ๊ด€์—†์ด ๋ฐ˜๋“œ์‹œ ํ•œ๋ฒˆ ์ฏค์€ ๋ถ€๋”ช์น˜๊ณ  ๊ณ ๋ฏผํ•  ๋ฒ• ํ•œ ์ฃผ์ œ๋ฅผ ๋”ฅ๋‹ค์ด๋ธŒ ํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€์˜ ์žฅํ™ฉํ•œ ์„ค๋ช…์„ ์š”์•ฝํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ •๋ฆฌ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํŒจํ„ด์žฅ์ ๋‹จ์ ์–ธ์ œ ์“ฐ๋‚˜
๋™๊ธฐ + ๋ธ”๋กœํ‚น๊ตฌํ˜„ ๋‹จ์ˆœ, ์ง๊ด€์ ์Šค๋ ˆ๋“œ ๋‚ญ๋น„, ํ™•์žฅ์„ฑ ๋‚ฎ์Œ์™ธ๋ถ€ API ์—ฐ์‡„ ํ˜ธ์ถœ, ํŠธ๋žœ์žญ์…˜ ๋“ฑ
๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น์Šค๋ ˆ๋“œ ์ ˆ์•ฝ, ๋ถ€๋ถ„ ์ตœ์ ํ™”๊ฑฐ์˜ ๋ธ”๋กœํ‚น๊ณผ ์ฐจ์ด ์ž‘์Œ๋™๊ธฐ ํ๋ฆ„ ์œ ์ง€ํ•˜๋ฉฐ I/O ์ตœ์ ํ™”
๋น„๋™๊ธฐ + ๋ธ”๋กœํ‚น์ ์ง„์  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์šฉ์ด์Šค๋ ˆ๋“œํ’€ ๋ˆ„์ˆ˜, ์˜ˆ์™ธ ์ถ”์  ์–ด๋ ค์›€๋ ˆ๊ฑฐ์‹œ ํ˜ธ์ถœ ์„ž์–ด์•ผ ํ•  ๋•Œ
๋น„๋™๊ธฐ + ๋…ผ๋ธ”๋กœํ‚น์ตœ๊ณ  ์„ฑ๋Šฅ, ์ ์€ ๋ฆฌ์†Œ์Šค๋กœ ๋‹ค์ˆ˜ ์ฒ˜๋ฆฌ์ฝœ๋ฐฑ ์ง€์˜ฅยท๋””๋ฒ„๊น…ยทํ˜ธํ™˜์„ฑ ๋ฌธ์ œํŠธ๋ž˜ํ”ฝ ๋งŽ์€ ์„œ๋น„์Šค, SSE, WS ๋“ฑ

๊ธ€์ด ์ฒ˜์Œ์ด ์ƒ๊ฐํ–ˆ๋˜ ๊ฒƒ์— ๋น„ํ•ด ๋งŽ์ด ๊ธธ์–ด์กŒ์Šต๋‹ˆ๋‹ค. ๋”ฅ๋‹ค์ด๋ธŒ๋ผ๋Š” ์ฃผ์ œ๋‹ค๋ณด๋‹ˆ ํ‰์†Œ๋ณด๋‹ค ํ›จ์”ฌ ๊ธธ์–ด์กŒ๋„ค์š”...๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์กฐ๊ธˆ ๋” ์ž‘์€ ์ฃผ์ œ๋กœ ๊ธ€์„ ๊นŠ๊ฒŒ ์จ ๋ณผ๊นŒ ํ•ฉ๋‹ˆ๋‹ค.

๋„์›€์ด ๋˜์…จ๋‹ค๋ฉด ๋‹คํ–‰์ด๊ณ  ํ˜น์‹œ ๋” ์„ค๋ช…์ด ํ•„์š”ํ•˜์‹œ๊ฑฐ๋‚˜ ํ”ผ๋“œ๋ฐฑ ํ•˜์‹ค ๋ถ€๋ถ„์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“ ์ง€ ์š”์ฒญ ์ฃผ์„ธ์š”!

๐Ÿ“š 7. Reference