腾讯云服务器上cdn 原理,cdn的工作原理图

  

  ProtoBuf作为一种跨平台、语言无关、可扩展的结构化数据序列化方法,已经广泛应用于网络数据交换和存储。随着互联网的发展,系统的异构性会越来越突出,跨语言需求会越来越明显。同时,gRPC有很大的潜力替代Restful。ProtoBuf作为g RPC跨语言、高性能的法宝,是我们技术人员必备的。   

  

  深入了解ProtoBuf的原理,为以后的技术更新和选型打下基础。   

  

  我将把自己过去的学习过程和实践经验总结成系列文章,和大家一起探讨学习。希望你能有所收获。当然,也欢迎大家批评指正一些不正确的地方。   

  

  这一系列文章主要包括:   

  

  对ProtoBuf原理和工程实践的深刻理解(概述)对ProtoBuf原理和工程实践的深刻理解(编码)对ProtoBuf原理和工程实践的深刻理解(序列化)对ProtoBuf原理和工程实践的深刻理解(工程实践)一、什么是protobuf(协议缓冲区)是一种跨平台、语言无关、可扩展的结构化数据序列化方法,可用于网络数据交换和存储。   

  

  在结构化数据的序列化机制上,ProtoBuf灵活、高效、自动化。比较常见的是XML和JSON,描述的是同样的信息。ProtoBuf数据量更小,序列化/反序列化速度更快更简单。   

  

  一旦定义了要处理的数据的数据结构,就可以使用ProtoBuf的代码生成工具生成相关代码。使用Protobuf描述一次数据结构,就可以轻松读写不同语言(proto3支持C、Java、Python、Go、Ruby、Objective-C、C #)或者不同流的结构化数据。   

  

  第二,为什么是ProtoBuf?你可能认为Google发明ProtoBuf是为了解决序列化速度,但真正的原因并不是这样。   

  

  ProtoBuf最初是Google用来解决索引服务器请求/响应协议的。在ProtoBuf之前,Google已经有了请求/响应格式,用于手动处理请求/响应的编码和解码。它也可以支持多版本协议,但代码不够优雅:   

  

  if(protocol version=1){ do something();} else if(protocol version=2){ doOtherThing();} .如果是非常明确的格式协议,会让新协议变得非常复杂。因为开发者必须保证请求发起者和处理请求的实际服务器之间的所有服务器都能理解新协议,然后切换开关开始使用新协议。   

  

  也就是说,每个服务器开发者都遇到过与低版本和新旧协议兼容性相关的问题。   

  

  为了解决这些问题,ProtoBuf诞生了。   

  

  ProtoBuf最初具有以下两个特征:   

  

  更容易引入新的字段,和不需要检查数据的中间服务器可以简单地解析和传递数据,而不需要知道所有的字段。数据格式更加具有自我描述性可以用各种语言处理(C,Java和其他语言)。这个版本的ProtoBuf仍然需要自己编写解析后的代码。   

  

  但是,随着系统的发展和演进,ProtoBuf有了更多的特性:   

  

  自动生成的序列化和反序列化代码无需手动解析。(官方提供自动代码生成工具,基本所有语言平台都有)。除了数据交换,ProtoBuf还被用作持久性数据的一种方便的自描述格式。ProtoBuf现在是谷歌数据交换和存储的通用语言。谷歌的代码树中定义了48,162种不同的消息类型,包括12,183种。原型文件。它们不仅用于RPC系统,还用于各种存储系统中数据的持久存储。   

  

  ProtoBuf的诞生是为了解决服务器端新旧协议(高低版本)的兼容问题,它的名字很体贴,“协议缓冲”。只是到了后期,才逐渐发展成数据传输。   

  

  协议缓冲区的命名来自:   

  

  为什么叫“协议缓冲区”?   

  

  这个名字来源于格式的早期,那时我们还没有协议缓冲编译器来为我们生成类。当时,有一个名为原始缓冲液的类,它实际上充当了一个单独方法的缓冲区。用户可以通过调用AddValue(标签,值)这样的方法将标记/值对单独添加到这个缓冲区中。原始字节存储在一个缓冲区中,一旦消息出现,就可以将它写出来   

d been constructed.

  

Since that time, the "buffers" part of the name has lost its meaning, but it is still the name we use. Today, people usually use the term "protocol message" to refer to a message in an abstract sense, "protocol buffer" to refer to a serialized copy of a message, and "protocol message object" to refer to an in-memory object representing the parsed message.

  

三、如何使用 ProtoBuf3.1 ProtoBuf 协议的工作流程

  

可以看到,对于序列化协议来说,使用方只需要关注业务对象本身,即 idl 定义,序列化和反序列化的代码只需要通过工具生成即可。

  

C/C++Linux后台服务器开发高级架构师学习视频 点击 正在跳转 获取,内容知识点包括Linux,Nginx,ZeroMQ,MySQL,Redis,线程池,MongoDB,ZK,Linux内核,CDN,P2P,epoll,Docker,TCP/IP,协程,DPDK等等。免费学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂

  

  

3.2 ProtoBuf 消息定义ProtoBuf 的消息是在idl文件(.proto)中描述的。下面是本次样例中使用到的消息描述符customer.proto:

  

syntax = "proto3"; package domain; option java_package = "com.protobuf.generated.domain";option java_outer_classname = "CustomerProtos"; message Customers { repeated Customer customer = 1;} message Customer { int32 id = 1; string firstName = 2; string lastName = 3; enum EmailType { PRIVATE = 0; PROFESSIONAL = 1; } message EmailAddress { string email = 1; EmailType type = 2; } repeated EmailAddress email = 5;}上面的消息比较简单,Customers包含多个Customer,Customer包含一个id字段,一个firstName字段,一个lastName字段以及一个email的集合。

  

除了这些定义外,文件顶部还有三行可帮助代码生成器:

  

首先,syntax = "proto3"用于idl语法版本,目前有两个版本proto2和proto3,两个版本语法不兼容,如果不指定,默认语法是proto2。由于proto3比proto2支持的语言更多,语法更简洁,本文使用的是proto3。其次有一个package domain;定义。此配置用于嵌套生成的类/对象。有一个option java_package定义。生成器还使用此配置来嵌套生成的源。此处的区别在于这仅适用于Java。在使用Java创建代码和使用JavaScript创建代码时,使用了两种配置来使生成器的行为有所不同。也就是说,Java类是在包com.protobuf.generated.domain下创建的,而JavaScript对象是在包domain下创建的。ProtoBuf 提供了更多选项和数据类型,本文不做详细介绍,感兴趣可以参考这里。

  

3.3 代码生成首先安装 ProtoBuf 编译器 protoc,这里有详细的安装教程,安装完成后,可以使用以下命令生成 Java 源代码:

  

protoc --java_out=./src/main/java ./src/main/idl/customer.proto从项目的根路径执行该命令,并添加了两个参数:java_out,定义./src/main/java/为Java代码的输出目录;而./src/main/idl/customer.proto是.proto文件所在目录。

  

生成的代码非常复杂,但是幸运的是它的用法却非常简单。

  

CustomerProtos.Customer.EmailAddress email = CustomerProtos.Customer.EmailAddress.newBuilder() .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL) .setEmail("crichardson@email.com").build(); CustomerProtos.Customer customer = CustomerProtos.Customer.newBuilder() .setId(1) .setFirstName("Lee") .setLastName("Richardson") .addEmail(email) .build(); // 序列化 byte<> binaryInfo = customer.toByteArray(); System.out.println(bytes_String16(binaryInfo)); System.out.println(customer.toByteArray().length); // 反序列化 CustomerProtos.Customer anotherCustomer = CustomerProtos.Customer.parseFrom(binaryInfo); System.out.println(anotherCustomer.toString());3.4 性能数据我们简单地以Customers为模型,分别构造、选取小对象、普通对象、大对象进行性能对比。

  

序列化耗时以及序列化后数据大小对比

  

  

反序列化耗时

  

  

四、总结上面介绍了 ProtoBuf 是什么、产生的背景、基本用法,我们再总结下。

  

优点:

  

1. 效率高

  

从序列化后的数据体积角度,与XML、JSON这类文本协议相比,ProtoBuf通过T-(L)-V(TAG-LENGTH-VALUE)方式编码,不需要", {, }, :等分隔符来结构化信息,同时在编码层面使用varint压缩,所以描述同样的信息,ProtoBuf序列化后的体积要小很多,在网络中传输消耗的网络流量更少,进而对于网络资源紧张、性能要求非常高的场景,ProtoBuf协议是不错的选择。

  

// 我们简单做个对比// 要描述如下JSON数据{"id":1,"firstName":"Chris","lastName":"Richardson","email":<{"type":"PROFESSIONAL","email":"crichardson@email.com"}>}# 使用JSON序列化后的数据大小为118byte7b226964223a312c2266697273744e616d65223a224368726973222c226c6173744e616d65223a2252696368617264736f6e222c22656d61696c223a5b7b22747970<br>65223a2250524f46455353494f4e414c222c22656d61696c223a226372696368617264736f6e40656d61696c2e636f6d227d5d7d# 而使用ProtoBuf序列化后的数据大小为48byte0801120543687269731a0a52696368617264736f6e2a190a156372696368617264736f6e40656d61696c2e636f6d1001从序列化/反序列化速度角度,与XML、JSON相比,ProtoBuf序列化/反序列化的速度更快,比XML要快20-100倍。

  

2. 支持跨平台、多语言

  

ProtoBuf是平台无关的,无论是Android与PC,还是C#与Java都可以利用ProtoBuf进行无障碍通讯。

  

proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#。

  

3. 扩展性、兼容性好

  

具有向后兼容的特性,更新数据结构以后,老版本依旧可以兼容,这也是ProtoBuf诞生之初被寄予解决的问题。因为编译器对不识别的新增字段会跳过不处理。

  

4. 使用简单

  

ProtoBuf 提供了一套编译工具,可以自动生成序列化、反序列化的样板代码,这样开发者只要关注业务数据idl,简化了编码解码工作以及多语言交互的复杂度。

  

缺点:

  

可读性差,缺乏自描述

  

XML,JSON是自描述的,而ProtoBuf则不是。

  

ProtoBuf是二进制协议,编码后的数据可读性差,如果没有idl文件,就无法理解二进制数据流,对调试不友好。

  

不过Charles已经支持ProtoBuf协议,导入数据的描述文件即可。

  

此外,由于没有idl文件无法解析二进制数据流,ProtoBuf在一定程度上可以保护数据,提升核心数据被破解的门槛,降低核心数据被盗爬的风险。

相关文章