Software Architecture/MSA

[MSA] Spring Cloud Gateway์™€ Netflix Zuul์˜ ์ฐจ์ด์  (API Gateway)

bu119 2024. 3. 16. 09:00
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ”Š Spring Cloud Gateway๋ฅผ ํ™œ์šฉํ•˜์—ฌ API Gateway๋ฅผ ๊ตฌ์ถ•ํ•  ๋•Œ Spring Initializr์—์„œ ์˜์กด์„ฑ์œผ๋กœ Gateway๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ์•ˆ ๋˜๊ณ  Reactive Gateway๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ?

 

โ“ API Gateway ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Spring Initializr์—์„œ ์˜์กด์„ฑ์œผ๋กœ Gateway๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๊ฐ€ ์ดํ›„์— ์„ค์ •๋“ค์ด ์ž˜ ๋˜์ง€ ์•Š์•˜๋‹ค. ๊ทธ๋ž˜์„œ ์ด์œ ๋ฅผ ์ฐพ์•„๋ดค๋”๋‹ˆ Reactive Gateway๋ฅผ ์ถ”๊ฐ€ํ–ˆ์–ด์•ผ ํ–ˆ๋‹ค. ์™œ?!!!  Gateway๊ฐ€ ์•„๋‹Œ Reactive Gateway๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ• ๊นŒ? ๊ทธ ์ด์œ ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž!!

 

โญ ์˜์กด์„ฑ์— Gateway๊ฐ€ ์•„๋‹Œ Reactive Gateway๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ์ด์œ ?

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ API Gateway๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์—๋Š” Spring Cloud Gateway์™€ Netflix Zuul๊ฐ€ ์žˆ๋‹ค. Spring Cloud Gateway๋ฅผ ์‚ฌ์šฉํ•ด์„œ API Gateway๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” Spring Initializr์—์„œ " Reactive Gateway"๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.

"Gateway"๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด, Spring Cloud Gateway๊ฐ€ ์•„๋‹Œ Netflix Zuul ๋ฐฉ์‹์˜ API Gateway ์†”๋ฃจ์…˜์„ ์˜๋ฏธํ•œ๋‹ค.

 Netflix Zuu์€ Netflix์—์„œ ์ง€์›ํ•˜๋Š” API Gateway ๋ฐฉ์‹์ธ๋ฐ ์ตœ๊ทผ์—๋Š” ์ง€์›์ด ์ค‘๋‹จ๋˜์—ˆ๊ณ , Spring Cloud Gateway์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋Œ€์•ˆ์„ ์„ ํ˜ธํ•˜๋Š” ์ถ”์„ธ์ด๋‹ค.

์ฆ‰, Netflix Zuu์€ ๋” ์ด์ƒ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š” ์ ‘๊ทผ ๋ฐฉ์‹์ด๋ฉฐ, Spring Cloud Gateway๊ฐ€ ๋” ํ˜„๋Œ€์ ์ด๊ณ  ์œ ์—ฐํ•œ ๋Œ€์•ˆ์œผ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค.

 


 API Gateway ๋ž€?

API Gateway๋ผ๋Š” ๊ฒƒ์€, Reverse Proxy์ฒ˜๋Ÿผ ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์˜ ์•ž๋‹จ์— ์œ„์น˜ํ•œ๋‹ค. ๋งˆ์น˜ ‘๋„์–ด ๋งจ' ์—ญํ• ์ฒ˜๋Ÿผ ๋“ค์–ด์˜จ ์š”์ฒญ๋“ค์—๊ฒŒ ์–ด๋””๋กœ ๊ฐ€์•ผ ํ• ์ง€ ‘๋ผ์šฐํŒ…’ํ•ด์ค„ ์ˆ˜ ์žˆ๊ณ  ๋“ค์–ด์˜ค๊ณ  ๋‚˜๊ฐ€๋Š” ๋ช…๋‹จ์„ ‘๋กœ๊น…’ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.


๊ตฌ์ฒด์ ์œผ๋กœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—ญํ• ๋“ค์ด ์žˆ๋‹ค.

  • API ๋ผ์šฐํŒ…
  • ์ธ์ฆ ๋ฐ ๊ถŒํ•œ ๋ถ€์—ฌ
  • ์†๋„ ์ œํ•œ
  • ๋ถ€ํ•˜ ๋ถ„์‚ฐ (๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ)
  • ๋กœ๊น… (๋ชจ๋‹ˆํ„ฐ๋ง)
  • ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜

 

 

 

๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜์—์„œ API ๊ฒŒ์ดํŠธ์›จ์ด๋ฅผ ๊ตฌ์ถ•ํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์—๋Š” Spring Cloud Gateway์™€ Netflix Zuul๊ฐ€ ์žˆ๋‹ค.

 

Spring Cloud Gateway๋Š” ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ์œ ๋ฆฌํ•œ ๋ฐ˜๋ฉด, Zuul์€ ๊ทธ๋ ‡์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ Zuul์„ ์ง€์›ํ•˜์ง€ ์•Š๊ณ  Spring.io ๋Š” Spring Cloud Gateway๋ฅผ ๊ถŒ์žฅํ•œ๋‹ค.

 

Netflix Zuul ์ด๋ž€?

Netflix Zuul์€ Netflix OSS ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ถ€๋กœ์„œ, ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜์˜ ๋™๊ธฐ์‹ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Spring ๊ธฐ๋ฐ˜์˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Spring Cloud Netflix ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ†ตํ•ฉ๋œ๋‹ค.

 

Zuul์€ Netflix์—์„œ ์ง€์›๋˜์—ˆ์œผ๋‚˜, ์ตœ๊ทผ์—๋Š” ์ง€์›์ด ์ค‘๋‹จ๋˜์—ˆ๊ณ , Spring Cloud Gateway์™€ ๊ฐ™์€ ๋‹ค๋ฅธ ๋Œ€์•ˆ์„ ์„ ํ˜ธํ•˜๋Š” ์ถ”์„ธ์ด๋‹ค.

 

์˜์กด์„ฑ

  implementation 'org.springframework.cloud:spring-cloud-starter-gateway-mvc'

 

Spring Cloud Gateway ๋ž€?

Spring Cloud ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ถ€๋กœ์„œ, Spring Boot์™€ Spring WebFlux๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๋ฐ ๋…ผ๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

 

์˜์กด์„ฑ

  implementation 'org.springframework.cloud:spring-cloud-starter-gateway'

 

๋ฐ˜์‘ํ˜•

 

Spring Cloud Gateway์™€ Netflix Zuul์˜ ์ฐจ์ด์ 

Spring Cloud Gateway๋Š” ๊ฐ๊ฐ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ ์€ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Event-loop ๋ฐฉ์‹์„ ์ฑ„ํƒํ•œ๋‹ค. ์ด๋Š” Node.js์™€ ๋น„์Šทํ•œ ์ ‘๊ทผ ๋ฐฉ์‹์œผ๋กœ, ๊ฐ ์ž‘์—…์„ ์ž‘์€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์–ด ๋™์‹œ์— ์ฒ˜๋ฆฌํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์ ์€ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋กœ๋„ ๋งŽ์€ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฐ˜๋ฉด์— Netflix Zuul์€ ์ „ํ†ต์ ์ธ ๋ฐฉ์‹์œผ๋กœ, ๊ฐ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Thread pool์„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฐ ์š”์ฒญ์€ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค.

 

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

 

Spring Cloud Gateway

  1. ๊ธฐ์ˆ  ์Šคํƒ
    • Spring Cloud ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ถ€๋กœ์„œ, Spring Boot์™€ Spring WebFlux๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค.
    • ๋”ฐ๋ผ์„œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ๋ฐ ๋…ผ๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  2. ๋™์ž‘ ๋ฐฉ์‹
    • ๋น„๋™๊ธฐ์ ์ด๊ณ  ๋…ผ๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•˜์—ฌ ์ ์€ ์Šค๋ ˆ๋“œ๋กœ๋„ ๋งŽ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop) ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ณ ๋ถ€ํ•˜ ์ƒํ™ฉ์—์„œ๋„ ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.
  3. ์ ํ•ฉํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€
    • ๊ณ ์„ฑ๋Šฅ ๋ฐ ํ™•์žฅ์„ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ์ ํ•ฉํ•˜๋‹ค.
    • ๋น„๋™๊ธฐ์ ์ด๊ณ  ๋…ผ๋ธ”๋กœํ‚น ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜์—ฌ ์„œ๋ฒ„ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  4. Spring Webflux ์˜ˆ์‹œ
    • ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž๊ฐ€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ‘์†ํ•˜์—ฌ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
    • ๊ฐ ์š”์ฒญ์€ ์ด๋ฒคํŠธ ๋ฃจํ”„(Event Loop) ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
    • ์ด๋Š” ์ ์€ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋กœ ๋งŽ์€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž A์˜ ์š”์ฒญ์ด ๋„์ฐฉํ•˜๋ฉด ํ•˜๋‚˜์˜ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ์‚ฌ์šฉ์ž B์˜ ์š”์ฒญ์ด ๋„์ฐฉํ•˜๋ฉด ๋‹ค๋ฅธ ์ด๋ฒคํŠธ ๋ฃจํ”„๊ฐ€ ํ•ด๋‹น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ๊ฐ ์š”์ฒญ์€ ์ž‘์€ ๋‹จ์œ„๋กœ ์ชผ๊ฐœ์–ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ, ๋งŽ์€ ์š”์ฒญ์ด ๋™์‹œ์— ๋“ค์–ด์˜ค๋”๋ผ๋„ ์ ์€ ์ˆ˜์˜ ์Šค๋ ˆ๋“œ๋กœ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

Netflix Zuul

  1. ๊ธฐ์ˆ  ์Šคํƒ
    • Netflix์—์„œ ๋งŒ๋“  ๋„๊ตฌ๋กœ, ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜์˜ ๋™๊ธฐ์‹ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์ด๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š”๋ฐ ์Šค๋ ˆ๋“œ(Thread)๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๊ณ , ์š”์ฒญ๋งˆ๋‹ค ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค.
  2. ๋™์ž‘ ๋ฐฉ์‹
    • ๋™๊ธฐ์‹ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ๋งˆ๋‹ค ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์“ฐ๋ ˆ๋“œ ํ’€์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ ํ™•์žฅ๋˜๋ฏ€๋กœ ๋งŽ์€ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉฐ ๋†’์€ ๋ถ€ํ•˜ ์ƒํ™ฉ์—์„œ ํ™•์žฅ์„ฑ์ด ์ œํ•œ๋  ์ˆ˜ ์žˆ๋‹ค.
  3. ์ ํ•ฉํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€:
    • ๊ธฐ์กด์˜ ์„œ๋ธ”๋ฆฟ ๊ธฐ๋ฐ˜ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค์— ์ ํ•ฉํ•˜๋‹ค.
    • ๋˜ํ•œ ๋™๊ธฐ์‹ ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•˜๋Š” ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  4. Spring MVC ์˜ˆ์‹œ
    • ์ด ๋ฐฉ์‹์€ ์„œ๋ฒ„์—์„œ ๊ฐ๊ฐ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ(Thread)๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์˜ˆ๋ฅผ ๋“ค์–ด, Spring Boot ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.
    • ์ด ๋ฐฉ์‹์€ ๊ฐ๊ฐ์˜ ์š”์ฒญ๋งˆ๋‹ค ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์š”์ฒญ์˜ ์ˆ˜๊ฐ€ ์ œํ•œ๋œ๋‹ค.
    • ๋˜ํ•œ, ์Šค๋ ˆ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ๋ณต์žก์„ฑ์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋”ฐ๋ผ์„œ, Spring Cloud Gateway๋Š” ๋น„๋™๊ธฐ์ ์ด๊ณ  ํšจ์œจ์ ์ธ ์š”์ฒญ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ๋„๊ตฌ์ด๋ฉฐ, Netflix Zuul์€ ๊ธฐ์กด์˜ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์— ์ ํ•ฉํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ์š”์ฒญ์˜ ์ฒ˜๋ฆฌ ๋ฐฉ์‹๊ณผ ์„ฑ๋Šฅ, ํ™•์žฅ์„ฑ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ๋„๊ตฌ๋ฅผ ์„ ํƒํ•ด์•ผ ํ•œ๋‹ค.

 


์ฐธ๊ณ ์ž๋ฃŒ

https://velog.io/@jaehyunup/Srping-Webflux%EC%9D%98-%ED%83%84%EC%83%9D-%EB%B0%B0%EA%B2%BD%EA%B3%BC-MVC%EC%99%80%EC%9D%98-%EC%B0%A8%EC%9D%B4

https://devuna.tistory.com/108

https://velog.io/@gowjr207/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EA%B2%8C%EC%9D%B4%ED%8A%B8%EC%9B%A8%EC%9D%B4%EB%A5%BC-%EC%84%A4%EB%AA%85%ED%95%B4%EB%B3%B4%EB%8B%A4

https://stir.tistory.com/375

https://sky-h-kim.tistory.com/67

https://corono.tistory.com/33

728x90
๋ฐ˜์‘ํ˜•