포트폴리오

Select 모델 서버 프로젝트 09 - 서버 루프가 갑자기 0으로 꺼지는 현상 해결

묭묭.cpp 2024. 10. 30. 18:46

Select 모델 서버 프로젝트 09 - 서버 루프가 갑자기 0으로 꺼지는 현상 해결

문제점

서버에서 7000개의 클라이언트 더미 테스트를 진행

  • 30~40분에 한번씩 서버 FPS와 네트워크 Loop가 0으로 떨어지던 버그 발생
  • 그리고 다시 회복되어 정상 작동
  • 크래시 덤프를 남기고 디버깅을 해보자

크래시 덤프 코드 삽입

모니터링 스레드의 Update 루프에서

    // FPS가 5으로 떨어지면 Crash 유도
    if (m_lFPS < 5)
    {
        MonitoringFile(sessionCount, playerCount);
        CCrashDump::Crash();
    }
  • FPS가 5 밑으로 떨어지면 서버의 크래시를 유도하고
  • 서버가 크래시가 날 때까지 기다림

덤프 파일 확인

test18

  • 덤프 파일의 크기가 이상함
  • 덤프 파일의 크기는 실제로 프로세스가 사용중인 메모리 크기임
    • 딱 봐도 메모리 누수
  • 일단 메모리 누수부터 잡자!

메모리 누수 잡기

가장 간단한 것부터 확인하기

  • 가장 무식한 방법
    • 비주얼 스튜디오에서 솔루션 대상으로 모든 new를 검색하여 추적
  • 일단 모든 new와 delete를 추적해보자
    • 여기서 잡히면 베스트
    • 안잡히면 예전에 만들었던 new delete 오버로딩을 통한 추적기를 사용해볼 예정

Player와 Session 객체부터 확인

  • 여기는 할당되는 곳과 할당 해제되는 코드의 위치가 다름
  • 그리고 내가 직접 설계한 구조이기 때문에 어디서 할당 해제되는지 확실히 알고 있음
  • 각각 해당하는 부분을 체크함
    • 문제가 없었음

직렬화 버퍼

  • 이것은 직접 할당한 코드의 생명주기에서 할당 해제해야 함
    • 직접 할당 - new 가 아님
    • CGenPacket을 통한 할당
  • CGenPacket을 검색하여 추적
    • 이곳이 문제였음
    • CGameServer.cpp의 모든 부분이 해제를 안하고 있었음
      • 가장 처음 테스트 용도로 짰었음...
      • 모두 delete 코드를 넣어주고 확인

test19

  • 모니터링 결과 누수는 없었음

그럼 FPS 0은 왜 나왔는가?

FPS가 0으로 될 시점의 커널 CPU 사용률이 거의 25에 근접

  • 유저 모드로는 거의 못 돌았다는 것
  • 그런데 네트워크 TPS는 조금 조금씩 나옴

다른 케이스는

  • 아예 스레드가 블락되어서 돌지 못했음
  • CPU 사용률이 0에 근접

아래 로그는 모니터링 스레드를 Sleep 안걸고 Full로 돌릴 때의 케이스

// case 1
Process Usage
     Total     : 49.219566
     User     : 25.781677
     Kernel     : 23.437889

// case 2
Process Usage
     Total     : 28.525297
     User     : 23.836208
     Kernel     : 4.689090

덤프 파일을 확인한 결과 유의미한 결과를 얻지 못했음

  • 스레드가 블록된 위치가 정확하지 않음
  • 두 결과 모두 다른 위치

로컬에서 돌려보자

  • 직접 로컬에서 테스트한 결과
  • FPS가 0이 되는 상황이 많이 발생함
    • CPU가 바쁘게 돌고 있어 내 서버 프로세스가 CPU를 점유하지 못하는 상태에서 0이 되는 건 확실
    • 근데 아예 블록이 되는 건 이해되지 않음

FPS가 0이 되는 순간 서버 프로세스를 멈추어 봄

  • 거의 모든 순간에 로그를 작성하기 직전에 멈추어 있었음
  • 로그를 파일에 쓸 땐 SRWLock을 사용함

test20

  • 대부분의 상황에서 SRWLock 코드에서 걸려있음
  • 로그를 정말 많이 써야할 상황임
  • 정말 바쁜 상황에서 모니터링 코드에서도 락을 많이 검
    • 상황이 잘못 맞아 네트워크 스레드의 SRWLock이 스핀 카운트를 모두 돌고 블락에 빠짐
  • 혹은 저곳에서 스핀락을 돌고 있음

데드락은 아니었고 사실 정상적인 상황이었음

  • 정말 서버가 바빠서 코드를 수행하지 못하고 있던 것
    • 즉, 그냥 매우 느리게 동작함

위에서 메모리 누수를 잡고 서버에서 테스트한 결과

  • FPS가 떨어지지 않고 잘 도는 것을 확인

그럼에도 찔끔찔끔 메모리가 오르는 현상을 확인

  • std::unordered_map의 사이즈 확장 시 커진 사이즈를 그대로 냅둠
  • 처음 서버 초기화 시점에 reserve를 수행하면 사용 메모리가 안정적인 것을 확인
    • 아마 서버를 계속 켜뒀어도 메모리 누수는 아니고 적당히 오르다 안 올랐을 것
반응형