์ฑํ ์๋ฒ ๊ตฌ์ถ๊ธฐ 1 | Elixir Socket Server
- #fromm
- #์ฑํ
- #socket
- #Elixir
- #Phoenix
๋ค์ด๊ฐ๋ฉฐ
fromm ์๋น์ค๋ฅผ ์์ํ์ง๋ 1๋ ์ด ๋์์ต๋๋ค.
์๊ณ ๋น ๋ฅธ ์คํ๊ณผ ๋น์ฆ๋์ค๋ฅผ ์งํฅํ๋ ํ์ ํน์ฑ์ ์๋น์ค ์ด๊ธฐ์๋ ๋ชจ๋ ๊ฒ์ ์ฒ์๋ถํฐ ๊ฐ๋ฐํ์ง ์์์ต๋๋ค. fromm ์๋น์ค์ ํต์ฌ์ด ๋๋ ์ฑํ ์๋ฒ์ ๊ฒฝ์ฐ์๋ ๊ตฌ๊ธ์ Firestore๋ฅผ ์ฌ์ฉํ์ฌ ๋น ๋ฅด๊ฒ ๋น์ฆ๋์ค๋ฅผ ์์ํ์ต๋๋ค.
1๋ ๋์ ์๋น์ค์ ๊ธ๊ฒฉํ ์ฑ์ฅ๊ณผ ๋๋ถ์ด ํธ๋ํฝ ์ฆ๊ฐ์ ๋ค์ํ ํด์ธ ์ ์ ์ ์ฆ๊ฐ๋ฅผ ๊ฒฝํํ์ต๋๋ค. Firestore๋ก๋ ๊ฐ๋นํ๊ธฐ ์ด๋ ค์ด ํธ๋ํฝ ์์น๋ฅผ ๋ณด์ผ ๋๋ ์์๊ณ , ์ค๊ตญ์์๋ Firestore๊ฐ ์๋ํ์ง ์๋ ๋ฑ ๋ค์ํ ์ด์์ ๋ง์ฃผํ์ต๋๋ค. ์ด์ ํ ๋ด๋ถ์์๋ ๋ค๋ฅธ ์๋ฃจ์ ์ ์๋์ง ์ง์ ๊ตฌ์ถํ๋ ๊ฒ์ด ์ต์ ์ผ์ง ๋ค์ํ ๋ฐฉ๋ฉด์ผ๋ก ๊ฒํ ๋ฅผ ์งํํ๊ณ , ๊ฒฐ๊ตญ ์ง์ ๊ตฌ์ถํ๋ ๊ฒฐ์ ์ ๋ด๋ฆฌ๊ฒ๋์์ต๋๋ค.
์ด๋ฒ ๊ธ ์์๋ ์ฑํ ๊ณผ ๊ด๋ จ๋ ์์ ์ค, ์์ผ ์๋ฒ ๊ตฌ์ถ์ ํ๋ฉฐ ๊ฒช์๋ ๋ด์ฉ์ ๊ณต์ ํ๊ณ ์ ํฉ๋๋ค.
Elixir ?
์ฒซ ๋ฒ์งธ๋ก ๊ณ ๋ฏผํ๋ ๋ถ๋ถ์ ์ธ์ด์ ํ๋ ์์ํฌ ์์ต๋๋ค.
ํ์ฌ fromm ๋ฐฑ์๋์ ๋๋ถ๋ถ์ NodeJS ๊ธฐ๋ฐ์ Typescript๋ก ์์ฑ๋์ด ์์์ต๋๋ค. NodeJS๋ ๊ต์ฅํ ์ข์ ์ ํ์ง์ด๊ณ ๋ชจ๋ ํ์๋ค์ด ์ต์ํ๋ค๋ ์ ์์ ์ฅ์ ์ด ์์์ง๋ง, ์ข ๋ ๋ชฉ์ ์ ๋ง๋ ์ธ์ด๋ ์์๊น ์ด์ฌํ ์กฐ์ฌ๋ฅผ ํ๋ ์ค์ Elixir๋ฅผ ๋ฐ๊ฒฌํ๊ฒ ๋ฉ๋๋ค.
Elixir is a dynamic, functional language for building scalable and maintainable applications. (elixir-lang.org)
Elixir๋ ๊ณ ์ฑ๋ฅ ๋ถ์ฐ Erlang VM (BEAM) ์์ ๋์๊ฐ๋ Josรฉ Valim์ด ๊ฐ๋ฐํ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋๋ค. Erlang์ ์ ํ ๊ตํ ์ฅ๋น์์ ๋ํ ํต์ ์์คํ ์ ์ฌ์ฉํ๊ธฐ ์ํด 1986๋ ์ Ericsson์ฌ์์ ๊ฐ๋ฐ๋ ์ธ์ด์ ๋๋ค. ๋ถ์ฐ ํ๊ฒฝ์์ ์์ ์ ์ธ ์ค์๊ฐ ๋์ ์์คํ ์ ์ํด ๊ณ ์๋ ์ธ์ด์ธ ๋งํผ ๋ค์ํ ํต์ ์์คํ ๊ณผ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ๋ฉ๋๋ค.
์ค์ ๋ก Facebook, Rabbit MQ, Whatsapp ๋ฑ์์ ์ฑํ ๊ณผ ๋ฉ์์ง ์ฒ๋ฆฌ๋ก ๋ง์ด ์ฌ์ฉ๋๋ค๊ณ ํฉ๋๋ค.
Erlang์ด ์ค๋์ ์ ๊ฐ๋ฐ๋ ์ธ์ด๋ค ๋ณด๋, ํ๋์ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ๋ง๊ฒ ํ์ํ ๊ฒ์ด Elixir ์ ๋๋ค. ๋ง์น Java์ Kotlin์ ๊ด๊ณ์ ๋น์ทํฉ๋๋ค.
๋ญ๊ฐ ์๋ก์ด ๊ฒ์ด๋ผ ํฅ๋ฏธ๋กญ๊ธฐ๋ํ๊ณ , ์๋น์ค๊ฐ ์๊ตฌํ๋ ๊ธฐ๋ฅ์ ์๋ฒฝํ๊ฒ ๊ฐ์ถ๊ณ ์์ด์ Elixir๋ฅผ ์ฌ์ฉํด๋ณด๊ธฐ๋ก ํ์ต๋๋ค.
Elixir์ ์ธ๊ธฐ (Stackoverflow Programming, scripting and markup languages)
Phoenix Framework
Elixir ์์ฒด๋ก๋ ์ข์ง๋ง, ์ฝ๊ณ ๋น ๋ฅด๊ณ ์์ ์ ์ผ๋ก ๊ฐ๋ฐํ ์ ์๋๋ก ์ ๋ง๋ค์ด์ง ํ๋ ์์ํฌ๊ฐ ํ์ํ์ต๋๋ค. Phoenix๋ Elixir๋ก ์์ฑ๋ ๋ ๋ณด์ ์ธ ํ๋ ์์ํฌ๋ผ ๋ฐ๋ก ์ฐพ์ ์ ์์์ต๋๋ค.
Phoenix is a web development framework written in Elixir (phoenixframework.org)
Phoenix๋ Josรฉ Valim์ด Elixir๋ก ๋ง๋ ์น ํ๋ ์์ํฌ ์ ๋๋ค. Ruby์ ํต์ฌ ๊ฐ๋ฐ์์๋ ๊ทธ๊ฐ Ruby on Rails์ Phython Django์ ์๊ฐ์ ์ป์ด ๋ง๋ค์๋ค๊ณ ํฉ๋๋ค.
Phoenix์ ์ธ๊ธฐ (Stackoverflow Web frameworks and technologies)
Phoenix๋ ์์ฒด PubSub์ ์ฌ์ฉํ์ฌ Channel, Presence ๋ฑ์ ๊ธฐ๋ฅ์ด ์ ์ถ์ํ ๋์ด์์ด์ ๋น์ฆ๋์ค ๋ก์ง๋ง ๊ตฌํํ๋ฉด ๋ฉ๋๋ค. ๋ํ ๋ค์ํ ์ธ์ด๋ก Client SDK๋ฅผ ์ ๊ณตํ์ฌ ์น, Android, iOS ์์๋ ์ฝ๊ณ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
Local/Remote PubSub์ ์ฌ์ฉํ๋ฉด ๋ณดํต ๋ถ์ฐ ์์ผ ์๋ฒ์์ ์ฌ์ฉ๋๋ PubSub์ฉ Redis ๊ฐ์ ๊ฒ์ ์ฌ์ฉํ์ง ์์๋ ๋ฉ๋๋ค. ๋น์ฅ์ Phoenix์์ ์ ๊ณตํ๋ Local/Remote PubSub๋ง์ผ๋ก๋ ์ถฉ๋ถํ๋ค๊ณ ํ๋จํ์ผ๋, ์ด ๋ถ๋ถ์ ์ถํ์ ๋ค์ํ ์ด์ํ๊ฒฝ์์ ๋ชจ๋ํฐ๋ง์ ํด๋ด์ผ ํ ๊ฒ ๊ฐ์ต๋๋ค. ๋ํ RedisAdapter๋ฅผ ์ ๊ณตํ์ฌ Redis๋ฅผ PubSub์ผ๋ก ์ฌ์ฉํ๋ ๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค.
๋ค๋ง ๋ถ์ฐ ํ๊ฒฝ์์ ๊ฐ ๋ ธ๋๋ค์ ์ฐ๊ฒฐํด์ฃผ์ด์ผ ํ๋๋ฐ, ์ด๋ libcluster ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํด๊ฒฐํด์ค๋๋ค. libcluster๋ ๋ค์ํ ํ๊ฒฝ์์ ๋ ธ๋๋ค์ ์ฐพ์๋ด๊ณ ์ฐ๊ฒฐ์ ํด์ฃผ๋ ์ญํ ์ ํฉ๋๋ค. ์ฐ๊ฒฐ์ด ๋ ์ดํ์๋ PubSub์ ํตํด ๋ฉ์์ง๋ฅผ broadcastํ๋ฉด ์์์ ์ ์ฒด ๋ ธ๋์ ๋ฉ์์ง๊ฐ ์ ๋ฌ๋ฉ๋๋ค.
Local/Remote PubSub
Infra
์ด๋ ๊ฒ ๊ฐ๋ฐ๋ ์์ผ ์๋ฒ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ด๋ค ์ธํ๋ผ์์ ์ด์ํ ์ง ๊ณ ๋ฏผ์ด ๋์์ต๋๋ค. ํ์ฌ ์๋์์์๋ AWS๋ฅผ ๋ฉ์ธ ์ธํ๋ผ๋ก ์ฌ์ฉํ๊ณ ์์ต๋๋ค. AWS์์ ์์ผ์๋ฒ๋ฅผ ์ด์ํ๊ธฐ์ EKS์ ECS๊ฐ ๋ฌด๋ํ๋ค๋ ์๊ฐ์ด ๋ค์๊ณ ํ๋ด ๋ ธํ์ฐ๊ฐ ๋ ๋ง์ ECS๋ฅผ ์ต์ข ์ ํํ๊ฒ ๋์์ต๋๋ค.
Remote PubSub์ ์ํด ECS task(๋ ธ๋) ๊ฐ์ ์ฐ๊ฒฐ์ ํด์ค์ผํฉ๋๋ค. task์ IP ์ฃผ์๋ฅผ ์์์ผ libcluster๊ฐ ์ฐ๊ฒฐ์ ํด์ค ์ ์๊ธฐ ๋๋ฌธ์ Service Discovery๋ฅผ ๊ตฌ์ฑํ์ต๋๋ค. Route53์ private DNS๋ฅผ ์์ฑํ๊ณ libcluster์์ DNS query๋ฅผ ํตํด ๊ฐ task์ IP ์ฃผ์๋ฅผ ์์๋ด ์ฐ๊ฒฐ์ ๋งบ๊ฒ ๋ฉ๋๋ค.
Service Discovery
๋ํ ์์ผ ์๋ฒ์ ๊ณ ์ฑ๋ฅ์ด ์๊ตฌ๋๋ ์ํฉ์ด๊ธฐ ๋๋ฌธ์, ๋ถํ ๋ถ์ฐ์ ์ ํฉํ๋ฉฐ ๊ฐ์์ค๋ฌ์ด ํธ๋ํฝ ์ฆ๋์ ์ต์ ํ ๋์ด์๋ Network Load Balancer๋ฅผ ์ ํํ์ต๋๋ค.
๋ถํํ ์คํธ
์์ ๊ฐ์ด ๊ตฌ์ฑ ํ ์ค์ ์ด๋ ์ ๋์ ํธ๋ํฝ์ ๊ฐ๋นํ ์ ์์์ง ๋ถํํ ์คํธ๋ฅผ ์งํํด ๋ณด์์ต๋๋ค. ์ค์ ํด๋ผ์ด์ธํธ์์ ์์ผ ์ฐ๊ฒฐ์ ์์ฒญํ๋ socket connection ์ฑ๋ฅ ์ธก์ ๊ณผ, ์ฐ๊ฒฐ๋ ์์ผ์ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ๊ธฐ ์ํด ์๋ฒ์์ ํธ์ถํ๋ broadcast API ์ฑ๋ฅ ์ธก์ ์ผ๋ก ๋๋์ด ์งํํ์ต๋๋ค.
Socket Connection
์ด๋น 1,000๊ฐ์ ์์ฒญ x 100์ด = ์ด 100,000๊ฐ์ connection
Fargate 4 vCPU x 2 task
- connection time (P95): 100ms
- peak cpu: 66%
- peak memory: 30%
์ฃผ๋ชฉํ ๋งํ ์ ์ ์ด๋น ์์ฒญ์ด ์ฆ๊ฐํ ์๋ก peak cpu๊ฐ ๋์์ง๊ณ , ์ด connection ๊ฐ์๊ฐ ์ฆ๊ฐํ ์๋ก peak memory๊ฐ ์ฆ๊ฐํ๋ค๋์ ์ด์์ต๋๋ค.
broadcast API
์์ผ 15,000๊ฐ ์ฐ๊ฒฐ๋ ์ํ์์ ์ด๋น 10๊ฐ์ ์์ฒญ x ์์ฒญ๋น ๋ฉ์์ง 3,000๊ฐ = ์ด๋น ์ด 30,000๊ฐ์ ๋ฉ์์ง
์์ฒญ๋น ๋ฉ์์ง์ ์๊ฐ ์ด๋ ์์ค์ ๋์ด์๋ ์๋ต์๋๊ฐ ๋๋ ค์ง๊ณ , ์์ฒญ๋น ๋ฉ์์ง์ ์๋ฅผ ์ค์ด๋ ๋์ ์ด๋น ์์ฒญ์ ๋๋ ค๋ ๋๋ ค์ ธ์ ์ ์ ์์ค์ ์ฐพ์์ผ ํ์ต๋๋ค.
Fargate 4 vCPU x 20 task
- response time (P95): 671ms
- response time (P99): 713ms
- peak cpu: 9%
Fargate 16 vCPU x 1 task
- response time (P95): 383ms
- response time (P99): 399ms
- peak cpu: 16%
task๊ฐ ์ฌ๋ฌ๊ฐ์ธ ๊ฒฝ์ฐ ์ด ์คํ์ ๋ ๋์ ์ ์์ง๋ง, Remote PubSub์ ์๊ฐ์ด ํ์ํ๊ธฐ ๋๋ฌธ์ response time์ ๋ ๋์ด๋๊ฒ ๋ํ๋ฉ๋๋ค. ํด๋น ๋ถ๋ถ์ ์ถํ์ ์ต์ ํ๊ฐ ํ์ํ ๊ฒ ๊ฐ์ต๋๋ค.
๊ฐ์ ์ฌํญ
์ง๊ธ๊น์ง Elixir์ Phoenix Framework๋ฅผ ํ์ฉํ ์์ผ ์๋ฒ ๊ตฌ์ถํ ๊ฒ์ ์ ๋ฆฌํด๋ดค์ต๋๋ค. ํ์ฌ๋ ๋ง์ด๊ทธ๋ ์ด์ ๊ธฐ๊ฐ์ด๋ผ ํด๋ผ์ด์ธํธ์ Firestore์ ํจ๊ป ์ ์ฉํด๋๊ณ ๋ชจ๋ํฐ๋ง์ ์งํํ๊ณ ์์ต๋๋ค.
์ง๊ธ์ ๋จ์ํ๊ฒ ์์ผ ์ฐ๊ฒฐ๋ง ํ๊ณ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ๋ ์ญํ ๋ง ํ๊ณ ์์ง๋ง ์ฌ๋ฌ๊ฐ์ง ๊ณ ๋ํ๊ฐ ํ์ํฉ๋๋ค.
- ์๋ฒ ๋ฐฐํฌ์ ์์ผ ์ฐ๊ฒฐ์ด ํ ๋ฒ์ ๋์ด์ง๋ ์ด์
- ์ฐ๊ฒฐ์ด ๋๊ฒผ๋ค๊ฐ ์ฌ์ฐ๊ฒฐ ๋ ๊ฒฝ์ฐ ๋ฉ์์ง ๋๋ฝ ์ด์
- ์ฑํ ์์ ๋ณด์ฅ
ํ์ฌ๋ ํด๋ผ์ด์ธํธ์์ ํด๋น ์ด์๋ค์ ์ฒ๋ฆฌํ๊ณ ์์ง๋ง, ๋ฐฑ์๋์์๋ ์ฒ๋ฆฌํ ์ ์๋๋ก ์ฐจ๊ทผ์ฐจ๊ทผ ๊ฐ๋ฐํด๋๊ฐ์ผ ๊ฒ ์ต๋๋ค. ๊ทธ๋ผ ์ดํ์ ๊ฐ์ ๋ ๋ชจ์ต์ผ๋ก ๋ค์ ์ฐพ์ ์ค๊ฒ ์ต๋๋ค.
์ ํฌ์ ํจ๊ป ์ฌ๋ฐ๊ฒ ๊ฐ๋ฐํ์ค ๋ถ์ ์ฐพ์ต๋๋ค! ๊ด์ฌ ์์ผ์ ๋ถ์ ์๋ ์ฑ์ฉ ๊ณต๊ณ ๋ฅผ ํ์ธํด์ฃผ์ธ์ :)