Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Go语言gRPC微服务通信

Go语言gRPC实现高性能微服务通信

作者:王码码2035哦

gRPC是Google开源的高性能通用RPC框架,基于HTTP/2和ProtocolBuffers,本文主要介绍了Go语言gRPC实现高性能微服务通信,感兴趣的可以了解一下

作为一个写了十几年代码的Go后端老兵,我最近在项目中全面迁移到gRPC,体验了它的高性能和类型安全。今天就来分享一下gRPC的实战经验。

一、gRPC简介

gRPC是Google开源的高性能、通用的RPC框架,基于HTTP/2协议和Protocol Buffers序列化。

核心优势

二、环境搭建

1. 安装Protocol Buffers

# 安装protobuf编译器
brew install protobuf
# 安装Go的protobuf插件
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

2. 定义服务

创建proto/user.proto文件:

syntax = "proto3";
package user;
option go_package = "./user";
// 用户服务
service UserService {
  // 获取用户信息
  rpc GetUser(GetUserRequest) returns (GetUserResponse);
  // 创建用户
  rpc CreateUser(CreateUserRequest) returns (CreateUserResponse);
  // 流式获取用户列表
  rpc ListUsers(ListUsersRequest) returns (stream ListUsersResponse);
}
// 获取用户请求
message GetUserRequest {
  int32 id = 1;
}
// 获取用户响应
message GetUserResponse {
  User user = 1;
}
// 创建用户请求
message CreateUserRequest {
  string name = 1;
  string email = 2;
}
// 创建用户响应
message CreateUserResponse {
  User user = 1;
}
// 列表用户请求
message ListUsersRequest {
  int32 page = 1;
  int32 page_size = 2;
}
// 列表用户响应
message ListUsersResponse {
  User user = 1;
}
// 用户信息
message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

3. 生成代码

# 生成Go代码
protoc --go_out=. --go-grpc_out=. proto/user.proto

三、服务端实现

package main
import (
	"context"
	"fmt"
	"log"
	"net"
	"google.golang.org/grpc"
	pb "your-project/user"
)
// 实现UserService服务
type userService struct {
	pb.UnimplementedUserServiceServer
}
// GetUser实现
func (s *userService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
	// 模拟从数据库获取用户
	user := &pb.User{
		Id:    req.GetId(),
		Name:  "张三",
		Email: "zhangsan@example.com",
	}
	return &pb.GetUserResponse{User: user}, nil
}
// CreateUser实现
func (s *userService) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
	// 模拟创建用户
	user := &pb.User{
		Id:    1,
		Name:  req.GetName(),
		Email: req.GetEmail(),
	}
	return &pb.CreateUserResponse{User: user}, nil
}
// ListUsers实现(流式)
func (s *userService) ListUsers(req *pb.ListUsersRequest, stream pb.UserService_ListUsersServer) error {
	// 模拟批量获取用户
	users := []*pb.User{
		{Id: 1, Name: "张三", Email: "zhangsan@example.com"},
		{Id: 2, Name: "李四", Email: "lisi@example.com"},
		{Id: 3, Name: "王五", Email: "wangwu@example.com"},
	}
	for _, user := range users {
		if err := stream.Send(&pb.ListUsersResponse{User: user}); err != nil {
			return err
		}
	}
	return nil
}
func main() {
	// 创建gRPC服务器
	server := grpc.NewServer()
	// 注册服务
	pb.RegisterUserServiceServer(server, &userService{})
	// 监听端口
	listener, err := net.Listen("tcp", ":50051")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	fmt.Println("Server is running on port 50051")
	if err := server.Serve(listener); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}

四、客户端实现

package main
import (
	"context"
	"fmt"
	"log"
	"google.golang.org/grpc"
	pb "your-project/user"
)
func main() {
	// 连接服务器
	conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()
	// 创建客户端
	client := pb.NewUserServiceClient(conn)
	// 测试GetUser
	getUserReq := &pb.GetUserRequest{Id: 1}
	getUserResp, err := client.GetUser(context.Background(), getUserReq)
	if err != nil {
		log.Fatalf("Failed to get user: %v", err)
	}
	fmt.Printf("GetUser response: %v\n", getUserResp)
	// 测试CreateUser
	createUserReq := &pb.CreateUserRequest{
		Name:  "赵六",
		Email: "zhaoliu@example.com",
	}
	createUserResp, err := client.CreateUser(context.Background(), createUserReq)
	if err != nil {
		log.Fatalf("Failed to create user: %v", err)
	}
	fmt.Printf("CreateUser response: %v\n", createUserResp)
	// 测试ListUsers(流式)
	listUsersReq := &pb.ListUsersRequest{
		Page:     1,
		PageSize: 10,
	}
	stream, err := client.ListUsers(context.Background(), listUsersReq)
	if err != nil {
		log.Fatalf("Failed to list users: %v", err)
	}
	for {
		resp, err := stream.Recv()
		if err != nil {
			break
		}
		fmt.Printf("ListUsers response: %v\n", resp)
	}
}

五、高级特性

1. 拦截器

// 服务端拦截器
func loggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	log.Printf("Received request: %v", info.FullMethod)
	resp, err := handler(ctx, req)
	log.Printf("Sent response: %v", info.FullMethod)
	return resp, err
}
// 注册拦截器
server := grpc.NewServer(
	grpc.UnaryInterceptor(loggingInterceptor),
)

2. 超时控制

// 客户端设置超时
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
resp, err := client.GetUser(ctx, req)

3. 错误处理

// 服务端返回错误
func (s *userService) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
	if req.GetId() <= 0 {
		return nil, status.Errorf(codes.InvalidArgument, "Invalid user ID")
	}
	// 其他逻辑...
}
// 客户端处理错误
resp, err := client.GetUser(ctx, req)
if err != nil {
	if status, ok := status.FromError(err); ok {
		switch status.Code() {
		case codes.InvalidArgument:
			fmt.Println("Invalid argument error")
		case codes.NotFound:
			fmt.Println("User not found")
		default:
			fmt.Println("Unknown error")
		}
	}
}

六、踩坑记录

  1. 版本兼容性:Protocol Buffers版本和gRPC版本需要匹配
  2. 服务定义:字段编号一旦使用就不能修改
  3. 流式传输:需要注意流的关闭和错误处理
  4. 超时设置:必须设置合理的超时时间,避免请求挂起
  5. 性能优化:对于高频请求,需要合理设置连接池和并发数

七、总结

gRPC是一个强大的RPC框架,特别适合微服务架构。作为一个老程序员,我的建议是:

到此这篇关于Go语言gRPC实现高性能微服务通信的文章就介绍到这了,更多相关Go语言gRPC微服务通信内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文