Go 使用Micro编写微服务详解

在本章中,我们将介绍以下配方:

随着组织现在转向 DevOps,微服务也开始流行起来。由于这些服务本质上是独立的,可以用任何语言开发,因此组织可以专注于其开发。了解本章所涵盖的概念后,我们将能够以相当简单的方式使用 Go-Micro 编写微服务。

在本章中,我们将从编写协议缓冲区开始。然后,我们将学习如何启动 Concur,这是一个微服务发现客户端,并最终继续创建微服务,并通过命令行和 web 仪表板与它们交互。

协议缓冲区是一种灵活、高效、自动化的机制,用于编码和序列化 Go 支持的结构化数据。在此配方中,我们将学习如何编写第一个协议缓冲区。

  1. 通过执行以下命令验证protoc是否已安装:
$ protoc --version
 libprotoc 3.3.2
  1. 通过以下方式安装protobuf
$ git clone https://github.com/google/protobuf
$ cd protobuf
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ make install
  1. proto目录中创建hello.proto并定义一个名为Sayservice接口,该接口有RequestResponse两种数据类型,如下所示:
syntax = "proto3";
service Say 
{
  rpc Hello(Request) returns (Response) {}
}
message Request 
{
  string name = 1;
}
message Response 
{
  string msg = 1;
}
  1. 使用以下命令编译hello.proto
$ protoc --go_out=plugins=micro:. hello.proto

命令执行成功后,将在proto目录中创建hello.pb.go,如下图所示:

让我们了解一下我们编写的.proto文件:

  • syntax = "proto3";:这里我们指定我们使用的是proto3语法,这使编译器理解协议缓冲区必须使用版本 3 进行编译。如果我们没有明确指定语法,那么编译器会假定我们使用的是proto2
  • service Say { rpc Hello(Request) returns (Response) {} }:这里我们定义了一个名为Say的 RPC 服务和一个采用Request并返回ResponseHello方法。
  • message Request { string name = 1; }:这里我们定义了Request数据类型,它有一个name字段。
  • message Response { string msg = 1; }:这里我们定义了Response数据类型,它有一个msg字段。

在部署了多个服务的微服务体系结构中,服务发现客户端可以通过 DNS 或 HTTP 帮助应用找出它们所依赖的服务。当我们谈论服务发现客户机时,最常见和最著名的客户机之一是 HashiCorp 的Consul,我们将在本食谱中介绍它。

通过执行以下命令验证Consul是否已安装:

$ consul version
 Consul v0.8.5
 Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

执行以下命令,在服务器模式下启动consul agent

$ consul agent -dev

命令成功执行后,领事代理将开始在服务器模式下运行,并提供以下输出:

我们还可以通过执行以下命令列出领事集群的成员:

$ consul members

这将给我们带来以下结果:

由于至少有一台服务器可以在服务器模式或客户端模式下运行 CONSER,为了使设置保持最低限度,我们已在服务器模式下启动了代理,但不建议这样做,因为在故障情况下可能会丢失数据

此外,浏览到http://localhost:8500/ui/将显示 Consour web UI,我们可以在其中查看所有服务和节点,如下所示:

微服务只是一段代码,它作为一个独特的流程运行,并通过一个定义良好的轻量级机制进行通信,以服务于一个业务目标,我们将使用https://github.com/micro/micro在这个配方中编写它,尽管有许多可用的库,如https://github.com/go-kit/kithttps://github.com/grpc/grpc-go,它们也有相同的用途。

  1. 执行以下命令启动consul agent
$ consul agent -dev
  1. 通过执行以下命令安装并运行micro
$ go get github.com/micro/micro
$ micro api
 2018/02/06 00:03:36 Registering RPC Handler at /rpc
 2018/02/06 00:03:36 Registering API Default Handler at /
 2018/02/06 00:03:36 Listening on [::]:8080
 2018/02/06 00:03:36 Listening on [::]:54814
 2018/02/06 00:03:36 Broker Listening on [::]:54815
 2018/02/06 00:03:36 Registering node: go.micro.api-a6a82a54-0aaf-11e8-8d64-685b35d52676
  1. 通过执行命令$ mkdir services && cd services && touch first-greeting-service.goservices目录中创建first-greeting-service.go
  2. 将以下内容复制到first-greeting-service.go
package main
import 
(
  "log"
  "time"
  hello "../proto"
  "github.com/micro/go-micro"
)
type Say struct{}
func (s *Say) Hello(ctx context.Context, req *hello.Request, 
rsp *hello.Response) error 
{
  log.Print("Received Say.Hello request - first greeting service")
  rsp.Msg = "Hello " + req.Name
  return nil
}
func main() 
{
  service := micro.NewService
  (
    micro.Name("go.micro.service.greeter"),
    micro.RegisterTTL(time.Second*30),
    micro.RegisterInterval(time.Second*10),
  )
  service.Init()
  hello.RegisterSayHandler(service.Server(), new(Say))
  if err := service.Run(); err != nil 
  {
    log.Fatal("error starting service : ", err)
    return
  }
}

一切就绪后,目录结构应如下所示:

  1. 移动到services目录,使用以下命令运行程序:
$ go run first-greeting-service.go

一旦我们运行该程序,RPC 服务器将在端口8080上开始本地侦听

接下来,从命令行执行一个POST请求,如下所示:

$ curl -X POST -H 'Content-Type: application/json' -d '{"service": "go.micro.service.greeter", "method": "Say.Hello", "request": {"name": "Arpit Aggarwal"}}' http://localhost:8080/rpc

这将为我们提供 Hello,后面跟着名称,作为服务器的响应,如以下屏幕截图所示:

查看first-greeting-service.go的日志,我们会发现请求是由第一个问候服务提供的,如下所示:

让我们看看我们编写的程序:

  • 使用import ("log" "time" hello "../proto" "github.com/micro/go-micro" "golang.org/x/net/context"),我们导入了"hello "../proto",一个包含协议缓冲源代码和编译后的协议缓冲后缀.pb.go的目录。此外,我们还导入了github.com/micro/go-micro包,其中包含编写微服务所需的所有库。

  • 接下来,我们定义了一个main()处理程序,在这里我们使用micro.NewService()创建一个名为go.micro.service.greeter的新服务,初始化它,向它注册处理程序,最后启动它。

在此配方中,我们将使用go-micro创建另一个微服务,它是first-greeting-service.go的复制品,除了控制台上打印的记录器消息,该消息演示了具有相同名称的服务的两个不同实例之间客户端负载平衡的概念。

  1. 通过执行命令$ cd services && touch second-greeting-service.goservices目录中创建second-greeting-service.go
  2. 将以下内容复制到second-greeting-service.go
package main
import 
(
  "context"
  "log"
  "time"
  hello "../proto"
  "github.com/micro/go-micro"
)
type Say struct{}
func (s *Say) Hello(ctx context.Context, req *hello.Request, 
rsp *hello.Response) error 
{
  log.Print("Received Say.Hello request - second greeting
  service")
  rsp.Msg = "Hello " + req.Name
  return nil
}
func main() 
{
  service := micro.NewService
  (
    micro.Name("go.micro.service.greeter"),
    micro.RegisterTTL(time.Second*30),
    micro.RegisterInterval(time.Second*10),
  )
  service.Init()
  hello.RegisterSayHandler(service.Server(), new(Say))
  if err := service.Run(); err != nil 
  {
    log.Fatal("error starting service : ", err)
    return
  }
}

一切就绪后,目录结构应如下所示:

  1. 移动到services目录,使用以下命令运行程序:
$ go run second-greeting-service.go

一旦我们运行该程序,RPC 服务器将在端口8080上开始本地侦听

接下来,从命令行执行一个POST请求,如下所示:

$ curl -X POST -H 'Content-Type: application/json' -d '{"service": "go.micro.service.greeter", "method": "Say.Hello", "request": {"name": "Arpit Aggarwal"}}' http://localhost:8080/rpc

这将为我们提供 Hello,后面跟着名称,作为服务器的响应,如下所示:

查看second-greeting-service.go的日志,我们会发现请求是由第二个问候服务提供的:

现在,如果我们再次执行一个POST请求,那么它将在first-greeting-service.go控制台中打印日志,这是因为 Go Micro 提供的基于发现的智能客户端负载平衡服务:

到目前为止,我们已经通过名称和访问方法显式地调用了后端服务。在本食谱中,我们将学习如何使用 Go Micro API 访问服务,Go Micro API 实现 API 网关模式,为微服务提供单一入口点。使用 Go Micro API 的优点是,它通过 HTTP 提供服务,并使用 HTTP 处理程序动态路由到适当的后端服务。

通过执行以下命令,在单独的终端中启动consul agentmicro APIfirst-greeting-service.gosecond-greeting-service.go

$ consul agent -dev
$ micro api
$ go run first-greeting-service.go
$ go run second-greeting-service.go
  1. 通过执行命令$ mkdir api && cd api && touch greeting-api.goapi目录中创建greeting-api.go
  2. 将以下内容复制到greeting-api.go
package main
import 
(
  "context"
  "encoding/json"
  "log"
  "strings"
  hello "../proto"
  "github.com/micro/go-micro"
  api "github.com/micro/micro/api/proto"
)
type Say struct 
{
  Client hello.SayClient
}
func (s *Say) Hello(ctx context.Context, req *api.Request, 
rsp *api.Response) error 
{
  log.Print("Received Say.Hello request - Micro Greeter API")
  name, ok := req.Get["name"]
  if ok 
  {
    response, err := s.Client.Hello
    (
      ctx, &hello.Request
      {
        Name: strings.Join(name.Values, " "),
      }
    )
    if err != nil 
    {
      return err
    }
    message, _ := json.Marshal
    (
      map[string]string
      {
        "message": response.Msg,
      }
    )
    rsp.Body = string(message)
  }
  return nil
}
func main() 
{
  service := micro.NewService
  (
    micro.Name("go.micro.api.greeter"),
  )
  service.Init()
  service.Server().Handle
  (
    service.Server().NewHandler
    (
      &Say{Client: hello.NewSayClient("go.micro.service.
      greeter", service.Client())},
    ),
  )
  if err := service.Run(); err != nil 
  {
    log.Fatal("error starting micro api : ", err)
    return
  }
}

一切就绪后,目录结构应如下所示:

  1. 移动到api 目录,使用以下命令运行程序:
$ go run greeting-api.go

一旦我们运行程序,HTTP 服务器将在端口8080上开始本地侦听

接下来,浏览http://localhost:8080/greeter/say/hello?name=Arpit+Aggarwal如下:

这将为您提供响应 Hello,后跟作为 HTTP 请求变量接收的名称。此外,查看second-greeting-service.go的日志,我们会发现请求是由第二个问候服务提供的,如下所示:

现在,如果我们再次执行一个GET请求,那么它将在first-greeting-service.go控制台中打印日志,这是因为 Go Micro 提供的基于发现的智能客户端负载平衡服务:

到目前为止,我们已经使用命令行执行GETPOSTHTTP 请求来访问服务。这也可以通过 Go Micro web 用户界面实现。我们需要做的就是开始micro web,我们将在本食谱中介绍。

  1. 使用go get命令安装go get github.com/micro/micro包,如下所示:
$ go get github.com/micro/micro
  1. 使用以下命令运行 web UI:
$ micro web

命令执行成功后,浏览http://localhost:8082/registry将列出所有已注册的服务,如下图所示:

使用带有请求{"name" : "Arpit Aggarwal"}的 web UI 查询我们的greeter服务将向您提供响应{"msg": "Hello Arpit Aggarwal"} 

使用CLI命令query go.micro.service.greeter Say.Hello {"name" : "Arpit Aggarwal"}查询同一greeter服务时,您会得到响应{"msg": "Hello Arpit Aggarwal"}

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

从0开始做增长 -〔刘津〕

深入浅出云计算 -〔何恺铎〕

手机摄影 -〔@随你们去〕

恋爱必修课 -〔李一帆〕

跟着高手学复盘 -〔张鹏〕

高楼的性能工程实战课 -〔高楼〕

现代React Web开发实战 -〔宋一玮〕

大型Android系统重构实战 -〔黄俊彬〕

LangChain 实战课 -〔黄佳〕