※참고: 이 글은 Phoenix 프레임워크의 공식 가이드 문서 중 Channel 가이드를 기반으로 작성되었습니다.
Channel 이란?
Phoenix 애플리케이션에서 채널(channel)이란, 발신자와 수신자가 메시지를 주고받음으로써 실시간 애플리케이션 구현을 가능하게 해주는 컴포넌트들의 집합으로 구성된 시스템입니다. 발신자(senders)는 특정 토픽(topic)의 메시지를 브로드캐스트(broadcast)하고 수신자(receivers)들은 해당 토픽을 구독(subscribe)함으로써 새로운 메시지를 받을 수 있습니다.
한 명의 사용자는 발신자와 수신자의 역할을 필요에 따라 바꿔가며 메시지를 보내거나 받을 수 있습니다. 또한, 발신자와 수신자는 반드시 엘릭서 프로세스일 필요는 없습니다. 채널을 통해 메시지를 주고받을 수 있는 자바스크립트 클라이언트, 스마트폰 애플리케이션, 다른 Phoenix 애플리케이션 모두 Phoenix 애플리케이션의 발신자와 수신자가 될 수 있습니다.
Phoenix의 채널은 이러한 기능들을 구현하기 위한 여러 개의 컴포넌트(components)들의 조합으로 이루어진 일종의 레이어드 시스템(Layered System) 입니다. 그렇다면, Phoenix의 채널을 구성하는 컴포넌트에는 어떠한 것들이 있고 어떤 역할을 하는지에 대해서 살펴보도록 하겠습니다.
Socket handlers
이전 포스트인 “PHOENIX PRESENCE를 이용한 채팅 애플리케이션 만들기”를 본 적이 있으시다면 UserSocket 모듈을 기억하실 겁니다. 이러한 모듈이 바로 소켓 핸들러입니다. 소켓 핸들러는 소켓 연결을 관리(authenticate, identify)하고, 채널에서 사용할 값들(assigns)을 설정할 수 있게 합니다.
Channel routes
채널 라우트(routes)는 소켓 핸들러 안에 정의됩니다. 토픽 문자열과 매칭되는 요청을 지정된 채널 모듈에 전달하는 역할을 합니다. 토픽 문자열에서 애스터리스크(*)는 와일드카드 역할을 합니다. 예를 들어, “sample_topic:*” 라우트에는 “sample_topic:pizza”, “sample_topic:oranges” 등이 모두 매칭됩니다.
Channels
채널은 클라이언트의 요청을 처리한다는 점에서 컨트롤러와 유사합니다. 하지만 채널은 크게 두 가지 점에서 컨트롤러와 차이점을 가지고 있습니다. 우선, 채널은 들어오는(incoming) 이벤트뿐만 아니라, 밖으로 전달되는(outgoing) 이벤트도 처리합니다. 또한, 채널의 연결은 하나의 요청/응답(request/response) 사이클 동안 끊기지 않고 유지됩니다. 채널은 Phoenix의 실시간 커뮤니케이션 컴포넌트들 가운데 가장 높은 수준의 추상화(abstraction) 입니다.
각 채널은 다음의 네 가지 콜백 함수 중 하나 이상을 구현합니다.
- join/3
- terminate/2
- handle_in/3
- handle_out/3
PubSub
Phoenix의 PubSub 레이어는 Phoenix.PubSub 모듈과 다양한 종류의 어댑터 모듈과 GenServer로 구성되어 있습니다. 이러한 모듈에는 채널 커뮤니케이션을 위한 토픽 구독, 토픽 해지, 메시지 브로드캐스팅과 같은 함수들을 포함하고 있습니다. 이러한 모듈들은 Phoenix 내부적으로 사용되며, 실제 애플리케이션을 구현할 때 직접 만들거나 수정할 필요는 없습니다.
만약, 개발 환경이 분산 Elixir나 서버간의 직접 통신을 지원하지 않는다면 PubSub 데이터 교환을 위해서 Redis Adapter를 이용할 수도 있습니다.
Messages
Phoenix.Socket.Message 모듈은 아래와 같은 키를 갖는 구조체를 정의합니다.
- topic : 토픽 문자열 (예. “messages”, “messages:123″)
- event : 이벤트명 문자열 (예. phx_join)
- payload : 메시지 내용
- ref : 고유한 문자열 참조
Topics
토픽은 메시지가 적합한 위치로 전송되는 데에 사용되는 문자열 식별자입니다. 앞에서도 설명했지만, 토픽 문자열은 와일드카드(wildcards)를 통해 패턴 매칭을 가능하게 합니다. 관례상 “topic:subtopic” 형식을 주로 사용합니다.
Transport
트랜스포트 레이어는 메시지 전송에서 가장 중요한 역할을 하며, Phoenix.Channel.Transport 모듈은 채널로 들어오거나 나오는 모든 메시지를 처리합니다.
Transport Adapters
Phoenix에서 기본 전송 메커니즘은 WebSocket을 통해 이루어지며, WebSocket 사용이 불가한 경우에는 LongPolling 방식으로 전환됩니다. 이 외에도 다른 트랜스포트 어댑터(adapter)를 사용할 수 있으며 직접 어댑터를 정의하여 사용하는 것도 가능합니다.
Client libraries (phoenix.js, etc)
Phoenix의 채널을 구성하는 공식 자바스크립트 클라이언트 라이브러리는 phoenix.js 이며, 이 외에도 3rd-party 라이브러리로 SwiftPhoenix(Swift – iOS), JavaPhoenixChannels(Java – Android), PhoenixSharp(C#) 등이 있습니다.
이번 포스트에서는 Phoenix 채널의 개념에 대해서 간단히 살펴보고 채널 시스템을 구성하는 각 컴포넌트들의 역할에 대해서 알아보았습니다.
실제 Phoenix의 채널 시스템이 어떤 식으로 동작하는지 이해하기 위해서는 간단한 실시간 애플리케이션을 직접 구현해보는 것이 좋은 방법이 될 수 있습니다. 대표적인 실시간 애플리케이션인 채팅 애플리케이션의 구현에 대해서 좀 더 알아보고 싶다면 “Phoenix Presence를 이용한 채팅 애플리케이션 만들기” 포스트를 참고하시기 바랍니다.
원문: GURUBLE BLOG