使用gRPC构建一个简易的商品服务注册到etcd中

创建models/protos目录,新建商品模型

 1syntax = "proto3";
 2package models;
 3
 4// 商品模型
 5message ProdModel{
 6    // @inject_tag: json:"pid"
 7    int32 ProdId = 1;
 8    // @inject_tag: json:"pname"
 9    string ProdName = 2;
10}

使用protoc创建服务

 1syntax = "proto3";
 2package models;
 3
 4import "models.proto";
 5
 6message ProdRequest{
 7    int32 size = 1;
 8}
 9
10message ProdListResponse{
11    repeated ProdModel data = 1;
12}
13
14service ProdService{
15    rpc GetProdList(ProdRequest) returns (ProdListResponse);
16}

使用protoc生成go文件

1cd models/protos
2protoc --go_out=../ models.proto
3protoc --micro_out=../ --go_out=../ prodService.proto
4protoc-go-inject-tag --input=../models.pb.go

新建一个包用于实现ProdService服务

 1package prods
 2
 3import (
 4	"context"
 5	"grpc_server/models"
 6	"strconv"
 7)
 8
 9// 服务实现
10type ProdService struct {}
11
12func newProd(id int32, pname string) *models.ProdModel{
13	return &models.ProdModel{ProdId:id, ProdName:pname}
14}
15
16// 获取商品列表
17func (*ProdService) GetProdList(ctx context.Context,in *models.ProdRequest,res *models.ProdListResponse) error{
18	models := make([]*models.ProdModel,0)
19	var i int32
20	for i=0;i<in.Size;i++{
21		models = append(models, newProd(100 +i, "prodName"+ strconv.Itoa(100+int(i))))
22	}
23	res.Data = models
24	return nil
25}

main.go主函数

 1package main
 2
 3import (
 4	"github.com/micro/go-micro/v2"
 5	"github.com/micro/go-micro/v2/registry"
 6	"github.com/micro/go-micro/v2/registry/etcd"
 7	"grpc_server/models"
 8	"grpc_server/prods"
 9)
10
11func main(){
12
13	etcdReg := etcd.NewRegistry(
14		registry.Addrs("127.0.0.1:2379"),
15		)
16
17	app := micro.NewService(
18		micro.Name("api.hzde.com.testService"),
19		micro.Address("127.0.0.1:8000"),
20		micro.Registry(etcdReg),
21	)
22
23	app.Init()
24	err := models.RegisterProdServiceHandler(app.Server(), new(prods.ProdService))
25	if err != nil{
26		panic(err)
27	}
28	app.Run()
29}

目录结构如下

 1.
 2├── gen.sh
 3├── go.mod
 4├── go.sum
 5├── main.go
 6├── models
 7│   ├── models.pb.go
 8│   ├── prodService.pb.go
 9│   ├── prodService.pb.micro.go
10│   └── protos
11│       ├── models.proto
12│       └── prodService.proto
13└── prods
14    └── prodService.go

运行服务

1go build
2./grpc_server
32020-03-22 11:48:08  level=info Starting [service] api.hzde.com.testService
42020-03-22 11:48:08  level=info Server [grpc] Listening on 127.0.0.1:8000
52020-03-22 11:48:08  level=info Registry [etcd] Registering node: api.hzde.com.testService-69016977-0ea5-4ebd-905d-385400398cb2

看到服务已经注册到etcd中了

etcd查看

1etcdctl get /micro --keys-only --prefix
2/micro/registry/api.hzde.com.testService/api.hzde.com.testService-69016977-0ea5-4ebd-905d-385400398cb2

使用micro工具箱访问gRPC服务

grpc服务已经创建好了,可以创建http服务去调用gRPC服务,如果只是想要验证一下服务,可以直接使用micro工具箱。

1export MICRO_REGISTRY=etcd
2export MICRO_REGISTRY_ADDRESS=127.0.0.1:2379
3micro get service api.hzde.com.testService

输出结果

 1service  api.hzde.com.testService
 2
 3version latest
 4
 5ID	Address	Metadata
 6api.hzde.com.testService-69016977-0ea5-4ebd-905d-385400398cb2	127.0.0.1:8000	protocol=grpc,registry=etcd,server=grpc,transport=grpc,broker=eats
 7
 8Endpoint: ProdService.GetProdList
 9
10Request: {
11	size int32
12}
13
14Response: {
15	data []ProdModel
16}

访问服务

1micro call api.hzde.com.testService ProdService.GetProdList '{"size": 3}'

输出结果

 1{
 2	"data": [
 3		{
 4			"ProdId": 100,
 5			"ProdName": "prodName100"
 6		},
 7		{
 8			"ProdId": 101,
 9			"ProdName": "prodName101"
10		},
11		{
12			"ProdId": 102,
13			"ProdName": "prodName102"
14		}
15	]
16}

使用micro api创建网关给http访问

1export MICRO_REGISTRY=etcd
2export MICRO_REGISTRY_ADDRESS=127.0.0.1:2379
3export MICRO_API_HANDLER=rpc
4export MICRO_API_NAMESPACE=api.hzde.com
5micro api

程序默认监听在8080端口。

使用curl发送POST请求

1curl -X POST "http://localhost:8080/testService/ProdService/GetProdList" -d '{"size": 5}'

输出结果

1{"data":[{"ProdId":100,"ProdName":"prodName100"},{"ProdId":101,"ProdName":"prodName101"},{"ProdId":102,"ProdName":"prodName102"},{"ProdId":103,"ProdName":"prodName103"},{"ProdId":104,"ProdName":"prodName104"}]}

创建http服务调用gRPC供外部访问

将前面的protos文件拿过来,放到models下,然后重新生成go文件,具体操作略。http通过连接grpc

main.go

 1package main
 2
 3import (
 4	"context"
 5	"github.com/gin-gonic/gin"
 6	"github.com/micro/go-micro/v2"
 7	"github.com/micro/go-micro/v2/registry"
 8	"github.com/micro/go-micro/v2/registry/etcd"
 9	"github.com/micro/go-micro/v2/web"
10	"go-micro/models"
11)
12
13func main() {
14	r := gin.Default()
15	etcdReg := etcd.NewRegistry(
16		registry.Addrs("127.0.0.1:2379"),
17	)
18
19	service := web.NewService(
20		web.Name("testService.client"),
21		web.Address("127.0.0.1:9000"),
22		web.Handler(r),
23		web.Registry(etcdReg),
24	)
25
26	myService := micro.NewService(micro.Name("tetsService.client"))
27	prodService := models.NewProdService("api.hzde.com.testService", myService.Client())
28	v1Group := r.Group("/v1")
29	{
30		v1Group.Handle("POST", "/prods", func(c *gin.Context) {
31			var prodReq models.ProdRequest
32			err := c.Bind(&prodReq)
33			if err != nil {
34				c.JSON(500, gin.H{
35					"status": err.Error()})
36			} else {
37				prodRes, _ := prodService.GetProdList(context.Background(), &prodReq)
38				c.JSON(200, gin.H{
39					"data": prodRes.Data,
40				})
41			}
42		})
43	}
44
45	service.Init()
46	service.Run()
47}

运行服务,使用curl进行测试

1curl -X POST --form Size=4 http://127.0.0.1:9000/v1/prods

输出结果

1{"data":[{"pid":100,"pname":"prodName100"},{"pid":101,"pname":"prodName101"},{"pid":102,"pname":"prodName102"},{"pid":103,"pname":"prodName103"}]}

或者使用json请求

1curl -X POST -H "Content-Type:application/json" http://127.0.0.1:9000/v1/prods -d '{"size": 4}'

输出结果跟上面一样。