[▲ 문대경 아이펀팩토리 대표]
인벤에서는 게임업계 1.5세대 인물로 안정적인 게임서버엔진인 아이펀 엔진을 개발한 아이펀팩토리의 문대경 대표님을 모시고 서버 관련 컬럼을 기고 받게 되었습니다.

문대경 대표는 1999년 넥슨 입사 후 2005년까지 넥슨에서 출시되는 다수의 프로젝트 서버 프로그램을 책임졌으며, 현재 아이펀팩토리의 대표로 게임서버 엔진인 '아이펀엔진'을 개발하였습니다.

아이펀팩토리가 개발한 '아이펀 엔진'은 네트워크, DB(디비)처리, 분산 시스템 등 게임 서버 구현에 필요한 필수 기능을 손쉽게 구현해 개발 시간 단축을 돕는 모바일 게임 서버엔진입니다.

그 세 번째 시간으로 클라이언트 프로그래머와 서버 프로그래머, 비슷해 보이지만 서로 다른 고민을 가진 사람들 Part2 라는 타이틀을 가지고 내용을 이어가겠습니다.

* 본 내용은 본지의 편집방향과 일치하지 않을 수도 있습니다.


클라 프로그래머와 서버 프로그래머. 비슷해 보이지만 서로 다른 고민의 사람들. Part 2

지난 회에서는 게임 클라이언트에서의 성능 병목으로 1) 화면 만들어 내기 (렌더링), 2) 길찾기를 포함한 AI, 3) 현실감을 담아내기 위한 물리 엔진에 대해 설명했다. 그리고 가능하면 16 밀리세컨드 (60fps), 못해도 33 밀리세컨드 (30 fps) 안에 이런 작업들을 모두 마무리 해야된다는 말도 했다. 끝으로 이 작업들은 각각 난이도 있는 작업이긴 하지만, 복잡한 테스트 환경 없이 개발자의 작업 환경에서 화면에 물체들을 많이 올려보는 것으로도 클라의 성능 테스트를 할 수 있다고 이야기했다.

이번 회에서는 서버 쪽의 성능 병목과 서버는 어떻게 성능 테스트를 하는지에 대한 이야기를 해보겠다. 서버에서의 병목을 설명하기 위해서는, 클라가 서버에 접속해서 플레이하는 동안 어떤 일들이 발생하는지를 먼저 살펴볼 필요가 있다.


1) 패킷이 클라에서 생성되어 서버에서 처리되기 까지


위 그림은 언뜻 보기에 복잡해 보이는데, 일단 용어가 낯설어서 그런 것일뿐 그다지 복잡한 그림은 아니다. 용어부터 살펴보자.

게임 클라와 서버가 데이터를 주고 받는 단위를 ‘패킷' 이라고 한다. (컴퓨터 네트워크 학문 관점에서 엄밀히 구분하면 ‘메시지’ 라고 부르는게 맞지만, 한국에서는 아무도 메시지라고 부르지 않고 편의상 모두 ‘패킷' 이라고 부른다. 그러니 우리도 그냥 ‘패킷’이라고 부르자. 사실 패킷 (packet) 이라는 단어가 프로그래머들이 쓰다 보니 컴퓨터 네트워크 전공 용어라고 생각하기 쉬운데, packet 은 ‘포장하다' 라는 pack 에 작은 것을 뜻하는 접미사 -et 를 붙여서 작은 우편물/꾸러미를 뜻하는 실제 사용하는 영어 단어이다. 그러니 네트워크상에서 왔다 갔다 하는 작은 우편물이라는 의미로 packet 이라고 불린다고 보면 되겠다.)

패킷은 목적에 따라 세부적으로는 '로그인 패킷', '이동 패킷', '공격 패킷' 등 앞에 어떤 용도의 패킷인지를 붙여서 부른다. 그래서 개발자들은 “이번에 상점 구현하는데 상점 패킷 구조 정해졌어요?” 같은 대화를 나누는 것이다.

그리고 데이터베이스, 줄여서 '디비'라고 불리는 저장소는 위의 그림에서 우측 상단에 있는 원통형 물체들을 겹쳐 놓은 것처럼 그리는 것이 일반적이다. (정확히는 하드디스크 안에 들어 있는 플래터라고 불리는 원반들을 겹쳐 놓은 것을 형상화한건데, 데이터를 저장한다는 의미 때문에 이런 이미지가 된 것 같다)

이제 다시 위의 그림을 보자. (이제는 그림이 조잡해도 술술 이해되길 바란다) 위의 그림의 의미는 “서버는 1) 클라로부터 패킷을 받아서 순서대로 쌓아두고, 2) 이 패킷들을 하나씩 뽑아서 패킷 종류에 따라 적절한 처리를 하는데 3) 이런 처리를 하다 보면 디비에 있는 데이터를 읽고/쓰거나, 클라에게 내용을 전송해주거나, 아니면 외부 시스템과 통신을 하는 일이 발생할 수 있다.” 라고 해석할 수 있다. 실제 패킷 발생의 예제들을 살펴보면 이해가 쉬울 것이다.


2) 예제1 - 로그인 패킷

클라에서 로그인 버튼을 눌렀다고 해보자. 클라에서 로그인 패킷을 생성해서 서버에 전송할 것이다. 서버는 이것을 받아뒀다가 처리할 순서가 되면 로그인 처리를 하는 코드를 실행한다. 디비에서 아이디에 따른 유저 데이터가 있는지 확인할 것이고, 존재하는 아이디라면 유저 데이터를 불러올 것이다.

그리고는 비밀번호는 맞는지, 계정이 블럭 된 것은 아닌지, 중복 로그인한 것은 아닌지와 같은 확인 과정을 거치고, 문제가 없다면 클라에게 무사히 로그인을 마쳤다고 알려주고 문제가 있다면 적절하게 오류 메시지를 보여줄 것이다. 무사히 로그인을 마쳤다면 클라는 환상의 세계로 떠날 준비를 마치고 우리에게 아름다운 첫 화면을 보여줄 것이다. 참으로 긴장되는 순간이 아닐 수 없다.

위의 과정 중에서 만일, 카톡에 붙어있는 게임이라면 “비밀번호는 맞는지" 의 단계를 자체적으로 처리하는 것이 아니라 카톡 서버에게 “이 사용자가 제대로 된 카톡 유저가 맞는지” 를 확인하는 과정을 거치는 점이 다를 것이다. 다시 말해, 이렇게 카톡 연동을 하게 되면 카톡 인증 서버와의 통신이라는 “외부 시스템 호출”이 추가적으로 발생한다.


3) 예제2 - 다중 플레이에서의 공격 패킷

다른 예를 들어보자. 우리가 파티를 맺고 드래곤 사냥을 떠났을 때, 내가 드래곤에게 시원하게 블리자드를 쏴줬다고 하자. (부디 얼음 속성 드래곤이 아니길 바란다.)

이런 경우에 클라는 서버에게 블리자드를 시전했다는 패킷을 보낼 수도 있고, 몇 번 슬롯의 스킬을 썼다고 보낼 수도 있다. 이 둘이 별 차이는 없는데, 전자의 경우는 실제 유저 스킬 목록에 블리자드가 있는지 확인하는 과정을 넣어줘야 된다. 그렇지 않으면 클라가 해킹 당한 경우 가지고 있지도 않은 스킬을 마구 사용할 수 있기 때문이다.

서버에서는 이 패킷을 받아서 유저의 블리자드 스킬이 쿨타임에 걸렸는지 확인하고, 내 스킬 레벨과 드래곤의 레벨, 그리고 일정 확률에 따라 피격 여부와 데미지 정도를 계산한다. 그리고 그 판정 결과를 나와 내 파티원들에게 모두 알려준다. 이를 받은 각각의 클라는 얼음 이펙트와 함께 데미지 숫자를 띄우게 될 것이다. 이로써 내가 스킬을 사용했고 그것이 성공했는지 여부를 파티원들이 알 수 있게 된다.

▲ H.I.T 의 실시간 레이드 (출처: H.I.T 공식 홈페이지)
유저의 행동은 패킷을 통해서 다른 유저들에게 전송되어 어떤 행동을 했는지 공유된다

앞의 로그인의 과정과는 달리 이런 공격 패킷은 매번 디비에 그 내용을 쓰지는 않는다. 그럴 경우 디비까지 갔다 오려면 너무 오래 걸리기도 하고, 디비에 쓰는 양이 많아져서 디비가 병목이 되기 때문이다.

그래서 일반적으로는 유저 데이터를 메모리상에서만 수정을 해놨다가 레이드가 종료될 때 수정된 것들을 한꺼번에 디비에 기록 하는 방법을 쓴다. (물론 레어템이 깨지거나 하는 중요한 상황이 발생하면 바로 디비에 저장할 수도 있다.)


4) 잠깐 곁다리 이야기 - 백섭

이렇게 실시간으로 저장하지 않기 때문에 발생할 수 있는 문제가 소위 유저들이 말하는 '백섭'이다. (다들 잘 아시겠지만, 서버가 뒤로 돌아간다고 해서 백섭이라고 한다. 게임 내 버그가 있을 때 운영진이 특단의 조치로 유저데이터를 일괄적으로 과거로 돌리는 경우도 백섭이라고 한다. 그러나 여기서는 '서버가 다운되면서 일부 유저의 최근 플레이 기록이 누락되면서 데이터가 과거 상태가 되는 경우'를 이야기하는 것으로 하자.)

그리고 이는 아무리 실시간으로 저장한다고 하더라도, 게임 서버 안의 모든 유저를 저장하는 데는 시차가 발생할 수 있다는 점 때문에 어느 정도는 불가피한 문제다. 물론 저장 간격이 짧을수록 백섭 확률도 낮아지고 발생하더라도 피해가 적어지긴 한다. 대신 서버 쪽 부하는 커지게 된다. 세상사 모든 일은 이처럼 트레이드 오프다.

PC 온라인 시절, 일찍부터 이런 사실을 간파한 일부 유저들은 게임 서버를 죽일 수 있는 버그를 발견한 경우 유저들끼리 서로 아이템을 주고 받는 과정을 하다가 서버를 일부러 죽게 만들기도 했다. 그렇게 하면 운이 좋을 경우 아이템을 받은 유저의 데이터는 디비에 저장됐는데, 아이템을 준 유저의 데이터가 디비에 씌여지지 않아서 두 유저 모두가 아이템을 가지는 득템의 상황이 발생할 수 있기 때문이다.

사실 이런 아이템 복사 버그는 선량하게 노X다 를 뛰거나 현금 결제를 한 다른 유저들에게 심각한 박탈감을 주기 때문에 자제하도록 하자. (그리고 서버 개발자들을 분노시키는 것은 물론이다. 내가 바람의 나라 서버 프로그래밍을 할 때는 주 6일 시절이었는데, 황금 같은 토요일 오후를 이런 일들로 버린 경우가 몇 번 있었다. 디버깅으로 토요일 오후를 날린, 연애도 못 해본 20대 탈모 청년의 애끓는 마음을 생각해주길 바란다.)


5) 서버의 성능 지표1 - 처리 용량

클라의 성능은 fps 라는 단위를 통해 초당 몇 번의 그림을 그려낼 수 있느냐로 평가한다고 이야기했는데, 서버는 얼마나 많은 클라들을 서비스할 수 있는지로 성능을 평가한다. 이때 클라의 수라는 것은 말 그대로 동접이 될 수도 있고, 동접이라는 개념을 정하기 애매한 비동기식 모바일 게임 서버 같은 경우는 동접 대신 초당 처리 가능 패킷 수 혹은 처리 가능 세션 수 등으로 표현하기도 한다.

서버의 처리 용량은 높으면 높을수록 좋지만, 현실에서는 한 서버가 죽을 때 영향받는 유저 수가 너무 많은 것이 부담스럽다는 운영상의 이유로 용량이 남더라도 서버를 분리하기도 한다. 그리고 어떤 경우에는 운영하는 게임 서버가 많은 것이 일종의 '회사 내 입김의 세기'라고 생각해서 방만하게 서버를 늘리는 경우도 있었다. (전혀 바람직하지 않은 기업 문화다)

운영에서 기대하는 처리 용량이 케이스 바이 케이스이기도 하고 서버의 CPU 개수나 메모리 용량에 따라서도 달라지기도 하지만, 대충 암묵적인 기준으로는 서버당 2천명 에서 5천명 정도는 되어야 한다고 생각한다.

그리고 그에 맞춰서 서버 CPU 나 메모리를 조정한다. 만일 평균 이상의 서버 하드웨어 스펙에서도 처리 용량이 1천명도 안되는 수준이라면 이건 뭔가 잘못된 것이고, 1만명이 넘는 수준을 유지할 수 있다면 서버 구현이 매우 훌륭하다고 생각한다.


6) 서버의 성능 지표2 - 안정성

처리 용량과 더불어 서버의 성능 지표로 생각하는 것이 안정성인데, 이는 서버가 얼마나 안 죽고 잘 살아남는지를 의미한다. 간혹 서버가 얼마나 해킹에 대비가 잘 되어있는지를 안정성에 포함시키기도 하는데 이는 대부분 클라에서 넘어오는 패킷 검증 처리의 유무이다. 따라서 개인적으로는 성능 지표라기보다는 예외 처리를 얼마나 꼼꼼하게 하는지와 관계가 있다고 생각한다.

서버가 죽는 경우는 잘못 짠 코드 때문에 즉각적으로 죽는 경우도 있고, 메모리 누수가 생겨서 서서히 메모리 사용량이 증가하다가 죽는 경우가 있을 수 있다. 또한 유저가 갑자기 몰리거나 DDoS 공격 등으로 처리 용량을 초과하는 바람에 서버가 사실상 좀비 상태가 되어버리는 경우도 있을 수 있다.

보통 정기 점검 주기까지 서버가 죽지 않고 살아남으면 매우 안정적이라고 할 수 있다. 어차피 정기 점검 때는 서버를 리부팅하기 때문이다. 그런데 요즘에는 '무중단 서비스' 가 미덕으로 여겨지다 보니 서비스가 완전히 내려가는 정기 점검을 거는 대신 서버 중 일부분씩 점진적으로 점검하는 경우도 많다. 그렇기 때문에 요즘 요구되는 안정성의 기준은 이전에 비해 상당히 높다.

굳이 무중단 점검 때문만이 아니더라도, 게임 서버가 죽는 경우에 대한 대비는 필요하다. 세상에 절대로 죽지 않는 프로그램은 존재하지 않기 때문이다. 동작하는 동안 절대로 죽지 말아야 되는 OS 조차도 블루스크린을 띄우고 죽는 경우가 종종 있지 않은가.

▲ 윈도우즈 블루스크린
윈도우즈 버전이 올라감에 따라 블루스크린도 좀 더 유저 친화적으로 변했다...

그렇기 때문에 게임 서버가 절대 안 죽는 것도 중요하지만, 죽더라도 그 영향을 최소화할 수 있는 구조를 갖추는 것도 중요하다. 가령 서버가 10대 있을 때 한 대라도 죽으면 전체 서비스가 내려가는 구조보다는, 어떻게든 9대에 연결된 유저들은 플레이할 수 있는 구조가 바람직하다.

그리고 그보다는 죽은 서버에 연결되었던 유저들도 전혀 눈치 못 채게 다른 서버로 이전되어 계속 플레이할 수 있는 구조가 더 바람직하다. 이렇게 장애 처리를 할 수 있는 것을 fault tolerance 라고 하는데, 이중화나 (좀 복잡하게는) state replication 같은 방식이 이용된다.

그러나 세상 모든 일에는 트레이드 오프가 있는 법이라서, 이런 식의 장애 처리는 부하가 커서 시스템이 느려지거나 처리 용량이 감소되는 경우가 발생할 수 있다. 이 때문에 의도적으로 어느 한쪽은 포기하고 가는 경우가 많다.


7) 서버 프로그래밍 난이도의 근본 원인 - 목표 시간 1 미리세컨드

앞에서 서버의 성능 지표 중 제일 중요한 것으로 처리 용량에 대해서 이야기했다. 그럼 대충 서버는 한 패킷을 처리하는데 얼마나 시간적 여유가 있을까?

클라가 얼마나 자주 서버와 통신하는지는 게임의 성격에 따라 다른데, 높은 동기화 수준이 요구될수록 자주 통신하게 된다. 보통은 초당 3-5회 정도 통신을 하는 경우가 많다. 만일 클라가 서버에 초당 3회 정도 패킷을 보낸다면, 서버는 약 330 밀리세컨드 안에 클라 패킷을 처리하면 된다는 뜻이 된다.

이 숫자는 클라에서 60fps 를 만들어내기 위해 16밀리세컨드 안에 작업을 끝내야된다는 것에 비하면 굉장히 여유있게 보일 수 있다. 그러나 서버는 여러 사용자들을 처리해야 된다는 것을 잊지 말자. 서버가 천명만 서비스한다고 해도 '하나씩 순서대로 처리한다면' 약 330 마이크로세컨드안에 패킷을 처리해야 된다는 뜻이 된다.

그렇게 생각하면 이건 엄청나게 빡빡한 제약이 되고 만다. 그 때문에 서버는 '하나씩 순서대로 처리'하는 대신 '멀티쓰레드' 라는 방식으로 병렬적인 구성으로 한 번에 여러개를 처리함으로써 처리량을 올리려고 한다.

또한 디비나 외부 시스템과 통신을 하는 경우, 요청을 보내고 마냥 앉아서 기다리는 것이 아니라, 응답을 기다리는 동안 재빠르게 다른 일을 처리한다. 그리고 나중에 응답이 오면 그제서야 이전에 멈춰두던 작업을 재개한다. 이를 '비동기식' 처리라고 부른다.

어쨌거나 한 유저만 다루는 클라와 달리 몇천 명 이상의 유저들을 다뤄야되는 서버는 한 패킷을 처리하는데 굉장히 빡빡한 시간 제약을 갖고 있고, 많은 경우 패킷당 1-2 밀리세컨드 안에는 모든 처리를 마치는 것을 목표로 한다. 이는 클라의 최소 10배 가까운 처리 속도를 의미한다.

어떤 이는 서버는 고성능의 하드웨어를 가지고 있기 때문에 그 정도는 쉽게 가능하지 않냐고 생각할지 모르겠다. 물론 서버는 클라보다는 더 빠른 CPU 를 더 많이 사용하긴 한다. 그러나 그게 클라의 10배에 가까운 수치가 되지는 않는다.

특히나 온라인 게임과 비교해보면 유저들의 데스크탑 PC 와 서버의 CPU 성능 차이는 그다지 크지 않을 수도 있다. 그 때문에 서버에 기능을 추가할 때는 성능에 미치는 영향을 고려해서 손을 벌벌 떨며 매우 신중하게 접근해야 된다. 그럼 어떤 기능들이 주로 병목이 되는 걸까?

(출처: https://m.inven.co.kr/webzine/wznews.php?site=lineage&idx=92224)

클라는 한 유저만 상대해도 되지만, 서버는 최소 몇천 명의 유저를 서비스해야 된다는 것 때문에 어렵다. 물론 공성전처럼 화면에 많은 물체가 표시되는 경우는 서버/클라 모두에게 되지만, 클라는 화면에 보여지는 유저들만 다루면 되는 반면 서버는 화면에 보이지 않는 모든 유저들을 다뤄야 된다는 점이 다르다.


8) 서버의 부하 요소1 - 패킷 처리

앞서 설명한 대로 서버는 한 클라로부터 초당 약 3-5 개 정도의 패킷을 받게 된다. 그리고 서버는 대충 2천에서 5천 개의 클라를 받는다. 그렇게 계산하면 초당 6천 개에서 많게는 2만 5천 개의 패킷을 받아들인다는 뜻이 된다.

때문에 서버에서는 패킷이 들어왔을 때 가능하면 부하를 주지 않고 각 패킷별 처리 코드로 넘기려고 노력해야 된다. 보통 게임 서버에서 '제로 카피 (zero copy) 라고 하는 것이 이렇게 패킷을 읽어 들이고 불필요하게 패킷이 복사되지 않고 효율적으로 패킷이 전달되는 기술을 의미한다.

또한, 패킷을 읽어 들이는 것 자체가 아무리 빨라도 이들을 처리하는 패킷별 처리 코드가 느리면 모든게 무용지물이다보니, 각 패킷별 처리 코드 역시 복잡한 연산은 병렬적이나 비동기적으로 처리하게끔 노력한다. 패킷별 처리 코드 안에서 디스크에서 뭔가를 읽어 들인다거나 중요하지도 않은 복잡한 AI 를 돌린다거나 하는 것은 절대 바람직하지 않다.


9) 서버의 부하 요소2 - 디비 처리

한 프로그램 안에서 처리되는 일은 굉장히 빨리 처리되는 반면, 네트워크를 건너서 다른 서버와 통신을 해야 되는 작업은 오래 걸린다. 그리고 디스크에서 뭔가를 읽어 들이는 것 역시 오래 걸린다. 요즘의 네트워크 속도나 SSD 같은 저장장치의 속도가 눈부시게 빠르긴 하지만, 메모리 안에서 모든 것이 이루어지는 것과 비교하면 이들은 몇십 배에서 몇백 배 느리기 때문이다.

그 때문에 디비에서 뭔가를 읽어오거나 뭔가를 쓰려면 네트워크라는 '상대적으로 느린' 경로를 따라서, 디비 서버가 '상대적으로 느린' 디스크 작업을 마무리 지을 때까지 기다려야 되기 때문에 게임 서버 입장에서는 디비 서버와의 통신이 잦은 것은 바람직하지 않다.

그런데 디비 서버는 여러 서버에서 데이터를 접근하더라도 '트랜잭션' 이라는 방식으로 이들의 요청이 꼬이지 않게 잘 처리 해주는 편리한 속성을 가지고 있다. 그 때문에 많은 서버 프로그래머들이 이 달콤한 편리함의 유혹에 빠져서 서버 간의 동기화를 위해 디비 서버를 적극 활용하는 경우가 있다. 그렇게 만들어진 게임 서버는 서버의 처리 용량이 심각하게 떨어질 수밖에 없다.

이런 디비 처리를 피하기 위해서는 '메모리 캐시' 나 '서버 간 통신' 이 이용된다. 이런 것까지 설명하면 너무 골치 아프니 이런 것들은 혹시 내 글이 재미없다는 이유로 인벤으로부터 퇴출당하지 않는다면 다음에 다루도록 하겠다.


10) 서버의 부하 요소3 - 외부 시스템 연동

게임 서버가 외부 시스템을 호출해야 되는 경우는 다양하다. 앞서 예를 든 카카오 인증을 비롯해서 우리가 애플 앱스토어에서 게임 내 아이템을 결제할 때도, 게임 서버는 클라의 결제 결과를 그대로 믿는 것이 아니다. 애플의 결제 확인 서버에 결제 결과를 재차 확인하게 된다. 모바일 게임마다 너무나 당연하게 존재하는 랭킹 기능 역시 외부의 랭킹 서버와 통신해서 나오는 경우가 많다.

그리고 게임 서버를 운영하는 측면에서는 고객 지원이나 게임 내 통계 분석을 위해서 로그를 수집한다. 이런 로그가 게임 서버의 디스크에 바로 쓰여지는 경우도 있지만, 경우에 따라서는 로그를 수집하는 서버로 게임 서버가 쏴줘야되는 경우도 있다.

앞서 디비의 경우에서 말한 것처럼 네트워크를 타고 외부 서버와 통신하는 것은 게임 서버 입장에서는 엄청 느린 작업이지만, 그렇다고 외부 시스템과의 연동은 피할 수 없는 문제이기도 하다. 그래서 어떻게든 통신해야 되는 횟수를 줄이기 위해서 노력하거나, 통신을 하더라도 비동기'적으로 통신을 해서 마냥 응답을 기다리지는 않게 한다.


11) 왜 서버는 게임 오픈하고 나서 터지나?

이렇게 서버의 처리 용량에 영향을 줄 수 있는 것이 대충 눈에 보인다면 이것들을 미리 알아내서 고치는 것은 불가능할까? 물론 가능할 수도 있다. 이렇게 돌려보지도 않고 잠재적인 문제를 알 수 있다면 아주아주 훌륭한 프로그래머다. 그러나 이런 프로그래머들도 사람인지라, 서버 프로그램이 복잡해질수록 그걸 다 잡아내는 것은 결국 불가능에 가까워진다.

게임 개발 과정 중에는 개발팀원들은 계속 클라와 서버를 붙여가면서 테스트한다. 그러나 그 숫자는 기껏 개발팀원 정도의 숫자다 보니 몇십개 선이다. 서버의 많은 문제는 처리 용량의 문제이기 때문에 이런 환경에서는 어떤 것이 문제가 돼서 처리 용량에 영향을 미치는지 알기 힘들다.

또한, 단순히 처리 용량뿐만 아니라 처리 용량을 개선하기 위해서 병렬적인 구성으로 해 놓은 것이 꼬이는 경우가 발생할 수도 있다. 이 역시 충분한 수의 클라가 붙지 않으면 발생하지 않을 수 있다. 그 때문에 많은 경우 게임을 오픈하고 나서야 서버에 문제가 있다는 것을 알게 된다.

그러다 보니 서버 프로그래머에게 있어서 실제 서비스를 끝까지 론칭해 본 경험은 굉장히 중요하다. 사람이 모든 것을 미리 파악할 수는 없지만, 적어도 이전에 서비스를 론칭해보고 문제를 겪어봤던 사람들은 어디서 어떻게 문제가 생기는지를 좀 더 잘 파악하고 이를 미연에 방지할 수 있기 때문이다.

그러나 실제로 게임 서비스까지 주도적으로 론칭해 본 서버 프로그래머가 몇 명이나 될까? 이것이 게임 개발사들마다 좋은 서버 프로그래머를 구하지 못해서 고생하는 이유다.

그럼 어떻게 하면 서버에 문제가 있는지 미리 점검해볼 수 있을까? 이런 안정성 확보를 위해서 봇 (bot) 이라는 가상 클라이언트들을 붙여보는 테스트와 CBT/OBT 등을 활용하게 된다.


12) 부하 테스트 방법1 - 봇 테스트

봇은 영어 단어 bot 을 말하는데, 로봇을 의미한다. 정식 오픈 전에 실제 유저들을 몇천 명 모아서 플레이시킬 수 없기 때문에, 게임 서버와 통신을 할 수 있는 프로그램을 만들고 그것들을 게임 클라인 양 서버에 접속시켜서 이 패킷 저 패킷 보내는 것을 시키게 된다.

▲ 봇 테스트 예제

클라는 여러 개 띄우는 것이 어려우니, 클라 패킷을 보낼 수 있는 봇이라는 프로그램을 만들어서 동시에 여러 유저가 접속한 것을 흉내낸다.

그런데, 클라의 모든 기능을 그대로 bot 에 구현하는 것은 굉장히 오랜 시간이 걸린다. 그리고 bot실제 게임에서는 '이 행동 다음에 이 행동이 이어진다'와 같은 패턴들이 존재하기 때문에 bot 이 실제 사람처럼 플레이하게 하는 것도 어렵다. 그 때문에 봇 을 이용한 부하 테스트는 최소한의 성능 테스트이긴 하지만 bot 테스트를 해도 서비스 오픈 후에 서버가 터지는 일은 허다하다.


13) 부하 테스트2 - CBT / OBT / 소프트 론칭

실제 서비스 환경에서 테스트해볼 수 있는 것이 가장 이상적이기 때문에, 많은 게임사들은 CBT 나 OBT, 소프트 론칭 같이 작은 규모로 미리 서비스를 열어본다.

물론 이런 테스트들의 목적이 단순히 서버 성능 확인만으로 국한되지는 않는다. 게임 시스템에 대한 유저 피드백을 받거나, 게임 내 경제 등의 밸런스를 조정하는 등의 기획적인 튜닝 작업이 목적이기도 하고, 사전 기대감 증폭이라는 마케팅적인 이유도 포함된다.


어쨌거나 이런 베타 테스트들은 서버 프로그래머 측에서도 서버의 안정성을 확인할 수 있는 좋은 기회가 된다. 그 때문에 그 기간 동안 동접이나 패킷 처리량 등을 고려하여 서버의 부하를 점검하고,'프로파일링' 이라는 기법을 통해서 처리가 오래 걸리는 부분을 찾아낸다. 또한, 병렬 처리에 따른 복잡한 이상 동작이나 서버 크래시도 이 과정 중에서 수정되기도 한다.

사실 오픈 하고 나서 서버가 전혀 죽지 않고 안정적이기는 힘들다. 그러니 적어도 베타테스트라면 서버가 살짝 불안하더라도 서버가 죽었다는 사실 자체보다는 프로그래머들이 얼마나 빨리 문제를 수정하는지에 따라 박수를 쳐주면 불쌍한 서버 프로그래머들도 힘을 낼 수 있을 것이다.