비동기 프로그래밍 관점에서의 Akka

Posted by 엘키의 주절 주절 on June 21, 2018

Akka란 Actor 기반 시스템의 한 구현체이다. 메시지를 주고 받을 수 있는 단위를 Actor로 놓고, Actor간의 통신을 메시지 수신으로써 처리하는 개념이다.

Win32에서의 메시지 기반 프로그래밍의 수신자를 여러 개 두는 개념이라고 봐도 무방하다. 프로세스 내에서의 메시지 단위 통신이라고 할까?

지켜야 할 것은 다른 Actor간의 메소드 직접 호출이 있어선 안된다는 점이다. Life-cycle이 유지되고 있는 Actor에 대한 메소드 호출은 동기화가 깨진다.

Akka는 메소드 직접 호출보다는 느리지만, 메시지 큐를 통한 접근 스레드를 하나만 유지함으로써, 멀티 스레드 동기화 이슈를 우회하는 접근이다.

싱글 스레드 구조에서, 요청에 대한 위임, 그에 대한 응답을 메시지 큐를 통해서 처리하는 WIN32 메시지 기반 프로그래밍이나 Node.js 방식과 차별화 된 요소는 바로 이 점이다.

주체적으로 동작하는 개체를 여러 개로 두면서도 (=멀티 스레드로 로직이 동작하면서도), 스레드 동기화에 대한 이슈를 제거했다.

이 경우의 핵심 고려 요소는 메시징 시스템 자체는 멀티 스레드 기반하에 동작시키게끔 구현되어야 하며, 메시징 시스템의 성능이 크게 영향을 주므로, 뛰어난 성능이 보장되어야 한다.

또한 Actor에 대한 Life-Cycle관리가 아주 중요하다.

이런 몇가지 고려 요소에 대해 신경쓴다면, 그만큼 얻을 수 있는 이득은 크다.

가장 중요 한 것은 멀티 프로세스보다 성능이 좋은 멀티 스레드 비동기 병렬 프로그래밍 로직을 적은 고민으로 구현 해낼 수 있다는 점이다.

Akka는 인프로세스 메시징 큐를 사용하는 것보다 좀 더 고차원적인 병렬 처리와 fail-over, persistence 등을 지원한다.

자세한 내용은 http://wiki.webnori.com/pages/viewpage.action?pageId=1507350를 참고하면 더 깊게 이해할 수 있다.

내가 Akka를 쓰면서 놀라웠던 것은, 몇가지 쉬운 원칙만 지키면 멀티 스레드 로직 프로그래밍보다 안전하면서도 높은 성능(through-put)의 시스템을 구축 할 수 있었다는 점이다.

멀티스레드 로직 프로그래밍은 조금만 삐끗나도 lock이 길어지거나, spin-lock이 발생하거나, 경합, 데드락이 발생하기 쉽상인데 그런 측면에서의 우려가 적으면서도 성능도 우수했으며 scale out에도 유연했다.

즉 직접 네트워크 라이브러리를 구현하는 사람 (Netty, SuperSocket, Asio 등등)이 아니라면 난이도도 높고, 막상 멀티스레드 로직을 직접 구현할 것이 아니라 Akka와 같은 비동기 메시징 시스템을 사용하는 것이 좋다고 본다.

함수형 프로그래밍도 내부적 상태를 갖지 않는 함수들 만으로 구현함으로써, 가변 데이터로 인해 생기는 데이터 안정성과 병렬 처리의 어려움에 대해서 회피하고자 다시금 주목 받은 측면이 크다.

함수형 프로그래밍의 이질감과 비직관성에 대한 적응이, 멀티 스레드 로직 프로그래밍이 가진 높은 복잡도와 제약들 보다 낫다는 결론이 한쪽 진영에서 있었다고 생각한다.

그걸 감안한다면 Akka와 같은 Actor기반 프로그래밍은 또 하나의 좋은 대안이고, 많이 선택되어 왔다.

사실 Akka는 함수형 프로그래밍과 멀티스레드 로직 구현과의 중간점에 존재하는 느낌도 강하다.

Akka를 통해 상태 기반 프로그래밍도 가능하지만 이는 몇가지 대안과 함께하지 않으면 fail-over를 어렵게 만드는 리스크가 되기도 하고, 함수형으로 시스템을 완성할 수 있으면 굳이 Akka를 쓰지 않아도 되기 때문인 측면이 있기 때문이다.

하지만 상황에 따라선 상태 기반 프로그래밍을 써야할 때가 있다. 또한, 캐싱을 통해 크래시가 발생했을 때의 리스크를 줄이는 접근을 통해 리스크 최소화를 하는 접근도 납득할만하다.

여러가지 측면에서 봤을 때, 함수형 프로그래밍이 좀 더 지지를 받고 있는 상황임에도, Akka와 같은 Actor 기반 프로그래밍도 현재로썬 적절한 병렬 처리 선택지 중 하나 아닐까 싶다.