인프런 커뮤니티 질문&답변

윈우님의 프로필 이미지
윈우

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part9: MMO 컨텐츠 구현 (DB연동 + 대형 구조 + 라이브 준비)

3~4일 간격으로 CPU 99% 사용되는 문제

작성

·

243

·

수정됨

0

안녕하세요? 루키즈님 덕분에 서버에 대해 많은 것을 배우고 저만의 프로젝트도 개발하고 있는 개발자 입니다.

(항상 감사하게 생각하고 있습니다.)

 

질문은

3~4일 간격으로 CPU가 99% 사용되는 문제가 발생하여 원인 분석 차

CPU가 99% 사용되는 현상이 발현된 시점에 visual studio 성능 프로파일러를 통한 결과를 얻었습니다.

헌데 ServerCore.Listner.OnAcceptCompleted에서 많은 양의 CPU를 사용하고 있는 것으로 파악되는데

실제로 Connect요청은 없었습니다.

심지어 DummyClient를 이용해 1000명의 플레이어가 기본플레이 까지 했을때도 발생안하다가, 3~4일 후 아무도 접속안하고있는 시점에 발생합니다.

 

아래 RecvBuffer 코드와 diagsession 정보를 보시고 답변 부탁드립니다.

혹여 정보가 부족하거나 추가로 확인 필요한 부분 말씀해주시면 다시 확인해서 질문드리겠습니다.

감사합니다.


diagsession 캡쳐화면


RecvBuffer 코드

buffer size : 65535

public class RecvBuffer
{
    ArraySegment<byte> _buffer;
    int _readPos;
    int _writePos;

    public RecvBuffer(int bufferSize)
    {
        _buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
    }

    // [r] [] [] [w] [] [] [] [] [] [] [] 일때
    // <Data>[r] [] []</Data> <Free>[w] [] [] [] [] [] [] []</Free>  
    // read의 위치
    public int DataOffset => _buffer.Offset + _readPos;
    // read ~ write까지의 사이즈
    public int DataSize => _writePos - _readPos;

    // write의 위치
    public int FreeOffset => _buffer.Offset + _writePos;
    // wirte ~ buffer의 마지막
    public int FreeSize => _buffer.Count - _writePos;

    public ArraySegment<byte> ReadSegment => new ArraySegment<byte>(_buffer.Array, DataOffset, DataSize);
    public ArraySegment<byte> WriteSegment => new ArraySegment<byte>(_buffer.Array, FreeOffset, FreeSize);

    public void Clean()
    {
        int dataSize = DataSize;
        if (dataSize == 0)
        {
            // 남은 데이터가 없으면 커서 위치만 리셋
            _readPos = _writePos = 0;
            return;
        }

        // 남은 데이터가 있으면 시작위치로 복사
        Array.Copy(_buffer.Array, DataOffset, _buffer.Array, _buffer.Offset, dataSize);
        _readPos = 0;
        _writePos = dataSize;
    }

    public bool OnRead(int numOfBytes)
    {
        if (numOfBytes > DataSize)
            return false;

        _readPos += numOfBytes;
        return true;
    }

    public bool OnWrite(int numOfBytes)
    {
        if(numOfBytes > FreeSize) 
            return false;

        _writePos += numOfBytes;
        return true;
    }
}

 

답변 2

0

Rookiss님의 프로필 이미지
Rookiss
지식공유자

지난 번에 다른 분께서 제보주셨던 이슈 같은데
패킷 조립하는 부분에서, 사이즈가 0~4 일 때 처리가 누락되었을거에요.

윈우님의 프로필 이미지
윈우
질문자

먼저 답변달아주셔서 감사합니다.

말씀해주신 내용보고 패킷조립시 사이즈 관련 부분을 확인해봤는데 사이즈 0~4일때 처리를 제대로 하고있다고 생각되는데 이상한 부분이 있나요?

  1. 맨앞 2bytes는 전체 패킷 사이즈 - protobufSize + 2 + 2 ([사이즈(2)][MsgId(2)][Protobuf])

  2. 이후 패킷 사이즈 만큼 버퍼에 데이터가 들어오면 패킷 조립

  3. 패킷 조립시 사이즈, Id 제외한 부분에 대해서 Deserialize 진행

image

image

Rookiss님의 프로필 이미지
Rookiss
지식공유자

예를 들어 실제 패킷은 12바이트인데,
헤더에는 (조작이건, 버그이건) 0 바이트를 기입하면
image무한루프가 됩니다.

윈우님의 프로필 이미지
윈우
질문자

아! 이걸로 몇달을 고생했는데 정말감사합니다..

한편으론 몇달동안 문제 원인을 파악못한 제 자신에게 답답하네요.

실제 이런 문제가 발생하면 어떻게 접근해야 되는걸까요?

현상이 3~4일 뒤에나 발생되고 발생방법도 알 수 가없는 상황에서

발생될때까지 기다렸다가 발생 했을때 덤프생성해서 분석도 해봐도 찾질 못했는데

문제 발생에 대한 원인분석 방법이나 마음가짐 같은게 궁금합니다..

Rookiss님의 프로필 이미지
Rookiss
지식공유자

정해진 방법은 없고, 덤프를 열심히 분석해보면
어디선가 멈춰있는 부분이 있을텐데 (CPU 100%라면 보통 무한루프겠죠)
그 부분의 데이터를 관찰하며 의심할 수 밖에 없겠습니다.

0

안녕하세요, 인프런 AI 인턴입니다.

윈우님의 질문과 유사한 경우를 과거 데이터에서 신중히 검토했습니다. CPU 사용량이 100%에 도달하는 문제에 대한 유사 질문과 그에 대한 답변의 링크를 공유해드립니다.

해당 질문에서는 AWS 환경에서 서버가 특정 시점에 CPU 사용량이 100%에 도달하는 문제에 대해 질문하셨고, 여기에 대한 답변으로 지식공유자는 여러 가능성을 제시하며, 특히 Job 관련 문제 또는 반복적인 작업으로 인한 CPU 부하를 의심하고 있습니다.

cpu사용량 100%에 대한 답변에서 나온 같은 맥락에서, ServerCore.Listner.OnAcceptCompleted에서 발생한 고성능 부하 문제가 서버에서 처리하는 작업(Jobs)으로 인한 것일 수 있다는 점을 고려해봐야 할 것 같습니다.

이 경우, Job을 시작했는데 그 안에서 또 다른 Job을 생성하는 재귀적인 구조가 형성되어 일감이 밀리는 상태가 아닌가 싶습니다. 디버그 및 성능 최적화를 위해 파일 로그를 심어보거나 주기적으로 Job의 수를 확인하는 로그를 남겨보시는 것도 좋은 접근 방법일 것 같습니다.

또다른 맥락으로, 메모리가 줄줄 새고 있습니다 질문에서는 메모리 누수 문제에 대한 설명으로, 문제가 된 부분이 SendBuffer의 관리 방법이었다는 점도 유의해볼 만합니다. 윈우님의 경우 CPU 사용률과 관련되어 있으나, 리소스를 관리하는 방법에서 비슷한 원인이 있을 수 있습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

윈우님의 프로필 이미지
윈우

작성한 질문수

질문하기