LOGIN • JOININ

[Bench] CGSF 엔진의 I/O성능 테스트

webmaster 2015.08.02 01:17 조회 수 : 7411

앞의 글에서 C#과 CGCII 그리고 단순 asio의 성능을 테스트해 보았습니다.

국산 C++ 공개 서버 엔진인 CGSF의 성능에 대해서도 앞의 테스트(C# SuperSocket vs CGSSi vs asio 테스트)와 같은 내용의 테스트를 해보았습니다.


테스트를 위한 클라이언트는 역시 앞에서 소개한 TCPEchoClient를 사용해 진행했습니다. (서버 성능을 테스트해보자 (1) )


1. 테스트한 내용과 환경


1) 100개의 접속을 한다

2) 100개의 접속을 통해 크기가 8Byte인 메시지를 전송한다.

3) 전송을 받으면 메시지 단위(8Byte)로 나누어 메시지 단위로 에코 전송을 수행한다.
     즉 1개의 메시지는 1개의 Send함수의 호출로 전송하도록 합니다.
     
(메시지 단위로 Send를 건다는 이것이 매우 중요한 테스트 요소입니다.)


즉 100개의 연결을 만들어 8Byte크기의 메시지를 마구 전송해서 얼마나 많은 메시지를 에코 전송해 오는가 하는 성능을 테스트한 것입니다.
이 내용은 앞에서 수행했던 테스트와 동일한 내용이므로 테스트 의미에 대한 자세한 내용은 이전 테스트 글(C# SuperSocket vs CGSSi vs asio 테스트)을 참조해 주십시요.

테스트 환경은 다음과 같습니다.


Windows 7 64bit

Intel i7-3770k 3.5GHz  4Core

16GByte


테스트용 서버와 클라이언트는 하나의 하드웨어에서 동작을 시키도록 합니다.


2. CGSF Casual Game Server Framework

1) CGSF(Casual Game Server Framework)에 대한 간단한 소개

  CGSF(Casual Game Server Framework)는 국내에서 진행하는 사실상 유일한 공개 서버 엔진 프로젝트로 여러 공개 라이브러리를  통합하여  캐쥬얼 게임 서버 개발에 필요한 다양한 기능들을 프레임워크한 엔진으로 ACE(ADAPTIVE Communication Environment)를 기반으로 제작되어 있습니다.
 따라서 단순히 네트워크 I/O기능을 제공하는 네트워크 엔진이 아닌 로직 레이어와 데이터베이스  P2P레이어 등 서버 구조와 기능까지 지원을 목표로 제작된 몇 안되는 국산 서버 엔진 중에 하나이기도 합니다.

 다양한 공개 라이브러리를 제공해 주기 위한 인터페이스와 구조로 비교적 모듈 교체를 용이하도록 설계되어 있습니다.
메시시지 시스템 만해도 기본적인 바이너리 메시지 뿐만 아니라 JSON , protobuf 등 다양한 메시지 직렬화를 지원하며 CRC체크와 암호화 등과 같은 기능 역시 손쉽게 사용이 가능합니다.

2) CGSF 테스트 준비

CGSF로 테스트를 하기 위해 기본적으로 제공해주는 예제 프로젝트인 "EchoServer" 프로젝트를 참조하여 "ProtocolServer"와 엔진의 일부를 변경하여 제작하였습니다.

1) 먼저 기본 제공하는 메시지 헤드는 최소 12바이트였기 때문에 이를 다른 테스트와 동일하게 만들기 위해 8Byte로 조정했습니다. 

    이를 위해 DWORD 형인 packetOption과 dataCRC를 WORD형으로 변경했습니다.  

typedef struct tag_SFPacketHeader
{
	USHORT	dataSize;
	USHORT	packetID;
	WORD	packetOption;
	WORD	dataCRC;
	...
};


2) dataSize와 packetID의 순서도 뒤집어 순서도 변경했습니다.
3) dataSize의 계산방법도 달라 이도 변경했습니다.
4) CGSF에서 dataSize는 메시지 헤드 크기를 제외한 크기를 넣는 반면 기존 테스트는 모두 메시지 헤드까지 포함한 크기였으므로 이를 기존 기준에 맞춰 변경했습니다.        (SFPacketIOBuffer::GetPacket(...) 함수, SFPacket::GetPacketSize()
함수를 수정했습니다.)

5) 또 가장 단순한 메시지 단위의 Echo 구현을 위해 "ProcessPacket" 함수에서 SFPACKET_DATA일 경우 Echo 전송을 수행하도록 변경하였습니다.
template<typename T>
bool ProtocolLogicEntry<T>::ProcessPacket(BasePacket* pPacket)
{
	switch (pPacket->GetPacketType())
	{
	case SFPACKET_DATA:
		//return m_Dispatch.HandleMessage(pPacket->GetPacketID(), pPacket);
		SFEngine::GetInstance()->SendRequest(pPacket); // 이부분 수정
		break;
	case SFPACKET_CONNECT:
		printf("new user coming!!\n");
	}
return true;
}


이렇게 작업을 진행하여 테스트 클라이언트에 물려 테스트를 진행하였습니다.



3) CGSF 테스트 결과
CGSF는 기본적으로  ACE 등을 사용해 랩핑하는 등 여러 단계의 랩핑처리가 있었으니 만큼 성능에서는 크게 기대하지 않았습니다.

100개의 접속으로 8Byte크기의 메시지를 대규모로 전송한 테스트를 한 결과는 다음과 같습니다.
CGSF_02.PNG
위의 스샷은 테스트 중 한 송신량 만큼 에코되어 수신되는 최대 수치일 때를 잡아 캡춰를 한 것입니다.

8Byte 메시지를 초당 5만~5만 5천개 가량을 수신했고 초당 5만~5만 5천개 정도를 전송했습니다. 
초당 10~11만개 정도의 메시지를 처리했습니다.
데이터 처리량으로따지면 초당 430KByte 정도를 수신하고 430KByte 정도를 송신했습니다. 
초당 860KByte 정도의 I/O를 처리했습니다.
이때 CPU 사용율은 2~3% 수준에 불과했습니다.
하지만 메모리 사용량은 가히 엄청난 량을 소모합니다. 겨우 100개의 소켓을 사용해 메시지를 전송하는데 메모리 사용량은 450M~600M 정도에 육박하는 데다 지속적으로 메모리 사용량이 늘어나는 현상도 보입니다.  아무래도 메모리 릭(Memory Leak)이 의심됩니다. (이건 서버 엔진으로써 좀 상황이 심각한 문제라고 봅니다.)
 
여기서 더 전송량을 늘리게 되면 받은 만큼 처리를 하지 못해 메시지가 누적되기 시작하며 메모리 사용량이 기하급수적으로 증가해  순식간에 2GBytes에 육박하게 되고 곧 서버가 다운되어 버립니다. 
이 문제는 비단 CGSF뿐만 아니라 I/O 쓰레드와 Logic( 혹은 Work) 쓰레드를 분리하고 이 둘 간에 메시지 큐를 통해 처리하도록 한 서버 구조에서 나타날수 있는 고질적인 문제점 중에 하나입니다.
특히 I/O는 다중쓰레드로 로직 처리은 단일 쓰레드로 처리되어 있을 경우 I/O처리 속도보다 로직 처리 속도가 느릴 가능성이 높기에 더욱 심각할 수 있습니다. 
  되도록 I/O 처리와 Work처리 불균형 혹은 쏠림 문제를 유발할 수 있는 구조는 피하는 것이 좋겠지만 꼭 써야 할 경우 서버의 안정성을 위한 적절한 처리가 반드시 필요합니다만 아직 미적용 상태인 듯합니다.
CGSF_01_1.png

[받은 메시지만큼 처리를 못해  메시지큐에 해당하는 부분에서 std::bad_alloc 예외가 발생한 상황]



3. 테스트 결과 비교
CGSF는 공개 서버 엔진으로  ACE 등 여러 공개 라이브러리를 랩핑하여 제작되었고 로직 처리부도 아직 단일 쓰레드로 처리함으로 인해  성능에 있어서는 당연히 비교적 낮을 수 밖에 없긴합니다.

하지만 테스트 결과 생각보다도 더 낮은 성능을 보였습니다. C#의 Supersocket은 물론 아무 처리하지 않고 제작된 asio에 비해서도 너무 현격한 차이를 낸 것으로 보입니다.

IOTestPerformance02.PNG


단순 asio에 비해서도 거의 9분에 1 정도에 불과한 성능을 냈고 C#용 Supersocket에 비해서도 72분에 1,  CGCII에 비해서는 420분에 1 정도의 성능을 냈습니다.
일단은 성능 그 자체만 보아도 실서비스용  서버 엔진으로 사용하기에는 한계가 있을 것이라고 보입니다.
근데 더 큰 문제는 CGSF는 송수신에 따른 메모리 사용량이 너무 많고 또 메시지 전송 테스트를 지속하면 메모리가 지속적으로 증가하는 메모리 릭이 존재하는 것으로 보인다는 점입니다.
 서버로써 여러 I/O처리 시 발생하는 예외적 상황에 대한 안정화 로직 등도 역시 아직 마련되어 있지 않는 것으로 보여 서버용 엔진으로 사용되기 위해서는 많은 부분의 개선과 기능의 추가가 필요해 보입니다.
그 외에도 여러 개의 Acceptor를 고려하지 않은 설계라든지 Config 파일을 설정하지 않으면 nullptr 참조로 서버가 다운되어 버리는 등 소소한 점에서의 개선 사항도 있어 보입니다.

CGSF는 아직 아쉬운 점은 있지만 우리나라에는 거의 유일한 게임용 공개 서버 엔진 프로젝트란 것 자체만으로도 상당한 가치가 있고 아직 개발이 계속 진행인 프로젝트인 만큼 장점은 더욱 극대화되고 단점은 개선되어 나갈 것으로 보입니다.


4. 테스트 서버
CGSF의 엔진 부분을 수정한 관계로 제작한 서버 소스만 올릴 수가 없어 부득이하게 실행파일로 올리게 되었습니다.
소스의 내용은 CGSF의 예제에서 아주 간단히 변경한 소스인만큼 CGSF를 다운받아 앞에서 설명한 내용만 수정하면 간단히 테스트 가능하시리라고 봅니다. 

[CGSF github]
https://github.com/pdpdds/CGSF

[CGSF TCP Echo 테스트 서버]
CGSF_TestEchoServer.zip