
์ค์๊ฐ ์ฑํ ์๋น์ค๋ฅผ ๊ตฌ์ถํ ๋๋ ๋ฉ์์ง๊ฐ ์ฆ์ ์ ๋ฌ๋๊ณ , ์ฝ๊ฒ ๊ณผ๊ฑฐ ๊ธฐ๋ก์ ์กฐํํ ์ ์๋๋ก ์ง์์ ์ผ๋ก ์ ์ฅ๋์ด์ผ ํฉ๋๋ค.
๊ทธ๋ฌ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ฐ๋ฉด ๋์์ฑ์ด ๋์ ์๋๋ฆฌ์ค์์ ์ฝ๊ฒ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ด ๋ฐ์ํ์ฌ ๋ฉ์์ง์ ์ค์๊ฐ์ฑ์ ์ํฅ์ ๋ฏธ์น ์ ์์ต๋๋ค.
"๊ณ์ธต์ ์ถ๊ฐํ๋ฉด ํด๊ฒฐํ ์ ์๋ ๋ฌธ์ ๋ ์๋ค"๋ ๊ฐ๋ ์ ๊ณ ์ํ์ฌ ๋น๋๊ธฐ ์ ์ฅ์ ์ํ ๋ฉ์์ง ํ(MQ)๋ฅผ ๋์ ํ๋ ๊ฒ์ ์ฐ์ํ ์๋ฃจ์ ์ ๋๋ค.
๋ฉ์์ง๋ ์ฆ๊ฐ์ ์ธ ์ ๋ฌ์ ๋ณด์ฅํ๊ธฐ ์ํด ๋จผ์ MQ์ ๋น ๋ฅด๊ฒ ๊ธฐ๋ก๋ ๋ค์, ์ ๋ด ์๋น์ ์๋น์ค๋ฅผ ํตํด ๋๊ธฐ์ด์์ ๊บผ๋ด์ ธ ์ํํ๊ฒ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ธฐ๋ก๋ฉ๋๋ค.
์ด ๊ธ์์๋ Spring Boot 3์ ๋ฉ์์ง ํ ๊ธฐ์ ์ ๊ฒฐํฉํ์ฌ ํจ์จ์ ์ด๊ณ ์์ ์ ์ธ ์ฑํ ๋ฉ์์ง ์ ์ฅ ์์คํ ์ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์ดํด๋ณด๊ฒ ์ต๋๋ค.

์ฌ๊ธฐ์ MQ์ ์ฃผ์ ์ญํ ์ ์ฑํ
๊ธฐ๋ฅ์ ์ฑํ
์ฝํ
์ธ ์ ์ ์ฅ ํ๋ก์ธ์ค๋ก๋ถํฐ ๋ถ๋ฆฌํ๊ณ ๋ถ๋ฆฌํ๋ ๊ฒ์
๋๋ค.
์ด ๋ฉ์ปค๋์ฆ์ ๊ณต์ฅ๊ณผ ๋๋งค์
์ฒด ๊ฐ์ ์ฃผ๋ฌธ ๊ด๊ณ๋ฅผ ์ต์ ํํ๋ ๊ฒ๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค.
๊ธฐ์กด ๋ชจ๋ธ์์๋ ๊ณต์ฅ์์ ์ ํ์ ์ถํํ ๋๋ง๋ค ๊ฐ ๋๋งค์
์ฒด์ ๊ฐ๋ณ์ ์ผ๋ก ํต์งํด์ผ ํฉ๋๋ค.

MQ๊ฐ ๋์
๋ ํ, ์ด ํ๋ก์ธ์ค๋ ์ฐ์ํ๊ณ ํจ์จ์ ์ผ๋ก ๋ฐ๋์์ต๋๋ค.
๋ง์น ๊ณต์ฅ์์ ์นด์นด์คํก ๋จ์ฒดํก ๋ฉ์์ง๋ง ๊ฒ์ํ๋ฉด ๋ชจ๋ ๋๋งค์
์ฒด๊ฐ ์ผ๋์ผ ์๋ฆผ ์์ด ๋์์ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค.
๊ณต์ฅ์ ์์ฐ์ ์ง์คํ๊ณ , ๋๋งค์
์ฒด๋ ์์์ ๋ฐ๋ผ ์์ฐ์ ์ฒ๋ฆฌํ๋ฉฐ, ๊ฐ ์
์ฒด๋ ์์ฒด์ ์ธ ์๋ฌด๋ฅผ ์ํํฉ๋๋ค.

์๋น์ค ๊ฐ ํต์ ์ ์ํ ์ค๊ฐ์๋ก์ ๋ฉ์์ง ํ๋ ๋ถ์ฐ ์์คํ
์์ ์ค์ํ ์ญํ ์ ํฉ๋๋ค.
์ผ๋ฐ์ ์ธ ์๋ฃจ์
์ผ๋ก๋ ์ ๋ฌธ์ ์ธ ๋ฉ์์ง ํ ์์คํ
(์: RabbitMQ, Kafka, RocketMQ ๋ฑ), ๋ถ์ฐ ์กฐ์ ์๋น์ค Zookeeper, Redis ๊ธฐ๋ฐ์ ๊ฒฝ๋ ํ ๋ฑ์ด ์์ต๋๋ค.
๋ง์ ๋ฉ์์ง ํ ์ ํ๋ง๋ค ๊ณ ์ ํ ํน์ฑ๊ณผ ์ ์ฉ ๊ฐ๋ฅํ ์๋๋ฆฌ์ค๊ฐ ์์ต๋๋ค.
| ๋ฉ์์ง ํ | ๊ฐ๋ฐ ์ธ์ด | ํน์ง | ์ ์ฉ ๊ฐ๋ฅํ ์๋๋ฆฌ์ค |
|---|---|---|---|
| ๋๋น MQ | ๊ณ ๋ญ | ์ฑ์ํ๊ณ ์์ ์ ์ด๋ฉฐ ๋ฐฐํฌ๊ฐ ์ฝ๊ณ ๋ผ์ฐํ ๊ธฐ๋ฅ์ด ํ๋ถํ๋ฉฐ ์ปค๋ฎค๋ํฐ๊ฐ ํ์ฑํ๋์ด ์์ | ๋ณต์กํ ๋ผ์ฐํ ์๊ตฌ ์ฌํญ, ์ค์ ๊ท๋ชจ ๋ฉ์์ง ๋ณผ๋ฅจ ๋ฐ ์์ ์ฑ ๋ณด์ฅ์ด ํ์ํ ๋ |
| ์กํฐ๋ธ MQ | ์๋ฐ | ๊ตฌ์ MQ ๋ฐ JMS ๊ตฌํ, ๋์ ๋ฆฌ์์ค ์๋ชจ | Java ์ํ๊ณ์ ๊ธด๋ฐํ๊ฒ ํตํฉ๋ ๊ธฐ์กด ์ํฐํ๋ผ์ด์ฆ ์ ํ๋ฆฌ์ผ์ด์ |
| ๋ก์ผ MQ | ์๋ฐ | ๋์ ์ฒ๋ฆฌ๋, ๋ฎ์ ์ง์ฐ ์๊ฐ, ์ฌ์ ์ ์์ค์ ์์ ์ฑ ๋ฐ ๋์ฉ๋ ์คํ ๋ฆฌ์ง ์ง์ | ๋๊ท๋ชจ ์ธํฐ๋ท ์ ํ๋ฆฌ์ผ์ด์ ๋ฐ ๊ธ์ต ๊ฒฐ์ ์๋๋ฆฌ์ค |
| ์นดํ์นด | ์ค์นผ๋ผ / ์๋ฐ | ์ด๊ณ ์ฒ๋ฆฌ๋, ์ง์์ฑ, ํํฐ์ ์ค๊ณ, ์คํธ๋ฆผ ์ฒ๋ฆฌ์ ๋ฅ์ | ๋ก๊ทธ ์์ง, ๋น ๋ฐ์ดํฐ ์ค์๊ฐ ์ฒ๋ฆฌ, ์คํธ๋ฆฌ๋ฐ ๋ฐ์ดํฐ ๋ถ์ |
| ์ ๋ก MQ | C++ | ๊ฐ๋ณ๊ณ ๋ถ์ฐํ๋ ๋ด์ฅ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | ์ฑ๋ฅ, ์ง์ฐ ๊ฐ ํต์ ์ด ๋งค์ฐ ๋ฏผ๊ฐํ ์๋๋ฆฌ์ค |
| Redis ํ | C | ๊ฐ๋ณ๊ณ ๊ฐ๋จํ๋ฉฐ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ, ๋ฎ์ ๋๊ธฐ ์๊ฐ | ๊ฐ๋จํ ์๋๋ฆฌ์ค, ์์ ๋๊ธฐ์ด ๋ฐ ๋ฎ์ ์ง์์ฑ ์๊ตฌ ์ํฉ |
์ฑํ ๋ฉ์์ง ์ ์ฅ ์๋๋ฆฌ์ค์ ๊ฒฝ์ฐ, ์ฐ๋ฆฌ๋ ์ฃผ๋ก ๋ค์๊ณผ ๊ฐ์ ๊ณ ๋ ค ์ฌํญ์ ๊ธฐ๋ฐ์ผ๋ก RabbitMQ๋ฅผ ์ต์ข ์ ์ผ๋ก ์ ํํ์ต๋๋ค.
์ฑ์ํ๊ณ ์์ ์ ์ ๋๋ค: RabbitMQ๋ ์ค๋ ์ญ์ฌ๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ์ค์ ์ด์ ํ๊ฒฝ์์ ์๋ฒฝํ๊ฒ ๊ฒ์ฆ๋์์ผ๋ฉฐ ์์ ์ฑ์ด ๋ณด์ฅ๋ฉ๋๋ค.
์ ์ฐํ ๋ผ์ฐํ : ๋ค์ํ ์ ํ์ ๋ฉ์์ง์ ๋ํ ์ ๊ตํ ๋ผ์ฐํ ์ ๋ฌ์ฑํ๊ธฐ ์ํด ๋ค์ํ ์ค์์น ์ ํ๊ณผ ๋ฐ์ธ๋ฉ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํฉ๋๋ค.
ํตํฉ์ด ์ฝ์ต๋๋ค: Spring ์ํ๊ณ์ ๊ธด๋ฐํ๊ฒ ํตํฉ๋ Spring Boot๋ ํฌ๊ด์ ์ธ ์คํํฐ ์ง์์ ์ ๊ณตํฉ๋๋ค.
์ด์ ๋ฐ ์ ์ง ๊ด๋ฆฌ๊ฐ ํธ๋ฆฌํจ: ๊ฐ๋จํ ๋ฐฐํฌ, ๋ด์ฅ ๊ด๋ฆฌ ์ธํฐํ์ด์ค, ๋ชจ๋ํฐ๋ง ๋ฐ ๊ด๋ฆฌ ์ฉ์ด
์ปค๋ฎค๋ํฐ ์ง์: ํ๋ฐํ ์ปค๋ฎค๋ํฐ์ ํ๋ถํ ๋ฌธ์ ๋ฆฌ์์ค๋ฅผ ํตํด ๋ฌธ์ ๊ฐ ๋ฐ์ํ ๋ ์ฝ๊ฒ ํด๊ฒฐ์ฑ ์ ์ฐพ์ ์ ์์ต๋๋ค.
Kafka๋ RocketMQ๊ฐ ๊ทน๋๋ก ๋์ ๋์์ฑ ์๋๋ฆฌ์ค์์ ๋ ๋์ ์ฒ๋ฆฌ๋ ์ฑ๋ฅ์ ๋ณด์ผ ์ ์์ง๋ง, ์ฌ๊ธฐ์์ ์ด์ ์ด ์์คํ ๋ถ๋ฆฌ๋ผ๋ ์ ์ ๊ณ ๋ คํ๋ฉด RabbitMQ๋ ์ด๋ฏธ ๊ฐ๋ฐ ๋ฐ ์ ์ง ๊ด๋ฆฌ ๋น์ฉ์ ์ค์ด๋ ๋์์ ์๊ตฌ ์ฌํญ์ ์ ์ถฉ์กฑํ ์ ์์ต๋๋ค.
๋ฉ์์ง ํ๋ ์์คํ ์ํคํ ์ฒ์์ ๋ง์ ๊ณ ์ ์ ์ธ ์์ฉ ํ๋ก๊ทธ๋จ ์๋๋ฆฌ์ค๋ฅผ ๊ฐ์ต๋๋ค.
๋น๋๊ธฐ ์ฒ๋ฆฌ: ์๊ฐ์ด ๋ง์ด ์์๋๋ ์์ (์: ์ด๋ฉ์ผ ์ ์ก ๋ฐ ๋ก๊ทธ ์ฒ๋ฆฌ)์ ๋ฉ์์ง ํ๋ฅผ ํตํด ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด ์ฌ์ฉ์ ์์ฒญ์ ๋น ๋ฅด๊ฒ ์๋ตํ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํฉ๋๋ค.
์ฑ๋ฅ ํฅ์: ๋น๋๊ธฐ ๋ถ๋ฆฌ๋ฅผ ํตํด ์์คํ ์๋ต ์๊ฐ์ด ๋จ์ถ๋๊ณ ์ฒ๋ฆฌ๋์ด ํฅ์๋์ด ํนํ I/O ์ง์ฝ์ ์์ ์ ์ ํฉํฉ๋๋ค.
์์คํ ๋ถ๋ฆฌ: ์๋น์ค ๊ฐ์ ์ง์ ์ ์ธ ์ข ์์ฑ์ ์ค์ด๊ณ , ์์คํ ์ ํ๋ ฅ์ฑ๊ณผ ์ ์ง๊ด๋ฆฌ์ฑ์ ๊ฐ์ ํ๊ณ , ๋ ๋ฆฝ์ ์ธ ํ์ฅ๊ณผ ์ ๊ทธ๋ ์ด๋๋ฅผ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
ํผํฌ ์์ด๋น ๋ฐ ๋ฐธ๋ฆฌ ํ๋ง: ํธ๋ํฝ ํผํฌ ๋์ ๋ฉ์์ง ํ๋ ์์ฒญ์ ์บ์ํ๊ณ ์ฒ๋ฆฌ ์ฉ๋์ ๋ฐ๋ผ ์ ์ง์ ์ผ๋ก ์ฌ์ฉํ์ฌ ์์คํ ๊ณผ๋ถํ ๋ฐ ์ถฉ๋์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
์ฑํ ๋ฉ์์ง ์ ์ฅ ์๋๋ฆฌ์ค์์๋ ์ฃผ๋ก RabbitMQ๋ฅผ ์ฌ์ฉํ์ฌ ๋น๋๊ธฐ ๋ฉ์์ง ์ ์ฅ์ ๊ตฌํํฉ๋๋ค. ์ด๋ฅผ ํตํด ์ฑํ ๊ธฐ๋ฅ์ ์๋ต ์๋๋ฅผ ๋ณด์ฅํ ๋ฟ๋ง ์๋๋ผ ๋ฉ์์ง๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์ ์ ์ผ๋ก ๋ณด๊ดํ๊ณ ์์คํ ์ด ๋ฉ์์ง ํผํฌ์ ๋์ฒํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
RabbitMQ์์ ๋ฉ์์ง์ ์ ์ฒด ์๋ช ์ฃผ๊ธฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
ํ๋ก๋์๊ฐ ๋ฉ์์ง๋ฅผ ์์ฑํฉ๋๋ค: ์ฑํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ์๊ฐ ์ฑํ ์ฝํ ์ธ ๋ฅผ ๋ณด๋ด๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด๋ฅผ MQ ๋ฉ์์ง๋ก ์บก์ํํฉ๋๋ค.
๊ตํ์๋ก ์ ๋ฌ: ์์ฐ์๋ ์ง์ ๋ ๊ตํ์๋ก ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ๋ผ์ฐํ ํค๋ฅผ ์ง์ ํฉ๋๋ค.
์ค์์น ๋ผ์ฐํ ์ ๋ฌ: Exchange๋ ๋ฉ์์ง ๋ผ์ฐํ ํค์ ๋ฐ์ธ๋ฉ ๊ท์น์ ๋ฐ๋ผ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ๋๊ธฐ์ด์ ๊ฒฐ์ ํฉ๋๋ค.
๋๊ธฐ์ด์ ์ ์ฅ: ์ ๊ฒฉ ๋๊ธฐ์ด์ ๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ์ ์ฅํ๋ฉฐ ์๋น์๊ฐ ์ฒ๋ฆฌํ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
์๋น์๊ฐ ๋ฉ์์ง๋ฅผ ๋ฐ์ต๋๋ค: ์คํ ๋ฆฌ์ง ์๋น์ค๋ ํ์์ ๋ฉ์์ง๋ฅผ ๊ฐ์ ธ์ค๋ ์๋น์ ์ญํ ์ ํ๋ฉฐ, ์ด๋ ํธ์ ๋ชจ๋๋ ํ ๋ชจ๋์ผ ์ ์์ต๋๋ค.
ํ์ธ ์ฒ๋ฆฌ: ์๋น์๊ฐ ๋ฉ์์ง๋ฅผ ์ฑ๊ณต์ ์ผ๋ก ์ฒ๋ฆฌํ ํ(์: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฑํ ๋ด์ฉ ์ ์ฅ) RabbitMQ์ ํ์ธ(ACK)์ ๋ณด๋ ๋๋ค.
๋ฉ์์ง ์ญ์ : ํ์ธ์ ๋ฐ์ ํ RabbitMQ๋ ํ์์ ๋ฉ์์ง๋ฅผ ์ญ์ ํฉ๋๋ค.

RabbitMQ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ผ๋ก ์ค์นํ ์ ์์ผ๋ฉฐ, Docker๋ ๊ฐ์ฅ ํธ๋ฆฌํ ๋ฐฐํฌ ์๋ฃจ์
์ ์ ๊ณตํฉ๋๋ค.
Docker๋ฅผ ์ฌ์ฉํ์ฌ RabbitMQ๋ฅผ ๋น ๋ฅด๊ฒ ๋ฐฐํฌํ๋ ๋จ๊ณ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
๋จผ์ Docker Hub์์ RabbitMQ ๊ณต์ ์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
management์ดํ์ ์๊ฐ์ ์์
๋ฐ ๋ชจ๋ํฐ๋ง์ ์ํ ์น ๊ด๋ฆฌ ์ธํฐํ์ด์ค๊ฐ ํฌํจ๋ ํ๊ทธ๊ฐ ์๋ ๋ฒ์ ์ ์ ํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
docker pull rabbitmq:4.1-management
ํ: ๋ ์๋ Docker Hub๋ฅผ ๋ฐฉ๋ฌธํ์ฌ ์ฐ์ตํ ๋ ์ต์ ๋ฒ์ ์ ๋ณด๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด๋ฏธ์ง๋ฅผ ๊ฐ์ ธ์จ ํ ๋ค์ ๋ช ๋ น์ผ๋ก RabbitMQ ์ปจํ ์ด๋๋ฅผ ์์ํฉ๋๋ค.
docker run --name rabbitmq -p 5681:5671 -p 5682:5672 -p 4379:4369 -p 15681:15671 -p 15682:15672 -p 25682:25672 --restart always -d rabbitmq:4.1-management
์ฌ๊ธฐ์ ์ฐ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ๋งคํ๊ณผ ๊ตฌ์ฑ์ ๋ง๋ค์์ต๋๋ค.

์ฑ๊ณต์ ์ผ๋ก ์์ํ ํ ๋ธ๋ผ์ฐ์ ์์ http://127.0.0.1:15682 RabbitMQ ๊ด๋ฆฌ ์ฝ์์ ์ก์ธ์คํ์ฌ ์ฝ๋๋ค.
๊ธฐ๋ณธ ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ(๋ ๋ค guest)๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธํ์ธ์.

๋ก๊ทธ์ธ์ ์ฑ๊ณตํ๋ฉด RabbitMQ ๊ด๋ฆฌ ์ธํฐํ์ด์ค๊ฐ ๋ํ๋ฉ๋๋ค.
์ฌ๊ธฐ์ ์ค์์น์ ๋๊ธฐ์ด์ ์์ฑํ๊ณ , ์ฐ๊ฒฐ ์ํ๋ฅผ ๋ณด๊ณ , ๋ฉ์์ง ์ฒ๋ฆฌ๋๊ณผ ๊ฐ์ ์ค์ํ ์งํ๋ฅผ ๋ชจ๋ํฐ๋งํ ์ ์์ต๋๋ค.
์ฐธ๊ณ : ๊ธฐ๋ณธ ๊ฒ์คํธ ์ฌ์ฉ์๋ ๋ก์ปฌํธ์คํธ์์๋ง ์ ๊ทผํ ์ ์์ต๋๋ค.
์๊ฒฉ ์ก์ธ์ค๊ฐ ํ์ํ ๊ฒฝ์ฐ ์๋ก์ด ๊ด๋ฆฌ์ ์ฌ์ฉ์๋ฅผ ๋ง๋ค๊ณ ์ ์ ํ ๊ถํ์ ์ค์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
์์ํ๊ธฐ์ ์์ ๋ฉ์์ง ํ ์ด๋ธ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
์ด ๋ฌธ์์ ์ฑํ ์๋น์ค๋ ์ด์ ๋ฌธ์ "Java ์์ง๋์ด ๊ณ ๊ธ ํ์ ์ฌํญ: Spring Boot 3 + Netty๋ฅผ ์ด์ฉํ ๋์ ๋์์ฑ ์ธ์คํดํธ ๋ฉ์์ง ์๋น์ค ๊ตฌ์ถ"์ ๊ธฐ๋ฐ์ผ๋ก ํฉ๋๋ค.
๊ด์ฌ ์๋ ๋ ์๋ ํ์ธํด ๋ณด์ธ์.
DROP TABLE IF EXISTS `chat_message`;
CREATE TABLE `chat_message` (
`id` VARCHAR(32) NOT NULL COMMENT '๋ฉ์์ง ๊ณ ์ ID',
`sender_id` VARCHAR(32) NOT NULL COMMENT '๋ณด๋ธ ์ฌ๋ ์ฌ์ฉ์ ID',
`receiver_id` VARCHAR(32) NOT NULL COMMENT '๋ฐ๋ ์ฌ๋ ์ฌ์ฉ์ ID',
`receiver_type` INT NULL DEFAULT NULL COMMENT '์์ ์ ์ ํ (์: ์ฌ์ฉ์, ๊ทธ๋ฃน ๋ฑ)',
`msg_type` INT NOT NULL COMMENT '๋ฉ์์ง ์ ํ (์: ํ
์คํธ, ์ด๋ฏธ์ง, ๋น๋์ค ๋ฑ)',
`msg` VARCHAR(255) NOT NULL COMMENT 'ํ
์คํธ ๋ฉ์์ง ๋ด์ฉ',
`chat_time` DATETIME NOT NULL COMMENT '์ฑํ
์๊ฐ (๋ณด๋ธ ์๊ฐ๊ณผ ๋ฐ์ ์๊ฐ ๋์ผ)',
`show_msg_date_time_flag` INT NULL DEFAULT NULL COMMENT '๋ฉ์์ง ์๊ฐ ํ์ ์ฌ๋ถ ํ๋๊ทธ (1๋ถ ์ด์ ๊ฐ๊ฒฉ์ฉ)',
`is_read` TINYINT(1) NULL DEFAULT NULL COMMENT '์ฝ์ ์ฌ๋ถ (1: ์ฝ์, 0: ์ ์ฝ์)',
PRIMARY KEY (`id`)
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '๊ธฐ๋ณธ ์ฑํ
๋ฉ์์ง ํ
์ด๋ธ';
DROP TABLE IF EXISTS `chat_message_video`;
CREATE TABLE `chat_message_video` (
`message_id` VARCHAR(32) NOT NULL COMMENT '์ฐ๊ฒฐ๋ ๋ฉ์์ง ID',
`video_path` VARCHAR(128) NULL DEFAULT NULL COMMENT '๋น๋์ค ํ์ผ ๊ฒฝ๋ก',
`video_width` INT NULL DEFAULT NULL COMMENT '๋น๋์ค ํญ(px)',
`video_height` INT NULL DEFAULT NULL COMMENT '๋น๋์ค ๋์ด(px)',
`video_times` INT NULL DEFAULT NULL COMMENT '๋น๋์ค ์ฌ์ ์๊ฐ(์ด)',
PRIMARY KEY (`message_id`),
CONSTRAINT `fk_video_message` FOREIGN KEY (`message_id`) REFERENCES `chat_message`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '๋น๋์ค ๋ฉ์์ง ์์ธ ํ
์ด๋ธ';
DROP TABLE IF EXISTS `chat_message_voice`;
CREATE TABLE `chat_message_voice` (
`message_id` VARCHAR(32) NOT NULL COMMENT '์ฐ๊ฒฐ๋ ๋ฉ์์ง ID',
`voice_path` VARCHAR(128) NULL DEFAULT NULL COMMENT '์์ฑ ํ์ผ ๊ฒฝ๋ก',
`speak_voice_duration` INT NULL DEFAULT NULL COMMENT '์์ฑ ์ฌ์ ์๊ฐ(์ด)',
PRIMARY KEY (`message_id`),
CONSTRAINT `fk_voice_message` FOREIGN KEY (`message_id`) REFERENCES `chat_message`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '์์ฑ ๋ฉ์์ง ์์ธ ํ
์ด๋ธ';
๋จผ์ , pom.xml ํ๋ก์ ํธ์ ์ ์ฅ์ ํ์ผ์ RabbitMQ ์ข ์์ฑ์ ์ถ๊ฐํฉ๋๋ค.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
rabbitmq:
host: 127.0.0.1
port: 5682
username: guest
password: guest
virtual-host: /
RabbitMQ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ธฐ ์ํ ๋ฉ์์ง ๊ฒ์์ ํด๋์ค๋ฅผ ๋ง๋ญ๋๋ค.
import com.sleekydz.model.netty.ChatMsg;
import com.sleekydz.utils.JsonUtils;
public class MessagePublisher {
// ๊ตํ๊ธฐ ์ด๋ฆ ์ ์
public static final String EXCHANGE = "sleekydz86_exchange";
// ํ ์ด๋ฆ ์ ์
public static final String QUEUE = "sleekydz86_queue";
// ๋ฉ์์ง๋ฅผ ํ๋ก ์ ์กํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ธฐ ์ํ ๋ผ์ฐํ
ํค
public static final String ROUTING_KEY_SEND = "sleekydz86.kakao.send";
// ๋ฉ์์ง๋ฅผ ์ ์กํ๊ณ ์ ์ฅํ๋ ๋ฉ์๋
public static void sendMsgToSave(ChatMsg msg) throws Exception {
RabbitMQConnectUtils connectUtils = new RabbitMQConnectUtils();
connectUtils.sendMsg(JsonUtils.objectToJson(msg),
EXCHANGE,
ROUTING_KEY_SEND);
}
}
import com.rabbitmq.client.*;
import java.util.ArrayList;
import java.util.List;
public class RabbitMQConnectUtils {
private final List<Connection> connections = new ArrayList<>();
private final int maxConnection = 20;
// ๊ฐ๋ฐํ๊ฒฝ dev
private final String host = "59.45.23.1";
private final int port = 5682;
private final String username = "guest";
private final String password = "guest";
private final String virtualHost = "/";
public ConnectionFactory factory;
public ConnectionFactory getRabbitMqConnection() {
return getFactory();
}
public ConnectionFactory getFactory() {
initFactory();
return factory;
}
private void initFactory() {
try {
if (factory == null) {
factory = new ConnectionFactory();
factory.setHost(host);
factory.setPort(port);
factory.setUsername(username);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void sendMsg(String message, String queue) throws Exception {
Connection connection = getConnection();
Channel channel = connection.createChannel();
channel.basicPublish("",
queue,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("utf-8"));
channel.close();
setConnection(connection);
}
public void sendMsg(String message, String exchange, String routingKey) throws Exception {
Connection connection = getConnection();
Channel channel = connection.createChannel();
channel.basicPublish(exchange,
routingKey,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("utf-8"));
channel.close();
setConnection(connection);
}
public GetResponse basicGet(String queue, boolean autoAck) throws Exception {
GetResponse getResponse = null;
Connection connection = getConnection();
Channel channel = connection.createChannel();
getResponse = channel.basicGet(queue, autoAck);
channel.close();
setConnection(connection);
return getResponse;
}
public Connection getConnection() throws Exception {
return getAndSetConnection(true, null);
}
public void setConnection(Connection connection) throws Exception {
getAndSetConnection(false, connection);
}
private synchronized Connection getAndSetConnection(boolean isGet, Connection connection) throws Exception {
getRabbitMqConnection();
if (isGet) {
if (connections.isEmpty()) {
return factory.newConnection();
}
Connection newConnection = connections.get(0);
connections.remove(0);
if (newConnection.isOpen()) {
return newConnection;
} else {
return factory.newConnection();
}
} else {
if (connections.size() < maxConnection) {
connections.add(connection);
}
return null;
}
}
}
๋ฉ์์ง๋ฅผ ์์ ํ๊ณ ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฉ์์ง ์๋น์ ํด๋์ค๋ฅผ ๋ง๋ญ๋๋ค.
import com.sleekydz.model.netty.ChatMsg;
import com.sleekydz.service.ChatMessageService;
import com.sleekydz.utils.JsonUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
// ๋ฉ์์ง ์๋น์ ํด๋์ค
@Component
@Slf4j
public class RabbitMQConsumer {
@Resource
private ChatMessageService chatMessageService;
// ์ง์ ๋ ํ(RabbitMQConfig.QUEUE)์์ ๋ฉ์์ง๋ฅผ ์์ ํ๋ ๋ฉ์๋
@RabbitListener(queues = {RabbitMQConfig.QUEUE})
public void watchQueue(String payload, Message message) {
String routingKey = message.getMessageProperties().getReceivedRoutingKey();
log.info("์์ ๋ routingKey = {}", routingKey);
// ๋ฉ์์ง ๋ฐ์ ๋ผ์ฐํ
ํค์ ํด๋นํ๋ ๊ฒฝ์ฐ ์ฒ๋ฆฌ
if (routingKey.equals(RabbitMQConfig.ROUTING_KEY_SEND)) {
String msg = payload;
ChatMsg chatMsg = JsonUtils.jsonToPojo(msg, ChatMsg.class);
// ๋ฉ์์ง๋ฅผ DB์ ์ ์ฅ
chatMessageService.saveMsg(chatMsg);
}
}
}
RabbitMQ๋ฅผ Spring Boot์ ํตํฉํ์ฌ ๋น๋๊ธฐ ๋ฉ์์ง ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํ๊ณ , ์ฑํ ๋ฉ์์ง์ ์ ์ฅ ์์ ์ ๋ถ๋ฆฌํ๊ณ , ์์คํ ์ ์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์ ๊ฐ์ ํ์ต๋๋ค.
์ฌ์ฉ์๊ฐ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ฉด ํด๋น ๋ฉ์์ง๋ฅผ RabbitMQ๋ก ๋ณด๋ด๊ณ , ์ด ๋ฉ์์ง๋ ์๋น์์ ์ํด ๋น๋๊ธฐ์ ์ผ๋ก ์ฒ๋ฆฌ๋์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅ๋ฉ๋๋ค.
์ด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง์ ์ด์ํจ์ผ๋ก์จ ๋ฐ์ํ๋ ์ฑ๋ฅ ๋ณ๋ชฉ ํ์์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.