之前看到pemelo资料的时候,作者曾提到对pemolo的一次优化,json的完全序列化成为服务器消息转发的一个瓶颈. 目前我的游戏服务器中使用了protocbuf作为协议, 它的表现很稳定.让客户端和我对于协议的交流很流畅,极大的提高了两边的开发效率. 看起来很完美.但我总隐隐的觉得不安. 我有时候会怀疑:
目前的protobuf的方式会不会有问题.会不会让服务器的对协议对象的序列化和反序列化成为服务器的性能瓶颈.
由于我们游戏的消息类型比较多,大概有100种请求,为了方便对消息的序列/反序列化的操作.一般会使用一个大消息 包裹 子消息的方式来组织:
根据protobuf的官方文档描述了一种union 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; }
而在google group对此需求的讨论中,有人提出了内嵌消息字节流的方式:
message OneMessage { enum Type { FOO = 1; BAR = 2; BAZ = 3; } required Type type = 1; required bytes innerMessage = 2; }
我最终采用了后一个方法.因为我觉得前者会有三个缺点:
1. 大消息体过于冗长,对于一个子消息类型可能有几百种的项目来说,很难维护
2. 消息中的可选消息字段过多.但都为null,每个被序列化后的消息会占用很多无用的引用内存.而消息对象的数量又恰恰是数量最为庞大.可能会有隐患.
3. 内嵌对象不是每次都需要序列化. 服务器保存了对话的状态,每种状态只能发送类型的报文.如果客户端改善的报文类型和服务器状态不对应.则可以直接丢弃报文.无必要序列化内部消息.
就这样,项目稳定的运行了一段时间,但偶然的一次debug, 发现protbuf的内部代码对内部消息的序列存在一个性能隐患:
像protobuf中对字节的定义: required bytes innerMessage = 2;
Probobuf在序列化的时候,都会转化为不变的ByteString对象,但在生成ByteString对象时, 会对原始的消息字节数组进行一次拷贝,再传递给序列化后的对象(参见CodedInputStream.readBytes()).
虽然protbuf对字节数组的拷贝使用是System.arraycopy(native的 memcopy).但从功能上来说,这样的拷贝对于我来说,完全没有必要(google groups有人同样对此产生了怀疑 https://groups.google.com/forum/?fromgroups#!topic/protobuf/ZaDigptdcHM).
相对于一次性序列化的union 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
虽然产生了不科学的结果,但这次测试至少让我自己放了心.目前的使用协议方式和另一种方式相比性能上没有劣势.维护性上提高了不少.
相关推荐
protobuf-3.1.0.tar.gz 是一个包含Google Protocol Buffers(简称protobuf)版本3.1.0源代码的压缩包。Protocol Buffers是一种高效、灵活的数据序列化机制,广泛用于构建跨平台、跨语言的通信系统。在安装OpenCV 3.2...
protobuf-3.15.8.zip 是一个包含Google Protocol Buffers(简称protobuf)3.15.8版本的源码压缩包。Protocol Buffers是一种高效、灵活的数据序列化机制,常用于网络通信和数据存储。它是Google开发的一种跨平台、...
The descriptor.proto file deployed with 2.3.2.201609161849 seems to contain either an old or a custom version ...-- @gfecher [google/protobuf-dt/issues/4](https://github.com/google/protobuf-dt/issues/4)
这个库是Google的Protocol Buffers(通常简称为protobuf)在.NET平台上的实现,它提供了一种轻量级、快速且节省空间的数据交换格式。Protocol Buffers是一种结构化的数据表示方式,允许开发者定义数据结构,然后生成...
protobuf-2.4.1.tar.gz 是一个包含 Protocol Buffers(简称protobuf)版本2.4.1的源代码包,适用于Linux操作系统。Protocol Buffers是Google开发的一种数据序列化协议,它提供了一种高效、灵活且平台无关的方式来...
protobuf-3.1.x.zip是一个包含Google开源的Protocol Buffers(简称protobuf)版本3.1.x的压缩包。Protocol Buffers是一种数据序列化协议,它允许开发者定义数据结构,并将其编码为二进制格式,以便在网络间高效地...
标题中的"protobuf-2.6.1.tar.gz"是一个压缩包文件,其中包含了Protocol Buffers(简称protobuf)的2.6.1版本源代码。Protocol Buffers是Google开发的一种数据序列化协议,它允许开发者定义数据结构,然后生成能够...
protobuf-2.5.0.zip 是一个包含 Google 开源的 Protocol Buffers(简称 Protobuf)版本 2.5.0 的压缩包。Protocol Buffers 是一种数据序列化协议,它提供了一种高效、灵活且自动化的机制,用于结构化数据的序列化,...
标题中的"protobuf-2.5.0.tar.gz"是一个压缩包文件,其中包含了Protocol Buffers(简称protobuf)的源代码,版本为2.5.0。protobuf是Google开发的一种数据序列化协议,常用于结构化数据的存储和通信,它可以将复杂的...
protobuf-2.5.0是Protocol Buffers的一个旧版本,Protocol Buffers是由Google开发的一种数据序列化协议,常用于结构化数据的串行化,类似于XML、JSON,但更小、更快、更简单。它是跨平台的,并且有C++, Java和Python...
activemq-protobuf-1.1.jar;activemq-protobuf-1.1.jar
Protocol Buffers(简称Protobuf)是由Google开发的一种数据序列化协议,它能够将结构化的数据序列化,可用于数据存储、通信协议等方面。Protobuf提供的是一种比XML更小、更快、更简单的方式来序列化和反序列化数据...
git clone https://github.com/protocolbuffers/protobuf.git #get protobuf source code cd protobuf;git submodule update --init --recursive mkdir -p build/install;cd build #create directory for out-of-...
4. `scripts`或`tools`目录:包含构建和测试protobuf的脚本和工具,例如编译protobuf编译器的Makefile或者cmake文件。 5. `LICENSE`和`README`文件:分别提供了软件的许可信息和使用说明。 6. `CHANGELOG`或`RELEASE...
protobuf-3.0.0.tar.gz 是一个包含Google Protocol Buffers(简称protobuf)3.0.0版本源代码的压缩包。Protocol Buffers是一种高效、跨平台的数据序列化协议,由Google开发,广泛用于分布式系统中的数据交换。它是...
标题中的"protobuf-all-3.19.4.tar.gz"是一个包含Protocol Buffers(简称protobuf)版本3.19.4的归档文件,它是一个压缩格式,通常用于在不同平台之间分发软件。protobuf是一种高效的数据序列化协议,由Google开发,...
4. **仿真和测试**:在OAI的仿真和测试环境中,protobuf可以帮助定义和交换模拟数据,提高测试的可读性和可维护性。 至于"protobuf-3.3.0"这个目录,它可能包含了以下内容: 1. `src/`:源代码目录,包含了protobuf...
- Protobuf是由Google开发的一种数据序列化协议,2.5.0是其特定版本。 - 它可以将结构化的数据转换为二进制格式,用于网络通信或存储,比XML和JSON更高效。 - Protobuf支持多种语言,包括Java、Python、C++等,...