streamingChat
streamingChat copied to clipboard
๐ค An imaginary streaming chat service built with Go, Redis and gRPC
Streaming Chat service using GRPC
์์ ์์ ์คํธ๋ฆฌ๋ฐ ์ฑํ ์๋น์ค
(์ ํ๋ธ ๋ผ์ด๋ธ ์ฑํ ๊ฐ์ ๊ฑธ ์์ ์ค...)
์ค์ ์ฑํ ์๋น์ค๋ก ์ด์ํ๊ธฐ ์ํจ์ด ์๋ ์ด๋ฐ ์ ๋ฐ ๊ฐ๋ฐ์ ๋ด์ฉ๋ค์ ์ค์ ๋ก ์ ์ฉ์์ผ๋ณด๊ฑฐ๋ ์์ํด๋ณด๊ธฐ ์ํ ํ๋ก์ ํธ์ ๋๋ค.
- gRPC๋ฅผ ํตํ ์๋ฒ <---> ํด๋ผ์ด์ธํธ ๊ฐ์ ์๋ฐฉํฅ ํต์
- Go ์ธ์ด ํน์ ์ ๊ฐ๋ ฅํ ๋์์ฑ ์ง์์ ํ์ฉ
- Redis stream ๋ฐ Redis Pub/Sub์ ๋ฐํ์ผ๋ก ํ ์๋ฒ๊ฐ์ ํต์
- ๋ณต์กํ Join์ด ํ์ ์๊ณ ๋ค๋์ ๋ฐ์ดํฐ๋ฅผ ๋ฆฌ์ผํ์์ผ๋ก ์ ์ฅํด์ผํ๋ฏ๋ก No SQL DB ์ด์ฉ
- ์ฑํ ๋ฐฉ ์์ฑ ๋ฐ ๊ฐ์ข Create, Read ๊ธฐ๋ฅ์ Java Spring์ MVC์ JPA๋ก ํผํผํ๊ณ ์ฝ๊ฒ ๊ฐ๋ฐ
- ํธ๋ํฝ์ด ๋ชฐ๋ฆด ๊ฒฝ์ฐ๋ฅผ ๋๋นํด ์ฑํ ์ด๋ฒคํธ๋ Redis stream๋ฅผ ๋ฒํผ๋ก ๋๊ณ ์์ปค๊ฐ ์์ํ
- k8s + minikube๋ฅผ ์ด์ฉํด ๋ก์ปฌ์์๋ ์์ฝ๊ฒ ์ ์ฒด ์ธํ๋ผ๋ฅผ ๋์ธ ์ ์๋๋ก ํจ.
๐ง๐ค ๋จธ๋ฆฟ ์ ์์๋ค โโ๏ธ
- gRPC๋ ์ด๋ค ๊ฑธ๊น..? RESTful API๋ GrpahQL์ด๋ ๋น๊ตํ์ ๋๋ ์ด๋จ๊น? ์น์์ผ๊ณผ ๋น๊ตํ์ ๋ ์ด๋จ๊น?
- ๋ฉ์์ง ํ(Redis stream)์ ์ด์ฉํด์ ์ค์ ๋ก ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ์ ํต์ ์ ํด๋ณด๊ณ ์ถ๋ค.
- ๋ฉ์์ง ํ๋ฅผ ์ฐ๊ณ ๋ ์ถ์๋ฐ Kafka๋ RabbitMQ๋ ๋ฉ์์ง ํ๋ฅผ ์ด์ฉํ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ณ๋ฅผ ๊ฒฝํํด๋ณธ๋ค๊ธฐ๋ณด๋จ ํน์ ๊ธฐ์ ์ ๋ํ ์ง์์ด ๋ง์ด ํ์ํ ๋๋์ด๊ณ , ๊ด๋ฆฌํ๊ธฐ๊ฐ ์ฝ์ง ์๋ค.
- ๊ด๋ฆฌํ์ธ SNS + SQS ์กฐํฉ์ ์จ๋ณด๊ธด ํ์ง๋ง ๊ตฌ์ฑ ์์ฒด๊ฐ ํ ๋์ ์๋ณด์ด๋ ๋ถํธ์ด ์์๋ค.
- ์ค์ ์ด์ํ ์๋น์ค๋ ์๋๊ธฐ๋ ํ๊ณ Redis๋ ์บ์ฑ์๋ ํ์์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ธฐ์ ์ด๋ผ ๊ด์ฌ์์๊ธฐ์ ์ปจํ ์ด๋๋ก ๊ฐ๋ณ๊ฒ ์ด์ฉํ๋ฉด ๋ ๋ฏ~!
- ์ผ๋ง๋ ํธ๋ํฝ์ด ๋ชฐ๋ฆฌ๋ฉด DB๊ฐ ์ฅ์ ๊ฐ ๋ ๊น? ์ง์ง ๋ฒํผ๊ฐ ํ์ํ ๊น?
- Golang์ด ์ง์ง ๋์์ฑ ํ๋ก๊ทธ๋๋ฐ์ ์์ด ์ฑ๋ฅ์ด ์ข์๊น? ์ผ๋ง๋ ์ข์๊น?
- ์๋ฐฉํฅ ํต์ ์ ํ๋ ๊ฒฝ์ฐ ์ค์ ์ด์ํ ๋์๋ ์ด๋ป๊ฒ Gracefully shutdown์ ํ ์ ์์๊น? Golang์์๋ Context๋ฅผ ํตํด ์ต๋ํ Gracefulํ๊ฒ ํ ์ ์์ ๊ฒ ๊ฐ์๋ฐ..
- ๋ถํํ ์คํธ๋ ์ด๋ป๊ฒ ํ ์ ์์๊น?
gRPC & Protobuf
์ปดํ์ผํ๋ ๋ฐฉ๋ฒ
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
pb/chat.proto
gRPC์ Stream์ ์ด์ฉํ ์ฑํ ์ด๋ฒคํธ ์คํธ๋ฆฌ๋ฐ
Redis
Redis Pub/Sub์ ์ด์ฉํ ๋ฐ์ดํฐ ์ ์ก
- ๊ฐ ์๋ฒ๋ ์์ ๊ณผ ์ฐ๊ฒฐ๋์ด ์๋ ํด๋ผ์ด์ธํธ ์ ๋ณด๋ฅผ ๊ฐ๊ณ ์๋ค. ํด๋น ํด๋ผ์ด์ธํธ๋ค์๊ฒ ์์ (์๋ฒ)์ด ์๋ก์ด ๋ฉ์์ง ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํด์ฃผ์ด์ผํ๋ค.
- ์ด๋ค ์ฑํ ์๋ฒ replica์์ ์ฑํ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ ๋ ๋ค๋ฅธ ์ฑํ ์๋ฒ replica๋ ๊ทธ ์ด๋ฒคํธ๋ฅผ ์ด๋ป๊ฒ ์๊ณ ์์ ๊ณผ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ๋ค์๊ฒ ์ ๋ฌํ ์ ์์๊น?
- ์ด๋ Redis Pub/Sub์ ์ฌ์ฉํ๋ฉด ์ข๋ค!
- Redis stream์ ์ฐ๋ ๊ฑด ์ด๋จ๊น?
- Consumer group ๊ด๋ฆฌ๋ ACKnowledge ๋ฑ์ ๊ธฐ๋ฅ์ ์ํํ๋ Redis stream๋ณด๋ค๋ Pub/Sub์ด Real-time ์ฑ๊ฒฉ์ ์ด ์คํธ๋ฆฌ๋ฐํ ์ฑํ ์ ๋ ์ด์ธ๋ฆด ๊ฒ ๊ฐ์.
- ๋ง์ฝ Pub/Sub์ ์ด์ฉํ๋ค๊ฐ ์๋ฒ๊ฐ ์ฃฝ์ด์ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ฆผ์ ๋ณด๋ด์ค ์ ์๋ค๋ฉด?
- ์ผ๋จ์ ํด๋ผ์ด์ธํธ๋ ์์ ๊ณผ ์ฐ๊ฒฐ๋ ์๋ฒ๊ฐ ์ฃฝ์ผ๋ฉด ์ฌ๋นจ๋ฆฌ ๋ค๋ฅธ ์๋ฒ์ ์ปค๋ฅ์ ์ ๋งบ๋๋ก ๋์ด์์.
- ๊ทธ ์ฌ์ด์ ๋ฐ์ํ ์ฑํ ์? - ์ฌ์ค ๊ทธ๋ฅ ๋ฌด์ํ๋ค. ์ด๋ฐ ๊ฒ๊น์ง ๋ค ์ ๊ฒฝ์ ์ฐ๋ ๊ฑด ๋ค์ํ ๊ธฐ์ ์ ์ ์ฉํ ์ํคํ ์ณ๋ฅผ ์์ํด๋ณด๊ณ ์ ์ฉ์์ผ๋ณด๋ ์ด ํ๋ก์ ํธ์๋ ์ ์ ๊ฑฐ๋ฆฌ๊ฐ ๋ฉ์ด์ง๊ณ ์ฑํ ๋๋ฉ์ธ์ ๊ฐ๋ฐํ๋ฉด์ ๋๋ฉ์ธ ๋ก์ง์ด๋ ๋น์ฆ๋์ค ๋ก์ง์ ์ ์ ์ง์คํ๊ฒ ๋ ๊ฒ ๊ฐ๊ธฐ ๋๋ฌธ. ์ต๋ํ ๋ฆฌ์ผํ์ ์คํธ๋ฆฌ๋ฐํ์ด๋ผ๋ ๊ฒ์ ์ด์ ์ ๋๋ค!
Redis stream์ ์ด์ฉํ ๋ฐ์ดํฐ ์ ์ก
- Real-time ์ฑ๊ฒฉ์ด ์๋ ๋จ์ํ ์ฑํ ๋ฐ์ดํฐ๋ฅผ DB์ ์์ํ ์ํค๋ ๊ฒฝ์ฐ์๋ ์ฌ๋นจ๋ฆฌ ์ฑํ ์ด๋ฒคํธ๋ฅผ ํด๋ผ์ด์ธํธ๋ค์๊ฒ ๋ฟ๋ ค์ฃผ๋ ๊ฒ๋ณด๋ค ํด๋น ์ด๋ฒคํธ๊ฐ ์ ์ฒ๋ฆฌ๋๋์ง ACKnowledgeํ ์ ์์ด์ผ ํจ. ๋ฐ๋ผ์ Pub/Sub ๋ณด๋ค๋ Redis์ Stream์ ์ด์ฉํด Kafka์ฒ๋ผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
- Pub/Sub์ ๊ฒฝ์ฐ Consumer Group์ด๋ผ๋ ๊ฐ๋ ์ด ํ์ ์์ด ๊ฐ ๋ฐฑ์๋ replica๋ค์ด ๋์ผํ ์ด๋ฒคํธ๋ฅผ ๋ชจ๋ ์ ๋ฌ๋ฐ์์ผํ์ง๋ง ์ฑํ ๋ฐ์ดํฐ๋ฅผ DB์ ์์ํ ์ํค๋ ์์ ์ Consumer group์ ๊ฐ๋ ์ ์ด์ฉํด group ๋ด์ replica ์ค ํ ๋ช ๋ง ์ด๋ฒคํธ๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ ์ฒ๋ฆฌํด์ฃผ๋ฉด ๋๋ค. ๋ฐ๋ผ์ Consumer group์ ์ด์ฉํ๊ธฐ ์ํด Pub/Sub์ด ์๋ Redis stream์ ์ด์ฉํ๋ค.
Redis์ TTL์ ์ด์ฉํ ์ค์๊ฐ ์ธ๊ธฐ ๋จ์ด
์ฌ์ค ๋ณ๋ก ํ์ํ ๊ธฐ๋ฅ์ ์๋๋ฐ ใ ใ .. ๋ค์ํ Redis์ ์ ์ฆ์ผ์ด์ค๊ฐ ๊ถ๊ธํด์ ์์ํด๋ดค๋ค. ๊ทผ๋ฐ ์ฑํ ๋ฐ์ดํฐ์ ์ ๋ฐํ์ผ๋ก ํํ์ ๋ถ์์ ํด์ ์ธ๊ธฐ ๋จ์ด๋ฅผ ์นด์ดํธํ๋ ๊ฒ์ ์๋๊ณ ๊ทธ๋ฅ ๊ณต๋ฐฑ์ผ๋ก Split ์์ผ์ ๋จ์ด๋ก ์นด์ดํธ ํ๋ค๋ณด๋ ๊ทธ๋ฅ ๋์ฌ๋ค์ด ์ธ๊ธฐ ๋จ์ด๋ก ์ ์ ๋๊ธดํ๋ค.
๋ณดํต Realtime leaderboard๋ผ๋ ์ปจ์ ์ผ๋ก Sorted Set์ ์ด์ฉํด ๋ฆฌ์ผํ์ ๋ญํน ์๋น์ค๋ฅผ ์๊ฐํ๋ ๊ฒ ๊ฐ์๋ฐ ์ด ๊ฒฝ์ฐ๋ ์ ์ฒด ๊ธฐ๊ฐ ๋์์ ๋ํ Ranking๋ง ์ ๊ณตํ๊ณ ํน์ ๊ธฐ๊ฐ ๋์์ ๋ญํน์ ์ ๊ณตํ ์ ์๋ค. Sorted Set์ TTL์ด ์๊ธฐ ๋๋ฌธ์ด๊ธฐ๋ ํ๊ณ , ๊ฒฐ๊ตญ ํน์ ๊ธฐ๊ฐ ๋์์ ์ด๋ฒคํธ๋ก๋ง ๋ญํน์ ์ ๋ ฌํ๋ ค๋ฉด ์ด์ฉ๋๋ ๊ฐ ์ด๋ฒคํธ์ ์ ๋ณด๊ฐ ์์ด์ผํ๋ค. ๊ทผ๋ฐ ๋ง์นจ ์ด์ ๋ํด ๋์ ์์๊ณผ ๋น์ทํ ํด๊ฒฐ์ฑ ์ ๋ค๋ฃฌ ์คํ์ค๋ฒ ํ๋ก์ฐ ๊ธ์ด ์์๋ค.
- Redis์ Expiration time(TTL)์ ์ด์ฉํ๋ฉด ์ธ๊ธฐ ๋จ์ด ์ง๊ณ์ ์ฌ์ฉ๋๋ ๋จ์ด ์ด๋ฒคํธ ๋ฐ์ดํฐ๊ฐ ์์ฝ๊ฒ ์์์ ํน์ ์๊ฐ ์ดํ ์ญ์ ๋๋๋ก ํ ์ ์๋ค.
- ๊ทธ๋ผ ํน์ ๊ธฐ๊ฐ(์๋ฅผ ๋ค์ด ์ง๋ 1๋ถ) ๊ฐ์ ์ธ๊ธฐ ๋จ์ด๋ฅผ ๋ณด๊ธฐ ์ํด์ TTL์ 1๋ถ์ผ๋ก ์ค์ ํด๋๊ณ ๋จ์์๋ ๋จ์ด ์ด๋ฒคํธ๋ง์ผ๋ก ์ง๊ณํ๋ฉด ๋๋ค.
- ๋จ์ ์ Sorted Set์ ์ด์ฉํ ๋๋ ๋ญํน ์์ ์์ฒด๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ ์ ์ฅ๋๋ค๋ ๊ฒ์ด์๋๋ฐ, ์ด ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ฉด ์ ๋ ฌ์ ๋งค ์ฟผ๋ฆฌ ๋๋ง๋ค ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ด๋นํด์ผํ๋ค.
hotWord@{{word}}@{{username}}: 0์ด๋ฐ ์์ผ๋ก Key๋ฅผ ์ค์ ํ๊ณ empty value๋ฅผ ๋ด์ ๋คhotWord@{{word}}@*์ ํด๋นํ๋ key์ ๊ฐ์๋ฅผ ์ธ์ด ์ ๋ ฌํ๋ฉด ๋๋ค.- "Keeping Redis simple" ์ด๋ผ๋ ์ฒ ํ ๋๋ฌธ์ธ์ง ๋ค์
@๋ก 'howWord ๋ญํน ์ฐ์ถ์ ์ฌ์ฉ๋๋ ํค์ด๋ฉฐ{{word}}๋ผ๋ ๋จ์ด์ ๋ํ{{username}}์ ์ ์ ์ฑํ ๊ธฐ๋ก์ด๋ค' ๋ผ๋ ์๋ฏธ๋ฅผ ๋ํ๋ด๋ ๊ฒ์ด ๋ค์ ๊น๋ํ์ง ์์๋ณด์ผ ์ ์์ง๋ง ๋ญ RDB๋ ๋ค๋ฅธ DB๋ฅผ ์ผ์ผ๋ฉด TTL์ ์ํด ๋ ๋ค๋ฅธ ์ด๋ฐ ์ ๋ฐ ๊ณ ์์ ํ์ด์ผํ ๊ฒ ๊ฐ๊ธด ํ๋๊น Redis๋ฅผ ์ฉ์ํด์ฃผ๋ ๊ฑธ๋ก ํ๊ฒ ๋ค.
์ฐธ๊ณ ์๋ฃ
์ํ ์ฑํ ๋ฐ์ดํฐ - https://github.com/songys/Chatbot_data