【协议篇】RPC、gRPC

打印 上一主题 下一主题

主题 954|帖子 954|积分 2862

一、RPC

1、RPC 概述

RPC(Remote Procedure Call Protocol,长途过程调用协议)允许程序像调用当地函数一样调用另一台盘算机(或进程)上的服务,隐蔽了底层网络通信的复杂性。
RPC 的核心思想:


  • 透明性:开发者无需关心网络细节(网络协议、网络IO模型),像调用当地函数一样调用长途服务。
  • 抽象性:将网络通信、序列化、传输等细节封装在协议中,简化分布式系统开发。
2、RPC 调用流程


范例的 RPC 流程分为以下步骤:


  • 客户端调用:客户端调用当地存根(Stub)方法,传入参数。
  • 参数序列化:客户端存根将参数序列化为字节流(如 JSON、Protobuf)。
  • 网络传输:序列化后的数据通过协议(如 TCP、HTTP)发送到服务端。
  • 服务端反序列化:服务端存根吸收数据并反序列化为参数。
  • 服务端实行:服务端调用实际的方法实现,并处置惩罚请求。
  • 效果返回:服务端将效果序列化后返回给客户端,客户端反序列化并处置惩罚效果。
3、RPC 的核心组件



  • 客户端存根(Client Stub):署理对象,负责序列化请求和发起网络调用。
  • 服务端存根(Server Stub):吸收请求并反序列化,调用实际服务方法。
  • 序列化协议:界说数据转换规则(如 JSON、XML、Protobuf、Thrift)。
  • 网络传输协议:负责数据传输(如 TCP、HTTP/1.1、HTTP/2)。
  • 服务注册与发现(可选):用于动态管理服务节点(如 ZooKeeper、Consul)。
4、常见 RPC 框架



  • gRPC:Google 开源,基于 HTTP/2 和 Protobuf,支持多语言、高性能。
  • Apache Thrift:Facebook 开源,支持多种序列化格式和传输协议。
  • Dubbo:阿里开源的 Java RPC 框架,集成服务管理功能。
  • Spring Cloud Feign:基于 RESTful 的声明式 HTTP 客户端,常用于微服务。
5、RPC 的优缺点

(1)优点


  • 开发高效:屏蔽网络细节,简化分布式系统开发。
  • 性能优化:基于二进制协议(如 Protobuf)的 RPC 通常比 RESTful API 更高效。
  • 跨语言支持:框架如 gRPC 支持多种编程语言。
(2)缺点


  • 耦合性:客户端和服务端需严格约定接口,升级时需同步更新。
  • 调试复杂性:网络问题(如超时、重试)可能导致调试困难。
  • 依赖管理:需处置惩罚服务发现、负载均衡、熔断等分布式问题。
6、RPC 与 RESTful API 的对比

特性RPCRESTful API协议自界说或高效协议(如 Protobuf)通常基于 HTTP + JSON/XML性能更高(二进制协议)较低(文本协议)灵活性接口严格约定资源化计划,扩展灵活实用场景内部服务通信对外暴露 API范例用例微服务间调用开放平台接口 7、RPC 的应用场景



  • 微服务架构:服务间的高效通信。
  • 分布式系统:跨节点调用(如数据库访问、盘算使命分发)。
  • 跨语言协作:多语言系统间的集成(如 Java 调用 Python 服务)。
8、挑衅与办理方案



  • 网络可靠性:通过重试机制、超时设置、熔断器(如 Hystrix)处置惩罚。
  • 服务管理:使用服务注册中心(如 Nacos)、负载均衡(如 Ribbon)。
  • 安全性:通过 TLS 加密通信、身份认证(如 OAuth2)保障安全。
二、gRPC

1、grpc 是什么?

   

  • 官网:https://grpc.io
  • 中文文档:http://doc.oschina.net/grpc
  • B站孙哥GRPC教程
  gRPC 是一个由 Google 开发的高性能、开源、通用的长途过程调用(RPC)框架,基于 HTTP/2 协议,使用 Protocol Buffers(protobuf) 作为接口界说语言(IDL)。其核心目标是简化跨语言、跨平台的分布式服务通信,尤其实用于微服务架构和低耽误场景。
在 gRPC 里,客户端应用可以像调用当地对象一样直接调用另一台差别的机器上服务端应用的方法,使得您能够更轻易地创建分布式应用和服务。与很多 RPC 系统雷同,gRPC 也是基于以下理念:界说一个服务,指定其能够被长途调用的方法(包含参数和返回范例)。在服务端实现这个接口,并运行一个 gRPC 服务器来处置惩罚客户端调用。在客户端拥有一个存根能够像服务端一样的方法。

gRPC 客户端和服务端可以在多种环境中运行和交互(从 google 内部的服务器到你自己的笔记本),并且可以用任何 gRPC 支持的语言来编写。所以,你可以很轻易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。别的,Google 最新 API 将有 gRPC 版本的接口,使你很轻易地将 Google 的功能集成到你的应用里。
2、gRPC 核心计划思路



  • 网络通信:gRPC自己封装网络通信的部门,提供多种语言的网络通信的封装 (c、Java[Netty]、G0)
  • 协议:HTTP2 二进制数据内容,支持双向流(双工)毗连的多路复用。
  • 序列化:protobuf(Protocol Buffers)google开源一种序列化方式,时间服从和空间服从是JSON的3到5倍。
  • 署理:让调用者像调用当地方法那样 去调用远端的服务方法stub
3、gRpc四种通信方式

gRPC 支持 四种通信模式,这些模式基于 HTTP/2 协议,充分利用其多路复用和流式传输本事。以下是每种模式的详细说明及实用场景:
3.1 一元 RPC(Unary RPC)



  • 界说:最简单的请求-响应模式,客户端发送单个请求,服务端返回单个响应。
  • 实用场景:雷同传统 HTTP API 的同步交互,如用户登录验证、单次数据查询。
  • Proto 界说:
    1. rpc GetUserInfo(UserRequest) returns (UserResponse) {};
    复制代码
  • 代码示例:
    1. // 客户端调用
    2. UserResponse response = stub.getUserInfo(UserRequest.newBuilder().setId(123).build());
    3. // 服务端实现
    4. public void getUserInfo(UserRequest request, StreamObserver<UserResponse> responseObserver) {
    5.     UserResponse response = ...; // 处理请求
    6.     responseObserver.onNext(response);
    7.     responseObserver.onCompleted();
    8. }
    复制代码
3.2 服务端流式 RPC(Server Streaming RPC)



  • 界说:客户端发送单个请求,服务端返回多个响应流,客户端顺序吸收。
  • 实用场景:服务端主动推送数据的场景,如及时日志推送、股票价格更新、分批次传输大数据。
  • Proto 界说:
    1. rpc StreamStockPrices(StockRequest) returns (stream StockResponse) {};
    复制代码
  • 代码示例:
    1. // 客户端调用
    2. Iterator<StockResponse> responses = stub.streamStockPrices(StockRequest.newBuilder().setSymbol("AAPL").build());
    3. while (responses.hasNext()) {
    4.     StockResponse response = responses.next();
    5.     // 处理每个响应
    6. }
    7. // 服务端实现
    8. public void streamStockPrices(StockRequest request, StreamObserver<StockResponse> responseObserver) {
    9.     for (StockPrice price : fetchPrices(request.getSymbol())) {
    10.         responseObserver.onNext(StockResponse.newBuilder().setPrice(price).build());
    11.     }
    12.     responseObserver.onCompleted();
    13. }
    复制代码
3.3 客户端流式 RPC(Client Streaming RPC)



  • 界说:客户端发送多个请求流,服务端吸收所有请求后返回单个响应。
  • 实用场景:客户端需要上传大量数据或分批次提交请求,如文件上传、传感器数据聚合。
  • Proto 界说:
    1. rpc UploadFile(stream FileChunk) returns (UploadStatus) {};
    复制代码
  • 代码示例:
    1. // 客户端调用
    2. StreamObserver<FileChunk> requestObserver = stub.uploadFile(new StreamObserver<UploadStatus>() {
    3.     public void onNext(UploadStatus status) { /* 处理最终响应 */ }
    4.     public void onCompleted() { /* 完成处理 */ }
    5. });
    6. for (FileChunk chunk : readFileChunks()) {
    7.     requestObserver.onNext(chunk);
    8. }
    9. requestObserver.onCompleted();
    10. // 服务端实现
    11. public StreamObserver<FileChunk> uploadFile(StreamObserver<UploadStatus> responseObserver) {
    12.     return new StreamObserver<FileChunk>() {
    13.         List<FileChunk> chunks = new ArrayList<>();
    14.         public void onNext(FileChunk chunk) { chunks.add(chunk); }
    15.         public void onCompleted() {
    16.             // 合并所有分块并保存
    17.             responseObserver.onNext(UploadStatus.newBuilder().setSuccess(true).build());
    18.             responseObserver.onCompleted();
    19.         }
    20.     };
    21. }
    复制代码
3.4 双向流式 RPC(Bidirectional Streaming RPC)



  • 界说:客户端和服务端各自独立发送请求和响应流,双方可异步读写,支持全双工通信。
  • 实用场景:及时双向交互,如谈天应用、在线游戏指令同步、协作编辑。
  • Proto 界说:
    1. rpc Chat(stream ChatMessage) returns (stream ChatMessage) {};
    复制代码
  • 代码示例:
    1. // 客户端调用
    2. StreamObserver<ChatMessage> requestObserver = stub.chat(new StreamObserver<ChatMessage>() {
    3.     public void onNext(ChatMessage msg) { /* 处理服务端消息 */ }
    4.     public void onCompleted() { /* 结束处理 */ }
    5. });
    6. // 发送消息到服务端
    7. requestObserver.onNext(ChatMessage.newBuilder().setText("Hello").build());
    8. // 服务端实现
    9. public StreamObserver<ChatMessage> chat(StreamObserver<ChatMessage> responseObserver) {
    10.     return new StreamObserver<ChatMessage>() {
    11.         public void onNext(ChatMessage msg) {
    12.             // 处理客户端消息并回复
    13.             responseObserver.onNext(ChatMessage.newBuilder().setText("Hi").build());
    14.         }
    15.         public void onCompleted() {
    16.             responseObserver.onCompleted();
    17.         }
    18.     };
    19. }
    复制代码
3.5 对比总结

模式请求流数量响应流数量范例场景一元 RPC11简单请求-响应(如 REST)服务端流式RPC1N服务端主动推送(如及时数据)客户端流式RPCN1客户端批量提交(如文件上传)双向流式RPCNN及时双向交互(如谈天) 3.6 选择发起



  • 优先一元 RPC:如果逻辑简单且无需流式传输。
  • 使用流式模式:当需要处置惩罚大数据、及时性要求高或需要异步交互时。
  • 注意资源斲丧:流式毗连会恒久占用 HTTP/2 的 Stream,需合理管理生命周期。
4、重要特性

(1) 高性能


  • 低耽误:HTTP/2 多路复用淘汰毗连开销。
  • 高吞吐:二进制协媾和高效序列化降低传输负载。
  • 基准测试:相比 REST/JSON,性能提升 5-10 倍。
(2) 跨语言支持


  • 多语言代码生成:支持主流编程语言(C++, Java, Python, Go, Ruby 等)。
  • 同一接口:差别语言的服务端和客户端可无缝交互。
(3) 流式处置惩罚


  • 及时双向通信:支持流式 RPC,实用于谈天、及时监控等场景。
(4) 高级功能


  • 拦截器(Interceptors):实现日志、认证、重试等全局逻辑。
  • 超时与取消:客户端可设置超时或主动取消请求。
  • TLS 加密:内置支持端到端加密。
  • 负载均衡:与服务发现工具(如 Kubernetes、Consul)集成。
5、优缺点

(1)优点


  • 强范例接口:淘汰接口不一致风险。
  • 高性能:得当高并发、低耽误场景。
  • 代码生成:自动化生成客户端和服务端代码。
  • 生态系统完善:支持认证、监控、链路追踪等工具链。
(2) 缺点


  • 欣赏器支持有限:需通过 gRPC-Web 转译。
  • 调试复杂度:二进制协议需专用工具(如 grpcurl)。
  • 学习曲线:需掌握 Protocol Buffers 和 HTTP/2 知识。
6、使用场景



  • 微服务通信:服务间高效、范例安全的 API 调用。
  • 及时系统:如游戏服务器、IoT 设备双向通信。
  • 跨语言协作:多语言团队开发同一接口的后端服务。
  • 移动端与后端:节省带宽,提升移动应用性能。
7、示例:实现一个 GRPC 服务



  • 新建一个go项目,项目结构如下:
    1. test/
    2. ├── grpc-client/                # 客户端
    3. │   └── main.go           #
    4. ├── grpc-server/                # 服务端
    5. │   └── main.go           #
    6. ├── proto/              # proto文件存放目录
    7. │   ├── test.proto                  #
    8. ├── go.mod              #
    9. ├── main.go             #
    复制代码
  • 安装 protoc与插件
    1. # 安装 protoc编译器
    2. brew install protobuf
    3. # 安装插件
    4. go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    5. go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
    复制代码

    • protoc 编译器用于将.proto文件编译成代码;
    • protoc-gen-go 插件用于生成Go语言的数据结构代码;
    • protoc-gen-go-grpc 插件用于生成Go语言的gRPC服务代码。

  • 界说服务(contract.proto)
    1. syntax = "proto3";                // 使用Proto3语法
    2. option go_package = ".;service";  // 指定生成的Go代码中应该使用的包名。
    3. message ContractRequest{          // 消息定义
    4.   string name = 1;
    5. }
    6. message ContractResponse{
    7.   string  tel = 1;
    8. }
    9. service ContractService{          // 服务定义
    10.   rpc query(ContractRequest) returns (ContractResponse){};
    11. }
    复制代码
  • 代码生成(在proto目次下)
    1. protoc --go_out=. --go-grpc_out=. contract.proto
    复制代码

    • go_out:这个参数会调用protoc-gen-go插件。protoc-gen-go插件的重要作用是将.proto文件转换为Go语言的代码。生成的文件通常包罗消息(message)和枚举(enum)范例的界说,以及序列化和反序列化的方法。
    • go-grpc_out:这个参数会调用protoc-gen-go-grpc插件。protoc-gen-go-grpc插件的重要作用是将.proto文件中的gRPC服务界说转换为Go语言的代码。生成的文件通常包罗gRPC服务接口和客户端存根(clientstub)的界说。

  • 服务端实现:在grpc-server下新建文件 main.go
    1. package main
    2. import (
    3.         "context"
    4.         "google.golang.org/grpc"
    5.         "log"
    6.         "net"
    7.         pb "test/proto/service"
    8. )
    9. type server struct {
    10.         pb.HelloServiceServer
    11. }
    12. func (s *server) SayHello(_ context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
    13.         return &pb.HelloResponse{Tel: "Hello, " + req.GetName()}, nil
    14. }
    15. func main() {
    16.         // 监听端口
    17.         lis, _ := net.Listen("tcp", ":9090")
    18.         // 创建一个新的 gRPC 服务器实例
    19.         s := grpc.NewServer()
    20.         // 注册我们的服务到 gRPC 服务器上
    21.         pb.RegisterHelloServiceServer(s, &server{})
    22.         log.Println("gRPC server is running at :9090")
    23.         // 在指定的端口上启动服务
    24.         _ = s.Serve(lis)
    25. }
    复制代码
  • 客户端调用:在grpc下新建一个main.go文件
    1. package main
    2. import (
    3.         "context"
    4.         "google.golang.org/grpc"
    5.         "google.golang.org/grpc/credentials/insecure"
    6.         "log"
    7.         pb "test/proto/service"
    8. )
    9. func main() {
    10.         conn, err := grpc.NewClient("127.0.0.1:9090", grpc.WithTransportCredentials(insecure.NewCredentials()))
    11.         if err != nil {
    12.                 log.Fatalf("failed to connect: %v", err)
    13.         }
    14.         defer func(conn *grpc.ClientConn) {
    15.                 err := conn.Close()
    16.                 if err != nil {
    17.                         log.Fatalf("failed to close connection: %v", err)
    18.                 }
    19.         }(conn)
    20.         client := pb.NewHelloServiceClient(conn)
    21.         resp, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "Mary"})
    22.         if err != nil {
    23.                 log.Fatalf("failed to SayHello: %v", err)
    24.         }
    25.         log.Println(resp.GetTel())
    26. }
    复制代码
8、工具与生态系统



  • grpcurl:雷同 curl 的命令行工具,用于调试 gRPC 服务。
  • gRPC Gateway:将 gRPC 服务转换为 RESTful API,支持欣赏器调用。
  • Envoy Proxy:支持 gRPC 流量管理、负载均衡和监控。
  • OpenTelemetry:集成分布式追踪和指标收集。
9、对比其他 RPC 框架

特性gRPCREST/JSONApache Thrift协议HTTP/2 + protobufHTTP/1.1 + JSON自界说传输 + 多种编码性能高低高流式支持是否(需 WebSocket)是欣赏器支持需 gRPC-Web原生支持有限代码生成多语言无多语言 十、资料



  • RPC框架:从原理到选型,一文带你搞懂RPC
  • 一文掌握gRPC

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

何小豆儿在此

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表