실패 한 protobuf 기준 테스트

더 읽 기
이전에 pemelo 자 료 를 보 았 을 때 작 가 는 pemolo 에 대한 최적화, json 의 완전 직렬 화 는 서버 메시지 전달 의 병목 이 되 었 다 고 언급 한 적 이 있다. 현재 제 게임 서버 에서 protocbuf 를 프로 토 콜 로 사용 하고 있 습 니 다. 그 표현 은 매우 안정 적 입 니 다. 클 라 이언 트 와 저 는 프로 토 콜 에 대한 교류 가 원활 하고 양쪽 의 개발 효율 을 크게 향상 시 켰 습 니 다. 완벽 해 보이 지만 저 는 항상 은근히 불안 합 니 다. 저 는 가끔 의심 합 니 다.
현재 protobuf 의 방식 에 문제 가 있 지 않 습 니까? 서버 가 프로 토 콜 대상 에 대한 직렬 화 와 반 직렬 화 를 서버 의 성능 병목 으로 만 들 지 않 습 니까? 
 
우리 게임 의 메시지 유형 이 비교적 많 기 때문에 약 100 가지 요청 이 있 습 니 다. 메시지 의 시퀀스 / 반 직렬 화 작업 을 편리 하 게 하기 위해 서 보통 큰 메 시 지 를 사용 합 니 다. 소포 하위 메시지 방식 으로 구성:
 
protobuf 의 공식 문서 에 따 르 면 유 니 온 type 의 조직 형식 을 묘사 하여 이 루어 집 니 다 (https://developers.google.com/protocol-buffers/docs/techniques):
 
message OneMessage {
  enum Type { FOO = 1; BAR = 2; BAZ = 3; }
  required Type type = 1;
  optional Foo foo = 2;
  optional Bar bar = 3;
  optional Baz baz = 4;
}

 
 
구 글 그룹 이 필요 로 하 는 토론 에서 메시지 바이트 흐름 을 내장 하 는 방식 을 제시 했다.
message OneMessage {
  enum Type { FOO = 1; BAR = 2; BAZ = 3; }
  required Type type = 1;
  required bytes innerMessage = 2;
}

 
나 는 결국 다음 방법 을 채택 했다. 왜냐하면 전 자 는 세 가지 단점 이 있 을 것 이 라 고 생각 하기 때문이다.
1. 큰 메시지 체 가 너무 지루 해서 하나의 키 메시지 유형 에 수백 가지 항목 이 있 을 수 있 으 므 로 유지 하기 어렵다.
2. 메시지 에 선택 할 수 있 는 메시지 필드 가 너무 많 습 니 다. 그러나 모두 null 입 니 다. 직렬 화 된 모든 메 시 지 는 쓸모없는 인용 메모 리 를 많이 차지 합 니 다. 메시지 대상 의 수량 은 바로 수량 이 가장 많 습 니 다. 위험 이 있 을 수 있 습 니 다.
3. 내장 대상 은 매번 직렬 화 되 어야 하 는 것 이 아 닙 니 다. 서버 는 대화 상 태 를 저장 하고 모든 상 태 는 유형의 메시지 만 보 낼 수 있 습 니 다. 클 라 이언 트 가 개선 한 메시지 유형 과 서버 상태 가 대응 하지 않 으 면 메 시 지 를 직접 버 릴 수 있 습 니 다. 내부 메 시 지 를 직렬 화 할 필요 가 없습니다.
 
이렇게 해서 프로젝트 는 한동안 안정 적 으로 실행 되 었 으 나 우연히 debug 를 통 해 protbuff 의 내부 코드 가 내부 메시지 의 시퀀스 에 성능 위험 이 존재 하 는 것 을 발견 했다.
protobuf 에서 바이트 에 대한 정의:  required bytes innerMessage = 2;
Probobuf 는 직렬 화 할 때 변 하지 않 는 ByteString 대상 으로 바 뀌 지만 ByteString 대상 을 생 성 할 때 원본 메시지 바이트 배열 을 복사 하여 직렬 화 된 대상 에 게 전달 합 니 다 (CodedInputStream. readBytes () 참조). 
protbuff 가 바이트 배열 의 복사 에 사용 하 는 것 은 System. array copy (native memcopy) 이지 만 기능 적 으로 이런 복사 가 저 에 게 는 전혀 필요 하지 않 습 니 다. (google groups 역시 이에 대해 의심 을 가지 고 있 습 니 다. https://groups.google.com/forum/?fromgroups#!topic/protobuf/ZaDigptdcHM).
 
일회 성 직렬 화 된 유 니 온 type 방식 에 비해 메시지 바이트 흐름 을 내장 하 는 방식 으로 바이트 배열 의 복사 본 을 한 번 더 할 수 있 습 니 다. 성능 에 문제 가 생 길 까 봐 걱정 입 니 다.
 
그래서 이 두 가지 방식 을 비교 하기 위해 서 나 는 간단 한 기본 테스트 를 했다.
 
 
message PBTestNestPacket {
	required PBClientRequestType clientRequestType = 1; //    
	optional bytes requestData = 2; //    
}

message PBTestUnionPacket {
	required PBClientRequestType clientRequestType = 1; //    
	optional PBDummyRequest dummyRequest = 2;
	.........
	optional PBAutoBattleRequest autoBattleRequest = 100;
}

 
 
두 가지 내용 이 같은 메 시 지 를 만 들 고 메시지 의 직렬 화 된 바이트 배열 을 각각 생 성 한 다음 에 서로 다른 바이트 배열 의 깊이 를 직렬 화 합 니 다.
각각 다른 몇 개의 테스트 를 실시 한 결과 두 가지 방식 의 응답 시간 은 큰 차이 가 없 는 것 으로 나 타 났 다. 대부분 바이트 배열 을 포함 하 는 방식 으로 응답 시간 이 빠르다.
 
                                     union      .
report: size:20, testTurn:5000 :  nest: 167 union: 216
report: size:100, testTurn:5000 nest 246 union 256
report: size:100, testTurn:50000 nest 1163 union 1236
report: size:500, testTurn:5000 nest 750 union 789
report: size:500, testTurn:50000 nest 10122 union 10129
report: size:1000, testTurn:5000 nest 1407 union 1421
report: size:5000, testTurn:5000 nest 9471 union 9690

 
 
비록 비 과학적 인 결과 가 나 왔 지만, 이번 테스트 는 적어도 나 자신 을 안심 시 켰 다. 현재 의 사용 협의 방식 은 다른 방식 에 비해 성능 에 있어 서 열세 가 없고, 유지 보수 성 이 많이 향상 되 었 다.

좋은 웹페이지 즐겨찾기