[Akka] Classic Dispatchers

smlee·2023년 8월 24일
0

Akka

목록 보기
9/50
post-thumbnail

Dispatcher

Akka의 MessageDispatcher는 Akka 액터들이 말할 수 있게 해준다. 모든 DispatcherExecutionContext 인터페이스를 implement한다. 따라서 Future를 실행시킬 수 있다.

모든 ActorSystem은 디폴트 디스패처를 가지고 있고 특별한 지정이 없으면 디폴트 디스패처를 사용한다. 이 디폴트 디스패처는 akka.actor.default-dispatcher.executor에 존재한다. 만약 executor가 선택되지 않았다면, 대부분의 경우 매우 우수한 성능을 발휘하는 "fork-join-executor"가 선택된다.

Dispatcher 선언 방식은 다음과 같다.

// for use with Futures, Scheduler, etc.
implicit val executionContext = system.dispatchers.lookup("my-dispatcher")

액터를 위한 Dispatcher 세팅하기

만약 기본으로 제공되는 디스패처 말고 다른 디스패처를 액터에게 제공하고 싶으면 2가지를 해야 한다.

  1. dispatcher configuration을 작성해야 한다.
  2. deployment configuration에 dispatcher를 선언해야 한다.

dispatcher configuration

위에서 알아보았듯, 가장 먼저 dispatcher configuration을 작성해야 한다.

(1) fork-join-executor를 사용한 configuration

가장 먼저 dispatcher configuration은 다음과 형태로 작성된다. 이때, Executor로 fork-join-executor를 사용했는데 그 이유는 fork-join-executor가 대부분의 경우 가장 좋은 성능을 내기 때문이다.

커스텀 디스패처 명 {
  type = Dispatcher
  # 사용할 Execution Service
  executor = "fork-join-executor"
  # Configuration for the fork join pool
  fork-join-executor {
    # Min number of threads to cap factor-based parallelism number to
    parallelism-min = 2
    # Parallelism (threads) ... ceil(available processors * factor)
    parallelism-factor = 2.0
    # Max number of threads to cap factor-based parallelism number to
    parallelism-max = 10
  }
  # Throughput defines the maximum number of messages to be
  # processed per actor before the thread jumps to the next actor.
  # Set to 1 for as fair as possible.
  throughput = 100
}

위의 예시는 dispatcher에서 가장 많이 사용되는 fork-join-executor를 사용해서 작성한 dispatcher configuration이다.

executor = 로 사용할 executor를 선언해주고 큰 따옴표 안에 사용할 executor 명을 넣는다. 그리고 executor 명으로 중괄호를 열어 해당 executor에 대한 설정을 진행해준다.

그리고, 메시지 개수를 throughput을 사용해 설정해준다.

위의 fork-join-executor의 병렬성을 알아보기 위해선 JDK의 ForkJoinPool documentation을 참고하는 것이 좋다.

(2) thread pool-executor를 사용한 dispatcher

executor에는 "thread-pool-executor" 역시 어느 정도 사용하는데, 이 경우 예시는 다음과 같다.

blocking-io-dispatcher {
  type = Dispatcher
  executor = "thread-pool-executor"
  thread-pool-executor {
    fixed-pool-size = 32
  }
  throughput = 1
}

코드의 내용은 fork-join-executor를 사용할 때와 대부분 유사하다.

여기서 주의 해야할 점은, thread-pool-executor는 java.util.concurrent.ThreadPoolExecutor를 사용하므로 JDK의 ThreadPoolExecutor documentation을 읽고 thread-pool-executor 내부 설정을 하는 것이 좋다.

deploy configuration

(1) 액터 선언 방식 유지

우리는 Akka에서 실행될 actor를 만들 때 다음과 같은 코드를 작성할 것이다.

// Main.scala

import akka.actor.Props
val myActor = context.actorOf(Props[MyActor](), "myactor")

액터 선언 방식은 같지만, configuration 파일에 다음과 같이 넣어야 한다.

akka.actor.deployment {
  /myactor {
    dispatcher = my-dispatcher
  }
}

커스터마이즈한 디스패처를 어떤 액터에 넣을 것인지 직접 설정해주면 된다.

(2) 액터 선언 방식 변경

액터 선언 방식에서 직접 디스패처를 설정해주는 방법도 있다.

import akka.actor.Props
val myActor =
  context.actorOf(Props[MyActor]().withDispatcher("my-dispatcher"), "myactor1")

기존에 Props 뒤에 .withDispatcher(디스패처명)을 사용하면 디폴트 디스패처가 아닌, 커스터마이즈한 디스패처를 액터에게 적용시킬 수 있다.

Reference

0개의 댓글