[java] Akka의 액터 모델과 메시지 패싱

Akka는 자바와 스칼라를 위한 액터 기반 프레임워크입니다. 액터는 동시성을 처리하기 위한 식별 가능한 엔티티로, 각각 독립적으로 실행되며 메시지를 주고받을 수 있습니다. 이러한 액터 모델은 선점형 스레드 대신 비선점형 메시지 패싱을 사용하여 동시성 문제를 해결합니다.

액터의 개념

액터는 최소 기능 단위로, 동작을 정의하고 메시지를 받거나 전송할 수 있는 개체입니다. 각 액터는 고유한 식별자(ID)를 가지며, 동작을 수행하는 동안 상태를 유지할 수 있습니다. 액터는 다른 액터와 상호작용하기 위해 메시지를 전송하며, 메시지는 비동기적으로 처리됩니다.

액터는 다음과 같이 정의할 수 있습니다.

public class MyActor extends AbstractActor {

  @Override
  public Receive createReceive() {
    return receiveBuilder()
        .match(Message.class, this::handleMessage)
        .build();
  }

  private void handleMessage(Message message) {
    // 메시지 처리 로직
  }
}

액터 클래스는 AbstractActor를 상속하고 createReceive 메서드를 오버라이드하여 메시지 핸들링 로직을 정의합니다. receiveBuilder를 사용하여 메시지 타입에 따른 처리를 등록할 수 있습니다.

메시지 패싱

액터는 메시지를 비동기적으로 전송하고 처리합니다. 메시지는 불변(immutable)하며, 액터 간에 전송될 때 복사되어 전달됩니다. 메시지를 보내려면 액터의 ActorRef를 획득하여 tell 메서드를 호출합니다.

ActorRef myActorRef = actorSystem.actorOf(Props.create(MyActor.class));
myActorRef.tell(new Message(), ActorRef.noSender());

ActorRef는 액터에 대한 참조로, 액터에게 메시지를 보내는 데 사용됩니다. tell 메서드의 두 번째 인자는 응답을 받을 액터의 ActorRef입니다. ActorRef.noSender()를 사용하여 응답 미수신을 나타낼 수 있습니다.

메시지 처리

액터가 메시지를 수신하면 createReceive 메서드에서 정의한 핸들러가 호출됩니다. 핸들러는 메시지 타입에 따라 분기하여 로직을 수행합니다. 메시지 처리 중 다른 액터와의 상호작용이 필요한 경우, 해당 액터에게 메시지를 보내거나 ActorRef를 전달하여 응답을 받을 수 있습니다.

private void handleMessage(Message message) {
  // 다른 액터에게 메시지 전송
  otherActorRef.tell(new OtherMessage(), getSelf());

  // 응답 처리
  getContext().become(waitingForResponse());
}

private PartialFunction<Object, BoxedUnit> waitingForResponse() {
  return ReceiveBuilder
    .match(Response.class, this::handleResponse)
    .build()
}

private void handleResponse(Response response) {
  // 응답 처리 로직
}

getSelf 메서드는 현재 액터의 ActorRef를 반환합니다. getContext를 통해 액터의 상태와 동작을 변경할 수 있는 메서드에 접근할 수 있습니다. 예를 들어, become 메서드를 사용하여 다음 메시지 처리를 위한 새로운 핸들러를 등록할 수 있습니다.

결론

Akka의 액터 모델과 메시지 패싱은 동시성 문제를 해결하는 강력한 도구입니다. 메시지를 주고받는 액터는 독립적으로 실행될 수 있으며, 비선점형 패러다임을 통해 더욱 안정적인 동시성 처리를 가능하게 합니다. Akka를 사용하여 복잡한 동시성 문제를 간결하게 해결할 수 있습니다.