You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 16 Next »

Remote 는, 기존 작성했던 액터를 그대로 재활용하여 , 액터설계의 코드변경없이

원격지에서 사용이 가능합니다. 이것은 아주 큰장점입니다. 대부분의 비동기처리에 있어서

로컬에서도 휼륭한 역활을 하지만 , 원격에 배치를 하여 메시지처리를 휼륭하게 합니다.

이것이 Actor를 굳이 RemoteActor라고 부르지 않는 이유입니다.


이전에 학습한 Router를 참조하여, 3대정도의 서비스를 뛰워 원격 라운드로빈 처리가 가능한지

샘플 코드작성을 해보는것을 추천합니다. 그리고 이것은 액터설계에 아무런 변경이 없다란 장점을 알게될것입니다.

설정
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는 해당 주소로 리모트서비스를 제공하겠다란 옵션입니다.


원격 처리를 위해 메시지정의 공용 DLL로 집합
    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에게 메시지를 보낸 상황을 가정해보겠습니다.

1.Data공용 ClassLib 프로젝트추가하기(DLL)

2.프로젝트에서 CommonActor 프로젝트 참조추가


공용 DLL이 필요한 이유는 간단합니다. 원격에 있는 SeviceA , ServiceB가 동일하게

정의된 Data구조를 참조하여 같은의미로 해석하게 하기위함입니다.

Actor는 같이 사용되지 않으면 공유될 필요는 없습니다. 학습편의상 동일한 곳에

집합하고 다른 프로젝트에서 동일한 액터가 필요할때 공용액터를 정의할수 있으나

프로젝트마다 DLL의존성이 생기기때문에 신중해야합니다.

Data 설계는 의존성을 피할수없으며 변경된것을 해당 Data를 다른액터에게 전달할수 있지만,

해석을 못할수 있으니 유연한 데이터설계가 필요합니다.

내부적으로 지정된 JsonSerialization이 자동으로 작동이됩니다.

원격간 Data설계 변경에 따른 DLL의존성은 AKKA.net 에서 어떻게 해결을 할지

관련 자료를 좀더 찾아볼 예정입니다.

ServiceA
			using (ActorSystem actorSystem = ActorSystem.Create("ServiceA"))
            {
                IActorRef myActor = actorSystem.ActorOf<EchoActor>("myactor");
                //콘솔 종료 방지 코드 생략...
            } //port 8001

ServiceA 는 EchoActor를 제공하기만 하면됩니다.



ServiceB
			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 특정 액터에게 전송이 가능합니다.

로컬에서 작동과 차이점은 주소체계를 앞부분에 넣은준것외에 다른점이 없습니다.


액터 설계시 주의점

우리는 EchoActor를 통해 자신이한 인사가 되돌아오는것을 확인하였습니다.

하지만 이러한 가정을 해봅시다. EchoActor1가 EcshoActor2 에게 인사를 합니다.

어떠한 상황이 펼쳐질까요? 메시지간 무한반복이 됩니다. 인사를하고 인사를 받고 또하고 받고하는

끝나지 않는 상황이 됩니다. 응답시간이 0 이라고 가정해봅시다.

이것은 무한대의 메시지 처리가 될것입니다. 마치 거울두개를 맞되어 무한의 이미지가 투영되는것으로

슈퍼컴퓨터도 이것을 처리할수 없습니다. 보통 메모리가 풀에 다다른 이후 GC에의한 CPU 100% 가 예상됩니다.

가끔 이것을 컴퓨터가 얼마나 버티냐? 호기심에 부하테스트를 하기도합니다.

네트워크상황이 더 좋을수록 이것은 보통 더 빨리 크래쉬가 납니다.


이러한 실수를 방지하려면 보통 네이밍 기법으로 해결합니다.

Hello ==> HellowReq , HelloRes 이렇게 요청과/응답을 분리를 합니다.

인사의 속성을 살펴보면, 같은 안녕이지만 처음 인사는 인사의 응답을 받는 숨은 의미가 있습니다.

그래서 HellowReq (Request) 입니다. 인사에 대응하는 안녕은 응답을 해주고, 다음에 그어떤 기대가

숨어있지 않습니다. 그래서 HellowRes(Response) 입니다.

하지만 이방식은 일반적인 방식은 아니며 , 전통적인 패킷설계방식을 적용한것입니다.

액터는 메시지 네이밍에 관여하지 않고, 처리지정된 메시지패턴만 가지고 처리하려고 하기때문에

이것은 응용개발자가 더 좋은 방법으로 설계를 할수가 있을것입니다.

추가적으로 액터메시지는, 전송이후 메시지를 변조하는것을(메시지는 전송이후 불변이여야한다의 원칙)

일반적으로 금지하고 있습니다.(어떠한 전략에의해 복사/변경할수 있는 전략을 쓰기도 하지만 일반적이진 않습니다.)




  • No labels