메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

JBoss 리모팅 사용하기

한빛미디어

|

2005-03-04

|

by HANBIT

12,349

저자: John Mazzitelli / 한동훈 역
원문: http://www.onjava.com/pub/a/onjava/2005/02/23/remoting.html


최근에 JBoss는 새로운 오픈 소스 리모팅 프레임워크인 JBoss Remoting을 선보였다. 이는 리모팅 JMX MBeans나 리모팅 EJB와 같은 리모트 서비스를 제공하기 위한 넥스트 제너레이션 JBoss Application Server- 이하 AS-를 위한 코어 프레임워크를 제공한다. JBoss 리모팅은 JBoss AS와 별도로 네트워크를 인지하는 서비스를 구축하기 위한 독립 프레임워크로 사용할 수도 있다.

RMI, EJB, 웹 서비스와 같이 기존에 있는 리모팅 프레임워크의 홍수를 고려할 때 첫번째 질문은 "왜 또 다른 리모팅 프레임워크를 만들어내는가?"일 것이다. JBoss 리모팅이 다른 리모팅 프레임워크에 비해 내세울 수 있는 장점은 매우 가벼우며 네트워크 전송에 중립적이며 확장하기 쉽다는 점이다. JBoss 리모팅은 오늘날 소개된 RMI나 웹 서비스와 달리 다양한 통신(invocation) 모델을 제공한다는 점이다.JBoss 리모팅은 각각의 서비스를 위해 클라이언트쪽에서 에이전트를 생성하고 컴파일할 필요가 없다. 따라서, JBoss 리모팅은 보다 복잡하고, 중량(heavyweight) 리모팅 프레임워크를 제공한다. 예를 들어, 넥스트 제너레이션 JBoss 웹 서비스 스택 JBossWS는 JBoss 리모팅에 기반한 사용자 지정 SOAP 데이터 마샬러에 기초하고 있다. 또다른 예는 annotation을 사용한 리모트 호출에 대한 페일오버(failover)와 리퀘스트 로드 밸런싱과 같은 클러스터링 기능을 제공하는 JBoss AOP 미로팅 프로젝트다. JBoss AOP Remoting은 또한 트랜잭션과 네트워크 상에서 보안 컨텍스트에 모두에 대한 전달기능과 비동기 통신을 제공한다.

사용자 관점에서 JBoss 리모팅을 사용하면 다양한 통신 메커니즘을 투명하게 사용하여 클라이언트가 원격에서 호출할 수 있는 서비스를 매우 쉽게 디자인, 구현, 배포할 수 있다. 또한 JBoss AS에 있는 기존 서비스를 접근하는 효율적인 방법을 제공한다. 이 기사에서는 JBoss 리모팅을 어떻게 시작하는지 살펴볼 것이다.


서버측 API

JBoss 리모팅 서비스를 구축할 때 가장 먼저 고려할 점은 엔드포인트(endpoint, 종단점) 레퍼런스를 무엇으로 할 것인가하는 점이다. 다시 말해서, 클라이언트가 JBoss 리모팅에 연결하기 위해 여러분의 서비스를 어떻게 식별할 것인가? 하는 것이다. JBoss Remoing은 이를 위해 org.jboss.remoting.InvokerLocator 클래스를 정의하고 있다. 어떤 경우든지 엔드포인트 레퍼런스는 약간의 제약사항이 있는 URL을 사용한다. 간단하게 얘기하자면, InvokerLocator는 여러분이 만든 특정 서비스의 엔드포인트 이름으로 식별되며, 데이터(URL이 의미하는 것처럼)를 전송할 때 사용할 전송 프로토콜을 정의한다. InvokerLocator URL의 형식은 기술적으로 다음과 같다.


transport://host:port/parameter1=value1¶meterN=valueN


이것은 진짜 URL이 아니다. 파라미터로 넘겨진 값을 고려하지 않더라도, 여기에는 프로토콜, 호스트이름, 포트 번호와 같은 식별 데이터와는 거리가 멀지만 생각하기에는 쉬운 방법이다. 서버는 로케이터 URL을 String으로 전달하여 InvokerLocator를 생성한다.


InvokerLocator myLocator = 
    new InvokerLocator("socket://mybox:8084");


이와 같은 코드를 작성하는 것으로 컴퓨터 mybox에 서비스를 제공할 것을 지시하며, 포트 8084에서 매우 단순한 TCP/IP 소켓 전송 레이터를 통해 네트워크를 인지할 수 있다.

InvokerLocator 는 클라이언트가 어디에 연결하고, 어떻게 서버에 연결할 것인가만 지시한다. 서버는 Connector를 생성해야하고, 실제로 네트워크로 제공되기 위해 Connector를 시작한다. 이는 org.jboss.remoting.transport.Connector를 생성하고 Connector와 InvokerLocator URL을 연관시키고, Connector를 시작하는 것으로 할 수 있다.


Connector connector = new Connector();
connector.setInvokerLocator(myLocator.getLocatorURI());
connector.start();


일단 시작되고 나면, Connector는 클라이언트로부터 연결을 받아들일 준비가 된다. Connector 객체는 실제로 유효한(valid) JMX MBeans이며, 아래에 있는 설정을 사용해서 JBossAS에 배치할 수 있다. 약간의 XML이 위의 자바 코드와 동일한 기능을 하며, 인보케이션 핸들러 설정을 정의하는 것으로 기능등을 추가할 수 있다. 이에 대한 자세한 것은 다음 절을 참고m랑 ;fyfsuf.


mmlt;mbean code="org.jboss.remoting.transport.Connector"
  xmbean-dd="org/jboss/remoting/transport/Connector.xml"
  name="jboss.remoting:service=Connector,transport=Socket"mmgt;
  mmlt;attribute name="InvokerLocator"mmgt;
    socket://mybox:8084
  mmlt;/attributemmgt;
  mmlt;attribute name="Configuration"mmgt;
    mmlt;handlersmmgt;
      mmlt;handler subsystem="SUBSYS"mmgt;
        com.abc.MyHandler
      mmlt;/handlermmgt; 
    mmlt;/handlersmmgt;
  mmlt;/attributemmgt;
mmlt;/mbeanmmgt;


이제, 문제는 다음과 같다: 클라이언트 요청에 대해 무엇을 할 것인가? 이 자리에 인보케이션 핸들러가 와야한다. Connector가 들어오는 요청을 받아들이고, 이 요청을 인보케이션 핸들러에 전달한다. 여러분은 com.jboss.remoting.ServerInvocationHandler를 구현하여 JBoss 리모팅 프레임워크에 자신의 코드를 플러그할 수 있으며, Connector안에 핸들러를 설치할 수 있다. 이를 구현하기 위한 중요한 메서드는 ServerInvocationHandler.invoke(InvocationRequest)다. invoke 메서드에서는 여러분의 서비스가 실제로 수행해야 하는 작업을 처리한다. InvocationRequest는 클라이언트에서 보내진 데이터를 캡슐화하며, InvocationRequest.getParameter()를 사용해서 인보케이션 핸들러는 클라이언트 데이터를 얻을 수 있다.


/** handler to simply echo incoming
    parameter"s toString value */
public class MyHandler
    implements ServerInvocationHandler {
  public Object invoke(InvocationRequest invocation) {
    return "Echo:" + invocation.getParameter();
  }
}


JBoss 리모팅은 여러분의 핸들러 코드에 대해서 스레드 안정성(safety)에 대한 어떠한 가정도 하지 않는다. 요청이 들어오면 가능한 한 빨리 핸들러에 요청을 전달한다. 따라서, 동시에 들어오는 요청을 처리하려면 스레드 안정성을 보장하도록(필요에 따라 동기화 코드를) 핸들러를 작성해야 한다는 것을 기억하기 바란다.

인보케이션 핸들러를 설치하는 것은 간단하다. 커넥터를 시작한 후 바로 Connector.addInvocationHandler(String, ServerInvocationHandler)를 사용해서 핸들러를 추가할 수 있다.


Connector.addInvocationHandler("SUBSYS",
                    new com.abc.MyHandler());


Connector MBean의 핸들러는 위 예제에서처럼 일반적인 JBoss 설정 파일을 사용하여 설정할 수도 있다. 다양한 서브시스템에 클라이언트 요청을 디-멀티플렉스(de-multiplex)해야 한다면 다양한 핸들러를 설치할 수도 있다. 이 글에서는 이에 대해 자세히 다루지 않지만, 이해하고 사용하기에 개념은 단순하다. 이에 대한 자세한 내용은 documentation found on the JBoss Remoting product web site를 참고하기 바란다. 서브 시스템 하나에 각 핸들러를 연관시키는 것으로 충분하다. 다시 말해서, 클라이언트는 특정 서브 시스템에 요청들을 보낼 수 있다. 여러분이 원한다면 서브시스템 개념을 완전히 무시할 수 있다. 널(null) 서브 시스템도 유효하며, 일부 API는 서브 시스템을 정의하지 않은 경우에 대해 오버로드되어있다.

기본적으로 서버측에서는 이것으로 모든 작업이 끝난다. 이제, 여러분은 네트워크에서 서비스를 제공하고 요청을 받아들일 수 있는 리모트 서비스를 갖게 되었다. Connector가 클라이언트에서 요청을 받아들이면 ServerInvocationHandler를 구현한 여러분의 코드가 실행된다. JBoss AOP 리모팅 프레임워크는 이 프로세스를 단순화시키며, 어노테이션을 통한 리모팅 엔드포인트와 같은 POJO 메서드를 노출시키는 것을 지원한다.


클라이언트측 API

지금까지 네트워크를 인지하는 서비스를 어떻게 시작하는지 살펴보았으니, 이제는 서비스에 요청을 보내는 클라이언트를 생성해보자. 먼저 InvokerLocator를 생성해야 한다. InvokerLocator는 서비스 위치를 식별하고, 무슨 전송 프로토콜을 사용할지를 기술하는 객체라는 점을 기억해야 한다. 서버에서 했던 것과 같은 작업을 한다.


InvokerLocator myLocator = 
    new InvokerLocator("socket://mybox:8084");


이제, 서비스 로케이터를 인식했으므로, org.jboss.remoting.Client 객체를 생성할 수 있다.


Client myClient = new Client(myLocator, "SUBSYS");


리모트 서비스를 특정시키고 연결하기 위해 사용할 수 있는 클라이언트를 만들기 위해 필요한 것을 모두 한 것이다. 이제, 클라이언트가 요청을 특정 서브 시스템으로 어떻게 전달하는지 살펴볼 차례다. 서브시스템을 사용하는 것은 필요하지 않다. 다시 얘기하지만, 서브 시스템 이름에 null을 전달하거나 파라미터에 아무것도 전달하지 않아도 된다.

이제, Client.invoke를 사용해서 서비스를 원격으로 호출하고, 그 결과를 가져올 수 있다.


System.out.println(
    myClient.invoke("please echo this message back"));


위 코드는 요청(request) 객체- 여기서는 문자열(String) 객체-를 리모트 서비스에 전송하고, 그 결과를 출력한다.


콜백 기초

지금까지, 클라이언트가 어떻게 리모트 서버를 참조하고, 요청을 리모트 서버에 전달하는 가에 대한 기초를 살펴보았다. 우리는 리모트 서버가 클라이언트 요청을 받아들이고 처리하는 코드를 작성하는 방법에 대해 살펴보았다. 두 가지를 알아둬야 한다.

1. 클라이언트는 서버가 요청을 처리하는 것을 끝낼 때 까지 대기한 후에 response 객체를 반환받을 수 있다. 리퀘스트 처리는 동기로 처리된다.
2. 클라이언트는 서버측에서 발생한 비동기 이벤트를 처리할 방법이 없다.

콜백을 사용하면 리모트 서버가 클라이언트 요청을 병렬로 처리하는 동안 클라이언트가 자신의 작업을 수행할 수 있게 해준다. 클라이언트는 응답을 받기 위해 리모트 서버에서 블록&대기하지 않고 서버에서 작업이 완료되었을 때 서버에게 요청을 통지해달라고(또는 콜백) 하는 것이다. 서버에서 통지를 받으면 클라이언트는 그에 따른 작업을 계속 수행할 수 있다. 서버가 요청 처리를 끝내면 클라이언트에 콜백할 것이다. 콜백은 요청 처리 결과에 해당하는 응답을 포함한다.

이 메커니즘은 클라이언트 요청을 비동기 처리하는 것에만 제한되는 것이 아니다. 비동기 이벤트에 대한 통지를 구현하기 위해 서버에서 콜백을 사용할 수도 있다. 특정 비동기 이벤트에 대해 알고 있는 클라이언트는 서버 이벤트에 자신을 리스너(listener)로 추가할 수 있다. 예를 들어, 서버가 실행되는 환경의 JVM 남은 메모리를 모니터링한다고 하자. 메모리가 특정 스레숄드 레벨이하로 떨어지면 "메모리가 부족합니다."라는 것을 모든 리스너에게 비동기 이벤트로 제공할 수 있다. 클라이언트는 이러한 이벤트를 감시하다가 적절한 조치를 취하거나 관리자에게 이메일을 보내는 것을 할 수 있을 것이다.

JBoss 리모팅에서 클라이언트는 콜백을 동기로 수신하거나(pull callback) 비동기로 수신(push callback)할 수 있다. 풀 콜백은 큐에 있는 데이터를 서버가 수집하기 위해 클라이언트가 주기적으로 멈추는 것이 필요하기 때문에 동기로 동작한다. 푸시 콜백은 요청 처리가 완료되고 응답이 이용할 수 있을 때 즉시 클라이언트에게 알려주기 때문에 비동기로 동작한다. 이는 한통의 메일을 대기하는 것과 비슷하다. - 주기적으로 편지가 도착했는지 알아보기 위해 우체통에 걸어가거나 우체부가 현관 벨을 울리기를 기다리는 것과 같다.


서버 콜백 처리

리모트 서버는 콜백을 처리할 수 있게 작성되어야 한다. 푸시나 풀이든 간에, 서버 구현 코드는 동일하다. JBoss 리모팅 프레임워크가 푸시와 풀 콜백간에 차이점을 처리해준다. 서버가 요청을 완료하거나 이벤트 통지를 보내고 싶을 때 모든 콜백에 대한 통지는 JBoss 리모팅 프레임워크가 담당한다.



InvocationRequest callbackInvocationRequest = new 
    InvocationRequest(null, mySubsystem,
                      responseObject, // this is your data
                      null, null, null);

Iterator itr = m_listeners.iterator();

while(itr.hasNext()) {
   InvokerCallbackHandler callbackHandler = 
      (InvokerCallbackHandler) itr.next();
   callbackHandler.handleCallback(callbackInvocationRequest);
}


콜백을 처리하는 것은 서버가 클라이언트에 인보케이션 리퀘스트를 돌려보내는 것과 같아보인다.(푸시 콜백의 경우에는 정확히 이렇게 동작한다) 따라서, org.jboss.remoting.InvocationRequest 객체에 handleCallback 메서드를 전달해야 한다.

InvocationRequest 생성자에 전달된 responseObject는 클라이언트 콜백에 전달하고자 하는 어떤 Object든 될 수 있다. 이벤트 통지의 경우 요청에 대한 응답은 이벤트 데이터에 대한 캡슐화가 될 수 있다. 참고: 콜백 인보케이션 요청을 생성하는 API는 앞으로 나올 JBoss 리모팅 버전에서 정리될 것이다. 따라서 사용되지 않는 많은 인자들을 전달하지 않아도 된다.

m_listeners 객체는 여러분의 서버에서 생성하고 관리해야 하는 어떤 객체가 된다. 여기에는 클라이언트가 서버 핸들러에 추가한 모든 리스너 목록을 포함한다. JBoss 리모팅의 ServerInvocationHandler 인터페이스는 리스너 목록에 리스너를 추가하거나 제거할 때 사용할 수 있는 훅(hook)을 제공한다.(ServerInvocationHandler 인터페이스의 addListener와 removeListener 메서드를 참고한다.)


풀 콜백

콜백(푸시 또는 풀)을 사용하기 위해 클라이언트는 먼저 콜백 핸들러를 구현해야 한다. 콜백 핸들러는 단순히 콜백 데이터(예를 들어, 요청의 응답이나 이벤트 통지)를 누가 처리해야 하는지를 지정하기 위해 obg.jboss.remoting.InvokerCallbackHandler 인터페이스를 구현하는 것이다.


public class MyCallbackHandler 
                   implements InvokerCallbackHandler {
   public void handleCallback(InvocationRequest invocation) {
      Object response = invocation.getParameter();
      System.out.println("The server returned: " + response);
   }
}


일단, 콜백 핸들러가 구현되고 나면 리스너에 핸들러를 추가하여 풀 콜백을 사용하고자 한다고 서버에 알려주어야 한다.


    Client client = new Client(myLocator, mySubsystem);
    InvokerCallbackHandler callbackHandler = 
                           new MyCallbackHandler();
    client.addListener(callbackHandler);


Client.addListener()에 유일한 인자로 핸들러를 전달하면 서버에 핸들러를 풀 콜백 핸들러로 설치한다.

풀 콜백을 사용할 계획이라면, 클라이언트는 반드시 주기적으로 서버를 폴링(polling)하는 부수적인 단계를 수행해야 한다. 이러한 콜링은 서버로 하여금 클라이언트에 콜백 데이터를 동기적으로 전달한다. 클라이언트가 서버에 폴을 원할 때마다, 다음 호출을 수행해야 한다.


    List callbacks = client.getCallbacks();


이는 서버에서 클라이언트에 대해 대기중인 모든 콜백을 가져온다. 이제, 클라이언트는 자신이 처리할 수 있는 것만 처리하면 된다.


푸시 콜백

푸시 콜백은 클라이언트 자체가 JBoss 리모팅 서버(콜백 서버라고 하는)가 되어야 한다. 푸시 콜백 서버는 여타 JBoss 리모팅 서버와 동일하다. 푸시 콜백 서버는 단순히 클라이언트에서 액세스할 수 있다. 콜백 서버는 들어오는 푸시 콜백을 비동기적으로 받아들이며, 클라이언트를 위해 이를 처리한다. 이미 JBoss 리모팅 서버를 준비하는 것에 대해 논의했으므로 여기서 다시 다루지는 않겠다. 리모트 서버가 클라이언트 콜백 서버에 대해 알 수 있게 하기 위해, 클라이언트는 콜백 서버의 InvokerLocator에 두번째 인자로 addListner 메서드를 보내기만 하면 된다.


InvokerLocator callbackLocator = 
          new InvokerLocator(callbackURL);
    client.addListener(callbackHandler, callbackLocator);


콜백을 리스닝하는 것은 서버 처리와 동일하다. 콜백 서버의 invoke 메서드는 콜백 데이터를 갖고 있을 수신되는 인보케이션 요청을 받아들인다. 콜백 서버는 단순히 이를 다른 것들과 마찬가지로 처리한다.


public class MyCallbackServer 
    implements ServerInvocationHandler {
   public void invoke( InvocationRequest invocation ) {
      Object response = invocation.getParameter();
      System.out.println("The callback data: " + response);
   }
}


콜백 서버의 invoke 메서드는 수신되는 데이터로 무엇을 할 것인가 결정해야 한다. 이것이 클라이언트 요청에 대한 비동기 응답이라면, 클라이언트는 요청이 완료되었고, 반환값을 받았는지 확인해야 한다. 이벤트 통지의 경우 클라이언트는 자신에게 해당하는 이벤트에만 반응해야 한다.
주의할 점은 방화벽 또는 NAT를 사용하는 경우 리모트 서버와 콜백 서버가 실제로 통신하는 것이 불가능할 수도 있다는 것이다. 이런 경우에 풀 콜백은 원격 클라이언트에 데이터를 보내는데 리모트 서버가 필요없으므로 해결책이 될 수 있다.
푸시 콜백을 사용하는 경우 몇 가지 흥미로운 상황이 발생할 수 있다. 예를 들어, 위에서 언급한 방화벽 문제가 있으며, 다른 예로는 클라이언트가 첫번째 요청에 대한 콜백 응답이 도착하기 전에 두번째 요청을 하는 경우에 무슨 일이 벌어질 것인가? 콜백 이벤트 홍수(flood)는 어떻게 처리할 것인가?와 같은 문제가 있다. 몇 가지 문제는 서버와 클라이언트 구현 내에서 쉽게 처리할 수 있지만, 일부 문제는 JBoss 리모팅 프레임워크에서 해결해야 할 필요가 있다. 보다 깊은 논의를 위해서는 JBoss 사용자 포럼에 참여할 것을 권한다.


결론

리모트 서비스를 개발하고, 클라이언트가 이를 사용할 때 JBoss 리모팅이 제공하는 것을 사용하는 것이다. RMI의 보다 복잡한 프로그래밍 모델을 제거하고 서비스와 서비스를 이용하는 클라이언트를 정의하는데 필수적인 것만을 남겨놓았다는 점이다. 보다 중요한 점은 RMI 프로그래밍 모델의 복잡함은 사라지고 JBoss 리모팅이 전송 프로토콜로 RMI를 사용할 수 있다는 점이다. 단순히 인보커 로케이션에 socket: 대신에 rmi: 프로토콜로 바꾸기만 하면 된다. 나중에는 사용할 수 있는 통신 프로토콜이 추가될 것이며, 손쉽게 서로 바꿀 수 있을 것이다. 또한, 자신이 직접 전송 프로토콜을 작성할 수도 있다.

JBoss 리모팅은 이 기사에서 다루지 않은 다른 기능들도 제공하고 있다. 특히, 복제된 네트워크 레지스트리에 리모트 서버를 등록하고, 클라이언트가 네트워크상에서 이러한 리모트 서버를 자동으로 발견할 수 있는 기능을 제공한다. JBoss 리모팅의 현재 릴리스에 제공되는 문서에서 이러한 사항들을 자세히 다루고 있으며, 학습할 수 있는 예제 코드를 포함하고 있다.

참고자로
· Download the JBoss Remoting software, sample code, and documentation
· A Flash demo of JBoss Remoting
· Clustering feature using JBoss AOP Remoting


참고: 제1회 정기 JBoss 사용자 컨퍼런스가 2005년 3월 1일과 2일에 조지아 주 애틀랜타 시내의 Omni/CNN 센터에서 개최될 예정이다.

www.jboss.com/company/events/jbossworld2005

John Mazzitelli is a developer for JBoss, Inc, currently focusing on the implementation of the new JBoss Network.
TAG :
댓글 입력
자료실

최근 본 책0