지금까지 로컬에서 액터를 만드는 연습을 하였다고 하면, 이번 장에서는
자신의 로컬 객체가 어떻게 코드변경을 최소화하고 두개의 분리된 어플리케이션이 액터를 통하여 고성능 통신을 할수 있는가 살펴보겠습니다.
리모트 객체만으로도 액터는 휼륭한 기능들을 수행하지만, 클러스터로 가기위한 워밍업을 위해 리모트 객체의 이해는 필수입니다.
Remote 는, 기존 작성했던 액터를 그대로 재활용하여 , 액터설계의 코드변경없이
원격지에서 사용이 가능합니다. 이것은 아주 큰장점입니다. 대부분의 비동기처리에 있어서
로컬에서도 휼륭한 역활을 하지만 , 코드 변경없이 원격 배치가 가능합니다.
akka {
actor {
provider = "Akka.Remote.RemoteActorRefProvider, Akka.Remote"
}
remote {
helios.tcp {
port = 8001 #bound to a specific port
hostname = 127.0.0.1
}
}
}
App.config 에 앞 섹션에서 이미 설정했듯이, 위 설정을 통해 이미 원격사용하기 위한 환경설정이 끝났습니다.
- provider : 원격 객체처리를 위한 원격처리 모듈을 어떤걸로 쓸것인가 지정 가능합니다. ( 현재 기준 기본값 사용)
- helios.tcp : provider중에 제공하는것중에 실제로 , transports에 해당하는 옵션으로 tcp / udp 등선택이 가능합니다.
- 그외 ip/port는 해당 주소로 리모트서비스를 제공하겠다란 옵션입니다.
public class Hello { public Hello(string message) { Message = message; } public string Message { get; private set; } } public class EchoActor2 : ReceiveActor { public EchoActor2() { Receive<Hello>(hello => { Console.WriteLine("[{0}]: {1}", Sender, hello.Message); Sender.Tell(hello); }); } }
전송에 사용될 Class는 공용 DLL에 정의 되어 , 공용 DLL에 위 내용을 추가한후
ServiceA / ServiceB가 에 참조를 하여야 하고
ServiceB가 ServiceA의 EcshoActor에게 메시지를 보낸 상황을 가정해보겠습니다.
using (ActorSystem actorSystem = ActorSystem.Create("ServiceA")) { IActorRef myActor = actorSystem.ActorOf<EchoActor>("myactor"); //콘솔 종료 방지 코드 생략... } //port 8001
ServiceA 는 EchoActor를 제공하기만 하면됩니다.
using (ActorSystem actorSystem = ActorSystem.Create("ServiceB")) { //자신이 가진액터가 아닌, 원격지의 액터 선택이기 때문에 ActorSelection 을 사용합니다. ActorSelection otherActor = actorSystem.ActorSelection("akka.tcp://ServiceA@127.0.0.1:8001/user/myactor"); Hello msg = new Hello("Hello"); otherActor.Tell(msg); //콘솔 종료 방지 코드 생략... } //동일 컴퓨터이니 ServiceB의 설정포트를 8002로 변경
위와 같이 ActorSelection을 원격주소를 입력함으로, 상대 AkkaSystem 특정 액터에게 전송이 가능합니다.
로컬에서 작동과 차이점은 주소체계를 앞부분에 넣은준것외에 다른점이 없습니다.
액터 메시지 설계시 주의점
두 액터간 메시지를 주고 받을때, 인사(Hello)에 항상 반응 하는 두 액터가 있다고 가정해봅시다.
두 액터중 아무나 먼저 상대 액터에게 인사를 시작하면 두액터는 무한대로 인사를 주고 받을것입니다.
네트워크에서 발생할수 있는 무한루프이며, 네트워크 지연이없을수록 하드웨어 자원(CPU,메모리)를 빠르게 고갈시킬것입니다.
이러한 실수를 방지하기위해 전통적인 방법으로는 전송 오브젝트에대해 요청(Req)과 응답(Res)을 분리하여 네이밍을 할수 있습니다.