출처 : http://funcreators.net/wp/c%ec%9c%bc%eb%a1%9c-%ea%b2%8c%ec%9e%84%ec%84%9c%eb%b2%84%eb%a5%bc-%ea%b0%9c%eb%b0%9c%ed%95%9c%eb%8b%a4%eb%a9%b4/

 

 

 

c# 서버 제작하시는 분 있으신가요?

게임 코디에 올라온 c# 서버 제작하시는 분 있으신가요?1라는 질문에 대해 나름대로 답변을 하고자 한다.

구글 검색, GPG 검색으로 c# 개발에 대해 부정적인 시각이 매우 많네요.
그런데 요즘 구인 글 보면 c# 서버 개발 가능자란 문구가 좀 보이는데요…
아직까지 캐주얼 게임에만 적용된 C#서버만 보였는데,
MMORPG 개발사인데 C#서버 개발 가능자를 뽑긴 하던데…
요즘엔 MMORPG에 C#서버로 돌리나요?
업계 동향 보니깐 아예 c#으로 가는 팀도 많아 보이던데….
혹시 경험 및 사례 있으시면 조금 공유 부탁 드려봅니다.

질문과 답변 형식으로 궁금증을 해소하는 편이 읽는 이가 이해하기에 나을 듯 싶다.

참고로 굳이 C#을 고려한 걸 보면 C#을 도입했을 때의 장점은 분명히 알리라 믿고 이 글에서는 성능 문제에만 초점을 맞춘다.

C#이 느리다던데요?

무엇과 비교하는냐에 달렸다. C/C++과 비교하면 느리다. 그런데 얼마나?

2

C# versus C++ versus Java performance comparison2에서 가져온 이 자료에 따르면 Windows에서 C++은 C#보다 단지 15%가 빠를 뿐이다. 2009년도에 성능 차이가 이 정도였으니 현재는 격차가 더 적을 것이다. 물론 벤치마크의 방식과 샘플 데이터에 따라 결과는 달라진다. 하지만 대부분의 벤치마크에서 비슷한 수치를 보고한다.

그런데 왜 사람들은 C#이 느리다고 하죠?

C# 응용프로그램이 느리다고 느끼는 이유는 몇 가지 있다.

Just-in-time 컴파일

.NET Framework 는 JIT 컴파일을 한다. 여러분이 Visual Studio 에서 C#을 컴파일하면 바이너리 코드가 아닌 VM(가상머신) 언어로 결과가 나올 뿐이다. 나중에 응용프로그램을 실행할 때 .NET Framework 런타임이 VM 언어를 다시 네이티브 바이너리로 컴파일한다.

이런 까닭에 응용프로그램의 초기 구동시 반응이 느릴 수밖에 없다. 대부분의 프로그래머는 코드를 몇 줄 고치고 프로그램을 실행하고 닫는다. 이런 과정을 반복하기 때문에 장시간 운영되는 라이브 환경에서 나오는 성능보다 훨씬 낮은 체감 성능을 느낀다.

.NET Framework 에는 C# 코드를 바로 네이티브 코드로 컴파일하는 도구가 있긴 하다. 하지만 이런 도구를 사용하면 JIT가 제공하는 최적화를 놓치게 된다. 이러한 도구는 구동 시간이 중요한 클라이언트에 써야지 전체 처리량(Throughput)이 중요한 서버에 쓸 게 아니다.

가비지 컬렉션 방식

.NET Framework의 메모리 할당 방식은 간단히 말해 스택 할당이다. 따라서 할당 속도는 C++ 보다 빠르다. 물론 C++ 처럼 메모리 할당 전략을 프로그래머가 마음껏 바꿀 재량권은 상당히 박탈당한다.

빠른 할당에 비해 해제는 상당히 느린 편이다. 메모리가 부족하다 싶을 때 가비지 콜렉터가 한꺼번에 정리하기 때문이다. .NET Framework 의 런타임은 전체 처리량에 맞춰 최적화했다. 따라서 이러한 전략은 웹 서버와 같이 일시적인 느려짐이 크게 문제되지 않는 곳에 매우 적합하다. .NET Framework 초기에 ASP .NET 에 초점을 맞춰 마케팅이 이뤄진 점만 봐도 이러한 설계 철학이 이해가 된다.

따라서 C# 으로 서버를 개발한다면 소위 말하는 렉이 주기적으로 발생한다. 렉이 가끔 발생해도 문제되지 않는 서버에 쓰는 게 좋다. 렉이 발생해도 플레이어가 크게 불평하지 않는 캐주얼 게임이 아니라면 게임서버보다는 캐시서버 등에 적합하다고 보면 된다.

메모리 부족

같은 양의 데이터를 처리한다고 볼 때 C# 응용프로그램이 메모리 소모량이 심하다. 몇 가지 이유가 있지만 무엇보다 가비지 콜렉션을 최후까지 미루는 탓도 크다.

이렇다 보니 메모리가 부족한 환경에서는 가비지 콜렉션을 자주 해야 한다. 그뿐 아니라 스왑도 자주 발생한다. I/O 가 서버 성능에 가장 큰 영향을 미치는 요소 중 하나라는 점을 생각해야 한다.

단, 라이브 환경에서는 값싼 메모리를 마구 투입하면 되므로 큰 문제가 되지 않을 수도 있다.

참고로 .NET Framework 는 COM 을 통해 메모리 할당 전략을 어느 정도 바꿀 수 있다. 다만 해제 전략과 관련된 어떠한 API 도 제공하지 않는다.

C# 으로 구현한 상용 게임이 있어요?

있다. 마비노기 영웅전3! 그 외에도 개발 중인 MMORPG 도 있다. 단, 프로젝트마다 아키텍처와 문제해결 방식이 다르다. 고민 많이 해야 한다.

나쁘지 않은데?4

그렇게 좋다면 왜 C# 서버를 도입한 곳이 별로 없죠?

렉 문제와 설계의 어려움

앞서 말한 렉 문제가 게임 플레이에 크게 악영향을 주는 경우가 있다. 각 서버군 별로 나눠서 필요한 곳에만 C#을 적용해도 된다. 하지만 여러 개의 프로그래밍 언어를 개발팀이 익히고 유지보수해야 하는 문제가 있다. 또한 어떻게 아키텍처를 설계해야 C# 도입의 장점을 최대한 살리고 그 단점을 최소로 줄일 수 있는지 파악하기 힘들다.

느리다

어라, 방금 전까지 C#의 성능이 훌륭하다고 말하지 않았나? 아니, 그건 오해다. 15%? 작다면 작지만 어떤 경우에는 크다. 그게 핵심 엔진 코드라면 치명적일 수도 있다. 대체로 이러한 성능 차이는 분산 서비스로 설계하면 문제가 되지 않지만 단일 게임 서버에 하는 일이 몰린다면 심각한 문제가 야기될 가능성이 있다.

설계의 유연성이 부족하다

C++ 과 같은 네이티브 프로그래밍 환경이 주는 최대 장점은 설계의 유연성이다. 메모리 할당 및 해제 전략을 내 취미대로 고친다거나 무잠금 알고리즘을 적용한다던가(C#에서도 가능하지만, 그냥 해보면 안다) 초고성능을 추구하는 이에게 C# 환경은 답답한 면이 많다.

결론

여기까지 경험담을 정리했다. 잘 알고 잘 알아서 설계해서 알차게 살아보자. 어차피 내가 여러분의 프로젝트 책임자도 아니니 여기서부턴 나도 모르겠다.

급소 가격

 

회사에서 작업으로 받은 컴퓨터가 더 이상 작업하는데 인내심을 요구해서

(팬4 RAM 2GB ... ㅡㅡ... 아무리 장인은 연장탓을 안한다곤 하지만.. 기획자들은 i7에 ssd 보급해주면서 참...  )

현재 안쓰는 테스팅 컴퓨터가 굴러다니길래 (쿼드Q8300 RAM 5GB) 여기에

윈7 64bit 를 설치하고, 가능한 최신 컴파일러의 힘을 보고싶어서 Visual Studio도 2005 -> 2010으로 올렸습니다.

 

그런데.....

가뜩이나 빌드 환경을 적용 시키고

Lua 의 LNK2001 _lua ... 의 에러도 일일히 lib 파일을 지정 시켜서 서버 프로그램 빌드를 성공 시키는건 좋았습니다만...

 

이걸 테스트 서버 (윈2003) 에서 돌리니 프로그램이 걍 죽어 버리더군요.

 

처음엔 64비트로 컴파일 환경이 바껴서 그런가 해서 컴파일 옵션에서 전부 x86환경으로 맞췄는데 결과는 똑같아서

천상 원격 디버깅 까지 해가면서 원인을 찾아보니

 

CADODataBase::CADODataBase()
{
     ::CoInitialize(NULL);
     m_pConnection.CreateInstance(__uuidof(Connection));
     if( m_pConnection == NULL ){ 
          ASSERT(false && "CoInitialize() 를 먼저 호출해야합니다.");
          LOGCON(_T("[CADODataBase][ERROR][ADODB.Connection]\n"));  
     }
}

 

위의 ASSERT에서 죽어버리더군요.

 

그런데... 이게, 컴파일한 win7환경에선 전혀 문제없이 객체 할당에 성공시키니 뭐가 문제일까 하고 열심히 검색하던중

저랑 같은 증상으로 고생하신 분이 계시더군요.

(참고한분 블러그 입니다. http://icartsh.tistory.com/3)

 

결론은 msado15.dll 이 윈7이전이랑 이후 버젼이 있어서 만약 이후 버젼에서 컴파일 하면 위와 같은 함수에서 객체 생성에 실패할 수 도 있다는 이야기 입니다.

 

ms에선 이렇게 설명하고 있습니다.

http://support.microsoft.com/kb/2517589

 

 C:\Program Files\Common Files\System\ado

 

msado15.dll

 

실제로 저 파일의 타임 스템프가 2010년으로 찍혀 있고, 용량도 2배로 늘어있더군요.

MS가 무슨짓을 했는지 잘 모르지만, 해당 폴더의 원래 있던 msado15.dll 을 msado15_win7.dll 로 바꿔준뒤

저 파일을 다운 받아 재 컴파일 해서 테스트 해보니 이상없이 돌아가네요.

 

ㅜㅜ... 이것땜에 하루가 또... ㅠㅠ


일본에 있으면서.. 슬슬 어학과정도 끝나고해서, 이전의 프로그래밍 감각을 살려볼까 하는 취지에
만들었습니다.

이전 학교에서 턴프로젝트로 만들었던 리눅스 epoll 소스를 사용해서 (덕분에 DB는 MySQL을 사용했습니다)
윈도우 IOCP 서버 구축에 1주일,
클라이언트 제작에 3일.. 서로 데이터 동기화에 3일
총 2주 걸렸네요 orz

일단 결과물 입니다..
<서버 화면>

별볼일 없는 콘솔 화면 입니다..
현재 서버 시간을 1초 마다 갱신하게 만들었습니다.
위의 /last 같은것은 명령어 입니다.


다음 클라이언트 화면 입니다.
3D를 하는것이 좋긴 하지만, 그런거 빠지다간 끝이 없기때문에,
간단하게 현재 서버가 잘 작동되는지 눈으로 확인 가능한 2D GUI 클라이언트 입니다.
DirectX 2D 조차 쓰지 않은 순전 MFC 입니다.. @_@
맵도 원래는 바둑판처럼 가이드선을 그을려고 했는데
재미 없을꺼 같아서 소프트맥스의 창세기 외전2 템페스트의 세계 지도를 가져와 멋대로 붙였습니다.

밑에 서버 IP, port 입력하고 (디폴트 127.0.0.1:9000) connect 하면 서버에 연결됩니다.

ID와 암호를 채팅창으로 입력하면
플레이어 (마리오), 주변의 적(쿠퍼) 들이 뜹니다.

월드의 전체 크기는 5000x3200 으로 적은 렌덤으로 1000개가 뿌려지게 했습니다.
그리고 내 주변의 적들의 위치(거리 약 400), 방향, 타입, 등등의 위치를 recv 받아서 근처에 뿌려줍니다.

물론 다른 플레이어(클라이언트)도 마리오 형상으로 띄어줍니다.
단, 마리오 머리 위에 해당 클라이언트의 ID를 띄어놓게 했습니다.

채팅서버가 기본이므로. 채팅이 제대로 되는지 확인하기 위해 3개의 클라이언트를 띄었습니다.
클라이언트의 채팅은, 자기 주변 (약 200)안의 것들만 통신이 되게 했습니다.

1번 클라이언트 Miss.Ninja의 화면


2번 클라이언트의  Miss.Kim의 화면


3번 클라이언트 Miss.Rin의 화면


채팅내용을 잘 살펴보시면
가운데 닌자 클라이언트는 Kim과 Rin의 이야기를 다 듣지만, 다른 클라이언트는 닌자 클라이언트만 통신이 됩니다.


+ Recent posts