内容简介:微服务想必大家都不陌生了。刚接触到示例代码通过目录可以看到这里使用了
微服务想必大家都不陌生了。刚接触到 golang ,那么在 golang 中怎么使用微服务呢。这里使用 gRRC 框架写了一个简单的例子。
环境要求
- go>=1.13; set GO111MODULE=on
- 安装 protoc
- 安装 Protoc plugin-go
示例代码 iris-grpc-example
项目结构
iris-grpc-example
│ .gitignore
│ go.mod
│ go.sum
│ README.md
│
├─proto
│ README.md
│ servers.pb.go
│ servers.proto
│
└─servers
main.go
services.go
通过目录可以看到这里使用了 go mod ,当前 golang 版本 1.13 。
proto
使用 Protobuf 定义了通信的IDL,可以理解为 rpc 中接口定义。
-
protocol buf
可扩展的序列化数据结构,在通信协议中使用的比较广泛。比 json 更快,更小。比 xml 更简洁。
servers.proto
syntax = "proto3";
package proto;
message Id {
int32 id=1;
}
message Name {
string name=1;
}
message Age {
int32 age=1;
}
// 用户变量
message User {
int32 id=1;
string name=2;
int32 age=3;
}
// 用户参数
message UserParams{
Name name=1;
Age age=2;
}
// 声明那些方法可以使用rpc
service ServiceSearch{
rpc SaveUser(UserParams) returns (Id){}
rpc UserInfo(Id) returns (User){}
}
简单说明
syntax = "proto3"; 声明了 proto 语法版本。
package 声明包名
message Id {
int32 id=1;
}
接口中使用的变量声明 变量名称: Id ,类型: int32 ,等号后面表示字段编号为 1
service ServiceSearch{
rpc SaveUser(UserParams) returns (Id){}
rpc UserInfo(Id) returns (User){}
}
声明了两个函数 SaveUser(),UserInfo() 是使用 RPC 协议,接收的参数与返回参数分别为什么。
servers.go
该文件是使用 servers.proto 编译生成的
。在完成 servers.proto 之后 在 proto 目录下执行
protoc --go_out=plugins=grpc:. *.proto
Protoc plugin-go grpc
编译命令执行完之后,就会生成 servers.go 。而我们在 go 的模块中实际使用的代码也就是这个文件。
如果有兴趣的同学可以看看里面的代码,主要就是一些参数定义【 我们在proto中所定义的 】,还有一个接口的声明。
......
// ServiceSearchServer is the server API for ServiceSearch service.
type ServiceSearchServer interface {
SaveUser(context.Context, *UserParams) (*Id, error)
UserInfo(context.Context, *Id) (*User, error)
}
// UnimplementedServiceSearchServer can be embedded to have forward compatible implementations.
type UnimplementedServiceSearchServer struct {
}
func (*UnimplementedServiceSearchServer) SaveUser(ctx context.Context, req *UserParams) (*Id, error) {
return nil, status.Errorf(codes.Unimplemented, "method SaveUser not implemented")
}
func (*UnimplementedServiceSearchServer) UserInfo(ctx context.Context, req *Id) (*User, error) {
return nil, status.Errorf(codes.Unimplemented, "method UserInfo not implemented")
}
func RegisterServiceSearchServer(s *grpc.Server, srv ServiceSearchServer) {
s.RegisterService(&_ServiceSearch_serviceDesc, srv)
}
......
可以看到最后有一个 RegisterServiceSearchServer 注册服务的方法,接受一个 grpc.Server 与一个 ServiceSearchServer 的接口。而我们在 servers/services.go 中,主要就是实现 ServiceSearchServer 这个接口,并通过 RegisterServiceSearchServer 将接口实现的函数注册 rpc 服务中。
servers
rpc 接口的实现与调用
services.go 接口的实现
package main
import (
"context"
"fmt"
"google.golang.org/grpc"
"iris-grpc-example/proto"
"log"
"math/rand"
"net"
)
type ServiceSearch struct{}
func main() {
listen, err := net.Listen("tcp", "127.0.0.1:9527")
if err != nil {
log.Fatalf("tcp listen failed:%v", err)
}
server := grpc.NewServer()
fmt.Println("services start success")
proto.RegisterServiceSearchServer(server, &ServiceSearch{})
server.Serve(listen)
}
//保存用户
func (Service *ServiceSearch) SaveUser(ctx context.Context, params *proto.UserParams) (*proto.Id, error) {
id := rand.Int31n(10) //随机生成id 模式保存成功
res := &proto.Id{Id: id}
fmt.Printf("username:%s,age:%d\r\n", params.Name, params.Age)
return res, nil
}
func (Service *ServiceSearch) UserInfo(ctx context.Context, id *proto.Id) (*proto.User, error) {
res := &proto.User{Id:id.GetId(),Name:"test",Age:31}
return res, nil
}
- 实现
ServiceSearchServer接口,在代码中声明了一个ServiceSearch来实现了ServiceSearchServer接口。 -
SaveUser,实现了proto中定义的SaveUser方法,需要注意的是这里需要返回两个参,数第一个是我们预先定好的参数,第二个为定义的错误信息。 -
main函数声明当前服务的ip以及端口,并创建了一个grpc server然后通过proto.RegisterServiceSearchServer(server, &ServiceSearch{})将ServiceSearch注册到grpc中
main.go 接口的调用
package main
import (
"context"
"github.com/kataras/iris/v12"
"google.golang.org/grpc"
"iris-grpc-example/proto"
"log"
)
var client proto.ServiceSearchClient
func main() {
app := iris.New()
app.Logger().SetLevel("debug") //debug
app.Handle("GET", "/testSaveUser", saveUser)
app.Handle("GET", "/testUserInfo", userInfo)
app.Run(iris.Addr("127.0.0.1:8080"))
}
func saveUser(ctx iris.Context) {
params := proto.UserParams{}
params.Age = &proto.Age{Age: 31}
params.Name = &proto.Name{Name: "test"}
res, err := client.SaveUser(context.Background(), ¶ms)
if err != nil {
log.Fatalf("client.SaveUser err: %v", err)
}
ctx.JSON(res)
}
func userInfo(ctx iris.Context) {
res, err := client.UserInfo(context.Background(), &proto.Id{Id: 1})
if err != nil {
log.Fatalf("client.userInfo err: %v", err)
}
ctx.JSON(res)
}
func init() {
connect, err := grpc.Dial("127.0.0.1:9527", grpc.WithInsecure())
if err != nil {
log.Fatalln(err)
}
client = proto.NewServiceSearchClient(connect)
}
这里使用了 iris 作为了一个 client 。与传统 http 的区别主要是在
func init() {
connect, err := grpc.Dial("127.0.0.1:9527", grpc.WithInsecure())
if err != nil {
log.Fatalln(err)
}
client = proto.NewServiceSearchClient(connect)
}
这里创建了一个 rpc 的 client 。在使用的时候我们只需要调用 services 里面已经写好的函数即可。
测试
\iris-grpc-example>cd servers
开启服务: go run services.go
开启Client: go run main.go
浏览器访问
http://127.0.0.1:8080/testSaveUser
{
"id": 1
}
http://127.0.0.1:8080/testUserInfo
{
"id": 1,
"name": "test",
"age": 31
}
期待一起交流
以上所述就是小编给大家介绍的《go-gRPC 初体验》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Mastering Regular Expressions, Second Edition
Jeffrey E F Friedl / O'Reilly Media / 2002-07-15 / USD 39.95
Regular expressions are an extremely powerful tool for manipulating text and data. They have spread like wildfire in recent years, now offered as standard features in Perl, Java, VB.NET and C# (and an......一起来看看 《Mastering Regular Expressions, Second Edition》 这本书的介绍吧!