golang实现高性能HTTP/2 RPC通信的gRPC框架插件库grpc-go的使用

Golang实现高性能HTTP/2 RPC通信的gRPC框架插件库grpc-go的使用

简介

grpc-go是Go语言实现的gRPC框架,它是一个高性能、开源的通用RPC框架,基于HTTP/2协议设计,特别适合移动和HTTP/2场景。

前提条件

  • Go: 需要安装最新的两个主要版本之一

安装

只需在代码中添加以下导入,然后go [build|run|test]会自动获取必要的依赖:

import "google.golang.org/grpc"

注意: 如果你在中国访问grpc-go遇到问题,请参考下面的FAQ部分。

完整示例Demo

下面是一个完整的gRPC服务端和客户端通信示例:

1. 定义proto文件 (hello.proto)

syntax = "proto3";

package hello;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

2. 生成Go代码

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    hello.proto

3. 服务端实现 (server.go)

package main

import (
	"context"
	"log"
	"net"

	pb "path/to/your/hello" // 替换为你的包路径
	"google.golang.org/grpc"
)

const (
	port = ":50051"
)

// server 用于实现Greeter服务
type server struct {
	pb.UnimplementedGreeterServer
}

// SayHello 实现Greeter服务的SayHello方法
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

4. 客户端实现 (client.go)

package main

import (
	"context"
	"log"
	"os"
	"time"

	pb "path/to/your/hello" // 替换为你的包路径
	"google.golang.org/grpc"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func main() {
	// 建立到服务器的连接
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// 从命令行参数获取名字,如果没有则使用默认值
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	
	// 调用SayHello RPC方法
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

常见问题

I/O超时错误

如果你在中国,可能会遇到golang.org域名被屏蔽的问题。解决方案:

  1. 设置VPN访问google.golang.org
  2. 使用Go模块的replace功能:
go mod edit -replace=google.golang.org/grpc=github.com/grpc/grpc-go@latest
go mod tidy
go mod vendor
go build -mod=vendor

编译错误: undefined: grpc.SupportPackageIsVersion

请更新到最新版本的grpc-go:

go get google.golang.org/grpc

如何开启日志

通过环境变量控制默认日志记录器:

export GRPC_GO_LOG_VERBOSITY_LEVEL=99
export GRPC_GO_LOG_SEVERITY_LEVEL=info

RPC失败错误: “code = Unavailable desc = transport is closing”

这个错误意味着RPC使用的连接被关闭了,可能的原因包括:

  1. 传输凭证配置错误,握手失败
  2. 字节传输中断,可能是中间有代理
  3. 服务器关闭
  4. Keepalive参数导致连接关闭

了解更多

  • Go gRPC文档,包括快速入门和API参考等资源
  • 本仓库中的底层技术文档
  • 性能基准测试
  • 示例代码
  • 贡献指南

更多关于golang实现高性能HTTP/2 RPC通信的gRPC框架插件库grpc-go的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现高性能HTTP/2 RPC通信的gRPC框架插件库grpc-go的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


grpc-go 框架使用指南

grpc-go 是 Go 语言实现的 gRPC 框架,支持高性能 HTTP/2 RPC 通信。下面我将详细介绍如何使用 grpc-go 进行开发。

1. 安装 grpc-go

首先需要安装必要的依赖:

go get google.golang.org/grpc
go get google.golang.org/protobuf

2. 定义 Proto 文件

创建一个 hello.proto 文件定义服务:

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

3. 生成 Go 代码

使用 protoc 工具生成代码:

protoc --go_out=. --go_opt=paths=source_relative \
    --go-grpc_out=. --go-grpc_opt=paths=source_relative \
    hello.proto

这会生成 hello.pb.gohello_grpc.pb.go 两个文件。

4. 实现服务端

package main

import (
	"context"
	"log"
	"net"

	pb "path/to/your/proto/package" // 替换为你的包路径
	"google.golang.org/grpc"
)

const (
	port = ":50051"
)

type server struct {
	pb.UnimplementedGreeterServer
}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	log.Printf("Received: %v", in.GetName())
	return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}

func main() {
	lis, err := net.Listen("tcp", port)
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}
	s := grpc.NewServer()
	pb.RegisterGreeterServer(s, &server{})
	log.Printf("server listening at %v", lis.Addr())
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

5. 实现客户端

package main

import (
	"context"
	"log"
	"os"
	"time"

	pb "path/to/your/proto/package" // 替换为你的包路径
	"google.golang.org/grpc"
)

const (
	address     = "localhost:50051"
	defaultName = "world"
)

func main() {
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

6. 高级功能

6.1 拦截器

// 服务端拦截器
func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	log.Printf("--> %s", info.FullMethod)
	return handler(ctx, req)
}

func main() {
	s := grpc.NewServer(
		grpc.UnaryInterceptor(unaryInterceptor),
	)
	// ...
}

6.2 流式 RPC

在 proto 文件中添加流式方法:

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
  rpc LotsOfReplies (HelloRequest) returns (stream HelloReply) {}
}

实现流式服务端:

func (s *server) LotsOfReplies(in *pb.HelloRequest, stream pb.Greeter_LotsOfRepliesServer) error {
	for i := 0; i < 5; i++ {
		if err := stream.Send(&pb.HelloReply{
			Message: fmt.Sprintf("Hello %s %d", in.GetName(), i),
		}); err != nil {
			return err
		}
	}
	return nil
}

6.3 负载均衡

conn, err := grpc.Dial(
	address,
	grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
	grpc.WithTransportCredentials(insecure.NewCredentials()),
)

6.4 超时控制

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

response, err := client.SomeMethod(ctx, request)
if err != nil {
	if status.Code(err) == codes.DeadlineExceeded {
		log.Println("Timeout hit!")
	}
}

7. 性能优化建议

  1. 连接池:重用 gRPC 连接
  2. 压缩:启用 gRPC 压缩
    conn, err := grpc.Dial(address, grpc.WithDefaultCallOptions(grpc.UseCompressor("gzip")))
    
  3. Keepalive:配置 keepalive 参数
  4. 批处理:对于大量小请求,考虑批处理
  5. 监控:集成 Prometheus 监控

8. 错误处理

if err != nil {
	if st, ok := status.FromError(err); ok {
		log.Printf("gRPC error: %v, code: %v", st.Message(), st.Code())
	} else {
		log.Printf("non-gRPC error: %v", err)
	}
}

通过以上步骤,你可以构建一个高性能的 gRPC 服务。grpc-go 提供了丰富的功能和良好的性能,适合构建微服务架构中的内部通信组件。

回到顶部