๐Ÿ‘๐Ÿผ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Reactive Programming) ์•Œ์•„๋ณด๊ธฐ

EHOIยท2025๋…„ 2์›” 12์ผ

์˜ค๋Š˜์˜ TIL ์ฃผ์ œ๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ด๋‹ค.

๊ฐœ๋ฐœ์ž ๋ชจ์ž„์—์„œ Spring WebFlux์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๊ฐ€ ๋‚˜์™”์—ˆ๊ณ , ๊ฐ•์˜๋ฅผ ๋“ค์œผ๋ฉด์„œ ์ด ๊ธฐ์ˆ ์— ๋Œ€ํ•ด ํ•œ๋ฒˆ ๋” ๋“ค์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ˜„์žฌ ํŒŒ๊ฒฌ์˜จ ํšŒ์‚ฌ์—์„œ ์ด ๊ธฐ์ˆ ์„ ์“ฐ๋Š” ๊ฒƒ์„ ๋ณด๊ณ , 3๋ฒˆ์ด๋‚˜ ๋งˆ์ฃผ์ณค์œผ๋‹ˆ ๊ทธ๋Ÿผ ๋‚ด๊ฐ€ ์ง์ ‘ ๊ณต๋ถ€ํ•ด๋ณด์ž. ๋ผ๋Š” ์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ชจ๋ฅด๋Š” ๊ฒƒ์€ ๋ฐฉ๋Œ€ํ•œ๋ฐ ๋ชจ๋“  ๊ฒƒ์„ ๋‹ค ๊ณต๋ถ€ํ•  ์ˆ˜๋Š” ์—†์œผ๋‹ˆ, 3๋ฒˆ ์ •๋„ ๋“ฃ๊ณ  ๋ณด๊ฒŒ ๋˜๋ฉด ๊ทธ๋•Œ๋Š” ๊ณต๋ถ€๋ฅผ ์‹œ์ž‘ํ•˜์ž, ๋Š” ์œ ํŠœ๋ธŒ๋ฅผ ๋ณธ ์ ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์ด Spring WebFlux๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ์›น ํ”„๋ ˆ์ž„์›Œํฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•ด ๋จผ์ € ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.


Reactive Programming

๋น„๋™๊ธฐ์ ์ด๊ณ  ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜์˜ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ฒ˜๋ฆฌํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํŒจ๋Ÿฌ๋‹ค์ž„์ด๋‹ค.

์ฐจ๋ก€๋Œ€๋กœ ๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ , ์ด๋ฒคํŠธ ์„ฑ์œผ๋กœ ๋ฐœ์ƒํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํ๋ฆ„(Flow)๊ณผ ๋ณ€ํ™”์— ๋ฐ˜์‘(Reactive)ํ•˜๋Š” ์‹œ์Šคํ…œ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ์ดˆ์ ์ด ๋งž์ถฐ์ ธ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์‹œ์Šคํ…œ ๋‚ด์—์„œ ์ผ์–ด๋‚˜๋Š” ์ด๋ฒคํŠธ๋‚˜ ๋ฐ์ดํ„ฐ์˜ ๋ณ€ํ™”์— ๋ฐ˜์‘ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•œ๋‹ค.

๋จผ์ € ๋ช‡๊ฐ€์ง€ ์ค‘์š”ํ•œ ๊ฐœ๋…์„ ์ •๋ฆฌํ•ด๋ณด์ž

1. ๋น„๋™๊ธฐ์„ฑ(Asynchronous)

๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š”

  • ์ž‘์—…์ด ๋™๊ธฐ์ ์œผ๋กœ ์ฐจ๋ก€๋Œ€๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ,
  • ์—ฌ๋Ÿฌ ์ž‘์—…์ด ๋™์‹œ์— ์ผ์–ด๋‚˜๋ฉด์„œ ๊ฒฐ๊ณผ๊ฐ€ ์ค€๋น„๋˜๋ฉด ์•Œ๋ฆผ์„ ์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.
  • ์˜ˆ์‹œ: ๋„คํŠธ์›Œํฌ ์š”์ฒญ, ํŒŒ์ผ I/O, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ๋“ฑ์„ ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๋น„๋™๊ธฐ์  ์ฒ˜๋ฆฌ๋ฅผ ๋” ์ง๊ด€์ ์ด๊ณ  ์„ ์–ธ์ ์œผ๋กœ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

2. ๋ฐ์ดํ„ฐ ํ๋ฆ„(Flow of Data)

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ์ค‘์š”ํ•œ ์ ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ๋ฅธ๋‹ค๋Š” ์ ์ด๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜ํ•˜๋‚˜ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์—์„œ ๋ฒ—์–ด๋‚˜ โ†’ ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ •์˜ํ•˜๊ณ  ๊ทธ ํ๋ฆ„์— ๋ฐ˜์‘ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

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

3. Publisher์™€ Subscriber

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ Publisher์™€ Subscriber ๊ฐœ๋…์„ ์‚ฌ์šฉํ•œ๋‹ค.

  • Publisher: ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐœํ–‰ํ•˜๋Š” ๊ฐ์ฒด๋กœ, ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๊ตฌ๋…์ž์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.
  • Subscriber: Publisher๊ฐ€ ๋ฐœํ–‰ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋…ํ•˜๋Š” ๊ฐ์ฒด๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๊ณ  ์ฒ˜๋ฆฌํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

์ด ๊ตฌ์กฐ๋Š” ์˜ต์ €๋ฒ„ ํŒจํ„ด(Observer Pattern)์ด๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•˜๋Š” ๊ฒƒ์„ ๊ด€์ฐฐํ•˜๊ณ  ์žˆ๋‹ค๊ฐ€, Publisher๋Š” ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๊ตฌ๋…์ž์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐœํ–‰ํ•˜๋Š” ์ธก๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›๋Š” ์ธก์ด ๋ถ„๋ฆฌ๋˜์–ด ์žˆ์œผ๋ฉฐ, ๊ตฌ๋…์ž๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

4. ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ(Reactive Streams)

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ์€ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์ด๋ผ๋Š” ๊ฐœ๋…์— ์žˆ๋‹ค.

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ = ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์˜๋ฏธ. ๋ฐ์ดํ„ฐ ํ๋ฆ„๊ณผ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋ฐ˜์‘ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•จ.

์ฃผ์š” ํŠน์ง•

  • Non-blocking: ์ฒ˜๋ฆฌ ์ค‘์ธ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ ! ๋‹ค๋ฅธ ์ž‘์—…์„ ๋™์‹œ์— ์ฒ˜๋ฆฌ ํ•จ
  • Backpressure: ๋ฐ์ดํ„ฐ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์ด ํ˜๋Ÿฌ๋“ค์–ด์˜ฌ๋•Œ, ์ด๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ๋„ˆ๋ฌด ๋น ๋ฅด๊ฒŒ ๋„์ฐฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์ฒ˜๋ฆฌ๋„๋ก ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.

5. Flux์™€ Mono (Project Reactor)

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ Project Reactor๊ฐ€ ์žˆ๋Š”๋ฐ ์—ฌ๊ธฐ์„œ Flux์™€ Mono๋ผ๋Š” ๋‘๊ฐ€์ง€ ์ฃผ์š” ํƒ€์ž…์„ ์ œ๊ณตํ•œ๋‹ค.

  • Mono: ๋‹จ์ผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ
    • ์˜ˆ์‹œ: ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ๋‹จ์ผ ๊ฐ’์„ ์กฐํšŒ๋Š” ๊ฒฝ์šฐ
  • Flux: ์—ฌ๋Ÿฌ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ
    • ์˜ˆ์‹œ: ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—ฐ์†์ ์œผ๋กœ ํ๋ฅผ ๋•Œ ์‚ฌ์šฉ

6. ๋ฆฌ์•กํ‹ฐ๋ธŒ ์—ฐ์‚ฐ์ž

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ์—ฐ์‚ฐ์ž๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ๋ณ€ํ˜•ํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

  • map(): ๋ฐ์ดํ„ฐ ํ•ญ๋ชฉ์„ ๋ณ€ํ™˜
  • flatMap(); ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ‰ํƒ„ํ™”
  • reduce(): ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒฐํ•ฉํ•˜๊ฑฐ๋‚˜ ์ถ•์†Œ

๊ฐ„๋‹จํ•œ ์ฝ”๋“œ

import reactor.core.publisher.Flux;

public class ReactiveExample {
		public static void main(String[] args) {
				// Flux๋ฅผ ์ด์šฉํ•ด ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ ์ƒ์„ฑ
				Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
				
				// ๊ฐ ๊ฐ’์„ 2๋ฐฐ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ์ถœ๋ ฅ
				numbers.map(n -> n * 2)
								.subscribe(n -> System.out.println("Number: " + n));
		}
}

์ด๋Ÿฐ ์—ฐ์‚ฐ์ž๋ฅผ ์กฐํ•ฉํ•ด์„œ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์ž‘์—…์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

7. ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์˜ˆ์‹œ

  • UI ์—…๋ฐ์ดํŠธ: ์‚ฌ์šฉ์ž๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€ UI๋ฅผ ์ž๋™์œผ๋กœ ๊ฐฑ์‹ ํ•˜๋Š” ์‹œ์Šคํ…œ
  • ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ: ์ฃผ์‹ ๊ฐ€๊ฒฉ์ด๋‚˜ ๋‚ ์”จ ์ •๋ณด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ›์•„์„œ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” ์‹œ์Šคํ…œ
  • ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ/์—…๋กœ๋“œ: ํฐ ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ์—…๋กœ๋“œ ํ•  ๋•Œ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ + ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ์‹œ์Šคํ…œ

8. ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ์žฅ์ 

  • ํšจ์œจ์„ฑ: ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์„œ, ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์œ ์—ฐ์„ฑ: ๋ฐ์ดํ„ฐ ํ๋ฆ„์„ ์ •์˜ํ•˜๊ณ  ๊ทธ ํ๋ฆ„์— ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹œ์Šคํ…œ์ด ์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ์„ฑ์ด ๋†’๋‹ค.
  • ์Šค์ผ€์ผ๋ง: ๋†’์€ ๋™์‹œ์„ฑ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋Œ€๊ทœ๋ชจ ์‹œ์Šคํ…œ์—์„œ๋„ ์„ฑ๋Šฅ์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
profile
#์„ฑ์žฅ #๋‹จ๋‹จํ•จ #ํ‰์˜จํ•จ

0๊ฐœ์˜ ๋Œ“๊ธ€