Akka의 MessageDispatcher
는 Akka 액터들이 말할 수 있게 해준다. 모든 Dispatcher
는 ExecutionContext
인터페이스를 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")
만약 기본으로 제공되는 디스패처 말고 다른 디스패처를 액터에게 제공하고 싶으면 2가지를 해야 한다.
위에서 알아보았듯, 가장 먼저 dispatcher 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을 참고하는 것이 좋다.
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 내부 설정을 하는 것이 좋다.
우리는 Akka에서 실행될 actor를 만들 때 다음과 같은 코드를 작성할 것이다.
// Main.scala
import akka.actor.Props
val myActor = context.actorOf(Props[MyActor](), "myactor")
액터 선언 방식은 같지만, configuration 파일에 다음과 같이 넣어야 한다.
akka.actor.deployment {
/myactor {
dispatcher = my-dispatcher
}
}
커스터마이즈한 디스패처를 어떤 액터에 넣을 것인지 직접 설정해주면 된다.
액터 선언 방식에서 직접 디스패처를 설정해주는 방법도 있다.
import akka.actor.Props
val myActor =
context.actorOf(Props[MyActor]().withDispatcher("my-dispatcher"), "myactor1")
기존에 Props
뒤에 .withDispatcher(디스패처명)
을 사용하면 디폴트 디스패처가 아닌, 커스터마이즈한 디스패처를 액터에게 적용시킬 수 있다.