RPC和gRPC的区别

1. 协议和传输层

  • RPC

    • 概念:RPC 是一个通用的概念,指的是程序在网络上调用远程服务的技术。
    • 传输协议:可以使用多种传输协议(如 TCP、HTTP、甚至自定义协议),具体取决于实现。
    • 序列化格式:传统 RPC 可以使用不同的序列化格式,如 XML-RPC 使用 XML,JSON-RPC 使用 JSON。
  • gRPC

    • 概念:gRPC 是 Google 开发的具体 RPC 框架,基于 HTTP/2 和 Protocol Buffers(protobuf)。
    • 传输协议:基于 HTTP/2,支持多路复用、流控制、头部压缩等特性。
    • 序列化格式:默认使用 Protocol Buffers(protobuf),一种高效的二进制序列化格式。

2. 性能

  • RPC

    • 性能:传统 RPC(如 XML-RPC 和 JSON-RPC)通常使用文本格式,序列化和反序列化开销较大,性能可能较低。
    • 适用场景:适用于较简单的、性能要求不高的场景。
  • gRPC

    • 性能:由于使用了 HTTP/2 和 protobuf,gRPC 提供了高性能和低延迟,适合高并发和大规模系统。
    • 适用场景:非常适合需要高性能、低延迟的分布式系统和微服务架构。

3. 功能特性

  • RPC

    • 功能:通常只支持基本的请求-响应模式,不支持复杂的通信模式。
    • 扩展性:功能较为基础,可能需要额外的组件来实现负载均衡、服务发现等功能。
  • gRPC

    • 功能:支持多种通信模式,包括单向 RPC、服务器流式 RPC、客户端流式 RPC 和双向流式 RPC。
    • 扩展性:内置负载均衡、服务发现、超时控制、重试机制等高级功能。
    • 安全性:提供内置的 SSL/TLS 支持,确保通信安全。

4. 多语言支持

  • RPC

    • 语言支持:传统 RPC 实现可能针对特定语言(如 Java RMI、Python 的 xmlrpc),跨语言支持较弱。
    • 工具和库:需要额外的工具或库来实现不同语言之间的互操作性。
  • gRPC

    • 语言支持:支持多种编程语言,包括 C++, Java, Python, Go, Ruby, C#, Node.js 等。
    • 工具和库:提供自动生成的客户端和服务器端代码,简化了不同语言之间的互操作性。

5. 版本和演进

  • RPC

    • 版本:传统 RPC 可能没有标准的版本控制机制。
    • 演进:通常没有内置的版本控制支持,可能需要额外的设计和实现。
  • gRPC

    • 版本:支持 API 版本控制,通过在定义文件中指定不同的服务版本来实现。
    • 演进:随着技术的发展,gRPC 继续扩展和改进,增加了新的特性和功能。

在 gRPC 中,支持四种不同的 RPC 模式:单向 RPC、服务器流式 RPC、客户端流式 RPC 和双向流式 RPC。每种模式适用于不同的应用场景。以下是每种模式的详细说明:

1. 单向 RPC(Unary RPC)

概念

客户端发送一个单独的请求到服务器并等待响应。这是最常见的 RPC 模式,类似于普通的函数调用。

使用场景
  • 简单的请求-响应模式。
  • 需要立即返回结果的操作,如获取某个对象的详情。
示例

客户端发送一个请求来获取用户信息,服务器返回该用户的信息。

ervice UserService 
{ rpc GetUser (UserRequest) returns (UserResponse) {} } 
message UserRequest { int32 user_id = 1; } 
message UserResponse { string name = 1; int32 age = 2; } 

2. 服务器流式 RPC(Server Streaming RPC)

概念

客户端发送一个请求到服务器,服务器返回一个流式响应。客户端可以读取从服务器返回的多个消息,直到流结束。

使用场景
  • 需要返回大量数据时,例如从数据库中检索多条记录。
  • 实时数据更新,如股票价格流。
示例

客户端请求一个用户的所有订单,服务器以流的形式返回订单信息。

service OrderService
{
 rpc ListOrders (OrderRequest) returns (stream OrderResponse) {} 
} 
message OrderRequest { int32 user_id = 1; }
 message OrderResponse
 { int32 order_id = 1; 
string product_name = 2; 
double price = 3; } 

3. 客户端流式 RPC(Client Streaming RPC)

概念

客户端发送一个流式请求到服务器,服务器在接收到所有请求消息后返回一个响应。

使用场景
  • 客户端需要发送大量数据到服务器进行处理。
  • 例如,上传一个大文件,分块传输。
示例

客户端以流的形式发送多个传感器数据点,服务器处理后返回处理结果

service SensorService { rpc RecordMetrics (stream MetricRequest) returns (MetricResponse) {} } message MetricRequest { double value = 1; string timestamp = 2; } message MetricResponse { string status = 1; }

4. 双向流式 RPC(Bidirectional Streaming RPC)

概念

客户端和服务器都可以发送和接收多个消息。消息在流中按顺序发送,客户端和服务器可以随时读写消息。

使用场景
  • 实时聊天应用。
  • 在线游戏中客户端和服务器的实时通信。
  • 需要双向数据流的复杂应用场景。
示例

客户端和服务器之间的实时聊天。

proto 文件定义
 service ChatService { rpc Chat (stream ChatMessage)
 returns (stream ChatMessage) {} } 
message ChatMessage { string user = 1; string message = 2; string timestamp = 3; } 

实现

以 Python 为例,这里是实现上述模式的一些基本代码:

单向 RPC

服务端代码

rviceServicer(user_pb2_grpc.UserServiceServicer):
 def GetUser(self, request, context): 
response = user_pb2.UserResponse(name="John Doe", age=30) 
return response 

客户端代码

with grpc.insecure_channel('localhost:50051') as channel: stub = user_pb2_grpc.UserServiceStub(channel) response = stub.GetUser(user_pb2.UserRequest(user_id=1)) print(response)

服务器流式 RPC

服务端代码

class OrderServiceServicer(order_pb2_grpc.OrderServiceServicer): def ListOrders(self, request, context): orders = [order_pb2.OrderResponse(order_id=1, product_name="Product1", price=100.0), order_pb2.OrderResponse(order_id=2, product_name="Product2", price=150.0)] for order in orders: yield order

客户端代码

with grpc.insecure_channel('localhost:50051') as channel: stub = order_pb2_grpc.OrderServiceStub(channel) responses = stub.ListOrders(order_pb2.OrderRequest(user_id=1)) for response in responses: print(response)

客户端流式 RPC

服务端代码

class SensorServiceServicer(sensor_pb2_grpc.SensorServiceServicer):
 def RecordMetrics(self, request_iterator, context): 
for request in request_iterator: print(f"Received metric: 
{request.value} at {request.timestamp}") 
return sensor_pb2.MetricResponse(status="Metrics Recorded") 

客户端代码

with grpc.insecure_channel('localhost:50051') as channel: stub = sensor_pb2_grpc.SensorServiceStub(channel) requests = (sensor_pb2.MetricRequest(value=i, timestamp=str(i)) for i in range(5)) response = stub.RecordMetrics(requests) print(response)

双向流式 RPC

服务端代码

class ChatServiceServicer(chat_pb2_grpc.ChatServiceServicer): def Chat(self, request_iterator, context): for chat_message in request_iterator: print(f"Received message from {chat_message.user}: {chat_message.message}") yield chat_pb2.ChatMessage(user="Server", message="Hello " + chat_message.user, timestamp="now")

客户端代码

with grpc.insecure_channel('localhost:50051')
 as channel: stub = chat_pb2_grpc.ChatServiceStub(channel) 
def generate_messages(): for i in range(5): 
yield chat_pb2.ChatMessage(user="Client", message=f"Message {i}", 
timestamp=str(i)) responses = stub.Chat(generate_messages())
 for response in responses: print(response) 

头部压缩(Header Compression)是 HTTP/2 引入的一项技术,用于减少 HTTP 请求和响应头部的大小,从而提高网络传输的效率和性能。在 HTTP/1.x 中,每个请求和相应地都会承载完整的头部信息,这些头部信息往往包含大量的波形数据。头部压缩通过减少波形和优化传输效率,显着提升了性能。

头部压缩的机制

HTTP/2 使用了一种名为 HPACK 的头部压缩算法,主要包含以下两个部分:

  1. 静态表(Static Table)

    • 静态表包含了一组常用的 HTTP 头部字段及其值的预定义列表。这些字段在每个 HTTP/2 实现中都是固定的。
    • 通过静态表,可以使用一个较小的索引值来表示常见的头部字段,从而减少数据传输量。
  2. 动态表(Dynamic Table)

    • 动态表在连接生命周期内动态维护头部字段值。
相关推荐
傻啦嘿哟12 分钟前
代理IP在后端开发中的应用与后端工程师的角色
网络·网络协议·tcp/ip
Red Red16 分钟前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全
向阳121843 分钟前
Dubbo HTTP接入之triple协议
网络协议·http·dubbo
亚远景aspice2 小时前
ISO 21434标准:汽车网络安全管理的利与弊
网络·web安全·汽车
草莓base2 小时前
【手写一个spring】spring源码的简单实现--bean对象的创建
java·spring·rpc
Estar.Lee2 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
友友马3 小时前
『 Linux 』网络层 - IP协议(一)
linux·网络·tcp/ip
码老白4 小时前
【老白学 Java】Warshipv2.0(二)
java·网络
HackKong4 小时前
小白怎样入门网络安全?
网络·学习·安全·web安全·网络安全·黑客