Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info

Actor로 설계된것은 원격으로 확장이 가능하기때문에 RemoteActor라는 객체는 존재하지 않습니다.

단지 로컬액터와 동일한 방식으로, 원격지 액터와 대화를 할수 있으며

직렬화,TCP 통신방식등은 몇가지 설정으로 변경가능하며 Akka에게 맞기면 됩니다.


사용준비조건

No Format
//메이븐 설정추가
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-remote_2.11<12</artifactId>
  <version>${akka.version}</version>
</dependency>


//application.conf 설정 추가
akka {
  actor {
    provider = remote
  }
  remote {
    enabled-transports = ["akka.remote.netty.tcp"]
    netty.tcp {
      hostname = "0.0.0.0"
      port = 2552
    }
 }
}



// 로컬로 설계된 메시지,직렬화 상속받기
public class SomeMessage implements Serializable {
....}

...

  • 메이븐에 Remote추가 : netty를 비롯하여 원격통신에 필요한 몇가지 라이브러리가 포함됩니다.
  • 원격포트 설정 : 하나의 통신 포트에 수십만개의 액터를 등록하여 관리할수 있습니다. 그리고 이것은 스레드가아닌 힙에관리되기때문에 가볍습니다.
  • 로컬메시지 객체 직렬화하기 : 로컬에서만 작동가능한 메시지에 Serializable 상속을 받아, 단지 직렬화 가능한 객체를 전송을 하면됩니다.


액터주소의 이해

Image Added

  • protocol : akka 는 기본적으로 tcp 연결지향형 프로토콜을 사용합니다.
  • actorsystem : 액터시스템은 하나의 이름을 가지게됩니다. 액터시스템 생성시 결정이됩니다.
  • address : 액터시스템이 있는 물리적 위치입니다.
  • path : 액터는 탑다운방식으로 생성되며 user하위에 계층적으로 생성되게 됩니다.
ActorSelection testActorRemote = actorSystem.actorSelection("akka.tcp://app@localhost:2552/user/service1");

액터시스템은 원격의 액터선택이 가능하며

testActor.Remote.tell(...) 을 통해 메시지 전송이 가능합니다.


컨셉

draw.io Diagram
bordertrue
viewerToolbartrue
fitWindowfalse
diagramNameremoteactor
simpleViewerfalse
width
diagramWidth903
revision2

...

구현 단순화를 위해서 RestAPI로 전환할수도 있지만, 안정적으로 대량의 데이터를 고성능으로 전송하기에는 무리가 있습니다.


구현코드의 난이도를 올리지 않고 연결지향적이면서도 고성능통신을 할수 있는방법중 하나가

TCP 피어투피어방식을 사용하는 RemoteActor입니다.

구현코드는 간단해지고, 일반적인 일반적으로 재접속 처리 문제를 신경쓸필요가 없습니다. ( 연결복구기능이 기본 탑재되며, 필요하면 장애시 재전송룰 적용가능)  


활용될수 있는 기능

  • A1,A3에 일어난일을 A2에게 모두보고하여 로그를 집합할수 있습니다. 
  • B1에서 일어난 일을 A2에게 보고하고 DB형님이 안바쁠때 변경사항을 알려줄수 있습니다.(A2만 DB제어를 한다고 가정하고 DB 호출량제어가능)
  • 이미 존재하는 미들웨어에서 쌍반간 통신의 길을 뚫어줌으로, 관리요소추가(MQ시스템)없이 스스로 연락을 할수 있습니다.
  • 라운드로빈/브로드캐스트등 특수한 라우티이용도가능하며, 클러스터화 전환도 용이합니다. ( 보너스 기능).
  • 메시지기반으로 설계된 것은, RabbitMQ및 카프카와같은 외부 MQ 시스템과도 연동이 수월해집니다.


그럼 구현체가 얼마나 간단해졌는지 살펴보겠습니다.

서버 구현체

Code Block
languagejava
themeEmacs
public class TestActor extends UntypedActor UntypedAbstractActor{
    private final LoggingAdapter log = Logging
            .getLogger(getContext().system(), "TestActor");

    @Override
    public void onReceive(Object message) throws Exception {    	    	
    	if(message instanceof String) {	//String뿐만 아니라 모든 Java객체 통신가능
    		log.info("Incommessage {}", message);
    		sender().tell("너의 메시지에 응답을함", ActorRef.noSender());    		
    	}else {
    		log.info("Unhandle Message {}", message);    		
    	}    	
    }
}


//service1 이름으로 액터의 엔드포인트를 생성했습니다.
ActorRef testActor = system.actorOf(ext.props("testActor"),"service1");  //Service1이란 이름으로 TestActor를 생성함


사용측

Code Block
languagejava
themeEmacs
//엔드포인트를 통한 액터선택자
ActorSelection testActorRemote = system.actorSelection("akka.tcp://app@localhost:2552/user/service1");


//리모트를 통한 전송
testActorRemote.tell("발사후망각-응답필요없음",ActorRef.noSender() );  //ActorRef에 수신녀석을 지정하여 어떠한 결과를 받을수도 있습니다.

//응답이 동기적으로 필요한경우
CompletableFuture<Object> future1 =
		  ask(testActorRemote, "응답하라 1979", 1000).toCompletableFuture();

//너의 메시지에 응답을함 이란 메시지를 받음 -이해를 돕기위해 동기처리로 전환
String result = String.valueOf(future1.get());  
Expand
title실행로그

[INFO] [05/05/2018 15:15:29.433] [AkkaTestApp-akka.actor.default-dispatcher-5] [TestActor] Incommessage ready spring boot

[INFO] [05/05/2018 15:15:29.435] [AkkaTestApp-akka.actor.default-dispatcher-5] [TestActor] Incommessage ready spring boot -again
[INFO] [05/05/2018 15:15:29.435] [AkkaTestApp-akka.actor.default-dispatcher-5] [TestActor] Incommessage 발사후망각-응답
[INFO] [05/05/2018 15:15:29.438] [AkkaTestApp-akka.actor.default-dispatcher-3] [TestActor] Incommessage 응답하라 1979
[INFO] [05/05/2018 15:15:29.441] [main] [Application] msg result:너의 메시지에 응답을함
[INFO] [05/05/2018 15:15:29.800] [AkkaTestApp-akka.actor.default-dispatcher-4] [TestActor] Incommessage fasmsg to slow 0[INFO] [05/05/2018 15:15:29.800] [AkkaTestApp-akka.actor.default-dispatcher-2] [akka://AkkaTestApp/deadLetters] Message [java.lang.String] without sender to Actor[akka://AkkaTestApp/deadLetters] was not delivered. [4] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
[INFO] [05/05/2018 15:15:29.934] [AkkaTestApp-akka.actor.default-dispatcher-4] [TestActor] Incommessage fasmsg to slow 1
[INFO] [05/05/2018 15:15:30.022] [AkkaTestApp-akka.actor.default-dispatcher-4] [TestActor] Incommessage fasmsg to slow 2
[INFO] [05/05/2018 15:15:30.121] [AkkaTestApp-akka.actor.default-dispatcher-3] [TestActor] Incommessage fasmsg to slow 3
[INFO] [05/05/2018 15:15:30.207] [AkkaTestApp-akka.actor.default-dispatcher-2] [TestActor] Incommessage fasmsg to slow 4


순수한 메시지 교환에서 RestAPI에 비해 성능은 비약적으로 상승한반면

...

...

Note

원격메시지에대한 안정적인 공급/소비 문제를 해결하기위한 좋은 툴로 Kafka가 등장하였고 범용적으로 사용되고 있습니다.

하지만 모든 실시간 메시지를 중앙에서 분산관리하느냐? 로컬적인 메시지를 자기들끼리 알아서 처리하게하느냐?

목적성에 따라 장단점이 있는부분입니다.

리모트 액터로 Kafka와 같은 역활을 모두 대체시키는것은 권장되지 않으며,

모든 실시간 메시지를 Kafka를 통해서 하는것도 올바른 설계방법이 아닙니다.

액터로 설계된것은 Kafka와도 완벽하게 상호연동이 되기때문에 목적성에 맞게

잘구분하여 사용할 필요가 있습니다.


아래와 같은 차이가 있으며, RemoteActor와 Kafka 전송 난이도는 큰차이가 없으며

이기종통신일때 Kafka가 이점이 있으며, 같은 기종 Java객체 전달할때 RemoteActor가

조금더 설계의 이점이 있습니다.


실시간 메시지전송기는 추상화정도및 내장화가 되었냐에 따라 3가지로 구분이 가능합니다.

  • netty를사 용하여 저수준 메시지전송 기능을 구현한다. ( 분산처리를 직접설계해야해서 어려움 )
  • netty가 추상화된 RemoteActor를 사용하여 메시지 전송을 구현한다. (분산처리를 위해 AkkaCluster를 이용하고 내장형)
  • kafka를 이용하여 메시지를 전송한다 ( 분산처리를 위해서 주키퍼의 클러스터 구성이 필요하며 외장형임)


...