2016년 5월 25일 수요일

Vert.x 3.0.0 시작해보기...(5)

제가 요즘 요긴하게 써먹고 있는 Vert.x 을 소개하고자 합니다. 폴리글랏이긴 한데, 저는 Java 만을 사용해서 개발하고 있습니다. 그래서 Java 코드만 올리겠습니다.

장문의 글을 올리기 보다는, 바로 어떤 결과가 나오는 짧은 팁만 올리고, 댓글로 보충 내용을 올리는 쪽으로 해보겠습니다. 방송 형태가 적합하겠지만, 할 줄을 몰라서...(컴맹입니다)

------------------------------------------------------------------------------------------------------

오랫만에 글을 올리네요. 하루에 한 개씩 올릴 수 있을 줄 알았으나, 게으름을 이기지 못하네요.

이번에는 Vert.x 의 Verticle 이 가지는 아주 기초적인 특성 하나만 알아볼 것입니다. 바로 독립적으로 돌아가는 특성입니다.

먼저, 가장 기본적인 Java 에서의 싱글톤(Singleton)을 한 번 구성해봤습니다. 너무 쉬운 내용이지만, 다음 내용 설명을 위해서 기초적인 형태로 구성한 점, 양해 바랍니다.

public class Test5_1 {

 private Test5_1() {

 }

 private static Test5_1 instance;

 public static Test5_1 getInstance() {

  if (instance == null) {

   System.out.println("Create Instance Test5_1");

   instance = new Test5_1();

  }

  return instance;

 }

}

정말 단순한 형태의 싱글톤입니다. 단지, 클래스가 생성될 때 인스턴스를 생성하게 하지 않고, 아직 인스턴스가 null 인지 확인한 뒤 생성해줄 때 로그를 한 번 출력해주고(생성되는 횟수도 알겸) 개체를 생성한 다음 결과로 인스턴스를 넘겨주도록 구성했습니다.

그리고 이걸 불러서 호출하는 클래스를 2 개 만들어 봤습니다.

import java.util.Random;

public class Test5_2 {

 public static void main(String[] args) throws Exception {

  System.out.println("Start Test5_2");

  Test5_2 test5_2 = new Test5_2();
  Test5_3 test5_3 = new Test5_3();

  Random random = new Random(System.currentTimeMillis());

  for (int iCount = 0; iCount < 10; iCount++) {

   if (random.nextInt(2) == 0) {

    if (random.nextInt(2) == 0) {

     test5_2.test1();

    } else {

     test5_2.test2();

    }

   } else {

    if (random.nextInt(2) == 0) {

     test5_3.test3();

    } else {

     test5_3.test4();

    }

   }

  }

  System.out.println("End Test5_2");

 }

 public void test1() {

  Test5_1 test5_1 = Test5_1.getInstance();

  System.out.println("Get Instance Test5_1 : test1");

 }

 public void test2() {

  Test5_1 test5_1 = Test5_1.getInstance();

  System.out.println("Get Instance Test5_1 : test2");

 }

}

public class Test5_3 {

 public void test3() {

  Test5_1 test5_1 = Test5_1.getInstance();

  System.out.println("Get Instance Test5_1 : test3");

 }

 public void test4() {

  Test5_1 test5_1 = Test5_1.getInstance();

  System.out.println("Get Instance Test5_1 : test4");

 }

}

main 은 Test5_2 에 있고, main 이 호출되면 Random 을 이용해서 임의적으로 4 개의 매서드 중 하나를 호출해서 인스턴스를 가져오는 아주 간단한 예제입니다.

출력 결과는 다음과 같습니다.

Start Test5_2
Create Instance Test5_1
Get Instance Test5_1 : test3
Get Instance Test5_1 : test1
Get Instance Test5_1 : test2
Get Instance Test5_1 : test1
Get Instance Test5_1 : test2
Get Instance Test5_1 : test4
Get Instance Test5_1 : test1
Get Instance Test5_1 : test3
Get Instance Test5_1 : test2
Get Instance Test5_1 : test2
End Test5_2

물론 출력되는 Get Instance Test5_1 : 이후의 내용은 Random 하게 바뀌겠지만, Start 후 Create 가 한 번만 나오고 End 가 마지막에 나오는 것은 누구나 예측할 수 있을 것입니다. 이게 싱클톤이니까요. 보통 이런 싱글톤은 JDBC 을 이용해서 DB Connection 을 가져오는 문장에서 많이들 사용하셨을 겁니다.

그런데, Vert.x 에서는 이렇게 싱글톤을 이용할 경우 큰일이 납니다. 다음 예제를 한 번 보시죠.

import io.vertx.core.AbstractVerticle;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;

import java.util.Random;

public class Test5_4 extends AbstractVerticle {

 @Override
 public void start() throws Exception {

  super.start();

  vertx.deployVerticle("Test5_5.java");

  EventBus eventBus = vertx.eventBus();

  eventBus.consumer("Test5_4.test1", (Message<Object> message) -> {

   Test5_1 test5_1 = Test5_1.getInstance();

   System.out.println("Get Instance Test5_1 : test1");

   message.reply(null);

  });

  eventBus.consumer("Test5_4.test2", (Message<Object> message) -> {

   Test5_1 test5_1 = Test5_1.getInstance();

   System.out.println("Get Instance Test5_1 : test2");

   message.reply(null);

  });

  Random random = new Random(System.currentTimeMillis());

  for (int iCount = 0; iCount < 10; iCount++) {

   if (random.nextInt(2) == 0) {

    if (random.nextInt(2) == 0) {

     eventBus.send("Test5_4.test1", null);

    } else {

     eventBus.send("Test5_4.test2", null);

    }

   } else {

    if (random.nextInt(2) == 0) {

     eventBus.send("Test5_5.test3", null);

    } else {

     eventBus.send("Test5_5.test4", null);

    }

   }

  }

 }

 @Override
 public void stop() throws Exception {

 }

}

import io.vertx.core.AbstractVerticle;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;

public class Test5_5 extends AbstractVerticle {

 @Override
 public void start() throws Exception {

  super.start();

  EventBus eventBus = vertx.eventBus();

  eventBus.consumer("Test5_5.test3", (Message<Object> message) -> {

   Test5_1 test5_1 = Test5_1.getInstance();

   System.out.println("Get Instance Test5_1 : test3");

   message.reply(null);

  });

  eventBus.consumer("Test5_5.test4", (Message<Object> message) -> {

   Test5_1 test5_1 = Test5_1.getInstance();

   System.out.println("Get Instance Test5_1 : test4");

   message.reply(null);

  });

 }

 @Override
 public void stop() throws Exception {

 }

}

위 예제를 보시면 메서드를 EventBus 로 단순히 바꾼 형태라는 걸 눈치채실 겁니다. 이 코드를 이용해서 Test5_4.java 을 Vert.x 로 실행하면 어떤 결과가 나올까요? 대략 아래와 같은 결과가 나옵니다.

> vertx run Test5_4.java
Create Instance Test5_1
Get Instance Test5_1 : test3
Get Instance Test5_1 : test4
Get Instance Test5_1 : test4
Create Instance Test5_1
Get Instance Test5_1 : test1
Get Instance Test5_1 : test2
Get Instance Test5_1 : test1
Get Instance Test5_1 : test2
Get Instance Test5_1 : test1
Get Instance Test5_1 : test4
Get Instance Test5_1 : test3
Succeeded in deploying verticle

예상하신 분들은 예상하셨겠지만...Create 가 두 번 발생합니다.

만약 Verticle 이 10 개라면, 10 개의 Create 가 발생한다는 이야기입니다. 즉, 모든 Verticle 은 별개로 동작하고, 이걸 내부적으로 Hazelcast 로 통신하면서 값을 전달하기 때문에 기존의 Singleton 을 가지고 하나의 접속만을 유지하면서 사용한다는 개념으로 접근해버리면, 전혀 엉뚱한 결과에 멘탈이 붕괴되는 현상을 경험하실 겁니다.

그래서, DB 접속이든 쿼리를 실행하는 구문이든, Singleton 으로 Connection 개체를 받아와서 처리하는 형태로 구성해서는 안되고, 쿼리를 처리하는 하나의 버티클을 만들고 그 안에 쿼리를 처리하는 EventBus 을 만든 뒤, 모든 요청을 그 EventBus 로 보내서 처리하고 결과만 JsonObject 등으로 받아오는 형태로 프로그램을 작성해야 합니다. 그래서, 오히려 처리가 더 힘든 면이 있지 않나 싶네요.


오늘은 여기까지...


이 글은 제 개인 블로그(http://zepinos.blogspot.kr)와 okky(http://okky.kr)에만 공개되는 글입니다. 퍼 가는 것은 금해주시고, 링크로 대신해주시기 바랍니다. 당연히 상업적 용도로 이용하시면...저랑 경찰서에서 정모하셔야 합니다. ^^;;;

위에 작성한 코드 등은 실제 컴파일한 것이 아니라 제가 글을 적으면서 키보드 코딩(?...손 코딩의 친구) 한 것이므로, 오류가 있다면 저에게 알려주시면 고맙겠습니다.

댓글 없음:

댓글 쓰기