两个主要原因。
看了不少关于REST与JSON和gRPC的性能基准测试。其中一些测试显示,gRPC将每个请求的延迟减少了一半。
那么,它为什么这么快呢?🤔
⚡ 第一个原因是HTTP/2。
HTTP/1.1的请求和响应是同步的,一次只能处理一个请求。而HTTP/2请求是异步的,可以同时发送多个请求,不需要等待前一个请求的响应。减少了等待前一个请求完成的时间,同时连接复用,也避免了TCP和TLS握手的时间。
这对gRPC来说是一个重要因素,因为gRPC在底层利用了HTTP/2协议。
虽然对用户来说可能看起来只是简单的RPC调用,但它在底层使用的是HTTP。
📦 第二个原因是Protobuf。
HTTP/2 + JSON本身就可以相当快,但使用Protobuf代替JSON可以进一步推动性能提升。
像JSON一样,Protobuf是一种用于交换数据的结构化消息格式,但最大的不同是Protobuf是基于二进制的。
作为基于二进制的,Protobuf在网络传输数据时更加紧凑。
以下是一个简单的对比示例。
假设我们有一个表示用户信息的结构:
{
"id": 12345,
"name": "Alice",
"email": "alice@example.com",
"isAdmin": true,
"scores": [85, 92, 88]
}
对应的 Protobuf 定义如下:
syntax = "proto3";
message User {
int32 id = 1;
string name = 2;
string email = 3;
bool isAdmin = 4;
repeated int32 scores = 5;
}
数据编码后的对比
我们将上述数据分别序列化为 JSON 和 Protobuf,得到如下结果:
- JSON 格式
序列化后的 JSON 数据如下(未压缩):
{
"id": 12345,
"name": "Alice",
"email": "alice@example.com",
"isAdmin": true,
"scores": [85, 92, 88]
}
JSON 字符串的总大小为 115 字节。
- Protobuf 格式
序列化后的 Protobuf 数据(二进制形式,无法直接阅读,但可以解析为字节数组表示):
08 b9 60 12 05 41 6c 69 63 65 1a 12 61 6c 69 63 65 40 65 78 61 6d 70 6c 65 2e 63 6f 6d 20 01 2a 03 55 5c 58
Protobuf 字节数组的总大小为 37 字节。
JSON采用了文本格式,包含大量描述性的标签(如 "id"、"name" 等)以及符号(如引号、逗号等),如果有json字符串的嵌套可能还有一堆的斜杠。而二进制格式,无需描述性标签,仅包含数据和简洁的字段标识符(字段 ID)。
Protobuf 使用二进制编码和字段号(如 id = 1)来标识数据,而 JSON 使用键值对字符串描述数据结构,增加了额外开销。所以,Protobuf 的数据大小显著小于 JSON,尤其是字段较多、数据量较大时,差距会更明显。
因此,在带宽敏感或高性能需求的场景中,Protobuf 优势突出。
而且Protobuf在序列化和反序列化过程中也比JSON快得多。据测试显示Protobuf 序列化速度比 JSON 快 10 到 100 倍。
格式 | 序列化时间(毫秒) | 反序列化时间(毫秒) | 序列化/反序列化次数每秒 |
---|---|---|---|
JSON | 180ms | 160ms | 5556 |
Protobuf | 16ms | 8ms | 62500 |
JSON 需要解析文本中的每个字符,尤其是长字符串和数字字段时,会面临较高的开销。解析 JSON 数据时,必须将文本解析为原始数据类型,并且每次解析时需要处理字符串键名、符号(如括号、逗号等),这比直接解析二进制数据慢得多。
因此,Protobuf不仅传输速度更快,而且处理速度也更快。
💎 但性能并非没有代价。
虽然gRPC有很多优势,甚至超越了性能,它也带来了一些复杂性。
🔀 复杂性:负载分配
和HTTP/2一样,gRPC默认会为多个请求重用连接。如果主要依赖基于连接的负载均衡,这种多路复用可能导致负载分配不均衡。
使用第七层负载均衡器或客户端负载均衡可以解决这个问题,但需要考虑这一点。
🧰 复杂性:故障排除
虽然用于故障排除gRPC服务的工具集正在增长,但它仍然不如REST + JSON那样容易。
gRPC使得执行临时请求、捕获和调试有效载荷、验证端点等变得更加困难。
📄 复杂性:契约
Protobuf的一个优势是清晰的契约。每个人都使用相同的proto文件来生成序列化和反序列化的包。
这种方法很棒,因为它消除了误解,但在分发和版本控制该文件时可能会变得复杂,尤其是当试图将其分发给外部用户时。
💡 总结
如果你需要性能提升,或者你的环境能够处理gRPC带来的复杂性,那么gRPC是一个很好的方法。
如果你对REST + JSON感到满意,并且对gRPC的复杂性感到困扰,那也没关系;REST依然很多人在使用。
本文由mdnice多平台发布
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。