返回列表 发布新帖
查看: 47|回复: 0

gRPC 和传统 RPC 有啥不一样?

发表于 2025-4-23 13:53:43 | 查看全部 |阅读模式

这里或许是互联网从业者的最后一片净土,随客社区期待您的加入!

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

×
本帖最后由 mrkong 于 2025-4-23 14:33 编辑

现在大家做系统开发,都喜欢搞“微服务架构”——简单说就是把一个大系统拆成很多小服务,这样更灵活也更容易扩展。那这些服务之间怎么沟通呢?就得靠一种技术叫 RPC(远程过程调用)。今天我们就来聊聊它的“进化版”:gRPC,看看它和传统的 RPC 到底有啥不一样。

一、先搞懂几个概念什么是 RPC?
可以把它理解成“跨机器调用函数”的方式。就像你在本地调用一个函数一样,但其实它是在另一台服务器上运行的。传统 RPC 有很多种实现,比如 XML-RPC、JSON-RPC、SOAP 等,数据格式多是 XML 或 JSON。
那 gRPC 是啥?
Google 出品的一个更高效的 RPC 框架,基于 HTTP/2 协议,数据格式使用 Protocol Buffers(Protobuf)。性能好、效率高,还能自动生成代码,听起来就很香对吧?

二、gRPC 和传统 RPC 的几大区别(白话版)[td]
对比点传统 RPCgRPC
传输协议HTTP/1 或 TCPHTTP/2,多路复用、速度快
数据格式XML/JSON,可读但体积大Protobuf,体积小、解析快
代码生成多为手写支持自动生成客户端/服务端代码
流式处理一般不支持支持四种调用模式,支持双向流
跨语言支持较麻烦官方支持多语言(Go、Python、Java、C++等)
错误处理HTTP 状态码处理标准错误码机制 + 详细描述

三、举个例子更直观用传统 JSON-RPC 调接口(Go 示例)
  1. package main

  2. import (
  3.     "bytes"
  4.     "encoding/json"
  5.     "fmt"
  6.     "net/http"
  7. )

  8. func main() {
  9.     payload := map[string]interface{}{
  10.         "jsonrpc": "2.0",
  11.         "method":  "getUserProfile",
  12.         "params": map[string]interface{}{
  13.             "userId":         123,
  14.             "includeDetails": true,
  15.         },
  16.         "id": 1,
  17.     }

  18.     data, _ := json.Marshal(payload)
  19.     resp, _ := http.Post("http://localhost:8000", "application/json", bytes.NewReader(data))
  20.     defer resp.Body.Close()

  21.     var result map[string]interface{}
  22.     json.NewDecoder(resp.Body).Decode(&result)

  23.     fmt.Printf("结果: %+v\n", result)
  24. }
复制代码


用 gRPC + Protobuf(Go 示例)
Protobuf 协议定义:
  1. syntax = "proto3";

  2. service UserService {
  3.   rpc GetUserProfile(UserRequest) returns (UserProfile) {}
  4. }

  5. message UserRequest {
  6.   int32 user_id = 1;
  7.   bool include_details = 2;
  8. }

  9. message UserProfile {
  10.   int32 user_id = 1;
  11.   string username = 2;
  12.   string email = 3;
  13. }
复制代码
Go 客户端调用:
  1. conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
  2. defer conn.Close()

  3. client := pb.NewUserServiceClient(conn)
  4. req := &pb.UserRequest{UserId: 123, IncludeDetails: true}
  5. res, _ := client.GetUserProfile(context.Background(), req)

  6. fmt.Printf("用户名: %s\n", res.Username)
复制代码
结构更清晰、体积更小、传输效率更高。

四、请求处理方式对比
传统 RPC 的调用方式(Go 示例)
  1. client, _ := xmlrpc.NewClient("http://localhost:8000", nil)

  2. var result string
  3. _ = client.Call("get_user_info", []interface{}{123}, &result)
  4. fmt.Println("用户信息:", result)

  5. // 再调另一个方法,又要重新连接
  6. var product string
  7. _ = client.Call("get_product_details", []interface{}{456}, &product)
  8. fmt.Println("商品信息:", product)
复制代码
每次调用都像重新打一次电话,很慢。

gRPC 的调用方式(Go 示例)
  1. conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
  2. defer conn.Close()

  3. client := pb.NewUserServiceClient(conn)

  4. // 同一个连接可以复用多次调用
  5. userRes, _ := client.GetUser(context.Background(), &pb.GetUserRequest{UserId: 123})
  6. productRes, _ := client.GetProduct(context.Background(), &pb.GetProductRequest{ProductId: 456})

  7. fmt.Println("用户:", userRes.Username)
  8. fmt.Println("商品:", productRes.Name)

  9. // 流式接收商品列表
  10. stream, _ := client.ListProducts(context.Background(), &pb.ListProductsRequest{Category: "手机"})
  11. for {
  12.     product, err := stream.Recv()
  13.     if err == io.EOF {
  14.         break
  15.     }
  16.     fmt.Printf("产品: %s, 价格: %.2f\n", product.Name, product.Price)
  17. }
复制代码
gRPC 就像是拉了一条专线,调用高效还支持流式处理。

五、性能差距有多大?REST(HTTP/1 + JSON)版本(Go 示例)
  1. start := time.Now()
  2. users := []map[string]interface{}{}

  3. for i := 0; i < 1000; i++ {
  4.     resp, _ := http.Get(fmt.Sprintf("http://api.example.com/users/%d", i))
  5.     var user map[string]interface{}
  6.     json.NewDecoder(resp.Body).Decode(&user)
  7.     users = append(users, user)
  8.     resp.Body.Close()
  9. }

  10. fmt.Printf("REST API: 获取了 %d 个用户,耗时 %.2f 秒\n", len(users), time.Since(start).Seconds())
复制代码
gRPC 版本(Go 示例)
  1. conn, _ := grpc.Dial("api.example.com:50051", grpc.WithInsecure())
  2. defer conn.Close()

  3. client := pb.NewUserServiceClient(conn)

  4. start := time.Now()
  5. res, _ := client.GetUsers(context.Background(), &pb.GetUsersRequest{Limit: 1000})

  6. fmt.Printf("gRPC: 获取了 %d 个用户,耗时 %.2f 秒\n", len(res.Users), time.Since(start).Seconds())
复制代码

gRPC 更快的原因:
  • 支持连接复用
  • 使用 Protobuf,数据轻量
  • 支持流式、批量处理


六、错误处理方式对比REST 错误处理(Go 示例)
  1. resp, _ := http.Get("http://api.example.com/users/12345")
  2. if resp.StatusCode != http.StatusOK {
  3.     var errResp map[string]interface{}
  4.     json.NewDecoder(resp.Body).Decode(&errResp)
  5.     fmt.Printf("错误: %v\n", errResp["error"])
  6. }
复制代码
靠 HTTP 状态码和自定义结构,客户端处理比较麻烦。

gRPC 错误处理(Go 示例)
服务端代码:
  1. func (s *UserServiceServer) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.UserProfile, error) {
  2.     user := db.FindUser(req.UserId)
  3.     if user == nil {
  4.         return nil, status.Errorf(codes.NotFound, "找不到用户 %d", req.UserId)
  5.     }
  6.     return user, nil
  7. }
复制代码
客户端代码:
  1. res, err := client.GetUser(context.Background(), &pb.GetUserRequest{UserId: 12345})
  2. if err != nil {
  3.     st, _ := status.FromError(err)
  4.     if st.Code() == codes.NotFound {
  5.         fmt.Println("错误: 用户不存在 -", st.Message())
  6.     } else {
  7.         fmt.Println("RPC错误:", st.Code(), "-", st.Message())
  8.     }
  9. }
复制代码
gRPC 错误处理就像捕获本地异常一样自然。

七、实际应用场景选择用 REST API 的情况:
  • 浏览器调用接口:如前端页面 fetch('/api/products')
  • 对接第三方平台:比如微信支付、支付宝,接口是 REST 的
  • 中小项目:追求开发效率即可,不追求性能极致

用 gRPC 的情况:
  • 微服务通信:服务与服务之间高频通信,高性能必选 gRPC
  • 实时数据推送


Go 示例:
  1. func (s *StockServer) PriceStream(req *pb.StockRequest, stream pb.StockService_PriceStreamServer) error {
  2.     for {
  3.         price := getPrice(req.Symbol)
  4.         stream.Send(&pb.StockPrice{
  5.             Symbol:    req.Symbol,
  6.             Price:     price,
  7.             Timestamp: time.Now().Unix(),
  8.         })
  9.         time.Sleep(1 * time.Second)
  10.     }
  11. }
复制代码
  • 移动端通信:节省流量,响应更快
  • 多语言系统:Go 调 Java、Java 调 Python,gRPC 都能搞定


八、总结
REST API 就像普通话,大家都能听懂;gRPC 像高速公路,虽然门槛高些,但速度飞快!
  • 如果你在做面向用户的 Web 接口,或者项目简单,REST API 足够。
  • 如果你在构建微服务、高性能系统、多语言协作,那就果断上 gRPC!

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

本版积分规则

Copyright © 2001-2025 Suike Tech All Rights Reserved. 随客交流社区 (备案号:津ICP备19010126号) |Processed in 0.101256 second(s), 7 queries , Gzip On, MemCached On.
关灯 在本版发帖返回顶部
快速回复 返回顶部 返回列表