[Server Programming] 서버 프로젝트에서의 시리얼버퍼 사용, 그리고 GIT활용
기존 코드에 대한 의문점
서버 동작과정에서 데이터를 시리얼버퍼활용하여 다른 함수로 이동시킬때, (EX: RECV후에 컨텐츠레이어로 패킷을 전달할때) 기존에는 동적할당을 하고, 사용 후에는 delete하는 식이였다.
그런데 현재 에코서버는 iocp 워커스레드로 이벤트방식의 Recv한 데이터에 대해 컨텐츠(Echo)까지 한 스레드가 전부 책임을 지고 있는데, 굳이 그 과정에서 동적할당 후 free하는 성능 소모를 굳이 할 필요가 없어 보였다.
그래서 스택으로 교체하고 패킷 전달과정에서의 2번의 생성과 삭제 시간의 평균치를 측정하였다.
1:1(work:conc) Packet | 1.2953㎲
2:4 Packet | 1.3737㎲
1:1 Packet | 0.9957㎲
2:4 Packet | 1.0653㎲
커밋
https://github.com/OneCrazyman/game-server-portfolio/commit/82ccc9473338982b8cb0c2ec761e96daa793ab81
커밋 전 후에 성능 테스트할때, 깃을 활용하였다.
과거의 해당 커밋에서 새 브랜치를 판 후에 feat: 프로파일러 를 cherry-pick하고, 성능 비교를 위한 대조군에서 프로파일링 하는 환경을 구성하여 진행해보았다.
내부에도 동적할당이 존재
이어서, 두번의 동적할당과 해제와 단순스택과는 당연히 성능차이는 유의미해보인다. (서버에서 런타임 동적할당은 최대한 피하는게 좋겠지~)
아직 시리얼버퍼 내부에서도 객체 멤버 버퍼에 대한 동적할당이 존재하기 때문에, 결론적으로는 오브젝트풀을 후에 적용하여 시리얼버퍼에 대한 런타임에 동적할당을 완전히 제거하여 최적화 할 수 있겠다.
그럼에도 의문점이..
에코서버의 패킷 전달과정을 문득 다시 따라가보니, 의문점이 들었다. RECV완료통지가 오고, RECV링버퍼에서 카피해서 PACKET객체를 만들고,, 여차저차해서PACKET객체를 SEND링버퍼에 다시 카피해서 옮기고
그렇다면 애초에 RECV링버퍼에서 REAR포인터와 DATA LEN만 컨텐츠 레이어까지 전달해 SEND링버퍼에 카피하는 과정에서 해당 파라미터로 그대로 떠주면 되는거 아닌가??
여기서 주의할점은 그 과정에서 RECV링버퍼가 동기화가 되어야하는건데, 내 서버 구조에선 비동기 RECV는 최대 1개만 진행되고, RECV완료통지 이후 위의 컨텐츠과정을 다 처리한후에 다시 RECV IO를 요청하게 된다.
즉, SEND링버퍼에 카피하는 순간까지 해당 세션의 RECV링버퍼는 변경되지 않는것이 보장된다. 그렇다면, 해당 방법을 쓰는게 성능적으로 더 좋을것이고, 시리얼버퍼를 사용할 이유도 없다.
시리얼 버퍼를 사용해서 성능을 높이려면?
제로카피로 사용할 수 있겠다. RECV,SEND에서 각 패킷 스트림을 링버퍼에 카피했다면, 시리얼버퍼에 RECV받고, SEND링버퍼에 시리얼버퍼 포인터를 담았다가, POST SEND시, WSABUF에 시리얼버퍼를 다 태워서 비동기 IO를 보내면 된다.
후에 직접 구현을 해서 성능을 비교해봐야 정확히 이해할 수 있을거 같다..