vertx의 고가용성(High Availability)

잠깐 쉬어가는 타임으로 간단하게 vertx의 고가용성에 대해 알아보자
고가용성이란 서버와 네트워크, 프로그램 등의 정보 시스템이 상당히 오랜 기간 동안 지속적으로 정상 운영이 가능한 성질을 말한다.
(출처 위키피디아)
만약 한개의 vertx를 돌린다면 서버가 죽으면 답이 없다.
그래서 서버들을 관리 코디 하는 주키퍼를 써도 되는데 주키퍼가 죽으면 어카지..흠 물론 주기퍼도 여러개를 돌려야된다.
아무튼 이번시간에 주키퍼시간이 아니니까 생략 (다음편에 아마 주키퍼를 할듯하다.)
vertx의 고가용성에 대해 보자. vertx는 고가용성에 대해 지원해주고 있다.
서버를 돌리다가 서버가 죽으면 기다리고 있던 서버가 다시 배포되어 돌아간다. 한번 살펴보자.
아주 간단하다. 물론 예제라 그런지.
우리는 일단 hazelcast를 사용해야 된다.

<dependency>
    <groupId>io.vertx</groupId>
    <artifactId>vertx-hazelcast</artifactId>
    <version>3.2.1</version>
</dependency>

다음과 같이 maven을 추가 하자
그리고 나서 실질적으로 서버를 돌려야 된다.

public class HaServer extends AbstractVerticle{

  public static void main(String[] args) {
    Launcher.main(new String[] { "run", HaServer.class.getName(), "-ha"});
  }

  @Override
  public void start() throws Exception {
    vertx.createHttpServer().requestHandler(req -> {
      final String name = ManagementFactory.getRuntimeMXBean().getName();
      req.response().end("Happily served by " + name);
    }).listen(8080);
  }
}

평범한 http 서버이다. 8080으로 서버를 띄었다.
그리고 나서 대기하고 있는 서버를 만들어보자

public class BareInstance {

  public static void main(String[] args) {
    Launcher.main(new String[]{"bare"});
  }
}

어이쿠 간단하다.
처음에 HaServer서버를 기동하고 다음으로 BareInstance 서버를 기동하자.
localhost:8080 에 접속 해보자.

Happily served by 1292@lee-ui-MacBook-Air.local

필자는 이렇게 나왔다. 1292를 잘보고 있자.

그러고 나서 command에서 haserver를 kill하자. (IDE에서 죽이면 안된다.)

kill -9 ${PID}

kill하고 나서 다시 localhost:8080에 접속해보자

Happily served by 1294@lee-ui-MacBook-Air.local

이렇게 조금 달라진 모습을 볼 수 있다
실제 IDE에 가보면 HaServer는 돌아 가셨다.
아주 잘 써먹어도 될듯하다.

vertx http tcp

이번엔 netty 를 코어로 만든 vertx http 서버와 tcp 서버를 만들어보자

필자가 원하는건 이거였다.
http로 날리면 tcp로 푸시를 해주는 그런 서버?
그러기 위해서는 http서버와 tcp 서버를 만들어줘야된다.

vertx 3.x 에는 Router로 수정되었다.
그리고 BusModBase이 아닌 AbstractVerticle 를 상속받아 구현해야 된다. 소스를 보자

public class VerticleProducer extends AbstractVerticle {

  @Override
  public void start() throws Exception {

    Router router = Router.router(vertx);
    router.route().handler(BodyHandler.create());

    router.get("/").handler(this::getOk);
    vertx.createHttpServer().requestHandler(router::accept).listen(8080);
  }

  private void getOk(RoutingContext routingContext) {
    HttpServerResponse response = routingContext.response();
    MultiMap params = routingContext.request().params();
    String id = params.get("id");
    JsonObject code = new JsonObject().put("code", "000").put("id", id);
    response.putHeader("content-type", "application/json").end(code.toString());
  }
}

간단한 http 서버다. 루트로 접속을 하면 그냥 json으로 리턴하는 코드이다.
하지만 필자는 tcp로 푸시를 줘야되는데..
그러기 위해선 eventBus를 사용해야 된다.

routingContext.vertx().eventBus().publish("tcp.push.message", code);

eventBus에는 publish와 send가 있는데 차이점은 모두 주냐 한개만 주냐이다.
publish는 해당 주소에 모두 전달하지만 send는 특정 한개만 전달한다. 그 기준은 잘모르겠다. 먼저 등록되는 놈?

그럼 이제 tcp로 전달해주는 소스를 보자

public class VerticleConsumer extends AbstractVerticle {

  private NetServer server;
  private Map<String, NetSocket> userInfo = new HashMap<>();

  @Override
  public void start() throws Exception {
    server = vertx.createNetServer();

    server.connectHandler(socket ->
      socket.handler(buffer -> userInfo.put(buffer.toString(Charset.defaultCharset()).replaceAll("(\r)?\n", ""), socket))
    );

    server.close(socket -> userInfo.remove(socket));

    EventBus eventBus = vertx.eventBus();

    eventBus.consumer("tcp.push.message", message -> {
      JsonObject body = (JsonObject) message.body();
      NetSocket socket = userInfo.get(body.getString("id"));
      socket.write(body.toString());
    });
    server.listen(8888);
  }
}

보면 일단 tcp로 연결된 아이가 있어야된다.
먼저 연결 한 후에 id를 넘겨야 되는데 클라이언트와 잘맞춰서 해야된다.
consumer는 원래 registerHandler 이거 였다 3.x 로 가면서 변경 되었다.

그럼 테스트를 해보자
서버를 돌린 후에 telnet으로 접속하자

telnet localhost 8888

접속이 되면 임의의 아이디를 넣자.
wonwoo라 넣었다 필자는
그러고 나서 http 서버로 접속을 해보자

http://localhost:8080?id=wonwoo

그러면 telnet에 푸시가 갈 것이다.
잘 작동한다. push서버가 만들어졌다.ㅎㅎㅎ

이 예제는 GitHub에 올라가 있다.