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

Compare with Current View Page History

« Previous Version 22 Next »

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

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

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


사용준비조건

//메이븐 설정추가
<dependency>
  <groupId>com.typesafe.akka</groupId>
  <artifactId>akka-remote_2.11</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 {
....}

이미 작성된 AKKA 어플리케이션에 원격 메시지 기능을 부여하기위해서 3가지만 하면됩니다.

이것은 로컬에서의 액터사용법과 리모트에서의 사용법이 일치하다란 것입니다.

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


컨셉

  • 푸른색: 모든처리를 DB형님에게 알리고 묻는 전통적인 방식
  • 붉은색: 피어투피어로 자신에게 일어난 일을 형제(A1 to A2) 또는 성격이 약간 다른 사촌간(B1 to A2) 에게도 묻고답하는것이 가능한구조

중앙집중형의 한계는 관리할 동생들이 너무많아지고, 지속적으로 추가됨에따라 전체에 발생하는 모든 트래픽처리를 감당하기 어렵다란 점입니다.

개선점으로 붉은색과 같이 TCP/IP 패킷설계를 통해 여러가지 실시간일들을 자기들끼리 처리할수 있는 루트를 뚫을수있고

이렇게 변환된 패킷처리에대해 고성능 작동이 가능하지만 리커넥트 문제를 비롯 구현및 관리가 어려워진다란 것입니다.

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


연결지향적이면서도 고성능통신을 할수 있는방법중 하나가 RemoteActor입니다.

구현코드는 간단해지고, 일반적인 재접속 처리 문제를 신경쓸필요가 없습니다. ( 연결복구기능이 기본 탑재됨)  


활용될수 있는 기능

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


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

서버 구현체

public class TestActor extends UntypedActor {
    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를 생성함


사용측

//엔드포인트를 통한 액터선택자
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());  


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

푸시기능과 폴링기능 두가지 모두사용할수 있을뿐더러, 받을대상 큐(액터)를 다른놈으로 지정도 가능합니다. (포워드라고도 합니다.)

구현체는 Restapi방식과 비슷하거나  더 쉬워졌으며

JAVA의 비동기 객체(Future) 와 완벽하게 호환이 됩니다.


직렬화도 성능에 관련된 이슈이며 자바Object를 던지는 방법도 간단합니다.

SomeJavaObject someObj = new SomeJavaObject()

testActorRemote.tell(SomeJavaObject,null)

기본 직렬화를 사용하여 네트워크에 전달이 가능하며, 직렬화 라이브러리역시 선택이 가능합니다. (양측이 맞아야함)


그외 참고자료 


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

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

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

리모트 액터로 Kafka와 같은 기능을 구현하는것은 권장되지 않으며, 액터로 설계된것은 Kafka와도 완벽하게

상호연동이 되기때문에 목적성에 맞게 잘구분하여 사용할 필요가 있습니다.


고성능 저수준 패킷설계를 하던 서버개발영역을 추상화하여 웹개발에서 간단하게 쓰일수 있다라고

의미를 부여해야 하는게 맞는듯 보입니다.

RabbitMQ/Kafka와 직접 비교하는것은 비교 대상이 잘못되었다라고 언급하고 싶습니다.


netty로 직접 메시지전송 플랫폼을 만든다 VS netty가 추상화된 RemoteActor를 사용한다. 정도가 맞을듯 보입니다.





  • No labels