内容简介:What is gRPC: gRPC,顾名思义, Google远程过程调用。这是Google创建的一种远程通信协议,可让不同的服务轻松高效地相互通信。它提供与服务之间的同步和异步通信。要了解有关gRPC的更多信息,请访问gRPC最适合内部通信。它使客户调用变得更加简洁,我们无需担心序列化,类型安全以及所有这些事情,因为gRPC为我们做到了这一点。gPRC使用protobuf,一种类型安全的二进制传输格式,旨在实现有效的网络通信。要了解有关protobuf的更多信息,请访问此
What is gRPC: gRPC,顾名思义, Google远程过程调用。这是Google创建的一种远程通信协议,可让不同的服务轻松高效地相互通信。它提供与服务之间的同步和异步通信。要了解有关gRPC的更多信息,请访问 gRPC.io
gRPC最适合内部通信。它使客户调用变得更加简洁,我们无需担心序列化,类型安全以及所有这些事情,因为gRPC为我们做到了这一点。
gPRC使用protobuf,一种类型安全的二进制传输格式,旨在实现有效的网络通信。要了解有关protobuf的更多信息,请访问此 链接 。
性能基准测试结果表明,如果开发人员需要性能和本地调用体验,则gRPC比http/http2更好。具体测评细节查看该文章。
使用Golang构建微服务
我们选择Golang(也称为Go)作为此服务的编程语言,选择gRPC作为其他服务的通信协议,以与我们的服务进行对话,并使用经过验证的OAuth 2.0协议上的OpenId身份层来保护我们的服务。
创建Message
为此,首先我们需要在gRPC中创建一个简单的实体表示形式,称为message。用gRPC术语表示的消息可以用作从另一个服务到一个服务的消息(使用protobuf语法定义的消息)。您可以想象一只鸽子从一个承载“冬天来了”消息的服务到另一个服务,而该服务正在消费该消息来执行上下文操作。
现在,在上面的示例中,发送鸽子的服务是gRPC客户端,“冬天来了”是我们的消息,而使用该消息的服务是gRPC服务器在侦听该消息。关于消息的好处是它可以来回传送。
message Repository {
int64 id = 1;
string name = 2;
int64 userId = 3;
bool isPrivate = 4;
}
定义 gRPC 服务
现在我们已经创建了一个名为存储库的message以用于通信,下一步是定义gRPC服务。
service RepositoryService {
//For now we'll try to implement "insert" operation.
rpc add (Repository) returns (AddRepositoryResponse);
}
message AddRepositoryResponse {
Repository addedRepository = 1;
Error error = 2;
}
message Error {
string code = 1;
string message = 2;
}
在这里,我们告诉gRPC编译器,以“service”关键字开头的代码段应被视为gRPC服务。带有“rpc”关键字的方法表示它是一个远程过程调用,并且编译器应为客户端和服务器运行时生成适当的存根。
我们还定义了2条消息,告诉鸽子在执行操作后返回成功响应或错误响应。
为Golang服务创建文件夹结构
我假设您已经安装了 Go 运行时。如果不这样做,请按照其官方文档中的步骤进行操作,网址为 https://golang.org/doc/instal...
我们还将使用dep作为我们项目的依赖管理工具。 Dep是用于管理golang项目中外部依赖关系的成熟解决方案。我们使用dep是因为尚未正式发布Go模块支持。
如果您是Windows用户,则将dep安装的路径放在环境的PATH变量中。这使您更容易使用,而无需指定可执行文件的完整路径即可使用它。
安装Go运行时后,请执行以下步骤。
在 $GOPATH/src 中创建名为 bitbucket-repository-management-service”的目录。
然后在目录中设置标准子包,整个项目架构具体如下:
-
导航到项目的根目录并执行以下命令
- 如果是windows系统, "dep.exe init"
- 如果是 linux 系统, "dep init"
- 上面的命令将创建一个名为“vendor”的文件夹以及“Gopkg.lock”和“ Gopkg.toml”文件。这两个文件对于管理我们项目的不同依赖关系很重要。
- 我们的下一步是将原型文件放入“ internal ”文件夹,因为这些文件严格绑定到我们的应用程序。以后,如果我们想使用不同的编程语言将相同的文件用于不同的服务,则将为此创建一个单独的存储库。但是为了简单起见,我们现在将它们放在同一目录中。
- 如下图所示,在“内部”包中创建名为“proto-files”的文件夹。
-
在“proto-files”文件夹中,创建两个子文件夹:
- domain
- service
因此最终项目的程序架构布局将如下所示。
接下来,我们将以下代码粘贴到名为“ repository.proto ”的文件中。此代码定义了用protobuf语法编写的框架消息,该消息将在grpc客户端和服务器之间交换。
syntax = "proto3";
package domain;
option go_package = "bitbucket-repository-management-service/internal/gRPC/domain";
message Repository {
int64 id = 1;
string name = 2;
int64 userId = 3;
bool isPrivate = 4;
}
之后,我们将下面的代码粘贴到名为“ repository-service.proto ”的文件中。该代码定义了grpc服务定义。它定义了grpc服务器将支持的操作以及可能的输入和返回类型。
syntax = "proto3";
package service;
option go_package = "bitbucket-repository-management-service/internal/gRPC/service";
import "bitbucket-repository-management-service/internal/proto-files/domain/repository.proto";
//RepositoryService Definition
service RepositoryService {
rpc add (domain.Repository) returns (AddRepositoryResponse);
}
message AddRepositoryResponse {
domain.Repository addedRepository = 1;
Error error = 2;
}
message Error {
string code = 1;
string message = 2;
}
安装gRPC编译器
如果在我们的系统中未安装gRPC编译器,我们将无法生成存根。
要安装协议编译器,
- 导航到此 链接
- 选择最新版本的标签,请确保选择一个稳定的版本。
- 下载适合您的操作系统的二进制文件。
- 下载后,将其解压缩到操作系统的path变量正在扫描的位置。
安装Go绑定并生成存根
没有Go绑定,我们的存根就没有用了。 Go绑定提供了辅助结构,接口和函数,可用于注册gRPC服务,封送和解封二进制消息等。
为此,我们首先需要将非常简单的Go代码添加到我们的server.go文件中,因为默认情况下,如果项目中没有go代码,则dep(我们的依赖性管理工具)不会下载任何库。
为了满足dep的要求,我们将一些非常基本的go代码放入cmd/gRPC/main.go文件。
package main
import "fmt"
func main() {
fmt.Println("gRPC In Action!")
}
现在,我们都可以为原型缓冲区安装go绑定了。我们将执行以下命令进行安装。
Linux
dep ensure --add google.golang.org/gRPC/github.com/golang/protobuf/protoc-gen-go
Windows
dep.exe ensure -add google.golang.org/gRPC github.com/golang/protobuf/protoc-gen-go
上面的命令会将go绑定下载到“ vendor ”文件夹中。
现在该生成存根了。
如果您在Windows上,请执行此命令。
protoc.exe -I $env:GOPATH\src --go_out=$env:GOPATH\src $env:GOPATH\src\bitbucket-repository-management-service\internal\proto-files\domain\repository.proto protoc.exe -I $env:GOPATH\src --go_out=plugins=gRPC:$env:GOPATH\src $env:GOPATH\src\bitbucket-repository-management-service\internal\proto-files\service\repository-service.proto
如果您在Linux上,请执行此命令。
protoc -I $GOPATH/src --go_out=$GOPATH/src $GOPATH/src/bitbucket-repository-management-service/internal/proto-files/domain/repository.proto protoc -I $GOPATH/src --go_out=plugins=gRPC:$GOPATH/src $GOPATH/src/bitbucket-repository-management-service/internal/proto-files/service/repository-service.proto
上面的命令将在以下标记的子目录中生成存根。
实现 gRPC Service Stub
接下来,编写我们自己的服务实现,
- 我们将在“ internal ”目录中创建一个名为“ impl ”的软件包。
- 我们将创建一个名为RepositoryServiceGrpcImpl的结构,
- 确保我们的结构实现了所有gRPC存根方法。
因此,我们知道我们的gRPC服务有一个称为add的方法。在此过程的早期,我们将其定义写入了原始文件中。
rpc add (domain.Repository) returns (AddRepositoryResponse);
为了实现它的服务契约,我们将首先声明一个负责RepositoryService实现的结构。
package impl
import (
"bitbucket-repository-management-service/internal/gRPC/domain"
"bitbucket-repository-management-service/internal/gRPC/service"
"context"
"log"
)
//RepositoryServiceGrpcImpl is a implementation of RepositoryService Grpc Service.
type RepositoryServiceGrpcImpl struct {
}
//NewRepositoryServiceGrpcImpl returns the pointer to the implementation.
func NewRepositoryServiceGrpcImpl() *RepositoryServiceGrpcImpl {
return &RepositoryServiceGrpcImpl{}
}
//Add function implementation of gRPC Service.
func (serviceImpl *RepositoryServiceGrpcImpl) Add(ctx context.Context, in *domain.Repository) (*service.AddRepositoryResponse, error) {
log.Println("Received request for adding repository with id " + strconv.FormatInt(in.Id, 10))
//Logic to persist to database or storage.
log.Println("Repository persisted to the storage")
return &service.AddRepositoryResponse{
AddedRepository: in,
Error: nil,
}, nil
}
现在是时候编写服务器配置,端口配置和最小的测试客户端了,我们可以执行这些操作来验证整个流程。
让我们先从gRPC服务器开始。
配置 gRPC Server
我们将创建一个RepositoryServiceGrpcImpl的实例。
repositoryServiceImpl:= impl.NewRepositoryServiceGrpcImpl()
我们将创建net.Listener:
func getNetListener(port uint) net.Listener {
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
panic(fmt.Sprintf("failed to listen: %v", err))
}
return lis
}
创建gRPC server:
gRPCServer := gRPC.NewServer()
我们将服务实现注册到gRPC服务器。
service.RegisterRepositoryServiceServer(gRPCServer, repositoryServiceImpl)
我们将绑定net.Listener和gRPC服务器,以使其从指定端口进行通信。
// start the server
if err := gRPCServer.Serve(netListener); err != nil {
log.Fatalf("failed to serve: %s", err)
}
如果我们把所有东西都连接起来,我们将得到以下内容:
package main
import (
"bitbucket-repository-management-service/internal/gRPC/impl"
"bitbucket-repository-management-service/internal/gRPC/service"
"fmt"
"log"
"net"
"google.golang.org/gRPC"
)
func main() {
netListener := getNetListener(7000)
gRPCServer := gRPC.NewServer()
repositoryServiceImpl := impl.NewRepositoryServiceGrpcImpl()
service.RegisterRepositoryServiceServer(gRPCServer, repositoryServiceImpl)
// start the server
if err := gRPCServer.Serve(netListener); err != nil {
log.Fatalf("failed to serve: %s", err)
}
}
func getNetListener(port uint) net.Listener {
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
panic(fmt.Sprintf("failed to listen: %v", err))
}
return lis
}
配置gRPC Client
要配置客户端:
我们将创建与gRPC服务器的连接。
serverAddress := "localhost:7000" conn, e := gRPC.Dial(serverAddress, gRPC.WithInsecure())
我们将把该连接传递给gRPC客户端。
client := service.NewRepositoryServiceClient(conn)
调用gRPC方法:
client.Add(context.Background(), &repositoryModel);
如果我们在这里也连接起来,它将像:
package main
import (
"bitbucket-repository-management-service/internal/gRPC/domain"
"bitbucket-repository-management-service/internal/gRPC/service"
"context"
"fmt"
"google.golang.org/gRPC"
)
func main() {
serverAddress := "localhost:7000"
conn, e := gRPC.Dial(serverAddress, gRPC.WithInsecure())
if e != nil {
panic(e)
}
defer conn.Close()
client := service.NewRepositoryServiceClient(conn)
for i := range [10]int{} {
repositoryModel := domain.Repository{
Id: int64(i),
IsPrivate: true,
Name: string("Grpc-Demo"),
UserId: 1245,
}
if responseMessage, e := client.Add(context.Background(), &repositoryModel); e != nil {
panic(fmt.Sprintf("Was not able to insert Record %v", e))
} else {
fmt.Println("Record Inserted..")
fmt.Println(responseMessage)
fmt.Println("=============================")
}
}
}
测试
要运行gRPC服务器,请从项目的根目录执行以下命令。
go run .\cmd\gRPC\server\main.go
运行客户端:
go run .\cmd\gRPC\client\main.go
您应该在客户端的标准输出流上看到类似的内容。
在服务端应该可以看到如下的内容:
总结
我们创建了一个最小程序,并考虑了gRPC请求响应的最佳实践。一方面,我们的gRPC服务器正在侦听和处理请求,另一方面,客户端正在向服务器发送请求。我们正在使用自定义消息来往/从gRPC服务器/客户端传递消息。
我们上面的实现是同步的。我们尚未解决服务器的异步响应和流式处理。
以上所述就是小编给大家介绍的《gRPC实战--用Golang编写通过gRPC进行通信的服务》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Vue实战-头部模块编写(5)
- 10 个实战及面试常用 Shell 脚本编写
- Netty 实战:如何编写一个麻小俱全的 web 框架
- 如何通过 JavaScript 编写高质量的函数(四):函数式编程之实战篇
- 基于顺丰同城接口编写sdk,java三方sdk编写思路
- 使用 Clojure 编写 OpenWhisk 操作,第 1 部分: 使用 Lisp 方言为 OpenWhisk 编写简明的代码
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Practical Django Projects, Second Edition
James Bennett / Apress / 2009 / 44.99
Build a django content management system, blog, and social networking site with James Bennett as he introduces version 1.1 of the popular Django framework. You’ll work through the development of ea......一起来看看 《Practical Django Projects, Second Edition》 这本书的介绍吧!