Hello Kitty Eyes Shut
λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

πŸ’» ν”„λ‘œμ νŠΈ/πŸ“Œ νŠΈλŸ¬λΈ”μŠˆνŒ…

[νŠΈλŸ¬λΈ”μŠˆνŒ…] μ‹€μ‹œκ°„ μ•Œλ¦Ό μ „μ†‘ν•˜κΈ°

λ°˜μ‘ν˜•

 

 

πŸ“ͺ Redis Pub / Sub 섀계

μ‹€μ‹œκ°„ μ•Œλ¦Ό μ‹œμŠ€ν…œμ„ 섀계할 λ•Œ κ°€μž₯ μ€‘μš”ν•œ μš”μ†Œ 쀑 ν•˜λ‚˜λŠ”

μ‚¬μš©μžμ—κ²Œ μ¦‰κ°μ μœΌλ‘œ λ©”μ„Έμ§€λ₯Ό μ „λ‹¬ν•˜λŠ” 방법을 μ„ νƒν•˜λŠ” 것이닀.

 

이λ₯Ό μœ„ν•΄μ„œλŠ” λ‹€μ–‘ν•œ 기술이 μ‘΄μž¬ν•˜κ² μ§€λ§Œ,

λ‚΄κ°€ μ§„ν–‰ν–ˆλ˜ ν”„λ‘œμ νŠΈμ—μ„œλŠ” Redis의 Pub / Sub κΈ°λŠ₯을 μ΄μš©ν•΄μ„œ μ„œλ²„ κ°„ λ©”μ‹œμ§€λ₯Ό μ€‘κ³„ν•˜κ³ ,

ν΄λΌμ΄μ–ΈνŠΈμ—κ²ŒλŠ” WeSocket을 톡해 μ‹€μ‹œκ°„ μ•Œλ¦Όμ„ μ „λ‹¬ν•˜λŠ” ꡬ쑰λ₯Ό μ‚¬μš©ν–ˆλ‹€.

 

μ—¬κΈ°μ„œ 핡심이 λ˜λŠ” 섀계 μš”μ†ŒλŠ” Redis μ±„λ„μ˜ ꡬ성 λ°©μ‹μ΄μ—ˆλŠ”λ°,

λ‚΄ ν”„λ‘œμ νŠΈμ—μ„œλŠ” notification:{userId} ν˜•μ‹μ„ μ±„νƒν–ˆλ‹€.

 


🏷️ μ‚¬μš©μž λ‹¨μœ„ 채널 넀이밍

Redis의 Pub / Sub μ—μ„œ λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•˜κΈ° μœ„ν•΄μ„œλŠ” 채널을 μ§€μ •ν•΄μ•Ό ν•˜λŠ”λ°,

μ΄λ•Œ 채널은 μΌμ’…μ˜ λΌμš°νŒ… 경둜 역할을 ν•˜λ©°, λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•  주제λ₯Ό μ˜λ―Έν•œλ‹€.

 

λ‚΄ ν”„λ‘œμ νŠΈμ—μ„œλŠ” μ‚¬μš©μžλ§ˆλ‹€ κ°œλ³„ 채널을 λ§Œλ“€μ–΄μ£ΌκΈ° μœ„ν•΄μ„œ notification:{userId} ν˜•νƒœμ˜ 넀이밍 κ·œμΉ™μ„ μ μš©ν–ˆλ‹€.

 

 

 

μ΄λ ‡κ²Œ 채널 이름을 κ΅¬μ„±ν•œ μ΄μœ λŠ” μ•„λž˜μ™€ κ°™λ‹€.

 

λ¨Όμ €, notificationμ΄λΌλŠ” μ ‘λ‘μ‚¬λŠ” Redis에 μ €μž₯λ˜λŠ” ν‚€λ“€ μ€‘μ—μ„œ μ•Œλ¦Όκ³Ό κ΄€λ ¨λœ μ±„λ„μ΄λΌλŠ” 것을 λͺ…ν™•ν•˜κ²Œ ꡬ뢄해쀄 수 있기 λ•Œλ¬Έμ΄λ‹€.

Redisμ—λŠ” μ’…μ’… λ‹€μ–‘ν•œ λ„λ©”μΈμ˜ 킀듀이 ν•¨κ»˜ μ €μž₯되기 λ•Œλ¬Έμ—,

λͺ…μ‹œμ μΈ prefixλ₯Ό λ‘λŠ” 것이 관리와 디버깅 μΈ‘λ©΄μ—μ„œ 도움이 λœλ‹€κ³  λ°°μ› κΈ° λ•Œλ¬Έμ΄λ‹€.

 

κ·Έ λ‹€μŒ : κΈ°ν˜ΈλŠ”, Redis ν‚€ 넀이밍 관둀에 따라 계측을 λΆ„λ¦¬ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•œ 것이며,

 

{userId}λŠ” νŠΉμ • μ‚¬μš©μžμ˜ 고유 μ‹λ³„μžμ΄λ‹€.

 

 

 

이 방식을 μ‚¬μš©ν•˜λ©΄ κ°œλ³„ μ‚¬μš©μžμ—κ²Œλ§Œ μ•Œλ¦Όμ„ 전솑할 수 있으며,

λΆˆν•„μš”ν•œ λΈŒλ‘œλ“œμΊμŠ€νŠΈλ₯Ό ν”Όν•  수 μžˆμ–΄μ„œ μ„±λŠ₯μ μœΌλ‘œλ„ μœ λ¦¬ν•˜λ‹€κ³  νŒλ‹¨ν–ˆλ‹€.

 

이제 μ„œλ²„λŠ” μ•Œλ¦Όμ„ 전솑할 λ•Œ notification:42 와 같이 μˆ˜μ‹  λŒ€μƒμ΄ λ˜λŠ” μ‚¬μš©μž IDλ₯Ό ν¬ν•¨ν•œ 채널을 μ§€μ •ν•˜μ—¬ λ©”μ‹œμ§€λ₯Ό λ°œν–‰ν•˜κ²Œ λ˜λŠ” 것이닀.

 


πŸ“­ λ©”μ‹œμ§€ λ°œν–‰κ³Ό μˆ˜μ‹ : Redis와 WebSocket μ—°κ²° ꡬ쑰

μ‹€μ œλ‘œ μ•Œλ¦Όμ„ μ „μ†‘ν•˜λŠ” 과정은 μ•„λž˜μ™€ 같이 λ™μž‘ν•œλ‹€.

 

μ‚¬μš©μž Aμ—κ²Œ μ•Œλ¦Όμ„ 보내야 ν•  상황이 λ°œμƒν•˜λ©΄,

μ„œλ²„μ—μ„œλŠ” ν•΄λ‹Ή μ•Œλ¦Ό 정보λ₯Ό 담은 λ©”μ‹œμ§€λ₯Ό JSON ν˜•μ‹μœΌλ‘œ μ§λ ¬ν™”ν•˜κ³ ,

notification:{userId} 채널에 λ©”μ‹œμ§€λ₯Ό publishν•œλ‹€.

 

μ„œλ²„λŠ” Redis의 RedisMessageListenerContainerλ₯Ό 톡해 이 채널듀을 κ΅¬λ…ν•˜κ³  μžˆλŠ”λ°,

채널이 μ‚¬μš©μž ID에 따라 λ™μ μœΌλ‘œ κ΅¬μ„±λ˜κΈ° λ•Œλ¬Έμ—

μ„œλ²„λŠ” νŠΉμ • μ±„λ„λ§Œ κ΅¬λ…ν•˜λŠ” 것이 μ•„λ‹ˆλΌ

νŒ¨ν„΄ ꡬ독 (notification:*)을 톡해 λͺ¨λ“  μ‚¬μš©μž μ•Œλ¦Ό 채널을 ν•œ λ²ˆμ— κ΅¬λ…ν•˜λ„λ‘ μ„€μ •ν•΄μ£Όμ—ˆλ‹€.

 

이 ꡬ쑰 덕뢄에 μ„œλ²„ μΈμŠ€ν„΄μŠ€κ°€ μ—¬λŸ¬ 개둜 λŠ˜μ–΄λ‚˜λ”λΌλ„,

λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ λ™μΌν•œ 채널에 λŒ€ν•΄ λ©”μ‹œμ§€λ₯Ό 받을 수 있으며,

이λ₯Ό 톡해 μˆ˜ν‰ ν™•μž₯성을 확보할 수 μžˆμ—ˆλ‹€.

 

이제 각 μ„œλ²„λŠ” μžμ‹ μ—κ²Œ μ—°κ²°λœ ν΄λΌμ΄μ–ΈνŠΈ WebSocket μ„Έμ…˜ μ€‘μ—μ„œ

μˆ˜μ‹  λŒ€μƒ μ‚¬μš©μžμ™€ μΌμΉ˜ν•˜λŠ” μ„Έμ…˜μ΄ μžˆμ„ 경우

ν•΄λ‹Ή μ‚¬μš©μžμ—κ²Œ WebSocket λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•œλ‹€.

 


βŒ› λ©”μ‹œμ§€ 보쑴성: Redis에 λ©”μ‹œμ§€λ₯Ό μ €μž₯ν•˜μ§€ μ•Šμ€ 이유

Redis Pub / Sub은 λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ μžμ—κ²Œ μ „λ‹¬ν•œ ν›„, ν•΄λ‹Ή λ©”μ‹œμ§€λ₯Ό μ €μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.

즉, λ°œν–‰ λ‹Ήμ‹œ ꡬ독 쀑인 ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œλ§Œ λ©”μ‹œμ§€κ°€ μ „λ‹¬λ˜κ³ , μ΄ν›„μ—λŠ” λ©”μ‹œμ§€κ°€ Redis 내뢀에 남지 μ•ŠλŠ” 것이닀.

 

μ΄λŠ” Redis Pub / Sub의 섀계 철학이 μ‹€μ‹œκ°„μ„±μ— μ§‘μ€‘λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ΄λ‹€.

 

 

λ”°λΌμ„œ λ‚˜λŠ” μ•Œλ¦Ό μžμ²΄λŠ” λ¨Όμ € RDB에 영ꡬ적으둜 μ €μž₯되고,

RedisλŠ” λ‹¨μˆœνžˆ 이λ₯Ό μ‹€μ‹œκ°„μœΌλ‘œ μ „λ‹¬ν•˜λŠ” 쀑계 역할을 ν•˜λ„λ‘ μ„€κ³„ν•˜μ˜€λ‹€.

 

 

이λ₯Ό ν†΅ν•΄μ„œ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ˜€ν”„λΌμΈμ΄κ±°λ‚˜ λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•˜μ§€ λͺ»ν•œ κ²½μš°μ—λ„,

μ‚¬μš©μžλŠ” λ‚˜μ€‘μ— μ „μ†‘ν•˜μ—¬ RDBμ—μ„œ μžμ‹ μ—κ²Œ 온 μ•Œλ¦Ό λͺ©λ‘μ„ 확인할 수 μžˆλ‹€.

 

 

μ΄λ ‡κ²Œ μ˜μ†μ„±κ³Ό μ‹€μ‹œκ°„μ„±μ„ 각각 λ‹€λ₯Έ 기술둜 λΆ„λ¦¬ν•¨μœΌλ‘œμ¨

μ‹œμŠ€ν…œμ€ μ•ˆμ •μ„±κ³Ό μ„±λŠ₯을 λͺ¨λ‘ 확보할 수 μžˆμ—ˆλ‹€ ✨

 


βš’οΈ μˆ˜ν‰ ν™•μž₯을 μœ„ν•œ ꡬ쑰 섀계

이 κ΅¬μ‘°λŠ” μ„œλ²„κ°€ μ—¬λŸ¬ μΈμŠ€ν„΄μŠ€λ‘œ ν™•μž₯λ˜λ”λΌλ„ λ©”μ‹œμ§€ 전달이 단일 λ…Έλ“œμ— μ˜μ‘΄ν•˜μ§€ μ•Šλ„λ‘ μ„€κ³„λ˜μ–΄ μžˆλ‹€.

 

λͺ¨λ“  μ„œλ²„ μΈμŠ€ν„΄μŠ€λŠ” λ™μΌν•˜κ²Œ notification:* νŒ¨ν„΄μ„ 톡해 Redis 채널을 κ΅¬λ…ν•˜κ³  있기 λ•Œλ¬Έμ—

μ•Œλ¦Όμ„ λ°œν–‰ν•œ μΈμŠ€ν„΄μŠ€μ™€ 상관없이, μ‚¬μš©μžμ—κ²Œ WebSocket μ„Έμ…˜μ΄ μ—°κ²°λœ μΈμŠ€ν„΄μŠ€μ—μ„œ λ©”μ‹œμ§€λ₯Ό λ°›μ•„ μ΅œμ’… μ „λ‹¬ν•˜κ²Œ λœλ‹€.

 

이 방식은 μ„œλ²„ 간에 λ³„λ„μ˜ μ„Έμ…˜ λ™κΈ°ν™”λ‚˜ 브둜컀λ₯Ό 두지 μ•Šκ³ λ„,

μžμ—°μŠ€λŸ½κ²Œ λΆ„μ‚° λ©”μ‹œμ§• ν™˜κ²½μ„ ꡬ성할 수 μžˆλ‹€λŠ” μž₯점이 μžˆλ‹€.

 

예λ₯Ό λ“€μ–΄, μ–΄λ–€ μ‚¬μš©μžκ°€ μΈμŠ€ν„΄μŠ€ A에 μ—°κ²°λœ μƒνƒœμ—μ„œ, μΈμŠ€ν„΄μŠ€ Bκ°€ μ•Œλ¦Όμ„ λ°œν–‰ν•˜λ”λΌλ„,

Redisκ°€ λ©”μ‹œμ§€λ₯Ό λͺ¨λ“  κ΅¬λ…μžμ—κ²Œ μ „νŒŒν•΄μ£ΌκΈ° λ•Œλ¬Έμ—

μΈμŠ€ν„΄μŠ€ Aκ°€ λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•˜κ³ , μ‚¬μš©μžμ˜ WebSocket으둜 μ „λ‹¬ν•˜λŠ” 것이 κ°€λŠ₯ν•œ 것이닀.

 


πŸ–₯️ κ΅¬ν˜„ 방법 μš”μ•½

μ•žμ„œ μ„€λͺ…ν•œ ꡬ쑰둜 κ΅¬ν˜„ν•œ 방식은 λŒ€λž΅ μ•„λž˜μ™€ κ°™λ‹€.

 

λ©”μ‹œμ§€ λ°œν–‰

redisTemplate.convertAndSend("notification:" + userId, jsonMessage);

 

λ©”μ‹œμ§€ μˆ˜μ‹ 

container.addMessageListener(listener, new PatternTopic("notification:*"));

 

WebSocket 전솑

messagingTemplate.convertAndSendToUser(userId.toString(), "/notification", messageDto);

 


πŸ—¨οΈ Redis Streamsκ°€ μ•„λ‹Œ Pub / Sub을 μ„ νƒν•œ 이유

μ‹€μ‹œκ°„ λ©”μ‹œμ§€ 전달을 μœ„ν•œ Redis κΈ°μˆ λ‘œλŠ” Pub / Sub 외에도 Redis Streamsκ°€ μ‘΄μž¬ν•œλ‹€.

 

κ·ΈλŸ¬λ‚˜ Redis StreamsλŠ” λ©”μ‹œμ§€ 보쑴, μ†ŒλΉ„μž κ·Έλ£Ή 관리, μˆ˜λ™ offset μ œμ–΄ λ“± λ§Žμ€ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” λŒ€μ‹ μ—

κ΅¬ν˜„μ΄ λ³΅μž‘ν•˜κ³  운영 λΉ„μš©μ΄ μ¦κ°€ν•œλ‹€κ³  λ“€μ—ˆλ‹€.

 

λ‚΄ ν”„λ‘œμ νŠΈμ—μ„œ κ΅¬ν˜„ν•œ μ•Œλ¦Ό μ‹œμŠ€ν…œμ€

"μ‹€μ‹œκ°„μœΌλ‘œ μ¦‰μ‹œ μ „λ‹¬λ˜λ˜, λ©”μ‹œμ§€ μœ μ‹€ μ‹œμ—λŠ” DBλ₯Ό 톡해 볡원 κ°€λŠ₯ν•œ ꡬ쑰"μ˜€λ‹€.

 

λ”°λΌμ„œ λ©”μ‹œμ§€ λˆ„λ½ κ°€λŠ₯성은 μ‹œμŠ€ν…œ μ „μ²΄μ μœΌλ‘œ 보완할 수 μžˆμ—ˆκ³ , λ³΅μž‘ν•œ offset 관리가 λΆˆν•„μš”ν–ˆλ‹€.

 

μ΄λŸ¬ν•œ μš”κ΅¬μ‚¬ν•­μ—λŠ” ꡬ쑰가 λ‹¨μˆœν•˜κ³  처리 속도가 λΉ λ₯Έ Pub / Sub이 훨씬 μ ν•©ν•˜λ‹€κ³  νŒλ‹¨ν–ˆκΈ°μ— 이λ₯Ό μ μš©ν•˜κΈ°λ‘œ κ²°μ •ν–ˆλ‹€.

 


πŸ“š κ²°λ‘ 

이처럼 Redis Pub / Subμ—μ„œ notification:{userId} ν˜•μ‹μ˜ 채널 넀이밍을 μ‚¬μš©ν•œ 것은,

μ‚¬μš©μž λ‹¨μœ„λ‘œ μ•Œλ¦Όμ„ μ •ν™•ν•˜κ²Œ μ „λ‹¬ν•˜κΈ° μœ„ν•œ μ„€κ³„μ˜€λ‹€.

 

λ©”μ‹œμ§€λ₯Ό Redis에 λ³΄μ‘΄ν•˜μ§€ μ•Šκ³  μ‹€μ‹œκ°„μœΌλ‘œλ§Œ μ „λ‹¬ν•˜λŠ” κ΅¬μ‘°λŠ” λ©”λͺ¨λ¦¬ μ‚¬μš©μ„ μ΅œμ†Œν™”ν•˜λ©°,

μ•Œλ¦Όμ˜ μ˜μ†μ„±μ€ λ³„λ„μ˜ RDBμ—μ„œ μ±…μž„μ§€λ„λ‘ 역할을 λΆ„λ¦¬ν–ˆλ‹€.

 

λ˜ν•œ, νŒ¨ν„΄ 기반 ꡬ독 (notification:*)을 μ‚¬μš©ν•¨μœΌλ‘œμ¨

μ„œλ²„κ°€ μˆ˜ν‰ ν™•μž₯λ˜μ–΄λ„ λͺ¨λ“  μΈμŠ€ν„΄μŠ€κ°€ λ™μΌν•œ λ°©μ‹μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό μˆ˜μ‹ ν•˜κ³  μ²˜λ¦¬ν•  수 μžˆλ„λ‘ κ΅¬μ„±ν•˜μ˜€μœΌλ©°,

WebSocketκ³Ό κ²°ν•©ν•˜μ—¬ 효율적이고 μ‹€μ‹œκ°„μ„±μ΄ 높은 μ•Œλ¦Ό μ‹œμŠ€ν…œμ„ μ™„μ„±ν•  수 μžˆμ—ˆλ‹€.

 

μ΄λŸ¬ν•œ κ΅¬μ‘°λŠ” μ‹€μ‹œκ°„μ„±κ³Ό ν™•μž₯μ„±, λ‹¨μˆœμ„±μ„ λͺ¨λ‘ κ³ λ €ν•œ 섀계이며,

우리처럼 νŒ€ λ‹¨μœ„μ˜ μ€‘μ†Œ 규λͺ¨ μ„œλΉ„μŠ€μ—μ„œ λΉ λ₯΄κ²Œ λ„μž…ν•˜κΈ°μ— μ ν•©ν•œ 방식이라고 νŒλ‹¨λœλ‹€.

 

λ‚΄ 아이디어λ₯Ό λ„ˆλ¬΄λ‚˜λ„ λ©‹μ§€κ²Œ μ‹€μ œ μ½”λ“œλ‘œ κ΅¬ν˜„ν•΄μ€€ νŒ€μ›μ—κ²Œ λ‹€μ‹œ ν•œ 번 λ„ˆλ¬΄λ‚˜λ„ κ°μ‚¬ν•˜λ‹€ ,, γ…Žγ…Ž πŸ‘πŸ»

λ°˜μ‘ν˜•