[Akka] Actor Selection을 통한 Actor 구분

smlee·2023년 8월 23일
0

Akka

목록 보기
4/50
post-thumbnail

각 Actor들은 고유한 논리적인 경로를 가지고 있다. 이러한 논리적 경로는 자식 액터부터 부모 액터로 타고 올라가 최후에는 액터 시스템의 루트, 즉 액터 시스템의 최상위까지 갈 수 있다.
이러한 경로들은 액터들을 찾기위해 사용된다. 예를 들어 메시지 수신자를 찾을 때, 직접적으로 갈 수 있는 경로를 찾는 것이다.
Actor들은 다른 액터들과의 상대 경로나 절대 경로를 통해 구분된다. 즉, 논리적 혹은 물리적 경로를 통해 구분된다. 그리고, 이 결과는 ActorSelection에서 결과를 가져올 수 있다.

대부분의 경우, ActorRef를 통해 다른 액터와 커뮤니케이션을 하는 것이 선호되지만, 다음과 같은 예외가 있다.
1. at least once delivery를 사용하며 메시지를 보낼 때
2. remote system과 최초로 컨택 후 초기화할 때

at least once delivery
at-least-once delivery는 분산 데이터 파이프라인에서 데이터 전달 보장 방법 중 하나이다.

at-least-once delivery는 최소한 한 번 메시지 전송 보장으로 sender가 메시지를 전송하고 일정 시간 내에 receiver에게 ACK를 받지 못했다면 다시 메시지를 전송하는 방식이다.
Receiver가 메시지를 받았다는 ACK 패킷을 확인할 때까지 계속 메시지를 전송하므로 최소한 한 번의 메시지 전송을 보장한다.
이 방법은 중복 메시지 발생 가능성이 높으므로 중복 메시지가 있어도 되는 경우 사용한다.

// will look up this absolute path
context.actorSelection("/user/serviceA/aggregator")
// will look up sibling beneath same supervisor
context.actorSelection("../joe")

코드에서는 위와 같이 context.actorSelection(상대 혹은 절대 경로) 형태로 코드를 작성한다. 이때, 안에 들어갈 경로들은 java.net.URI로 파싱된다. 즉, / 단위로 경로 원소들을 나누는 것이다. /로 시작한다면 루트로 시작한다고 생각한다. 그것이 아니라면, 현재 액터로부터 시작하는 경로로 생각한다.

// serviceB 디렉터리 내의 worker로 시작하는 모든 자손들을 확인
context.actorSelection("/user/serviceB/worker*")

context.actorSelection("../*")

위와 같이 *을 사용하여 와일드카드를 나타낼 수도 있다.
위와 같이 ActorSelection의 내부에 있는 경로를 통해 메시지들이 전송될 것이다. 그리고, 해당 메시지에 답신을 보내기 위해서는 sender라는 메서드를 사용할 것이다.

sender()
메시지의 발신자를 리턴한다.

이때, 모든 액터들이 이해하고 자동적으로 ActorRef를 담고 있는 ActorIdentity로 답신하는 빌트인 Identify 메시지가 있다. 이 매시지는 구체적인 이름 찾기가 실패할 경우 순회하여 답을 찾아낸다.

import akka.actor.{ Actor, ActorIdentity, Identify, Props, Terminated }

class Follower extends Actor {
  val identifyId = 1
  context.actorSelection("/user/another") ! Identify(identifyId)

  def receive = {
    case ActorIdentity(`identifyId`, Some(ref)) =>
      context.watch(ref)
      context.become(active(ref))
    case ActorIdentity(`identifyId`, None) => context.stop(self)

  }

  def active(another: ActorRef): Actor.Receive = {
    case Terminated(`another`) => context.stop(self)
  }
}

위의 코드는 /user/another라는 경로에서 액터를 찾아 Identify(1)을 보내고, 응답을 받았을 때 해당 ref에 active 메서드를 적용시키는 코드이다.
이때 유의할 점은 응답이 보장되는 것은 아니다라는 사실이다.

Reference

0개의 댓글