【问题标题】:protobuf payload bigger than JSON?protobuf 负载比 JSON 大?
【发布时间】:2017-06-24 10:46:34
【问题描述】:

我有一个“级别”对象列表的对象,我正在测试用 Spring Boot Rest Controller 以两种方式传输它们:

  1. 使用 JSON,在 Rest Controller 中我使用类似:

     @RequestMapping(value = "/api/v1/layers/{layername}", method =         RequestMethod.GET, produces = "application/json")
     public @ResponseBody List<Level>  query(@PathVariable String layername,
                   @RequestParam("northEastLat") Float northEastLat,
                   @RequestParam("northEastLng") Float northEastLng,
                   @RequestParam("northWestLat") Float northWestLat,
                   @RequestParam("northWestLng") Float northWestLng,
    
                   @RequestParam("southEastLat") Float southEastLat,
                   @RequestParam("southEastLng") Float southEastLng,
                   @RequestParam("southWestLat") Float southWestLat,
                   @RequestParam("southWestLng") Float southWestLng
    ) {
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
    int i=1;
    for (Level p : poligons) {
    
        System.out.println("poligon" + i++ + " is:" + p.toString());
    }
    
    return poligons;
    }
    
  2. 对于 Protostuff Protobuf 格式,我使用类似:

      @RequestMapping(value = "/api/v1/layers/{layername}", method = RequestMethod.GET,produces = "text/plain")
      public String query(@PathVariable String layername,
                    @RequestParam("northEastLat") Float northEastLat,
                    @RequestParam("northEastLng") Float northEastLng,
                    @RequestParam("northWestLat") Float northWestLat,
                    @RequestParam("northWestLng") Float northWestLng,
    
                    @RequestParam("southEastLat") Float southEastLat,
                    @RequestParam("southEastLng") Float southEastLng,
                    @RequestParam("southWestLat") Float southWestLat,
                    @RequestParam("southWestLng") Float southWestLng
      ) {
    
    
    List<Level> poligons=levelService.obtainLevels(layername,southWestLng,southWestLat,northWestLng,northWestLat,northEastLng,northEastLat,southEastLng,southEastLat);
    LevelList list = new LevelList(poligons);
    
    byte[] bytes;
    
    int i=1;
    for (Level p : poligons) {
    
        System.out.println("poligon" + i++ + " is:" + p.toString());
    }
    
    Schema<LevelList> schema = RuntimeSchema.getSchema(LevelList.class);
    LinkedBuffer buffer = LinkedBuffer.allocate();
    
    
    
    try
    {
        bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
    }
    finally
    {
        buffer.clear();
    }
    
     return new String(bytes);
    }
    

关卡对象格式为: [{"wkb_geometry":"{"type":"Polygon","coordinates":[[[24.446822,45.34997],[24.706508,45.352485]]]}","id":199,"level":"3 ","type":null}

关卡对象是:

@Entity(name = "Level")
@Table(name="Level2G")
@SecondaryTables({
    @SecondaryTable(name="Level3G"),
    @SecondaryTable(name="Level4G")
})
public class Level implements Serializable {

private static final long serialVersionUID = 1L;

// @Column(name = "wkb_geometry",columnDefinition="Geometry")
//@Type(type = "org.hibernate.spatial.GeometryType")
@Column(name="wkb_geometry")
private /*Geometry */ String  wkb_geometry;

@Id
@Column(name="id")
private Integer id;


@Column(name="level")
private String level;

@Transient
private String type;

public Level() {
}

public Level(String  wkb_geometry, Integer id, String level) {
    this.wkb_geometry = wkb_geometry;
    this.id = id;
    this.level = level;
    this.type = "Feature";
}

public Level(String  wkb_geometry, Integer id, String level, String type) {
    this.wkb_geometry = wkb_geometry;
    this.id = id;
    this.level = level;
    this.type = type;
}

public Object getWkb_geometry() {
    return wkb_geometry;
}

public void setWkb_geometry(String  wkb_geometry) {
    this.wkb_geometry = wkb_geometry;
}

public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getLevel() {
    return level;
}

public void setLevel(String level) {
    this.level = level;
}

public String getType() {
    return type;
}

public void setType(String type) {
    this.type = type;
}

@Override
public String toString() {
    return "Level{" +
            "wkb_geometry=" + wkb_geometry +
            ", id=" + id +
            ", level='" + level + '\'' +
            ", type='" + type + '\'' +
            '}';
}
 }

LevelList 对象只是关卡对象的列表

问题在于,与 JSON (3.7kb) 相比,使用 Protostuff 可以获得更大的有效负载 (26kb)。为什么?

对于第二个选项,我还尝试将“application/octet-stream”设置为直接返回字节,但结果仍然相同。我还比较了 JSON 和 protobuf 的速度;即使负载更大,protobuf 也具有更好的性能。知道为什么吗?

【问题讨论】:

  • 对于我尝试的第二个选项也产生 ="application/octet-stream" 直接返回字节但仍然是相同的结果
  • 您可以在此处复制/粘贴您正在序列化的实际对象吗?也许一种格式比另一种格式序列化更多信息?
  • 不知道对你有多大帮助,但是:spring.io/blog/2015/03/22/…

标签: java json protocol-buffers protostuff


【解决方案1】:

Protostuff 和 Protobuf 不是一回事。 Protostuff 是一个包装库,可以使用许多不同的序列化格式。它还支持您似乎正在使用的运行时模式生成。该运行时模式需要与消息一起发送额外的元数据,以告知接收者消息的模式。我猜你看到的大消息主要来自这个运行时模式数据。

使用标准 Protobuf,模式不会随消息一起发送,因为假定发送者和接收者已经就编译到两个程序中的 .proto 文件提供的模式达成一致。如果您将 Protobuf 与标准 .proto 文件一起使用,您会发现它生成的消息比 JSON 小得多。

【讨论】:

    【解决方案2】:

    你的测试中至少有一个问题。

    从字节数组到字符串的这种转换是无效的:

    bytes = ProtostuffIOUtil.toByteArray(list, schema, buffer);
    return new String(bytes);
    

    String 的此构造函数将尝试将字节数组解析为 UTF-8 字符串(很可能;取决于您的语言环境设置),但根据定义给定的数据不是有效的 UTF-8 字符串。

    如果你想进行更好的尺寸比较,你应该写一个如下形式的测试:

    LevelList source = testData();
    byte[] jsonData = generateJson(source);
    byte[] protobufData = generateProtobuf(source);
    System.out.println("JSON=" + jsonData.size() + " Protobuf=" + protobufData.size());
    

    这里的重点是使您的测试可重复,以便其他人可以重复它。

    【讨论】:

    • 谢谢。但就像我说的那样,对于第二个选项,我尝试过也产生 ="application/octet-stream" 直接返回字节但仍然是相同的结果。我还比较了 json 和 protobuf 的速度,即使有效载荷更高,protobuf 也有更好的速度。知道为什么吗?
    • 理论上不可能,二进制protobuf编码比JSON定义更紧凑。
    猜你喜欢
    • 2021-01-19
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多