6. 분산 시스템 기능으로 서버 여러대 띄우기

앞의 Flavor 기능을 이용해 서버 기능 분리하기 에서 설명한 로비 flavor 와 게임 flavor 를 띄운다고 해봅시다.

6.1. 분산 기능 켜기

둘을 다른 서버에 띄운다면 상관없지만, 우리는 이들을 같은 서버에 띄워볼 예정이니, 포트가 충돌되지 않도록 게임 flavor 의 MANIFEST.json 에서 포트 정보를 바꿔줘야됩니다. 또한 분산 기능도 켜줘야됩니다.

hello_world-source/src/MANIFEST.game.json 을 열어서 다음처럼 포트를 수정합니다.

...
"tcp_json_port": 9012,
...
"http_json_port": 9018,
...
"api_service_port": 9014
...
"rpc_enabled": true,
"rpc_port": 9015,
...

로비 flavor 는 기존 포트를 그대로 쓸 예정이니 분산 기능만 켜면 됩니다. hello_world-source/src/MANIFEST.lobby.json 을 다음처럼 수정합니다.

...
"rpc_enabled": true,
...

끝으로 iFun Engine 은 Apache Zookeeper 를 이용해 분산 기능을 구현합니다. Zookeeper 가 설치되어있지 않다면 설치합니다.

$ sudo apt-get install zookeeper zookeeperd

참고

만일 Zookeepr 서버가 다른 기계에 설치되어있다면 각 MANIFEST.json 파일에서 zookeeper_nodes 항목을 찾아 해당 Zookeepr 서버의 IP/port 로 바꿔주시면 됩니다.

6.2. 테스트용 클라이언트 패킷 추가하기

저희가 로비 서버에 로그인 한 사용자가 게임 서버에서 이를 확인할 수 있음을 테스트해보기 위해서 signin 이라는 클라이언트 패킷과 check 라는 클라이언트 패킷을 추가해보겠습니다. hello_world-src/src/event_handlers.cc 에 다음을 추가해주세요.

// 아래 함수는 ifun 이라는 유저를 로그인 처리합니다.
void OnSignin(const Ptr<Session> &session, const Json &message) {
  bool r = AccountManager::CheckAndSetLoggedIn("ifun", session);
  Json response;
  response["result"] = r;
  session->SendMessage("singin_reply", response);
}

// 아래 함수는 ifun 이라는 유저가 어느 서버에 로그인했는지 체크합니다.
// 만일 로그인 한 서버가 없으면 서버 아이디는 0000-00... 형태의 Null UUID 가 됩니다.
void OnCheck(const Ptr<Session> &session, const Json &message) {
  Rpc::PeerId server_id = AccountManager::Locate("ifun");
  Json response;
  response["result"] = boost::lexical_cast<string>(server_id);
  session->SendMessage("check_reply", response);
}


void RegisterEventHandlers() {
  ...
  // 두 패킷 핸들러를 등록합니다.
  HandlerRegistry::Register("signin", OnSignin);
  HandlerRegistry::Register("check", OnCheck);
  ...
}

자 이제 준비가 다 되었습니다. 로비 서버는 8018 번 포트, 게임 서버는 9018 번 포트로 사용되게 되었습니다. 각각의 script 로 이들을 실행합니다.

# 한 터미널에서
$ ./hello_world.lobby-local
# 다른 터미널에서
$ ./hello_world.game-local

6.3. 테스트 해보기

자, 이제 8018 번 로비 서버에 signin 을 보내서 ifun 을 로그인하겠습니다.

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/signin
{"result":true,"_sid":"497844e8-1885-40ed-b7d7-29f2931ddac2","_msgtype":"singin_reply"}

기대한대로 결과가 true 네요. 중복 로그인을 시도해볼까요?

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/signin
{"result":false,"_sid":"f0a511c0-ad16-4b1b-917f-f86da7809814","_msgtype":"singin_reply"}

이미 로그인되었으므로 결과가 false 입니다. 9018 번 게임 서버에 signin 을 보내면 어떨까요?

$ wget -qO- --post-data="{}" http://localhost:9018/v1/messages/signin
{"result":false,"_sid":"52a48a4a-58ef-462c-a08b-92371d298382","_msgtype":"singin_reply"}

예상대로 이미 로그인한 것으로 인지됩니다. 그럼 각각 어느 서버에 로그인했다고 알고 있을까요? 로비 서버와 게임 서버에 각각 check 요청을 보내보겠습니다.

$ wget -qO- --post-data="{}" http://localhost:8018/v1/messages/check
{"result":"aa561332-8aad-4f1f-0000-000000000000","_sid":"622e4ae2-3793-41ac-97ab-708840416a6d","_msgtype":"check_reply"}

$ wget -qO- --post-data="{}" http://localhost:9018/v1/messages/check
{"result":"aa561332-8aad-4f1f-0000-000000000000","_sid":"8bff8116-5583-40f7-b363-c18929ac9400","_msgtype":"check_reply"}

응답의 result 값이 같은 것을 뽈 때, 둘 다 ifun 이 같은 서버에 있는 것으로 인식하고 있네요. 로비 서버와 게임 서버간에 정보가 잘 공유되고 있다는 뜻입니다.

이제 분산 시스템으로 서비스 확장까지 했습니다. 다음 섹션에서는 게임 서버 프로그램의 패키지 관리와 관리용 RESTful API 를 추가해보겠습니다.