Akka framework 입문기

Youngoh Kim
Spoonlabs
Published in
6 min readSep 8, 2020

스푼라디오 서비스 플랫폼 팀의 메시징 파트에서 채팅 서버 개발을 맡고 있는 Elliott입니다. 현재 구축되어 있는 채팅 서버를 공부하면서 느낀 점과 Akka에 대한 내용을 조금 정리하려고 합니다.

들어가며

채팅 서버는 많은 트래픽을 안정적이고 확장성 있게 제공하는 것이 꽤나 어려운 일입니다. 이는 실시간으로 동작하는 서비스에서 고려해야 할 부분이 몇 가지 존재하기 때문인데요.

  • 물리적인 스케일 확장/축소에 대응이 되어야한다.
  • 새로운 배포가 발생하는 경우 기존에 접속한 사용자에 대한 끊김없는 서비스가 가능해야 한다.
로드 밸런싱에 의해서 같은 채팅방 사용자가 다른 인스턴스에 연결된다면??

이전에 “Go”을 이용하여 웹 소켓 서버를 구현할 때 물리적인 스케일 아웃을 고려하면서 개발하는 것에 상당히 어려움을 많이 겪었던 경험이 있습니다.

당시에는 결국 스케일 아웃이 되지 않는 중계 서버(WebSocket Hub)를 하나 만들어서 웹 소켓 서버들에 대한 메시징 처리를 했는데 이런 방식으로 구현된 서버는 스케일 Out/In에 대해 불안정하게 대응되며 서버들이 중계 서버에 완전하게 종속되어버리는 문제가 있었습니다.

이런 문제를 해결하기 위해서 실시간으로 처리되는 메시지들은 AMQP 서버를 사용하여 메시징을 처리하는 방식으로 좀 더 안정적으로 개량하긴 했으나 그렇게 만족스럽진 않았습니다.

그런데 이렇게 복잡하게 생각해야 하는 문제들을 Akka framework를 사용하게 되면 비교적 단순하게 해결할 수 있었습니다.

구성요소

일단 기본적으로 Akka가 어떤 형태로 구성되어 있는지 간단하게 살펴보도록 하겠습니다. Actor model 을 기반으로 만들어진 Akka는 몇 가지 Component로 구성되어 있습니다.

  • Dispatcher: Actor System 내에서 실행되는 모든 코드를 스케줄링하며 각 Actor의 처리량과 시간 점유율을 조정하여 각자에게 공정한 리소스를 제공한다.
  • Mailbox: Dispatcher에서 들어오는 메시지를 담는 메시징 큐로 Actor마다 Mailbox를 가지고 있으며 들어온 메시지의 순서대로 Actor에서 소비된다.
  • Actor: 시스템을 구성하는 일종의 행위 객체로 메시지를 실질적으로 필요로 하는 소비자 및 송/수신자이다.
액터는 어떤 구조로 통신을 하는가?

계층구조

Akka Actor 계층 구조는 트리 형태로 표현 가능하며, Parent Actor node는 다수의 Child Actor node를 가질 수 있어 Parent Actor 가 Child Actor를 생성, 삭제할 수 있습니다.

Akka framework Actor architecture

Actor 예제

ParentActor에서 메시지 라우팅을 통한 행동들을 정의한다.
ChildActor에서 메시지 라우팅을 통한 행동을 정의한다.

위와 같은 방식으로 Actor의 행동 및 계층 구조를 설계해서 메시지를 전송할 수 있게 만들면 유연하고 간단하게 메시지에 따라 프로세싱을 할 수 있습니다.

UserChat -> ChatRoom -> Broadcast to all users

채팅방을 구현한다고 한다면 그림과 같은 구조로 Actor들을 설계해서 구현할 수 있습니다.

정말 간단한 수준의 채팅 서버에 대한 Actor 설계지만 Akka framework를 이용하면 실제로 고성능의 채팅 서버를 비교적 간단하게 만들 수 있으며, Actor의 상태 변경 및 행동 지시는 메시지 통신을 통한 간접적 지시에 의해 처리됩니다.

메시지가 발생하면 원하는 액터에게 메시지를 보낼 수 있다.

메시지를 통해 행동이 결정되면 Actor 자신의 상태를 변경하거나 Child Actor를 만들거나 죽이고, 다른 Actor에 메시지를 보낼 수 있습니다.

마치면서..

Akka framework는 비교적 적은 비용을 들여서 동시성이 필요한 개발을 할 수 있게 해주는 좋은 도구로 여러 가지 장단점이 있는데 이 중에서 제가 직접 느낀 부분만을 정리해보자면 아래와 같습니다.

장점

  • 직관성: Actor model이라는 개념 자체가 꽤 직관적인 부분이 있어 내가 원하는 Actor를 정의해서 Actor 간의 통신을 구성하는 것이 상대적으로 쉽다.
  • 확장성: Akka framework는 클러스터 형식으로 운영할 수 있기 때문에 물리적인 확장성에서도 대응이 된다.
  • 격리성: Actor에 직접적인 제어권을 갖거나 접근하기 위한 API가 존재하는 게 아니라 모든 것이 메시지로 인해서 비동기적으로 동작하기 때문에 직접적으로 다른 Actor에 영향을 줄 가능성이 거의 없다.

단점

  • 유지 보수: Actor들의 행위가 메시징을 통해서 이뤄지다 보니 Actor의 행위 및 메시지 등에 의하여 전체 시스템에 대한 이해가 없으면 유지 보수하기 어려워질 수 있다.
  • Type Not Safe: 정적언어의 컴파일 타임에서 개발자의 실수를 최소한으로 줄여주는 장점을 활용하기 어렵다. Actor의 메시지 송수신 타입이 Any이기 때문이다.(Akka Typed를 사용하면 되긴 한다고 한다.)

--

--