Phoenix
Phoenix Framework
Elixir 기반 고성능 웹 프레임워크. LiveView로 실시간 UI 구현. Erlang VM의 동시성과 내결함성을 활용한 확장성 있는 웹 애플리케이션 개발.
Phoenix Framework
Elixir 기반 고성능 웹 프레임워크. LiveView로 실시간 UI 구현. Erlang VM의 동시성과 내결함성을 활용한 확장성 있는 웹 애플리케이션 개발.
Phoenix는 Elixir 언어로 작성된 고성능 웹 프레임워크로, Erlang VM(BEAM) 위에서 동작합니다. Ruby on Rails에서 영감을 받아 개발자 친화적인 구조를 갖추면서도, Erlang의 강력한 동시성 모델을 통해 수백만 개의 동시 연결을 처리할 수 있는 확장성을 제공합니다. MVC 패턴을 기반으로 하며, 채널(Channels)을 통한 실시간 통신을 네이티브로 지원합니다.
Chris McCord가 2014년에 개발을 시작한 Phoenix는 Rails의 생산성과 Erlang의 안정성을 결합하려는 목표로 탄생했습니다. McCord는 Rails 개발자로서 대규모 트래픽 처리의 한계를 경험한 후, Elixir와 Erlang VM의 가능성에 주목했습니다. 그 결과 "Rails의 편의성 + Erlang의 성능"이라는 독특한 포지셔닝을 확립했습니다.
Phoenix LiveView는 2019년에 도입된 혁신적인 기능으로, 서버 사이드 렌더링만으로 실시간 인터랙티브 UI를 구현합니다. WebSocket을 통해 서버와 클라이언트 상태를 동기화하며, JavaScript 없이도 SPA(Single Page Application)와 유사한 사용자 경험을 제공합니다. 이로 인해 프론트엔드와 백엔드를 하나의 언어로 개발할 수 있어 개발 생산성이 크게 향상됩니다.
실무에서 Phoenix의 가장 큰 장점은 동시성과 내결함성입니다. Erlang VM의 경량 프로세스는 OS 스레드보다 훨씬 가볍고, 프로세스 간 격리를 통해 하나의 오류가 전체 시스템에 영향을 미치지 않습니다. "Let it crash" 철학에 따라 Supervisor가 실패한 프로세스를 자동으로 재시작하여 99.9999%(Six Nines) 가용성을 달성할 수 있습니다. Discord, Pinterest, Bleacher Report 등이 Phoenix를 사용해 대규모 실시간 서비스를 운영하고 있습니다.
# lib/my_app_web/controllers/user_controller.ex
defmodule MyAppWeb.UserController do
use MyAppWeb, :controller
alias MyApp.Accounts
alias MyApp.Accounts.User
# GET /api/users
def index(conn, _params) do
users = Accounts.list_users()
render(conn, :index, users: users)
end
# GET /api/users/:id
def show(conn, %{"id" => id}) do
user = Accounts.get_user!(id)
render(conn, :show, user: user)
end
# POST /api/users
def create(conn, %{"user" => user_params}) do
case Accounts.create_user(user_params) do
{:ok, %User{} = user} ->
conn
|> put_status(:created)
|> put_resp_header("location", ~p"/api/users/#{user}")
|> render(:show, user: user)
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(:error, changeset: changeset)
end
end
end
# lib/my_app_web/live/counter_live.ex
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
# 초기 상태 설정
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
# 실시간 UI 렌더링 (HEEx 템플릿)
def render(assigns) do
~H"""
<div class="counter-container">
<h1>실시간 카운터</h1>
<p class="count"><%= @count %></p>
<div class="buttons">
<button phx-click="decrement">-</button>
<button phx-click="increment">+</button>
<button phx-click="reset">Reset</button>
</div>
</div>
"""
end
# 이벤트 핸들러 - 서버에서 처리, 자동으로 UI 업데이트
def handle_event("increment", _params, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
def handle_event("decrement", _params, socket) do
{:noreply, update(socket, :count, &(&1 - 1))}
end
def handle_event("reset", _params, socket) do
{:noreply, assign(socket, count: 0)}
end
end
# router.ex에 추가
# live "/counter", CounterLive
# lib/my_app_web/live/chat_live.ex
defmodule MyAppWeb.ChatLive do
use MyAppWeb, :live_view
def mount(%{"room" => room}, _session, socket) do
# 채팅방 토픽 구독
if connected?(socket) do
Phoenix.PubSub.subscribe(MyApp.PubSub, "chat:#{room}")
end
{:ok, assign(socket, room: room, messages: [], message: "")}
end
# 메시지 전송 - 모든 구독자에게 브로드캐스트
def handle_event("send", %{"message" => msg}, socket) do
Phoenix.PubSub.broadcast(
MyApp.PubSub,
"chat:#{socket.assigns.room}",
{:new_message, %{text: msg, time: DateTime.utc_now()}}
)
{:noreply, assign(socket, message: "")}
end
# 브로드캐스트 메시지 수신
def handle_info({:new_message, message}, socket) do
messages = socket.assigns.messages ++ [message]
{:noreply, assign(socket, messages: messages)}
end
end
"실시간 알림이랑 채팅을 구현해야 하는데, Node.js로 Socket.IO 붙이면 프론트엔드 상태 관리가 복잡해져요. Phoenix LiveView 쓰면 서버에서 상태 관리하고 WebSocket은 자동으로 처리되니까 코드량이 절반 이하로 줄어들어요. Discord도 수백만 동시접속을 Phoenix로 처리하고 있고요."
"Rails가 생태계는 넓지만, 우리 서비스는 실시간 대시보드가 핵심이에요. Phoenix는 단일 서버에서 200만 WebSocket 연결 처리한 벤치마크도 있어요. 게다가 Elixir 문법이 Ruby랑 비슷해서 Rails 개발자들이 2-3주면 적응합니다. 내결함성도 기본 내장이라 장애 복구에 별도 인프라가 필요 없어요."
"Phoenix가 고성능인 이유는 Erlang VM의 경량 프로세스 모델 덕분입니다. 하나의 요청이 하나의 프로세스에서 처리되고, 각 프로세스는 약 2KB로 매우 가볍습니다. 그래서 수십만 개의 동시 연결도 단일 서버에서 처리할 수 있어요. 반면 Java나 Ruby는 스레드 기반이라 메모리 오버헤드가 크죠."
"이 LiveView에서 handle_event마다 전체 assigns를 업데이트하고 있네요. Phoenix LiveView는 변경된 부분만 클라이언트로 보내니까, 필요한 assign만 update하는 게 좋아요. assign(socket, items: new_items) 대신 update(socket, :items, fn _ -> new_items end)로 바꾸고, 무거운 리스트는 stream/3으로 처리하면 메모리 사용량도 줄어듭니다. 그리고 PubSub broadcast가 잦으면 debounce 고려해보세요."
Phoenix를 제대로 활용하려면 Elixir와 함수형 프로그래밍에 대한 이해가 필수입니다. 패턴 매칭, 불변성, 재귀, 파이프 연산자 등 OOP와 다른 패러다임에 적응 시간이 필요합니다. 팀 전체 교육 비용과 시간을 프로젝트 계획에 반영하세요.
Elixir/Phoenix 생태계는 Node.js나 Python에 비해 라이브러리 수가 적습니다. 특정 서드파티 API SDK나 전문 도메인 라이브러리가 없을 수 있어, 직접 구현하거나 Erlang 라이브러리를 연동해야 할 수 있습니다. 프로젝트 시작 전 필요한 라이브러리 가용성을 확인하세요.
Elixir/Phoenix 개발자 풀이 상대적으로 작습니다. 한국 시장에서는 특히 경력자 채용이 어려울 수 있습니다. 기존 팀원 교육, 원격 채용, 또는 Ruby/Erlang 경험자 영입 후 전환 교육 등의 대안을 고려해야 합니다.