百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

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

ccwgpt 2025-07-14 12:53 1 浏览 0 评论

引言

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##服务端#

相关推荐

RACI矩阵:项目管理中的角色与责任分配利器

作者:赵小燕RACI矩阵RACI矩阵是项目管理中的一种重要工具,旨在明确团队在各个任务中的角色和职责。通过将每个角色划分为负责人、最终责任人、咨询人和知情人四种类型,RACI矩阵确保每个人都清楚自己...

在弱矩阵组织中,如何做好项目管理工作?「慕哲制图」

慕哲出品必属精品系列在弱矩阵组织中,如何做好项目管理工作?【慕哲制图】-------------------------------慕哲制图系列0:一图掌握项目、项目集、项目组合、P2、商业分析和NP...

Scrum模式:每日站会(Daily Scrum)

定义每日站会(DailyScrum)是一个Scrum团队在进行Sprint期间的日常会议。这个会议的主要目的是为了应对Sprint计划中的不断变化,确保团队能够有效应对挑战并达成Sprint目标。为...

大家都在谈论的敏捷开发&Scrum,到底是什么?

敏捷开发作为一种开发模式,近年来深受研发团队欢迎,与瀑布式开发相比,敏捷开发更轻量,灵活性更高,在当下多变环境下,越来越多团队选择敏捷开发。什么是敏捷?敏捷是一种在不确定和变化的环境中,通过创造和响应...

敏捷与Scrum是什么?(scrum敏捷开发是什么)

敏捷是一种思维模式和哲学,它描述了敏捷宣言中的一系列原则。另一方面,Scrum是一个框架,规定了实现这种思维方式的角色,事件,工件和规则/指南。换句话说,敏捷是思维方式,Scrum是规定实施敏捷哲学的...

敏捷项目管理与敏捷:Scrum流程图一览

敏捷开发中的Scrum流程通常可以用一个简单的流程图来表示,以便更清晰地展示Scrum框架的各个阶段和活动。以下是一个常见的Scrum流程图示例:这个流程图涵盖了Scrum框架的主要阶段和活动,其中包...

一张图掌握项目生命周期模型及Scrum框架

Mockito 的最佳实践(mock方法)

记得以前面试的时候,面试官问我,平常开发过程中自己会不会测试?我回答当然会呀,自己写的代码怎么不测呢。现在想想我好像误会他的意思了,他应该是想问我关于单元测试,集成测试以及背后相关的知识,然而当时说到...

EffectiveJava-5-枚举和注解(java枚举的作用与好处)

用enum代替int常量1.int枚举:引入枚举前,一般是声明一组具名的int常量,每个常量代表一个类型成员,这种方法叫做int枚举模式。int枚举模式是类型不安全的,例如下面两组常量:性别和动物种...

Maven 干货 全篇共:28232 字。预计阅读时间:110 分钟。建议收藏!

Maven简介Maven这个词可以翻译为“知识的积累”,也可以翻译为“专家”或“内行”。Maven是一个跨平台的项目管理工具。主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。仔...

Java单元测试框架PowerMock学习(java单元测试是什么意思)

前言高德的技术大佬在谈论方法论时说到:“复杂的问题要简单化,简单的问题要深入化。”这句话让我感触颇深,这何尝不是一套编写代码的方法——把一个复杂逻辑拆分为许多简单逻辑,然后把每一个简单逻辑进行深入实现...

Spring框架基础知识-第六节内容(Spring高级话题)

Spring高级话题SpringAware基本概念Spring的依赖注入的最大亮点是你所有的Bean对Spring容器的存在是没有意识的。但是在实际的项目中,你的Bean必须要意识到Spring容器...

Java单元测试浅析(JUnit+Mockito)

作者:京东物流秦彪1.什么是单元测试(1)单元测试环节:测试过程按照阶段划分分为:单元测试、集成测试、系统测试、验收测试等。相关含义如下:1)单元测试:针对计算机程序模块进行输出正确性检验工作...

揭秘Java代码背后的质检双侠:JUnit与Mockito!

你有没有发现,现在我们用的手机App、逛的网站,甚至各种智能设备,功能越来越复杂,但用起来却越来越顺畅,很少遇到那种崩溃、卡顿的闹心事儿?这背后可不是程序员一拍脑袋写完代码就完事儿了!他们需要一套严谨...

单元测试框架哪家强?Junit来帮忙!

大家好,在前面的文章中,给大家介绍了以注解和XML的方式分别实现IOC和依赖注入。并且我们定义了一个测试类,通过测试类来获取到了容器中的Bean,具体的测试类定义如下:@Testpublicvoid...

取消回复欢迎 发表评论: