๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Spring

Spring ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ์„ธ์…˜ ๊ด€๋ฆฌํ•˜๊ธฐ (Redis Session Clustering)

by ์ฃผ๋ฐœ2 2023. 2. 12.
๋ฐ˜์‘ํ˜•

๐Ÿ”— Spring ๋ถ„์‚ฐ ํ™˜๊ฒฝ์—์„œ ์„ธ์…˜ ๊ด€๋ฆฌํ•˜๊ธฐ(์„ธ์…˜ ํด๋Ÿฌ์Šคํ„ฐ๋ง)

์•ˆ๋…•ํ•˜์„ธ์š”, ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์—ฌ๋Ÿฌ ์„œ๋ฒ„ ํ™˜๊ฒฝ์—์„œ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

(์ฝ”๋“œ๋Š” ๊นƒํ—ˆ๋ธŒ์—์„œ ํ™•์ธํ•˜์‹ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

 

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

 

์˜ˆ์‹œ๋กœ ์‚ดํŽด๋ณผ๊นŒ์š”?

๋‘ ๊ฐœ์˜ ์„œ๋ฒ„: localhost:8080, localhost:8081
localhost:8080

์‚ฌ์šฉ์ž A๊ฐ€ localhost:8080ํฌํŠธ๋กœ login ํ˜ธ์ถœ ์‹œ ์„ธ์…˜์ด ์ƒ์„ฑ๋˜๊ณ  JSESSIONID์— ์ž„์˜์˜ ๊ฐ’์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

JSESSIONID?
 - ์„ธ์…˜์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Tomcat Container์—์„œ ๋ฐœ๊ธ‰ํ•˜๋Š” Key์ด๊ณ  Value๋ฅผ ํ†ตํ•ด ์„ธ์…˜์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋™์ž‘ ๋ฐฉ์‹?
 1. ๋ธŒ๋ผ์šฐ์ € ์ตœ์ดˆ ์ ‘๊ทผ ์‹œ Tomcat Response์— JSESSIONID ๊ฐ’์„ ๋ฐœ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค(Set-Cookie)
 2. ๋ธŒ๋ผ์šฐ์ € ์žฌ์š”์ฒญ ์‹œ ์ด์ „์— ๋ฐœ๊ธ‰๋ฐ›์€ JSESSIONID๋ฅผ Request Headers์˜ ์ฟ ํ‚ค์— ๊ฐ’์„ ๋„ฃ์–ด ์„œ๋ฒ„์— ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.
 3. ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ์ „๋‹ฌ๋ฐ›์€ JSESSIONID์˜ ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ ์„œ๋ฒ„์—์„œ๋Š” ์„ธ์…˜์— ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ๊ฐ’๋“ค์„ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
JSESSIONID๋Š” ํฌํŠธ๋ฒˆํ˜ธ๋Š” ๋‹ฌ๋ผ๋„ ๋™์ผํ•œ ๊ฐ’์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.

 

localhost:8080

๋™์ผํ•˜๊ฒŒ localhost:8080 URL๋กœ myName์„ ํ˜ธ์ถœํ•˜๋ฉด ์ด์ „์— ๋ฐœ๊ธ‰๋ฐ›์€ JSESSIONID๋ฅผ Header์— ์„ค์ •ํ•˜์—ฌ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์ €์žฅ๋œ ์„ธ์…˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ •์ƒ์ ์œผ๋กœ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

 

localhost:8081

๋งŒ์•ฝ ๋‹ค๋ฅธ ์ปจํ…Œ์ด๋„ˆ์ธ localhost:8081 URL์„ ํ˜ธ์ถœํ•˜๋ฉด ๋‹ค๋ฅธ ์„œ๋ฒ„๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ JSESSIONID ๊ฐ’์œผ๋กœ ์š”์ฒญ์ด ์˜ค์ง€๋งŒ ์„ธ์…˜์— ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ์— ์•„๋ฌด๋Ÿฐ ๋ฐ์ดํ„ฐ๋„ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ Response Headers์˜ ์ฟ ํ‚ค์— ์ƒˆ๋กœ์šด JSESSIONID์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ดํ›„ ์š”์ฒญ์€ ํ•ด๋‹น ๊ฐ’์„ ํ†ตํ•ด ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

 

localhost:8081

์œ„์—์„œ ๋ฐœ๊ธ‰๋ฐ›์€ JSESSIONID ๊ฐ’์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

localhost:8080

๋‹ค๋ฅธ ์„œ๋ฒ„์ธ localhost:8080์— myName API๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์„ธ์…˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด JSESSIONID ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ , ์ดํ›„ ์š”์ฒญ์€ ํ•ด๋‹น ๊ฐ’์„ Header์— ๋„ฃ์–ด์„œ ์š”์ฒญํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ด์ฒ˜๋Ÿผ Scale-out ๋“ฑ์„ ํ†ตํ•ด ๋ถ„์‚ฐ๋œ ํ™˜๊ฒฝ์—์„œ ์„ธ์…˜์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ๋™์ผํ•˜๊ฒŒ ์„ธ์…˜์„ ์œ ์ง€ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Session Clustering, Sticky Session, Redis Session Clustering ๋“ฑ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

๊ทธ์ค‘ ์—ฌ๊ธฐ์„œ๋Š” Redis Session Clustering ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ณ , ๋‹ค๋ฅธ ๋ฐฉ์‹์— ๋น„ํ•ด ์–ด๋– ํ•œ ์ด์ ์ด ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

 

๐Ÿ”— Sticky Session

https://www.imperva.com/learn/availability/sticky-session-persistence-and-cookies/

 

Sticky session์€ ์„ธ์…˜์„ ์‚ฌ์šฉํ•ด ํŠธ๋ž˜ํ”ฝ์„ ๋ถ„์‚ฐํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ ํŠน์ • ์„ธ์…˜์˜ ์š”์ฒญ์„ ์ตœ์ดˆ ์ฒ˜๋ฆฌํ•œ ์„œ๋ฒ„๋กœ๋งŒ ์ „์†กํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ํšŒ์› 1์ด ์„œ๋ฒ„ A์—์„œ ์„ธ์…˜์„ ์ƒ์„ฑํ•œ๋‹ค๋ฉด, ์ดํ›„ ํšŒ์› 1์ด ๋ณด๋‚ด๋Š” ๋ชจ๋“  ์š”์ฒญ์€ ์„œ๋ฒ„ A๋กœ๋งŒ ์ „์†กํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ Sticky session์€ ์•„๋ž˜์™€ ๊ฐ™์€ ๋‹จ์ ์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  • ๋™์ผํ•œ ์„ธ์…˜์€ ๋™์ผํ•œ ์„œ๋ฒ„๋กœ๋งŒ ์ „์†กํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŠน์ • ์„œ๋ฒ„์— ์š”์ฒญ์ด ๋ชฐ๋ ค ๊ณผ๋ถ€ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํŠน์ • ์„œ๋ฒ„์— ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•  ์‹œ ํ•ด๋‹น ์„œ๋ฒ„์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์„ธ์…˜๋“ค์ด ๋ชจ๋‘ ์†Œ์‹ค๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์™€ ๊ฐ™์€ ๋‹จ์ ์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด Session Clustering ๋ฐฉ์‹์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

 

 

 

๐Ÿ”— Session Clustering (์„ธ์…˜ ํด๋Ÿฌ์Šคํ„ฐ๋ง)

https://smjeon.dev/web/sticky-session/

Session Clustering์˜ ๊ฐœ๋…์€ ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค. ํด๋Ÿฌ์Šคํ„ฐ๋ง ์ด๋ž€ ๊ฐœ๋…์ด ๊ตฐ์ง‘, ๋ญ‰์น˜๊ธฐ ๋“ฑ๊ณผ ๊ฐ™์€ ์˜๋ฏธ๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ๋Š”๋ฐ์š”, ์„ธ์…˜ ํด๋Ÿฌ์Šคํ„ฐ๋ง์€ ์—ฌ๋Ÿฌ WAS๊ฐ€ ์„ธ์…˜์„ ๊ณต์œ ํ•˜์—ฌ ๋™์ผํ•˜๊ฒŒ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

์„ธ์…˜ ํด๋Ÿฌ์Šคํ„ฐ๋ง ๋ฐฉ์‹์€ Sticky Session์—์„œ ๋ฐœ์ƒํ–ˆ๋˜ 1. ํŠน์ • ์„œ๋ฒ„์—๋งŒ ํŠธ๋ž˜ํ”ฝ์ด ๋งŽ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜, 2. ์žฅ์•  ๋ฐœ์ƒ ์‹œ ์„ธ์…˜ ์†Œ์‹ค์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

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

 

 

 

๐Ÿ”— Redis Session Clustering

Redis๋ฅผ ์ด์šฉํ•œ ์„ธ์…˜ ํด๋Ÿฌ์Šคํ„ฐ๋ง ๋ฐฉ์‹์€ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•  ์ €์žฅ์†Œ๋ฅผ Redis๋กœ ๋”ฐ๋กœ ๋‘์–ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ์„ธ์…˜์„ ๊ด€๋ฆฌํ•  ์ €์žฅ์†Œ๋ฅผ RDB๊ฐ€ ์•„๋‹Œ Redis๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์ด์ ์ด ์žˆ์„๊นŒ์š”?

๋Œ€๋žต์ ์œผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ด์ ์ด ์กด์žฌํ•  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ์„ธ์…˜์€ ๋ฐ์ดํ„ฐ ๋ชจ๋ธ์ด ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ฒ˜๋Ÿผ ๋ณต์žกํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์„ธ์…˜์€ ๋ณดํ†ต ๋งŒ๋ฃŒ์‹œ๊ฐ„์ด ์กด์žฌํ•˜๊ธฐ์— ์˜์†์„ฑ์ด ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์„ธ์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ํ›„ ์š”์ฒญ์„ ํ•  ๋•Œ๋งˆ๋‹ค ํ™•์ธ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋งŒํผ I/O๊ฐ€ ๋งŽ์ด ๋ฐœ์ƒํ•˜๊ณ , RDB๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ๋””์Šคํฌ I/O๋กœ ์ธํ•ด ์„ฑ๋Šฅ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ Redis๋Š” ์„ธ์…˜ ์ €์žฅ์†Œ์— ์ ํ•ฉํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

Spring Redis Session Clustering ์˜ˆ์ œ ์ฝ”๋“œ

Spring์—์„œ Redis๋ฅผ ์„ธ์…˜ ์ €์žฅ์†Œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

(redis ์„ค์น˜&์„ค์ • ๊ด€๋ จ์€ ์ƒ๋žตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.)

  1. redis ๊ด€๋ จ ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ณ 
  2. application. yml(properties) ํŒŒ์ผ์— ์„ค์ •์„ ์ถ”๊ฐ€ํ•˜๊ณ 
  3. API ์š”์ฒญ ์‹œ HttpSession ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

localhost:8080/login
localhost:8080
localhost:8081

์œ„ ์ด๋ฏธ์ง€๋ฅผ ํ™•์ธํ•ด ๋ณด๋ฉด localhost:8080 URL๋กœ login ์š”์ฒญ์„ ํ–ˆ์ง€๋งŒ, 8080ํฌํŠธ์™€ 8081ํฌํŠธ ๋ชจ๋‘ SESSION์ด๋ผ๋Š” Key๋ฅผ ํ†ตํ•ด ๋™์ผํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

Redis ํ™•์ธ

  • spring:session:expirations:(expire time) = expire time์— ์‚ญ์ œ๋  ์„ธ์…˜ ์ •๋ณด๋“ค์„ ๋‹ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. (Set)
  • spring:session:sessions:expire:(session id) = ํ•ด๋‹น ์„ธ์…˜์˜ ๋งŒ๋ฃŒ Key๋กœ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. (String)
  • spring:session:sessions:(session id) = ์„ธ์…˜์˜ ์ƒ์„ฑ ์‹œ๊ฐ„, ๋งˆ์ง€๋ง‰ ์„ธ์…˜ ์กฐํšŒ ์‹œ๊ฐ„, ์ตœ๋Œ€ ํƒ€์ž„์•„์›ƒ ํ—ˆ์šฉ์‹œ๊ฐ„, ์„ธ์…˜์— ์ €์žฅํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ ์žˆ์Šต๋‹ˆ๋‹ค. (Hash)

 

Hash ํƒ€์ž…์ธ spring:session:sessions:(session id)์„ ํ™•์ธํ•ด ๋ณด๋ฉด ์„ธ์…˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

spring.session.store-type์„ ํ†ตํ•ด Session ์„ค์ •์„ Redis๋กœ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

 

Spring Boot์˜ AutoConfiguration๋กœ ์ธํ•ด properties(yml) ํŒŒ์ผ์— ์œ„์™€ ๊ฐ™์ด ์„ค์ •๋งŒ ํ•˜๋Š”๊ฒƒ์œผ๋กœ Spring Session์„ Redis๋กœ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์†์‰ฝ๊ฒŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

 

SessionProperties ํด๋ž˜์Šค์˜ StoreType์„ ๋ณด๋ฉด Redis ์™ธ์—๋„ MongoDB, JDBC, HAZELCAST(?) ๋“ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ดํ›„ Session ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ ๊ธฐ์กด๊ณผ๋Š” ๋‹ฌ๋ฆฌ RedisIndexedSessionRepository ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด set์„ ์ง„ํ–‰ํ•˜์—ฌ ์„ธ์…˜๊ณผ ๊ด€๋ จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ spring:session์„ ๊ธฐ๋ณธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ๊ฐ key๋ฅผ ์„ค์ •ํ•˜์—ฌ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ขŒ) ๊ธฐ์กด Session, ์šฐ) Redis Session

 

 

 

๐Ÿ“„ ์ฐธ๊ณ  ๋ฌธ์„œ

 

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€