- Published on
๐คฟ ์จ ๊พน์ฐธ๊ณ ๋ฅ๋ค์ด๋ธ 1 : ๋๊ธฐ์ ๋น๋๊ธฐ
- Authors
- Name
- Woojin Son
๐คฟ ์จ ๊พน์ฐธ๊ณ ๋ฅ๋ค์ด๋ธ 1 : ๋๊ธฐ์ ๋น๋๊ธฐ
- ๐คฟ [์จ ๊พน์ฐธ๊ณ ๋ฅ๋ค์ด๋ธ] ๋๊ธฐ์ ๋น๋๊ธฐ
- ๐ 1. Intro
- โ๏ธ 2. ๋๊ธฐ VS ๋น๋๊ธฐ
- ๐ค 3. ์ธ์ ์ฌ์ฉํ๋์?
- ๐ฅ๏ธ 4. ๋ฐฑ์๋ ์์ง๋์ด๋ง์์์ ๋๊ธฐ, ๋น๋๊ธฐ ์ฒ๋ฆฌ
- โณ 4.1 ๋๊ธฐ + ๋ธ๋กํน : ์ผ๋ฐ์ ์ธ ๋ฐฑ์๋ ์์ฒญ-์๋ต ์ฒ๋ฆฌ ํจํด
- ๐ซ๐ 4.2 ๋ธ๋กํน, ๋ ผ๋ธ๋กํน
- ๐ 4.3 ๋๊ธฐ + ๋ ผ ๋ธ๋กํน : ์กฐ๊ธ ๋ ์ ์ฐํ ์ฒ๋ฆฌ๊ฐ ํ์ํ ๋
- ๐ 4.4 ๋น๋๊ธฐ + ๋ธ๋กํน : ์ผ๋ถ๋ง ๋ธ๋กํน์ ๊ฑธ๊ณ ์ถ์ ๊ฒฝ์ฐ
- ๐ 4.5 ๋น๋๊ธฐ + ๋ ผ๋ธ๋กํน : ์ฑ๋ฅ์ ์ข์ง๋ง ๋ง์ ๋ณต์ก์ฑ๊ณผ ์ ์ฝ์ด ๋์ด๋๋ ํจํด
- ๐จ 5. ์กฐ๊ธ ๋ ๋ค์ด๊ฐ๊ธฐ : ํ๋ก ํธ์๋ ์์ง๋์ด๋ง์์์ ๋๊ธฐ, ๋น๋๊ธฐ ๊ทธ๋ฆฌ๊ณ ๋ธ๋กํน, ๋ ผ ๋ธ๋กํน
- ๐ 6. Outro
- ๐ 7. Reference
๐ 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 ๋ฑ |
๊ธ์ด ์ฒ์์ด ์๊ฐํ๋ ๊ฒ์ ๋นํด ๋ง์ด ๊ธธ์ด์ก์ต๋๋ค. ๋ฅ๋ค์ด๋ธ๋ผ๋ ์ฃผ์ ๋ค๋ณด๋ ํ์๋ณด๋ค ํจ์ฌ ๊ธธ์ด์ก๋ค์...๋ค์๋ถํฐ๋ ์กฐ๊ธ ๋ ์์ ์ฃผ์ ๋ก ๊ธ์ ๊น๊ฒ ์จ ๋ณผ๊น ํฉ๋๋ค.
๋์์ด ๋์ จ๋ค๋ฉด ๋คํ์ด๊ณ ํน์ ๋ ์ค๋ช ์ด ํ์ํ์๊ฑฐ๋ ํผ๋๋ฐฑ ํ์ค ๋ถ๋ถ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ์์ฒญ ์ฃผ์ธ์!