• go-micro教程 — 第二章 go-micro v3 使用Gin、Etcd


    前言

    注意:本文使用的Go版本为 go1.17.6 使用 1.18.x 版本或其他版本在操作时总是碰到各种问题,比如依赖下载异常、版本不一致等问题。当然也可能是我电脑的问题。
    参考文档:go 微服务之go-micro v3+gin

    一、启动Etcd集群

    在使用Etcd作为注册中心前需要先有Etcd节点或者Etcd集群,Etcd集群的安装配置及启动,详见:Etcd教程 — 第四章 Etcd集群安全配置

    二、创建项目并安装相关依赖

    注意:2.3到 2.6 步骤执行完同时会在 ${GOPATH}\bin 下生成exe文件。
    在这里插入图片描述

    2.1 创建项目

    本文创建的项目名称为 go-micro-demo

    2.2 初始化项目

    go mod init go-micro-demo
    
    • 1

    2.3 安装 proto

    见:Go — 相关依赖对应的exe 1、protobuf

    2.4 安装 protoc-gen-go

    go get github.com/golang/protobuf/protoc-gen-go
    
    • 1

    2.5 安装 protoc-gen-micro

    注意:是安装 asim下的而不是micro下的,因为micro下的始终下载不了,这个也是go micro 3.0 框架。

    go get github.com/asim/go-micro/cmd/protoc-gen-micro/v3
    
    • 1

    2.6 安装micro v3 构建工具

    1. 需要用到Micro 3.0 的micro工具,主要是用于快速构建micro项目,但是不使用这个的配置,用下面2的
    go install github.com/micro/micro/v3@latest
    
    • 1
    1. 下载go micro 3.0 库,下面库没有上面micro构建工具
    go get github.com/asim/go-micro/v3
    
    • 1

    2.7 安装gin

    go get -u github.com/gin-gonic/gin
    
    • 1

    三、开发项目

    3.1 创建web模块

    go-micro-demo下创建web文件夹

    3.2 进入web文件夹

    创建main.go文件

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"net/http"
    )
    
    const addr = ":9000"
    
    func Index(c *gin.Context) {
    	c.JSON(http.StatusOK, map[string]interface{}{
    		"message": "Gin访问成功",
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.Handle("GET", "/", Index)
    	if err := r.Run(addr); err != nil {
    		fmt.Println("err")
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    然后执行 go run .或者在Goland中执行main函数,启动web服务。
    启动成功后,在浏览器访问 http://127.0.0.1:9000, 得到如下响应:

    // 20220704141435
    // http://127.0.0.1:9000/
    
    {
      "message": "Gin访问成功"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.3 创建services下的子模块

    go-micro-demo\services下执行micro new test命令,创建后端测试服务模块。

    H:\Goland\go-micro-demo\services>micro new test
    Creating service test
    
    .
    ├── micro.mu
    ├── main.go
    ├── generate.go
    ├── handler
    │   └── test.go
    ├── proto
    │   └── test.proto
    ├── Dockerfile
    ├── Makefile
    ├── README.md
    ├── .gitignore
    └── go.mod
    
    
    download protoc zip packages (protoc-$VERSION-$PLATFORM.zip) and install:
    
    visit https://github.com/protocolbuffers/protobuf/releases
    
    compile the proto file test.proto:
    
    cd test
    make init
    go mod vendor
    make proto
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3.4 删除go.mod文件

    删除services\test模块下的go.mod文件,统一使用go-micro-demo下的go.mod

    3.5 根据proto生成pb文件

    3.5.1 修改 test.proto

    主要是修改go_package指定生成pb文件的路经,这里是将 ./改为 ../即可。

    syntax = "proto3";
    
    package test;
    
    //option go_package = "./proto;test";
    //将 ./改为 ../
    option go_package = "../proto;test";
    
    service Test {
    	rpc Call(Request) returns (Response) {}
    	rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
    	rpc PingPong(stream Ping) returns (stream Pong) {}
    }
    
    message Message {
    	string say = 1;
    }
    
    message Request {
    	string name = 1;
    }
    
    message Response {
    	string msg = 1;
    }
    
    message StreamingRequest {
    	int64 count = 1;
    }
    
    message StreamingResponse {
    	int64 count = 1;
    }
    
    message Ping {
    	int64 stroke = 1;
    }
    
    message Pong {
    	int64 stroke = 1;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    3.5.2 生成pb文件

    进入到 go-micro-demo\services\test\proto 。执行生成命令:

    protoc --proto_path=. --micro_out=. --go_out=. *.proto
    
    • 1

    执行完后可以在go-micro-demo\services\test\proto看到生成的test.pb.gotest.pb.micro.go文件。

    3.6 修改handler/test.go文件

    修改 micro-demo\services\test\handler下的 test.go 主要是修改引入的 pb文件位置。

    import (
    	"context"
    
    	log "github.com/micro/micro/v3/service/logger"
    
    	test "go-micro-demo/services/test/proto"//test "test/proto"
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.7 修改services/test/main.go文件

    1. 修改引入的pb文件位置。
    2. 将原来 micro下的包替换成asim下的。
    package main
    
    import (
    	//修改 1
    	"go-micro-demo/services/test/handler"  //"test/handler"
    	pb "go-micro-demo/services/test/proto" //pb "test/proto"
    
    	//修改 2 替换micro为asim
    	service "github.com/asim/go-micro/v3" //"github.com/micro/micro/v3/service"
    	"github.com/asim/go-micro/v3/logger"  //"github.com/micro/micro/v3/service/logger"
    )
    
    func main() {
    	//修改 3
    	srv := service.NewService( // service.New
    		service.Name("test"),
    		service.Version("latest"),
    	)
    
    	// Register handler
    	//修改 4
    	_ = pb.RegisterTestHandler(srv.Server(), new(handler.Test))
    
    	// Run service
    	if err := srv.Run(); err != nil {
    		logger.Fatal(err)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    然后执行 go run .或者在Goland中执行main函数,启动名为test的服务。
    如果启动时报:

    handler\test.go:6:2: no required module provides package github.com/micro/micro/v3/service/logger; to add it:
    	go get github.com/micro/micro/v3/service/logger
    
    • 1
    • 2

    执行go mod tidy后重启。

    启动成功后,控制台显示内容:

    API server listening at: 127.0.0.1:58596
    2022-07-04 14:50:44  file=v3@v3.7.1/service.go:206 level=info Starting [service] test
    2022-07-04 14:50:44  file=server/rpc_server.go:820 level=info Transport [http] Listening on [::]:58603
    2022-07-04 14:50:44  file=server/rpc_server.go:840 level=info Broker [http] Connected to 127.0.0.1:58604
    2022-07-04 14:50:45  file=server/rpc_server.go:654 level=info Registry [mdns] Registering node: test-69072bf3-9123-4177-88cb-9d898a8219e5
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ※3.8 通过web模块直接调用services下的test服务

    3.8.1 创建web/handler/testHandler.go文件

    package handler
    
    import (
    	"github.com/asim/go-micro/v3"
    	"github.com/gin-gonic/gin"
    	testpb "go-micro-demo/services/test/proto"
    	"net/http"
    )
    
    func Index(c *gin.Context) {
    	c.JSON(http.StatusOK, map[string]interface{}{
    		"message": "index",
    	})
    }
    
    func ServiceOne(c *gin.Context) {
    
    	service := micro.NewService()
    
    	service.Init()
    
    	// 创建微服务客户端
    	client := testpb.NewTestService("test", service.Client())
    
    	// 调用服务
    	rsp, err := client.Call(c, &testpb.Request{
    		Name: c.Query("key"),
    	})
    
    	if err != nil {
    		c.JSON(200, gin.H{"code": 500, "msg": err.Error()})
    		return
    	}
    
    	c.JSON(200, gin.H{"code": 200, "msg": rsp.Msg})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    3.8.2 修改web/main.go文件

    package main
    
    import (
    	"fmt"
    	"github.com/gin-gonic/gin"
    	"go-micro-demo/web/handler"
    	"net/http"
    )
    
    const addr = ":9000"
    
    func Index(c *gin.Context) {
    	c.JSON(http.StatusOK, map[string]interface{}{
    		"message": "Gin访问成功",
    	})
    }
    
    func main() {
    	r := gin.Default()
    	r.Handle("GET", "/", Index)
    	r.Handle("GET", "/test-req", handler.ServiceOne)
    	if err := r.Run(addr); err != nil {
    		fmt.Println("err")
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    然后执行 go run .或者在Goland中执行main函数,重新启动web服务。
    启动结果:

    [GIN-debug] GET    /                         --> main.Index (3 handlers)
    [GIN-debug] GET    /test-req                 --> go-micro-demo/web/handler.ServiceOne (3 handlers)
    [GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
    Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
    [GIN-debug] Listening and serving HTTP on :9000
    
    • 1
    • 2
    • 3
    • 4
    • 5

    浏览器访问http://127.0.0.1:9000/test-req?key=哈哈,得到如下响应:

    // 20220704150031
    // http://127.0.0.1:9000/test-req?key=%E5%93%88%E5%93%88
    
    {
      "code": 200,
      "msg": "Hello 哈哈"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    ※四、使用consul作为注册中心注册服务

    注意:使用consul作为注册中心注册服务这块尚未实践,可能会有问题。

    4.1 安装配置consul

    首选需要安装配置consul服务,独立安装,或者使用docker安装均可。

    启动consul后,使用浏览器访问http://192.168.1.224:8500

    4.2 项目加入consul包

    go get -u github.com/asim/go-micro/plugins/registry/consul/v3
    
    • 1

    4.3 修改services/test/main.go

    1. 加入 consul包。
    2. 配置 consul 的地址及注册的名称。
    3. 修改 注册服务的方式为consul方式。

    主要修改或加入的地方 consul 1consul 2consul 3

    package main
    
    import (
    	//修改 1
    	"go-micro-demo/services/test/handler"  //"test/handler"
    	pb "go-micro-demo/services/test/proto" //pb "test/proto"
    
    	//修改 2 替换micro为asim
    	service "github.com/asim/go-micro/v3" //"github.com/micro/micro/v3/service"
    	"github.com/asim/go-micro/v3/logger"  //"github.com/micro/micro/v3/service/logger"
    
    	//consul 1
    	"github.com/asim/go-micro/plugins/registry/consul/v3"
    	"github.com/asim/go-micro/v3/registry"
    )
    
    //consul 2
    const (
    	ServerName = "test"
    	ConsulAddr = "192.168.1.224:8500"
    )
    
    
    func main() {
    	// consul 3
    	consulReg := consul.NewRegistry(
    		registry.Addrs(ConsulAddr),
    	)
    
    	srv := service.NewService(
    		service.Name(ServerName),	// 服务名字
    		service.Registry(consulReg),// 注册中心
    	)
    
    	// Register handler
    	//修改 4
    	_ = pb.RegisterTestHandler(srv.Server(), new(handler.Test))
    
    	// Run service
    	if err := srv.Run(); err != nil {
    		logger.Fatal(err)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    执行go run .,重新启动services/test模块的名为test的服务。

    4.4 修改web/handler/services01Handler.go

    主要修改或加入的地方 consul 1consul 2

    package handler
    
    import (
    	"github.com/asim/go-micro/v3"
    	"github.com/gin-gonic/gin"
    	servicepb "micro-demo/services/proto"
    	"net/http"
    
    	//consul 1
    	"github.com/asim/go-micro/plugins/registry/consul/v3"
    	"github.com/asim/go-micro/v3/registry
    
    )
    
    func Index(c *gin.Context) {
    	c.JSON(http.StatusOK, map[string]interface{}{
    		"message": "index",
    	})
    }
    
    func ServiceOne(c *gin.Context) {
    
    	//consul 2
    	consulReg := consul.NewRegistry(
    		registry.Addrs("192.168.1.224:8500"),
    	)
    
    	service := micro.NewService(
    		micro.Registry(consulReg), //设置注册中心
    	)
    
    	service.Init()
    
    	// 创建微服务客户端
    	client := servicepb.NewServicesService("services01", service.Client())
    
    	// 调用服务
    	rsp, err := client.Call(c, &servicepb.Request{
    		Name: c.Query("key"),
    	})
    
    	if err != nil {
    		c.JSON(200, gin.H{"code": 500, "msg": err.Error()})
    		return
    	}
    
    	c.JSON(200, gin.H{"code": 200, "msg": rsp.Msg})
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    执行go run .,重启web。

    五、使用etcd作为注册中心

    5.1 项目加入etcd包

    go get -u "github.com/asim/go-micro/plugins/registry/etcd/v3"
    
    • 1

    5.2 修改services/main.go

    package main
    
    import (
    	"micro-demo/services/handler"
    	pb "micro-demo/services/proto"
    
    	service "github.com/asim/go-micro/v3"
    	"github.com/asim/go-micro/v3/logger"
    
    	//etcd 1
    	"github.com/asim/go-micro/plugins/registry/etcd/v3"
    	"github.com/asim/go-micro/v3/registry"
    )
    
    //etcd 2
    const (
    	ServerName = "services01"
    	EtcdAddr   = "192.168.1.221:2379"
    )
    
    
    func main() {
    	//etcd 3
    	etcdReg := etcd.NewRegistry(
    		registry.Addrs(EtcdAddr),
    	)
    
    	srv := service.NewService(
    		service.Name(ServerName),  // 服务名字
    		service.Registry(etcdReg), // 注册中心
    	)
    
    	// Register handler
    	_ = pb.RegisterServicesHandler(srv.Server(), new(handler.Services))
    
    	// Run service
    	if err := srv.Run(); err != nil {
    		logger.Fatal(err)
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    5.3 修改web/handler/services01Handler.go

    package handler
    
    import (
    	"github.com/asim/go-micro/v3"
    	"github.com/gin-gonic/gin"
    	servicepb "micro-demo/services/proto"
    	"net/http"
    
    	//etcd 1
    	"github.com/asim/go-micro/plugins/registry/etcd/v3"
    	"github.com/asim/go-micro/v3/registry"
    
    )
    
    func Index(c *gin.Context) {
    	c.JSON(http.StatusOK, map[string]interface{}{
    		"message": "index",
    	})
    }
    
    func ServiceOne(c *gin.Context) {
    
    	// etcd 2
    	etcdReg := etcd.NewRegistry(
    		registry.Addrs("192.168.1.221:2379"),
    	)
    	service := micro.NewService(
    		micro.Registry(etcdReg), //设置注册中心
    	)
    
    	service.Init()
    
    	// 创建微服务客户端
    	client := servicepb.NewServicesService("services01", service.Client())
    
    	// 调用服务
    	rsp, err := client.Call(c, &servicepb.Request{
    		Name: c.Query("key"),
    	})
    
    	if err != nil {
    		c.JSON(200, gin.H{"code": 500, "msg": err.Error()})
    		return
    	}
    
    	c.JSON(200, gin.H{"code": 200, "msg": rsp.Msg})
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    执行go run .,重启web,然后再发送 http://127.0.0.1:8080/service-req?key=哈哈,返回结果:

    // 20220704132910
    // http://127.0.0.1:8080/service-req?key=%E5%93%88%E5%93%88
    
    {
      "code": 200,
      "msg": "Hello 哈哈"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    5.4 查看etcd中的服务注册情况

  • 相关阅读:
    Redis数据结构之quicklist
    软件测试的调用接口怎么调用,逻辑是什么?
    Kubernetes(K8S)的三种探针
    TypeError: __init__() got an unexpected keyword argument ‘pretrained_cfg‘
    连接查询
    ps命令实用例子
    fatal: bad boolean config value ‘“false”‘ for ‘http.sslverify
    企业IT机房中使用什么灭火器?
    RabbitMQ之消息可靠性投递解读
    【java8新特性】:常见的函数式接口
  • 原文地址:https://blog.csdn.net/Mr_XiMu/article/details/125593389