javaer选手快速入门grpc

本文前置内容 需要学过java微服务开发,至少知道使用过openfeign和dubbo等rpc微服务组件的相关内容

相信已经学习到微服务开发的对grpc或多或少都有了解,高效的性能和protobuf这样轻量序列化的方式 无论是go开发必学还是java 使用dubbo或者其他深入也是需要了解的

相关概念

Protocol Buffers(简称 Protobuf)是一种由 Google 开发的数据序列化协议,用于高效地定义和交换结构化数据。它允许定义数据的结构和类型,并生成不同编程语言的代码来处理这些数据。

gRPC 是一个高性能、开源和通用的 RPC 框架,由 Google 开发。它基于 HTTP/2 协议,支持多种编程语言。gRPC 使用 Protobuf 作为默认的序列化协议。

核心逻辑

对于grpc 其实和微服务开发的方式有很大的相同,java中是采取将rpc服务单独拆分为一个模块,每个服务有很多未实现的接口定义,然后上传中央仓库或者jar包 由被调用的服务方实现,调用方只需要引入该模块 jar包即可完成调用的开发思想

go中的核心逻辑也是如此,只是将单独抽离的rpc模块这一步在gpc中是编写protobuf文件 ,然后插件生成代码,服务方实现接口,消费调用方 引入客户端调用

gRPC 框架的核心流程
编写 Protobuf 文件

  • 定义服务:使用 service 关键字定义远程调用服务及其方法。
  • 定义消息:使用 message 关键字定义服务的请求和响应消息的结构。
    生成代码:

使用 protoc 工具根据 .proto 文件生成客户端和服务端的代码。
具体来说:

  • 消息类型:生成表示请求和响应数据结构的代码。
  • 服务接口:生成服务接口的代码,供服务端实现。
  • 客户端代码:生成客户端代码,用于调用服务端的方法。
  • 实现服务端:实现 Protobuf 定义的服务接口,处理客户端请求并返回响应。
  • 实现客户端:使用生成的客户端代码连接到服务端,调用远程方法并处理结果。

所以前置条件就是需要安装把protobuf生成go 代码的插件

安装插件

https://github.com/protocolbuffers/protobuf/releases/download/v3.9.0/protoc-3.9.0-win64.zip
go get github.com/golang/protobuf/proto
go get google.golang.org/grpc
go install github.com/golang/protobuf/protoc-gen-go

配置PATH环境变量 (go指令安装的文件都在项目的gopath目录)
在这里插入图片描述

认识protobuf文件

核心关键字

  • syntax:指定 Protobuf 版本。
  • package:定义命名空间。
  • option:指定生成代码的配置。
  • message:定义数据结构。
  • enum:定义枚举类型。
  • service:定义服务和 RPC 方法。
  • repeated:定义列表类型的字段。
  • oneof:定义一个字段组,表示只能设置一个字段。

比如:编写的user.proto

syntax = "proto3";

package example;

option go_package = "go-grpc-fast/protos;protos";

// 通用的结果封装
message Result {
  bool success = 1;                // 操作是否成功
  string message = 2;              // 错误信息或提示信息
}

// 用户信息
message User {
  int32 id = 1;                    // 用户 ID
  string name = 2;                 // 用户名称
  string email = 3;                // 用户邮箱
}

// 请求参数
message GetUserRequest {
  int32 user_id = 1;               // 请求的用户 ID
}

// 响应体
message GetUserResponse {
  Result result = 1;               // 操作结果
  User user = 2;                   // 用户信息
}

// 定义 RPC 服务
service UserService {
  // 获取用户信息
  rpc GetUser (GetUserRequest) returns (GetUserResponse);

  // 更新用户信息
  rpc UpdateUser (UpdateUserRequest) returns (UpdateUserResponse);
}

// 更新请求参数
message UpdateUserRequest {
  User user = 1;                   // 要更新的用户信息
}

// 更新响应体
message UpdateUserResponse {
  Result result = 1;               // 操作结果
}

在代码中 使用message定义了很多结构体 user,result ,俩个接口对应的请求体和相关的响应体,类型 参数名=1 这个数字是标识 只需要当前结构体唯一就好了

service 表示是一个rpc服务 rpc申明的 就是生成代码后的接口和返回值

使用插件生成

命令如下:


protoc -I . --go_out=paths=source_relative:. --go-grpc_out=paths=source_relative:. user.proto

生成模块代码
在这里插入图片描述

可以看到服务和客户端申明 以及方法接口申明

解释 protoc 指令

这个命令用于将 Protocol Buffers (.proto) 文件编译成 Go 语言代码,并生成 gRPC 相关的代码。让我们分解一下这个命令的各个部分:

  1. protoc: Protocol Buffers 编译器命令行工具,用于将 .proto 文件转换成各种编程语言的代码。
  2. -I .: 指定了 protoc 编译器的导入路径。在这里,. 表示当前目录。protoc 会在这个路径下查找 .proto 文件中的依赖文件。
  3. --go_out=paths=source_relative:.: 指定了如何生成 Go 语言的代码。
    • --go_out 表示生成的代码类型是 Protocol Buffers 消息和服务的基础 Go 代码。
    • paths=source_relative 表示生成的 Go 文件将相对于 .proto 文件的位置。这意味着生成的文件将保留与 .proto 文件相对的路径结构。
    • . 表示生成的代码将放在当前目录。
  4. --go-grpc_out=paths=source_relative:.: 指定了如何生成 gRPC 的代码。
    • --go-grpc_out 表示生成的代码类型是 gRPC 的 Go 代码,例如服务的客户端和服务器接口。
    • paths=source_relative. 的含义与 --go_out 中的相同。
  5. user.proto: 要编译的 Protocol Buffers 文件名。

生成的俩个文件

  • user.pb.go 包含了消息和数据结构的定义。

  • user_grpc.pb.go 包含了 gRPC 服务的接口和客户端代码。

实现生成的rpc服务接口 构造微服务

这里的服务端就是用原生http 模拟 ,当然也可以使用gin 和go-zero
服务端

package main

import (
	"context"
	"fmt"
	//生成的代码包
	"go-grpc-fast/protos/hello_grpc"
	"go-grpc-fast/protos/user"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
	"net"
)

// HelloServer 得有一个结构体,需要实现这个服务的全部方法,叫什么名字不重要
type HelloServer struct {
	hello_grpc.UnimplementedHelloServiceServer
}
type UserrpcServer struct {
	user.UnimplementedUserServiceServer
}

func (s *UserrpcServer) UpdateUser(ctx context.Context, in *user.UpdateUserRequest) (*user.UpdateUserResponse, error) {
	fmt.Println("user update request received")
	fmt.Println(in)
	return nil, nil
}

// GetUser 实现了 UserServiceServer 接口中的 GetUser 方法
func (s *UserrpcServer) GetUser(ctx context.Context, in *user.GetUserRequest) (*user.GetUserResponse, error) {
	// 这里你可以根据业务逻辑处理请求
	fmt.Println("Received request for user ID:", in.UserId)

	// 创建并返回响应
	return &user.GetUserResponse{
		Result: &user.Result{
			Success: true,
			Message: "成功查找用户",
		},
		User: &user.User{
			Id:    in.UserId,
			Name:  "乔治",
			Email: "john.doe@example.com",
		},
	}, nil
}
func (c *HelloServer) SayHello(ctx context.Context, request *hello_grpc.HelloRequest) (*hello_grpc.HelloResponse, error) {
	fmt.Println("入参:", request.Name, request.Message)
	return &hello_grpc.HelloResponse{
		Name:    "server",
		Message: "hello " + request.Name,
	}, nil
}

func main() {
	// 监听端口
	listen, err := net.Listen("tcp", ":4040")
	if err != nil {
		grpclog.Fatalf("Failed to listen: %v", err)
	}

	// 创建一个gRPC服务器实例。
	s := grpc.NewServer()

	server := HelloServer{}
	userServer := new(UserrpcServer)
	// 将server结构体注册为gRPC服务。
	hello_grpc.RegisterHelloServiceServer(s, &server)
	user.RegisterUserServiceServer(s, userServer)
	fmt.Println("启动一个搭建rpc服务的程序,监听端口 :4040")
	// 开始处理客户端请求。
	err = s.Serve(listen)
}

这样就实现了服务端 响应体直接引入生成的go文件
客户端

import (
	"context"
	"fmt"
	"go-grpc-fast/protos/hello_grpc"
	"go-grpc-fast/protos/user"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
	"log"
)

func main() {
	addr := ":4040"
	// 使用 grpc.Dial 创建一个到指定地址的 gRPC 连接。
	// 此处使用不安全的证书来实现 SSL/TLS 连接
	conn, err := grpc.Dial(addr, grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatalf(fmt.Sprintf("grpc connect addr [%s] 连接失败 %s", addr, err))
	}
	defer conn.Close()
	// 初始化客户端
	client := hello_grpc.NewHelloServiceClient(conn)
	userServiceClient := user.NewUserServiceClient(conn)
	result, err := client.SayHello(context.Background(), &hello_grpc.HelloRequest{
		Name:    "你好",
		Message: "hello",
	})
	//用户客户端发起请求

	if getUser, err := userServiceClient.GetUser(context.Background(), &user.GetUserRequest{
		UserId: 454545,
	}); err == nil {
		fmt.Println(getUser)
	}

	fmt.Println(result, err)
}

使用protobuf 生成的实列化注入rpc连接
userServiceClient := user.NewUserServiceClient(conn)

服务端 为什么要内嵌一个接口

type UserrpcServer struct {
	user.UnimplementedUserServiceServer
}

在这里插入图片描述
在 gRPC 中,服务端实现需要嵌入一个自动生成的基类类型,称为 UnimplementedServer。这个基类类型是由 protoc 工具生成的,目的是为了简化服务的实现,并提供一些便利功能。以下是详细解释:

UnimplementedServer 的作用

  • 简化实现:

UnimplementedServer 是由 protoc 生成的一个空接口,它包含了所有 RPC 方法的默认实现,通常是空的实现。
当你创建一个服务实现时,你可以嵌入这个类型,从而避免自己手动实现所有方法的空方法,减少样板代码。

  • 向后兼容性:

如果 gRPC 的库更新或者 .proto 文件中的服务定义被修改(例如,添加了新的方法),UnimplementedServer 类型会自动提供这些新方法的空实现。这样,当你的服务实现结构体嵌入了这个类型时,你的代码可以在不修改的情况下兼容未来的更新。
如果将来你的服务接口增加了新方法,UnimplementedServer 会自动提供这些新方法的空实现,从而避免了编译错误。

  • 提供默认实现:

UnimplementedServer 的存在意味着你可以只实现你关注的那些方法,而不需要提供所有方法的实现。对于那些尚未实现的方法,gRPC 框架会调用默认的空实现,而不会因缺少实现而崩溃。

所以使用grpc是很简单的 得益于protobuf ,grpc的性能和开发都是很指的学习的,就算是javer dubbo 官方也推荐这样实现
在这里插入图片描述
当然grpc 还可以生成其他语言的接口代码grpc官网

protobuf的编写规范

请查看go-zero微服务开发框架中的引用go-zero

  • 26
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝胖子不是胖子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值