`
lixiaoxin
  • 浏览: 18384 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

protobuf 、protostuff、json 经过nginx的gizp压缩前后的大小比较

 
阅读更多
公司一个cs架构项目接口,使用json传输数据大小接近10M,简单的研究了一下protobuf 、protostuff,以及针对这个接口场景 使用protobuf 、protostuff、json序列化nginx的gzip压缩传输后文件大小的比较。
1.protobuf简单使用
下载protoc-3.5.1-win32.zip 和 protobuf-java-3.5.1.zip 分别解压
把 protoc-3.5.1-win32.zip里的protoc.exe拷贝到 E:\develop\protobuf-3.5.1\src (不考也行)
E:\develop\protobuf-3.5.1\src\protoc.exe 是protoc.exe 所在目录
E:\develop\protobuf-3.5.1\examples 是 .proto所在的目录
进入要编译的.proto文件目录(E:\develop\protobuf-3.5.1\examples) 执行一下命令
E:\develop\protobuf-3.5.1\examples>E:\develop\protobuf-3.5.1\src\protoc.exe --j
va_out=. addressbook.proto
会在当前目录生成AddressBookProtos.java
还可使用maven插件使每次打包的时候自动把.proto文件编译成.java文件
这里没有这么做,使用protocol buffer主要的工作是要另外编写.proto文件
对应现有系统改的比较大所以没有使用protobuffer方案。
.proto还是比较简单,可以自行学习
下面给出一下例子,只是为了忘记时候可以回忆一下,可以略过
syntax = "proto3";
option java_package = "com.*.*.*.*.rcp.protobuf";
option java_outer_classname = "XXXXProto";
import public "FltBookResult.proto";
import "ResultBase.proto";
message XXXXInfo {
/**
* <p>
* Description:航段唯一 ID 号
* </p>
*/
string soflSeqNr = 1;
.......
FltBookResult fltBookResult = 96;
ResultBase resultBase = 97;
}
2.prostostuff的使用
结合springmvc的Converter
import com.google.common.base.Stopwatch;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtobufIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import net.jpountz.lz4.LZ4BlockOutputStream;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.xerial.snappy.SnappyOutputStream;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.zip.GZIPOutputStream;
 
/**
* <p>
* An {@code HttpMessageConverter} that can read and write
* <a href="https://developers.google.com/protocol-buffers/">Google Protocol Buffer (Protobuf)</a> messages using the
* open-source <a href="http://http://www.protostuff.io">Protostuff library</a>. Its advantage over native Protobuf
* serialization and deserialization is that it can work with normal {@code POJO}s, as compared to the native
* implementation that requires the objects to implement the {@code Message} interface from the Protobuf Java library.
* This allows applications to use Protobuf with existing classes instead of having to re-generate them using the
* Protobuf compiler.
* </p>
* <p>
* Supports the {@code application/x-protobuf} media type. Regular Spring MVC application clients can use this as the
* media type for the {@code Accept} and {@code Content-Type} HTTP headers for exchanging information as Protobuf
* messages.
* </p>
*/
public class ProtostuffHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
private Logger logger = LoggerFactory.getLogger(getClass());
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
public static final MediaType MEDIA_TYPE = new MediaType("application", "x-protobuf", DEFAULT_CHARSET);
public static final MediaType MEDIA_TYPE_LZ4 = new MediaType("application", "x-protobuf-lz4", DEFAULT_CHARSET);
public static final MediaType MEDIA_TYPE_GZIP = new MediaType("application", "x-protobuf-gzip", DEFAULT_CHARSET);
public static final MediaType MEDIA_TYPE_SNAPPY = new MediaType("application", "x-protobuf-snappy",
DEFAULT_CHARSET);
 
/**
* Construct a new instance.
*/
public ProtostuffHttpMessageConverter() {
super(MEDIA_TYPE, MEDIA_TYPE_LZ4, MEDIA_TYPE_GZIP, MEDIA_TYPE_SNAPPY);
}
 
/**
* {@inheritDoc}
*/
@Override
public boolean canRead(final Class<?> clazz, final MediaType mediaType) {
return canRead(mediaType);
}
 
/**
* {@inheritDoc}
*/
@Override
public boolean canWrite(final Class<?> clazz, final MediaType mediaType) {
return canWrite(mediaType);
}
 
/**
* {@inheritDoc}
*/
@Override
protected Object readInternal(final Class<?> clazz, final HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
if (MEDIA_TYPE.isCompatibleWith(inputMessage.getHeaders().getContentType())) {
final Schema<?> schema = RuntimeSchema.getSchema(clazz);
 
final Object value = schema.newMessage();
 
try (final InputStream stream = inputMessage.getBody()) {
ProtobufIOUtil.mergeFrom(stream, value, (Schema<Object>) schema);
 
return value;
}
}
 
throw new HttpMessageNotReadableException(
"Unrecognized HTTP media type " + inputMessage.getHeaders().getContentType().getType() + ".");
}
 
/**
* {@inheritDoc}
*/
@Override
protected boolean supports(final Class<?> clazz) {
// Should not be called, since we override canRead/canWrite.
throw new UnsupportedOperationException();
}
 
/**
* {@inheritDoc}
*/
@Override
protected void writeInternal(final Object o, final HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if(logger.isDebugEnabled()){
logger.info("Current type: {}", outputMessage.getHeaders().getContentType());
}
Stopwatch stopwatch = Stopwatch.createStarted();
OutputStream stream = null;
 
try {
stream = outputMessage.getBody();
if (MEDIA_TYPE.isCompatibleWith(outputMessage.getHeaders().getContentType())) {
} else if (MEDIA_TYPE_GZIP.isCompatibleWith(outputMessage.getHeaders().getContentType())) {
stream = new GZIPOutputStream(stream);
} else if (MEDIA_TYPE_LZ4.isCompatibleWith(outputMessage.getHeaders().getContentType())) {
stream = new LZ4BlockOutputStream(stream);
} else if (MEDIA_TYPE_SNAPPY.isCompatibleWith(outputMessage.getHeaders().getContentType())) {
stream = new SnappyOutputStream(stream);
} else {
throw new HttpMessageNotWritableException(
"Unrecognized HTTP media type " + outputMessage.getHeaders().getContentType().getType() + ".");
}
 
ProtobufIOUtil.writeTo(stream, o, RuntimeSchema.getSchema((Class<Object>) o.getClass()),
LinkedBuffer.allocate());
stream.flush();
} finally {
IOUtils.closeQuietly(stream);
}
if (logger.isDebugEnabled()){
logger.info("Output spend {}", stopwatch.toString());
}
 
}
}
springmvc配置
 
使用httpclient调用时候使用httpBase.addHeader("Accept","application/x-protobuf"); //
Schema<***Dto> schema = RuntimeSchema.getSchema(***Dto.class);
***Dto value = schema.newMessage();
ProtobufIOUtil.mergeFrom(result1, value, schema);
注意的地方,
1、服务不能直接返回map或者list,如果是map或者list要经过多层封装
2、不能返回带有泛型的实体如:DataGridBean<T> ,在服务器返回的时候没问题,
反序列化成实体时候报错,估计是
Schema<***Dto> schema = RuntimeSchema.getSchema(***Dto.class);
Schema<***Dto<T>> schema = RuntimeSchema.getSchema(***Dto<T>.class);//这里不能这样写,还没找到解决办法,所以只能另外写一个实体,不要使用泛型,把具体类型写进去
后来补充:对于上述问题静态已经解决了,要在声明Schema的时候使用Schema<? extends DataGridBean>
ProtobufIOUtil第三个参数schema强转一下(Schema<DataGridBean<XXXDto>>)schema如下:
// DataGridBean<XXXDto> o = new DataGridBean<XXXDto>();
// Schema<? extends DataGridBean> schema = RuntimeSchema.getSchema(o.getClass());
Schema<? extends DataGridBean> schema1 = RuntimeSchema.getSchema(DataGridBean.class);
DataGridBean<FlightGoccInfoDto> dataGridBean = schema1.newMessage();
ProtobufIOUtil.mergeFrom(result1, dataGridBean, (Schema<DataGridBean<XXXDto>>)schema1);
 
3.比较大小
只针对生产出现问题需要优化的一种常景
protostuff大小约为json的一半
protostuff
json
4.经过nginx gzip压缩后大小比较
经过fiddler抓包后 发现经过gzip压缩后大小相差不是很大
protostuff 52k左右 压缩了将近10倍
json 60k左右 压缩了将近20倍
5.在此过程中遇到到问题
5.1 使用postman调用接口的过程,postman显示的时候解压后的大小,还没找到压缩前的大小
5.2 使用httpclient4.3 返回的response会把返回类型为gzip,x-gzip自动封装成GzipDecompressingEntity
然后remove Content-Encoding 导致使用旧的判断方法时候一直都是进入非gzip的分支
使我一度怀疑nginx的gzip不起效果
最后经过debug查看源码以及使用fildder4抓包的才确定确实有压缩
ResponseContentEncoding.java
 
  • 大小: 11.9 KB
  • 大小: 8.6 KB
  • 大小: 8.6 KB
  • 大小: 10.7 KB
  • 大小: 12.7 KB
  • 大小: 8.4 KB
  • 大小: 15.5 KB
  • 大小: 17.8 KB
  • 大小: 12.8 KB
  • 大小: 12.8 KB
  • 大小: 26.3 KB
  • 大小: 36.8 KB
分享到:
评论

相关推荐

    实现protobuf与json的互转

    标题中的“实现protobuf与json的互转”是指在软件开发中,如何将使用Protocol Buffers(protobuf)编写的结构体数据转换成JSON格式,反之亦然。Protocol Buffers是Google推出的一种数据序列化协议,而JSON...

    实现protobuf和json互相转换python3源码

    与XML和JSON相比,protobuf具有更高的压缩效率和传输速度,同时占用更少的内存。 本主题关注的是在Python3环境中如何实现protobuf和JSON之间的互相转换。首先,我们需要安装`protobuf`库,可以通过pip进行安装: `...

    protobuf转换为json

    标题中的“protobuf转换为json”指的是将Protocol Buffers(protobuf)数据格式转换成JavaScript Object Notation(JSON)数据格式的过程。Protocol Buffers是Google开发的一种高效的数据序列化协议,常用于结构化...

    protobuf-jsonschema:将Protobuf IDL编译为JSON模式

    protobuf-jsonschema 将编译为定义。 用法 您可以将protobuf-jsonschema用作命令行工具,或用作node中的函数。 CLI可以输出JSON或YAML(例如,用于Swagger)。 如果您指定一个protobuf消息名称以及一个文件,它将...

    protoc-gen-jsonschema:从Protobuf到JSON-Schema编译器

    从Protobuf到JSON-Schema编译器这将采用protobuf定义并将其转换为JSONSchemas,可用于动态验证JSON消息。 对于使用ProtoBuf定义数据但将JSON用作“ wire”格式的人们很有用。 受到“重大影响”。安装注意:此工具...

    基于protobuf反射特性的pb、json相互转换的实例程序(C++)

    本资源提供了一个基于protobuf反射特性的pb结构与json相互转换的实例,该实例程序主要有两个核心函数myMessage2Json、myJson2Message。前者的作用是将pb结构转换成对应的json,后者是将json转换成对应的pb结构体。...

    protojson:比较 JS 中 protobuf 和 JSON 编码的简单示例

    标题“protojson:比较 JS 中 protobuf 和 JSON 编码的简单示例”暗示了我们将讨论如何在JavaScript环境中使用protobuf以及与JSON之间的差异。 首先,让我们了解什么是protobuf。Protocol Buffers是Google开发的一种...

    自己实现的protobuf 压缩类,并能序列化反序列化

    标题中的“自己实现的protobuf压缩类”指的是作者创建了一个自定义的类,该类能够处理Google的Protocol Buffers(protobuf)数据格式,并且具备数据压缩和解压的功能。protobuf是一种高效的数据序列化协议,它允许...

    protobuf与json转换小结

    在IT行业中,数据交换和序列化是一个关键环节,protobuf(Protocol Buffers)和JSON都是广泛使用的数据表示格式。protobuf是由Google开发的一种高效、结构化的数据序列化协议,而JSON则是一种轻量级的文本数据交换...

    Protobuffer和json深度对比

    为了高效地存储和传输数据,我们有多种序列化格式可供选择,其中最常见的是Protobuf(Protocol Buffers)和JSON(JavaScript Object Notation)。这两种格式各有优势,适用于不同的场景。本文将深入探讨它们的特性和...

    pbjson对象.zip

    标题中的"pbjson对象.zip"指的是使用Protobuf(Protocol Buffers)编写的JSON对象处理工具。Protocol Buffers是由Google开发的一种数据序列化协议,它能够将结构化数据序列化,可用于数据存储、通信协议等方面。在与...

    C#中使用二进制和ProtoBuf分别进行序列化、反序列化、压缩、解压缩对比测试示例源码.zip

    4. **数据大小比较**:计算序列化、压缩后数据的大小,分析哪种方法更能节省存储空间。 通过这个示例,开发者可以了解到在C#环境中如何使用二进制序列化和ProtoBuf,以及如何结合压缩技术来优化数据传输。对于需要...

    protobufxjson

    可支持protobuf 与 json 的互转. 但必须protobuf生成时不能带lite.

    pbjson_pbjson_pbjosn生成与解析_handsvw_pbjson.zip

    在IT行业中,`pbjson`通常指的是Protocol Buffers(protobuf)序列化库生成的JSON(JavaScript Object Notation)格式的数据。Protocol Buffers是Google开发的一种数据序列化协议,用于高效地编码和解码结构化数据。...

    json2pb:JSON到Protobuf转换器的C ++实现

    而Protobuf则是Google开发的一种高效、紧凑且跨语言的数据序列化协议,它提供了比JSON更小的序列化数据大小,以及更快的序列化和反序列化速度。 标题"json2pb: JSON到Protobuf转换器的C++实现"指出,这是一个C++...

    pb解析与生成json

    标题 "pb解析与生成json" 涉及到的技术主要围绕着ProtoBuf(Protocol Buffers)和JSON这两种数据序列化格式。ProtoBuf是由Google开发的一种高效的数据交换的序列化协议,而JSON则是一种轻量级的数据交换格式,广泛...

    iOS_Protobuf

    “对比JSON大小”意味着在实际应用中,可能会进行Protobuf与JSON(JavaScript Object Notation)的数据大小比较。JSON是一种常见的数据交换格式,易于人阅读和编写,也易于机器解析和生成。然而,相比于JSON,...

    protobuf-3.15.8.zip

    7. **protobuf与JSON互操作**:protobuf提供JSON格式的支持,可以方便地在protobuf和JSON之间转换,满足不同的应用场景需求。 8. **性能优势**:protobuf的二进制格式通常比XML或JSON更小、解析更快,尤其是在传输...

    pb解析json工具

    标题提到的"pb解析json工具"是一种专门用于处理protobuf(简称pb)与JSON两种数据格式相互转换的工具。这两种格式各有优势,广泛应用于不同场景。 首先,让我们了解一下JSON(JavaScript Object Notation)。JSON是...

    protobuf中文学习文档

    **四、protobuf与XML/JSON比较** 1. **效率**: protobuf序列化的二进制格式比XML/JSON更紧凑,减少网络传输和磁盘存储成本。 2. **速度**: 由于protobuf采用二进制格式,解析速度远超XML/JSON,尤其在大数据量时...

Global site tag (gtag.js) - Google Analytics