Scheduler & Thread Model

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์ฆˆ ๋ช…์„ธ ์ž์ฒด๋Š” ์Šค๋ ˆ๋”ฉ ๋ชจ๋ธ์„ ๊ฐ•์ œํ•˜์ง€ ์•Š์•„ ํŠน์ • ์Šค๋ ˆ๋“œ์—์„œ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•˜์ง€ ์•Š์œผ๋ฉฐ, ์ด๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์˜์—ญ์ด๋‹ค.

  • ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฆฌ์•กํ„ฐ(Reactor)์˜ ์—ฐ์‚ฐ์ž ์ฒด์ธ์€ ์ด์ „ ๋‹จ๊ณ„์˜ ์‹ ํ˜ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ์Šค๋ ˆ๋“œ์™€ ๋™์ผํ•œ ์Šค๋ ˆ๋“œ์—์„œ ๊ณ„์† ์‹คํ–‰

  • ์Šค์ผ€์ค„๋Ÿฌ๋Š” ์ด๋Ÿฌํ•œ ์‹คํ–‰ ํ๋ฆ„์„ ์˜๋„์ ์œผ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์ „ํ™˜ํ•  ๋•Œ ์‚ฌ์šฉ

Spring WebFlux์—์„œ๋Š” Scheduler๋ฅผ ํ†ตํ•ด ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ฉฐ, ์‹คํ–‰ ์ปจํ…์ŠคํŠธ(์Šค๋ ˆ๋“œ)๋ฅผ ์†์‰ฝ๊ฒŒ ์ „ํ™˜ํ•˜๊ณ  ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

ํ•ต์‹ฌ ์—ฐ์‚ฐ์ž: publishOn vs subscribeOn

publishOn๊ณผ subscribeOn๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์ „ํ™˜ํ•˜๋Š” ๋‘ ํ•ต์‹ฌ ์—ฐ์‚ฐ์ž์ด๋‹ค.

subscribeOn(Scheduler)

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ subscribe() ํ˜ธ์ถœ ์‹œ ๊ตฌ๋… ์‹ ํ˜ธ๊ฐ€ ์ฒด์ธ์˜ ๊ฐ€์žฅ ์•„๋ž˜์—์„œ๋ถ€ํ„ฐ ์œ„๋กœ(Upstream) ์ „ํŒŒ๋˜๋ฉด์„œ ์‹œ์ž‘๋œ๋‹ค.

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

  • ์‚ฌ์šฉ ํšŸ์ˆ˜: ์ฒด์ธ ๋‚ด์— ์—ฌ๋Ÿฌ ๋ฒˆ ์„ ์–ธ๋˜์–ด๋„, ์†Œ์Šค์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์ฒซ ๋ฒˆ์งธ(๋งจ ์œ„์ชฝ) subscribeOn๋งŒ ์œ ํšจ

  • ์šฉ๋„: ์ฃผ๋กœ ๋ธ”๋กœํ‚น I/O ์ž‘์—…์ด๋‚˜ ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ดˆ๊ธฐํ™” ์ž‘์—…์„ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ ํ’€์—์„œ ์‹คํ–‰ํ•˜์—ฌ ๊ธฐ๋ณธ ์Šค๋ ˆ๋“œ(์˜ˆ: Netty ์ด๋ฒคํŠธ ๋ฃจํ”„)๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ

์ด์ฒ˜๋Ÿผ subscribeOn์€ ์ด ๊ตฌ๋… ์‹ ํ˜ธ ์ „ํŒŒ ๋ฐ ์†Œ์Šค์˜ ๋ฐ์ดํ„ฐ ๋ฐœํ–‰์„ ์–ด๋–ค ์Šค๋ ˆ๋“œ์—์„œ ์ˆ˜ํ–‰ํ• ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค.

publishOn(Scheduler)

publishOn์€ ์ž์‹ ๋ณด๋‹ค ์•„๋ž˜์— ์žˆ๋Š”, ์ฆ‰ ๋‹ค์šด์ŠคํŠธ๋ฆผ(Downstream) ์—ฐ์‚ฐ์ž๋“ค์˜ ์‹คํ–‰ ์Šค๋ ˆ๋“œ๋ฅผ ์ง€์ •๋œ ์Šค์ผ€์ค„๋Ÿฌ์˜ ์Šค๋ ˆ๋“œ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

  • ์˜ํ–ฅ ๋ฒ”์œ„: publishOn ํ˜ธ์ถœ ์ดํ›„์˜ ๋ชจ๋“  ๋‹ค์šด์ŠคํŠธ๋ฆผ ์—ฐ์‚ฐ์ž

  • ์‚ฌ์šฉ ํšŸ์ˆ˜: ์ฒด์ธ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ๋กœ ์ „ํ™˜ ๊ฐ€๋Šฅ

  • ์šฉ๋„: ํŠน์ • ์—ฐ์‚ฐ(์˜ˆ: CPU ์ง‘์•ฝ์  ์ž‘์—…)์„ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ, ํ˜น์€ ํŠน์ • ์Šค๋ ˆ๋“œ ์ปจํ…์ŠคํŠธ๋กœ ๋‹ค์‹œ ๋Œ์•„์™€์•ผ ํ•  ๋•Œ ์‚ฌ์šฉ

์—ฐ์‚ฐ์ž ์ฒด์ธ์— ์Šค๋ ˆ๋“œ ๊ฒฝ๊ณ„๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์œผ๋ฉฐ, publishOn์€ ์—…์ŠคํŠธ๋ฆผ(Upstream)์œผ๋กœ๋ถ€ํ„ฐ ์‹ ํ˜ธ(onNext, onComplete, onError)๋ฅผ ๋ฐ›์•„, ๋‹ค์‹œ ์ „ํŒŒ(emit)ํ•œ๋‹ค.

ํ•ญ๋ชฉ

subscribeOn()

publishOn()

์ ์šฉ ๋ฒ”์œ„

์ŠคํŠธ๋ฆผ ์ „์ฒด์˜ ์‹œ์ž‘ ์Šค๋ ˆ๋“œ(Upstream)

์ž์‹  ์ดํ›„์˜ ์—ฐ์‚ฐ์ž๋“ค(Downstream)์˜ ์‹คํ–‰ ์Šค๋ ˆ๋“œ ์ง€์ •

์œ„์น˜ ๋ฏผ๊ฐ๋„

์†Œ์Šค ๊ทผ์ฒ˜ ์ฒซ ์„ ์–ธ๋งŒ ์ ์šฉ

ํ•ด๋‹น ์ง€์ ์—์„œ ์Šค๋ ˆ๋“œ ๊ฒฝ๊ณ„ ์ƒ์„ฑ

์ฃผ์š” ์šฉ๋„

๋ธ”๋กœํ‚น ์†Œ์Šค/์ดˆ๊ธฐํ™”๋ฅผ ๋…ผ๋ธ”๋กœํ‚น ํ™˜๊ฒฝ์œผ๋กœ ๊ฒฉ๋ฆฌ

์—ฐ์‚ฐ ํŠน์„ฑ์— ๋”ฐ๋ผ ์‹คํ–‰ ์Šค๋ ˆ๋“œ๋ฅผ ๋ถ„๋ฆฌ/์ „ํ™˜

์ฝ”๋“œ ์˜ˆ์ œ

์ฃผ์š” ์Šค์ผ€์ค„๋Ÿฌ ์ข…๋ฅ˜

Project Reactor๋Š” Schedulers ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ๋ฏธ๋ฆฌ ์ •์˜๋œ ์Šค์ผ€์ค„๋Ÿฌ๋“ค์„ ์ œ๊ณตํ•œ๋‹ค.

  • Schedulers.parallel(): CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ€์ง„ ๊ณ ์ •๋œ ์Šค๋ ˆ๋“œ ํ’€

    • CPU ์ง‘์•ฝ์ ์ธ ๊ณ„์‚ฐ ์ž‘์—…์— ์ตœ์ ํ™”

  • Schedulers.boundedElastic(): ํ•„์š”์— ๋”ฐ๋ผ ์Šค๋ ˆ๋“œ๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋Š” ์Šค๋ ˆ๋“œ ํ’€

    • ์Šค๋ ˆ๋“œ ์ˆ˜์— ์ƒํ•œ์„  ์กด์žฌ

    • ๋ธ”๋กœํ‚น(Blocking) I/O ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ ํ•ฉ

  • Schedulers.single(): ๋‹จ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ์Šค์ผ€์ค„๋Ÿฌ

    • ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์–ด์•ผ ํ•˜๋Š” ์ž‘์—… ์ฒ˜๋ฆฌ์— ์ ํ•ฉ


Spring WebFlux์—์„œ์˜ ํ™œ์šฉ

์ผ๋ฐ˜์ ์ธ WebFlux ์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ง์ ‘ ๋‹ค๋ฃฐ ์ผ์ด ๊ฑฐ์˜ ์—†๋Š”๋ฐ, ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ์—์„œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํ•˜์ง€๋งŒ ๋ ˆ๊ฑฐ์‹œ ๋ธ”๋กœํ‚น(Blocking) ์ฝ”๋“œ๋ฅผ WebFlux ํ™˜๊ฒฝ์—์„œ ํ˜ธ์ถœํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ์Šค์ผ€์ค„๋Ÿฌ ์‚ฌ์šฉ์€ ํ•„์ˆ˜์ ์ด๋‹ค. ๋ธ”๋กœํ‚น ์ฝ”๋“œ๊ฐ€ WebFlux์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

Schedulers.boundedElastic()๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด findUserByIdBlocking ๋ฉ”์„œ๋“œ๊ฐ€ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๋ฅผ ๋ง‰์ง€ ์•Š๊ณ , ๋ธ”๋กœํ‚น I/O ์ „์šฉ ์Šค๋ ˆ๋“œ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์‹คํ–‰๋˜๋„๋ก ๊ฒฉ๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

WebFlux์˜ ์Šค๋ ˆ๋“œ ๋ชจ๋ธ

Spring WebFlux๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ์€ ์ˆ˜์˜ ๊ณ ์ •๋œ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜๋งŽ์€ ๋™์‹œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

  • ๊ธฐ๋ณธ ์Šค๋ ˆ๋“œ: Netty๋ฅผ ๊ธฐ๋ณธ ์„œ๋ฒ„๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, CPU ์ฝ”์–ด ์ˆ˜์— ๋งž์ถฐ ์ƒ์„ฑ๋œ ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop) ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉ

  • ๋™์ž‘ ์›์น™: ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๋Š” ์ ˆ๋Œ€ ์ฐจ๋‹จ(block)๋˜์ง€ ์•Š์•„์•ผ ํ•˜๋ฉฐ, I/O ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์š”์ฒญ์„ ๊ณ„์† ์ฒ˜๋ฆฌ

    • ๋งŒ์•ฝ ํ•˜๋‚˜์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๊ฐ€ Thread.sleep(), ๋ธ”๋กœํ‚น DB ํ˜ธ์ถœ ๋“ฑ์œผ๋กœ ๋ฉˆ์ถ”๊ฒŒ ๋˜๋ฉด, ํ•ด๋‹น ์Šค๋ ˆ๋“œ์— ํ• ๋‹น๋œ ๋ชจ๋“  ์š”์ฒญ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ์ง€์—ฐ

    • ๊ฒฐ๊ตญ ์‹œ์Šคํ…œ ์ „์ฒด์˜ ์ฒ˜๋ฆฌ๋Ÿ‰๊ณผ ์‘๋‹ต์„ฑ์„ ์‹ฌ๊ฐํ•˜๊ฒŒ ์ €ํ•˜์‹œํ‚ค๋Š” ์›์ธ

์Šค๋ ˆ๋“œ ์‚ฌ์šฉ ๋ฐฉ์‹

์‹ค๋ฌด์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์— ๋งž์ถฐ Scheduler๋ฅผ ์ „๋žต์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  • ๋…ผ๋ธ”๋กœํ‚น ์ž‘์—…: ๋ณ„๋„์˜ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ง€์ •ํ•  ํ•„์š”๊ฐ€ ์—†์ด, WebFlux์˜ ๊ธฐ๋ณธ ์Šค๋ ˆ๋“œ(์ด๋ฒคํŠธ ๋ฃจํ”„)๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉ

  • ๋ธ”๋กœํ‚น I/O (์˜ˆ: R2DBC๊ฐ€ ์•„๋‹Œ JDBC, ์™ธ๋ถ€ API ๋™๊ธฐ ํ˜ธ์ถœ)

    • subscribeOn(Schedulers.boundedElastic())์„ ์‚ฌ์šฉ

    • boundedElastic ์Šค์ผ€์ค„๋Ÿฌ๋Š” ๋ธ”๋กœํ‚น I/O ์ž‘์—…์„ ์œ„ํ•ด ํŠน๋ณ„ํžˆ ์„ค๊ณ„

    • ํ•„์š”์— ๋”ฐ๋ผ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€๋งŒ, ๋ฌดํ•œ์ • ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์ƒํ•œ์„ ์ด ์žˆ์œผ๋ฉฐ ์œ ํœด ์Šค๋ ˆ๋“œ๋Š” ์ž๋™์œผ๋กœ ์ œ๊ฑฐ

    • ์ด๋ฒคํŠธ ๋ฃจํ”„ ์Šค๋ ˆ๋“œ๊ฐ€ ์•„๋‹Œ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋ธ”๋กœํ‚น ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•จ์œผ๋กœ์จ ์ „์ฒด ์‹œ์Šคํ…œ์˜ ๋ฐ˜์‘์„ฑ ์œ ์ง€ ๊ฐ€๋Šฅ

  • CPU ์ง‘์•ฝ์ ์ธ ๊ณ„์‚ฐ ์ž‘์—…

    • publishOn(Schedulers.parallel()) ์‚ฌ์šฉ

    • parallel ์Šค์ผ€์ค„๋Ÿฌ๋Š” CPU ์ฝ”์–ด ์ˆ˜๋งŒํผ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ€์ง„ ๊ณ ์ •๋œ ์Šค๋ ˆ๋“œ ํ’€ ์ œ๊ณต

    • ๊ณ„์‚ฐ์ด ๋งŽ์€ ์ž‘์—…์„ ์ด๋ฒคํŠธ ๋ฃจํ”„์—์„œ ๋ถ„๋ฆฌํ•˜์—ฌ ๋‹ค๋ฅธ ์š”์ฒญ ์ฒ˜๋ฆฌ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋„๋ก ํ•จ

Last updated

Was this helpful?