当前位置:首页 > 技术文章 > 正文内容

Go语言零到一:gRPC(远程过程调用)

zonemu1个月前 (09-13)技术文章17

引言

gRPC 是 Google 基于HTTP/2 协议开发的一个高性能的 RPC 框架,它使用 Protocol Buffers 作为接口定义语言,并支持多种语言。gRPC 提供了丰富的功能,如双向流式通信、消息压缩、身份验证等。

1. 准备

  • 安装 gRPC 必要的工具和依赖项:
go install google.golang.org/grpc/cmd/protoc-gen-go@latest 
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  • 新建文件夹grpccd ./grpc执行go mod init grpc初始化模块管理文件
  • 项目文件结构:
└─grpc     
    |   go.mod
    |   go.sum
    +---arith
    |       arith.pb.go
    |       arith_grpc.pb.go
    +---client
    |       main.go
    +---proto_file
    |       arith.proto
    \---server
            main.go

2. 定义 gRPC 服务

首先,定义一个 .proto 文件来描述服务接口。

2.1 .proto 文件

创建一个名为 arith.proto 的文件:

syntax = "proto3";

package arith;
option go_package = "../arith";

service Arithmetic {
  rpc Add (AddRequest) returns (AddResponse) {};
  rpc StreamSum (stream SumRequest) returns (stream SumResponse) {};
}

message AddRequest {
  int32 a = 1;
  int32 b = 2;
}

message AddResponse {
  int32 result = 1;
}

message SumRequest {
  int32 number = 1;
}

message SumResponse {
  int32 result = 1;
}

// protoc --go_out=. --go-grpc_out=. .\arith.proto

2.2 生成 Go 代码

进入 proto_file 目录,使用 protoc 编译器生成 Go 代码:

protoc --go_out=. --go-grpc_out=. .\arith.proto

这将生成两个文件:arith.pb.goarith_grpc.pb.go

3. 实现 gRPC 服务端

package main

import (
	"context"
	pb "grpc/arith"
	"log"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

type server struct {
	pb.UnimplementedArithmeticServer
}

func (*server) Add(ctx context.Context, req *pb.AddRequest) (*pb.AddResponse, error) {
	result := req.GetA() + req.GetB()
	return &pb.AddResponse{Result: result}, nil
}

func (*server) StreamSum(stream pb.Arithmetic_StreamSumServer) error {
	sum := int32(0)
	for {
		req, err := stream.Recv()
		if err != nil {
			return err
		}
		sum += req.GetNumber()
		if err := stream.Send(&pb.SumResponse{Result: sum}); err != nil {
			return err
		}
	}
}

func main() {
	lis, err := net.Listen("tcp", ":8086")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterArithmeticServer(s, &server{})
	reflection.Register(s) // Enable reflection for development
	log.Println("Starting gRPC server on :8086...")
	if err = s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

4. 实现 gRPC 客户端

package main

import (
	"context"
	pb "grpc/arith"
	"log"
	"time"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

func main() {
	conn, err := grpc.NewClient(":8086", grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	client := pb.NewArithmeticClient(conn)

	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()

	resp, err := client.Add(ctx, &pb.AddRequest{A: 100, B: 200})
	if err != nil {
		log.Fatalf("could not add: %v", err)
	}
	log.Printf("Addition Result: %d", resp.GetResult())

	log.Println("Starting streaming sum...")

	stream, err := client.StreamSum(ctx)
	if err != nil {
		log.Fatalf("could not stream sum: %v", err)
	}

	reqs := []*pb.SumRequest{
		{Number: 1},
		{Number: 2},
		{Number: 3},
		{Number: 4},
		{Number: 5},
	}

	for _, req := range reqs {
		if err := stream.Send(req); err != nil {
			log.Fatalf("could not send request: %v", err)
		}
		resp, err := stream.Recv()
		if err != nil {
			log.Fatalf("could not receive response: %v", err)
		}
		log.Printf("Streamed Sum: %d", resp.GetResult())
	}
}

5. 最佳实践

5.1 设计良好的 API

  • 明确的命名约定:确保所有服务、方法和字段的命名清晰且具描述性。
  • 合理的服务划分:将功能相关的 RPC 方法归类到同一个服务中。
  • 合理的请求和响应:请求和响应消息应该包含必要的信息,避免冗余。

5.2 使用 Protocol Buffers

  • 简洁的消息结构:保持消息结构简单,避免过于复杂的设计。
  • 使用枚举:对于有限的选择,使用枚举类型(enum)来定义,这样可以减少混淆和错误。
  • 版本控制:为协议缓冲区定义版本,确保向前兼容。

5.3 异常处理

  • 定义错误码:在 proto 文件中定义错误码,并在服务端返回相应的状态码。
  • 优雅地处理错误:在客户端优雅地处理错误,提供用户友好的反馈。

5.4 认证和安全

  • 使用 TLS/SSL:确保 gRPC 通信的安全性,使用 TLS/SSL 加密。
  • 认证机制:实现身份验证机制,例如 JWT(JSON Web Tokens)。

5.5 流量控制和限流

  • 流量控制:在服务端实现流量控制,防止过载。
  • 限流:根据需要实现限流策略,保护服务免受滥用。

5.6 日志记录和监控

  • 日志记录:记录详细的日志,便于调试和追踪问题。
  • 健康检查:实现健康检查机制,确保服务可用性。
  • 性能监控:使用 Prometheus、Grafana 等工具进行性能监控。

5.7 测试

  • 单元测试:为每个服务实现单元测试,确保基本功能的正确性。
  • 集成测试:编写集成测试,确保服务之间的交互正确无误。

5.8 文档

  • 编写文档:编写详细的 API 文档,包括每个服务、方法和消息的描述。
  • 生成文档:使用工具自动生成文档,例如 Swagger 或者其他文档生成工具。

5.9 代码生成

  • 代码生成工具:使用 protoc 生成客户端和服务端代码。
  • 遵循约定:遵循代码生成工具的约定,避免手动修改生成的代码。

5.10 高可用性和负载均衡

  • 高可用性:部署多个实例,实现高可用性。
  • 负载均衡:使用负载均衡器(如 Nginx 或 Envoy)来分发请求。

#golang##grpc##rpc##服务端#

相关文章

Garuda Linux:现代化、注重性能与美观的Linux发行版

什么是 Garuda Linux?Garuda Linux 是一个基于 Arch Linux 的现代化、注重性能与美观的桌面操作系统。它面向对性能有较高要求的用户,尤其受到 Linux 爱好者、游戏玩...

【Vue3 基础】05.组件化(组件使用vuex)

这是 Vue3 + Vite + Pinia +TS + Element-Plus 实战系列文档。最近比较忙没什么时间写文章,争取早日把这个系列完结吧~生命周期和模板引用在本章之前,我们通过响应式 a...

程序员效率提升!使用自动化工具gitx,每周节约半小时

你是否经历过这样的折磨?一个 JIRA 需求要同时修复 dev、qa、staging 三个分支每个版本涉及 A、B、C 三个项目手动执行以下操作:从 dev 切临时分支cherry-pick 提交推送...

html5你能把太阳系动态做出来,但是你能把月亮也做出来吗?

需要源码请评论后加前端学习群470593776课题:HTML5加原生js打造一个炫酷动态的太阳系简介:首先对于太阳系各大星球的运转关系,速度等资料,不然弄出来也是被喷的下场, 还有对于逻辑思维,算法的...

Web前端全套教程+视频包含JavaScript、Vue等

写在前面:web前端从入门到精通经典教程,老师精心讲,想从事编程或者数据分析行业的小伙伴点进来,只需你评论并关注私信留言“前端”。便可免费获取。WEB前端简介:WEB前端工程师,也叫Web前端开发工程...

一键看懂Html5,就这么简单(查看html的app推荐)

HTML5是WEB开发世界的一次重大的改变,事实上不管你是否喜欢,它都是代表着未来趋势。曾几何时,当HTML5出现在web端开发领域的时候,并没有引起太多人的注意,究其原因,一方面是它还没有被广泛的支...