import akka.actor.{Actor, ActorSystem, Props}
// 액터 정의
class HelloActor extends Actor {
def receive: Receive = {
case "hello" =>
sender() ! "world"
case msg =>
println(s"Unknown message: $msg")
}
}
// 메인 또는 테스트 앱
object HelloActorApp extends App {
// 액터 시스템 생성
val system = ActorSystem("HelloSystem")
// 액터 인스턴스 생성
val helloActor = system.actorOf(Props[HelloActor], name = "helloActor")
// 응답을 기다릴 임시 액터 생성
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.Await
import scala.concurrent.ExecutionContext.Implicits.global
implicit val timeout: Timeout = Timeout(5.seconds)
// 메시지 전송 및 응답 대기
val future = helloActor ? "hello"
val result = Await.result(future, timeout.duration)
println(s"응답: $result") // "world" 출력
// 종료
system.terminate()
}
|
"hello" 메시지를 받으면 sender() ! "world"로 응답을 보냄
ask 패턴(?)을 사용하여 응답을 Future로 받음
Await.result로 블로킹 방식으로 응답을 출력
public class HelloActor extends AbstractActor {
// 액터 생성 팩토리
public static Props props() {
return Props.create(HelloActor.class);
}
@Override
public Receive createReceive() {
return receiveBuilder()
.matchEquals("hello", msg -> {
getSender().tell("world", getSelf());
})
.matchAny(msg -> {
System.out.println("Unknown message: " + msg);
})
.build();
}
}
public class HelloActorApp {
public static void main(String[] args) throws Exception {
ActorSystem system = ActorSystem.create("HelloSystem");
ActorRef helloActor = system.actorOf(HelloActor.props(), "helloActor");
// 메시지 보내고 응답 기다리기
Future<Object> future = Patterns.ask(helloActor, "hello", 5000);
String result = (String) Await.result(future, Duration.create(5, TimeUnit.SECONDS));
System.out.println("응답: " + result); // "world"
system.terminate();
}
}
|
public class HelloActor : ReceiveActor
{
public HelloActor()
{
Receive<string>(msg =>
{
if (msg == "hello")
{
Sender.Tell("world");
}
else
{
Console.WriteLine($"Unknown message: {msg}");
}
});
}
}
class Program
{
static async Task Main(string[] args)
{
using var system = ActorSystem.Create("HelloSystem");
var helloActor = system.ActorOf<HelloActor>("helloActor");
// Ask 패턴으로 메시지 보내고 응답 받기
var response = await helloActor.Ask<string>("hello", TimeSpan.FromSeconds(5));
Console.WriteLine($"응답: {response}"); // "world"
await system.Terminate();
}
} |
class HelloActor : AbstractActor() {
override fun createReceive(): Receive {
return receiveBuilder()
.matchEquals("hello") {
sender.tell("world", self)
}
.matchAny {
println("Unknown message: $it")
}
.build()
}
companion object {
fun props(): Props = Props.create(HelloActor::class.java)
}
}
fun main() {
val system = ActorSystem.create("HelloSystem")
val helloActor = system.actorOf(HelloActor.props(), "helloActor")
val future = Patterns.ask(helloActor, "hello", 5000)
val result = Await.result(future, Duration.create(5, TimeUnit.SECONDS)) as String
println("응답: $result") // world 출력
system.terminate()
} |
코틀린은 액터모델을 채택했기때문에 서드파티툴없이 액터모델 이용가능합니다.
(akka,pekko 이용시 액터모델이 스트림,클러스터로 확장되는 툴은없기때문에 직접 구현해야함)
import kotlinx.coroutines.channels.actor
// 메시지 정의
sealed class Message
data class Greet(val replyTo: CompletableDeferred<String>) : Message
object Unknown : Message
// 액터 함수
fun CoroutineScope.helloActor() = actor<Message> {
for (msg in channel) {
when (msg) {
is Greet -> msg.replyTo.complete("world")
else -> println("Unknown message received: $msg")
}
}
}
fun main() = runBlocking {
val actor = helloActor()
val response = CompletableDeferred<String>()
actor.send(Greet(response))
println("응답: ${response.await()}") // 출력: world
actor.close()
} |
// hello_actor.py
import ray
# Ray 초기화
ray.init()
# 액터 클래스 정의
@ray.remote
class HelloActor:
def say(self, msg):
if msg == "hello":
return "world"
else:
return f"Unknown message: {msg}"
// main.py
import ray
from hello_actor import HelloActor
ray.init(ignore_reinit_error=True) # 이미 실행 중일 경우 무시
# 액터 생성
actor = HelloActor.remote()
# 메시지 전송 및 응답 받기
response = ray.get(actor.say.remote("hello"))
print(f"응답: {response}") # 출력: world
# 종료
ray.shutdown() |
-module(hello_actor).
-export([start/0, loop/0]).
start() ->
spawn(fun loop/0).
loop() ->
receive
{From, "hello"} ->
From ! "world",
loop();
{From, Msg} ->
From ! {error, "Unknown message: " ++ Msg},
loop()
end.
1> c(hello_actor). % 컴파일
2> Pid = hello_actor:start(). % 액터 시작
3> Pid ! {self(), "hello"}. % 메시지 전송
4> flush(). % 응답 확인
Shell output:
Shell got "world"
|
Lightweight 프로세스 (수십만 개 생성 가능)
모든 액터는 메시지 기반으로 통신
고장 격리 (let it crash 철학)
OTP 사용 시 supervision, 상태 관리, 분산까지 매우 쉬움
Akka는 Scala와 Java에서 사용 가능한 강력한 액터 기반 프레임워크로, 분산 시스템과 동시성 처리를 위한 도구를 제공합니다.
적용 사례:
LinkedIn: Akka를 활용하여 실시간 데이터 처리를 개선하고, 대규모 메시징 시스템의 성능을 향상시켰습니다.
Lightbend: Akka의 개발사로, 자체 제품과 서비스에 Akka를 적극 활용하여 고성능 애플리케이션을 구축하고 있습니다.
Java 진영에서는 Akka 외에도 Spring Integration과 같은 프레임워크를 통해 액터 모델의 개념을 적용하고 있습니다.
적용 사례:
Credit Karma: Akka를 사용하여 마이크로서비스 아키텍처를 구축하고, 사용자에게 실시간 신용 점수 업데이트를 제공하고 있습니다.
Netflix: Spring Integration을 활용하여 마이크로서비스 간의 메시지 기반 통신을 구현하고, 서비스 간의 결합도를 낮추는 데 기여했습니다.
Akka.NET은 .NET 환경에서 Akka의 기능을 제공하는 프레임워크로, C#과 F#에서 사용 가능합니다.
적용 사례:
Petabridge: Akka.NET의 주요 개발사로, 분산 시스템 구축을 위한 도구와 서비스를 제공하며, 자체 프로젝트에 Akka.NET을 활용하고 있습니다.
SIL International: Akka.NET을 사용하여 언어 학습 애플리케이션의 성능과 확장성을 개선하였습니다.
Kotlin에서는 언어 자체의 **코루틴(coroutines)**과 **채널(channels)**을 활용하여 액터 모델을 구현할 수 있습니다.
적용 사례:
JetBrains: Kotlin의 개발사로, 내부 도구와 애플리케이션에서 코루틴과 채널을 활용하여 비동기 프로그래밍과 동시성 처리를 효율화하고 있습니다.
Ray는 Python에서 분산 컴퓨팅을 위한 프레임워크로, 액터 모델을 지원하여 대규모 병렬 처리를 가능하게 합니다.
적용 사례:
OpenAI: Ray를 활용하여 대규모 머신 러닝 모델의 학습과 배포를 효율적으로 관리하고 있습니다.
Ant Group: 금융 서비스에서 Ray를 사용하여 실시간 데이터 분석과 위험 관리를 수행하고 있습니다.
Erlang은 언어 자체에 액터 모델이 내장되어 있어, 높은 동시성과 분산 시스템 구축에 적합합니다.
적용 사례:
WhatsApp: Erlang을 사용하여 수억 명의 사용자에게 안정적인 메시징 서비스를 제공하고 있습니다.
Ericsson: 통신 시스템의 신뢰성과 가용성을 높이기 위해 Erlang을 활용하고 있습니다.
Elixir는 Erlang VM 위에서 동작하는 언어로, 액터 모델을 활용하여 확장성과 유지보수성이 높은 애플리케이션을 개발할 수 있습니다.
적용 사례:
Discord: Elixir를 사용하여 대규모 실시간 채팅 시스템을 구축하고, 수백만 명의 동시 접속을 처리하고 있습니다.
Bleacher Report: Elixir를 활용하여 스포츠 뉴스와 관련 콘텐츠를 실시간으로 제공하는 플랫폼을 운영하고 있습니다.
이처럼 다양한 언어와 프레임워크에서 액터 모델이 구현되어, 여러 테크 기업에서 분산 시스템과 동시성 처리를 위한 핵심 도구로 활용되고 있습니다.
프레임워크: Akka
설명: JVM 기반의 대표적인 액터 프레임워크. 동시성, 분산, 스트리밍 처리 등에 최적화됨.
공식 문서:
프레임워크: kotlinx.coroutines
설명: Kotlin의 비동기 처리 라이브러리. Channel을 통해 액터 모델 구현 가능.
공식 문서:
프레임워크: Akka.NET
설명: Akka를 .NET 환경에 포팅한 분산 액터 시스템
공식 문서:
프레임워크: Ray
설명: 대규모 분산처리와 액터 모델을 지원하는 Python 진영 프레임워크
공식 문서:
프레임워크: Erlang/OTP
설명: 언어 자체에 액터 모델 내장, OTP로 supervisor, gen_server 등을 지원
공식 문서:
프레임워크: Elixir + OTP
설명: Erlang VM 위에서 작동, 액터 모델 구현에 친숙하고 생산성 높음
공식 문서:
Apache Pekko는 **Akka의 오픈소스 포크(fork)**입니다.
Lightbend가 Akka를 Business Source License(BSL)로 변경하면서, 커뮤니티는 Apache 2.0 기반인 Pekko로 갈라져 나왔습니다.
JVM 기반의 분산 액터 시스템이며 Akka와 거의 동일한 API를 사용합니다.
완전한 오픈소스 (Apache 2.0)
Akka와 거의 호환되며, 기존 코드를 마이그레이션 가능
액터, 스트림, HTTP, 클러스터링 기능 포함
마이크로서비스 아키텍처
실시간 메시징/스트리밍
이벤트 소싱 기반 시스템
Orleans는 Microsoft가 개발한 .NET 기반의 Virtual Actor 시스템입니다.
복잡한 상태 관리, 분산 스케줄링, 클러스터링을 추상화하여 쉽게 확장 가능한 시스템을 구축할 수 있게 해줍니다.
일반적인 액터 모델과 달리, Orleans는 가상 액터(Virtual Actor) 개념을 채택해 수명 관리가 자동화됩니다.
상태 기반의 액터 (Grain), 자동 활성화/비활성화
분산 캐시처럼 작동하면서도 동시성 처리 가능
Azure, Kubernetes 등 클라우드 친화적
Microsoft Xbox Live: 수억 명의 게이머 세션 관리
Halo 4 Backend: 대규모 게임 데이터와 이벤트 처리
재무, AI, IoT 백엔드 등에서 확장성 요구되는 분야