「go-micro」学习笔记——Micro

Micro 概述

Micro is a platform for cloud native development.

Micro是一个微服务工具包,包括:

API

提供并将HTTP请求路由到相应微服务的API网关。它充当微服务访问的单一入口,将HTTP请求转换为RPC并转发给相应的服务也可以用作反向代理。

image

Web

UI是go-micro的web版本,允许通过UI交互访问环境。在未来,它也将是一种聚合微型Web服务的方式。它包含一种Web应用程序的代理方式。将/[name]通过注册表路由到相应的服务。Web UI将前缀“go.micro.web。”(可以配置)添加到名称中,在注册表中查找它,然后将进行反向代理。

image

Sidecar

go-micro的HTTP接口版本。这是将非Go应用程序集成到微环境中的一种方式。
image

Bot

Hubot风格的bot,位于您的微服务平台中,可以通过Slack,HipChat,XMPP等进行交互。它通过消息传递提供CLI的功能。可以添加其他命令来自动执行常见的操作任务。
image

CLI

一个直接的命令行界面来与你的微服务进行交互,它提供了一种观察和与运行环境交互的方式。

Go-Micro

用于在Go中编写微服务的插件式RPC框架。它提供了用于服务发现,客户端负载平衡,编码,同步和异步通信库。go-micro 是一个独立的库,可以独立于其他工具包使用。

image
go-micro是组件化的框架,每一个基础功能都是一个interface,方便扩展。同时,组件又是分层的,上层基于下层功能向上提供服务,整体构成go-micro框架。go-micro框架的构成组件有:

Registry

提供服务发现机制:解析服务名字至服务地址。目前支持的注册中心有consul、etcd、 zookeeper、dns、gossip等

Selector

选择器通过选择提供负载均衡机制。当客户端向服务器发出请求时,它将首先查询服务的注册表。这通常会返回一个表示服务的正在运行的节点列表。选择器将选择这些节点中的一个用于查询。多次调用选择器将允许使用平衡算法。目前的方法是循环法,随机哈希和黑名单。

Broker

发布和订阅的可插入接口,服务之间基于消息中间件的异步通信方式,默认使用http方式,线上通常使用消息中间件,如Nats、Kafka、RabbitMQ 和 http(用于开发)。

Transport

通过点对点传输消息的可插拔接口。目前的实现是http,rabbitmq和nats。通过提供这种抽象,运输可以无缝地换出。。

Codec

服务之间消息的编码/解码。

Plugins

提供go-micro的micro/go-plugins插件。

Server

服务器是构建正在运行的微服务的接口。它提供了一种提供RPC请求的方法。该组件基于上面的Registry/Selector/Transport/Broker组件,对外提供一个统一的服务请求入口。

Client

提供一种制作RPC查询的方法访问微服务的客户端。它结合了注册表,选择器,代理和传输。它还提供重试,超时,使用上下文等。类似Server组件,它也是通过Registry/Selector/Transport/Broker组件实现查找服务、负载均衡、同步通信、异步消息等功能。


安装与应用

安装

Micro

# go get
$ go get github.com/micro/micro

# docker install
$ docker pull microhq/micro

Go-Micro

Go Micro是Go开发微服务的RPC框架

$ go get github.com/micro/go-micro

protobuf

如果使用代码生成,您还需要使用protoc-gen-go

$ go get github.com/micro/protobuf/{
    
    proto,protoc-gen-go}

gRPC 网关

protobuf

mkdir tmp
cd tmp
git clone https://github.com/google/protobuf
cd protobuf
./autogen.sh
./configure
make
make check
sudo make install

安装插件

go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway
go get -u github.com/micro/protobuf/protoc-gen-go

测试服务

# 运行 greeter 服务,需要 consul 依赖
$ go get github.com/micro/examples/greeter/srv && srv

# 服务清单
$ micro list services
consul
go.micro.srv.greeter

# 获取服务
$ micro get service go.micro.srv.greeter

service  go.micro.srv.greeter

version 1.0.0

Id	Address	Port	Metadata
go.micro.srv.greeter-34c55534-368b-11e6-b732-68a86d0d36b6	192.168.1.66	62525	server=rpc,registry=consul,transport=http,broker=http

Endpoint: Say.Hello
Metadata: stream=false

Request: {
    
    
	name string
}

Response: {
    
    
	msg string
}

# 查询服务
$ micro query go.micro.srv.greeter Say.Hello '{"name": "John"}'
{
    
    
	"msg": "Hello John"
}

Micro CLI 应用

创建服务

# 新建一个 helloworld 的服务
$ micro new helloworld

启动、运行服务

# 在本地运行该服务并确保其正常工作.
# 启动服务器
micro server

# 设置为本地环境
micro env set local

# 启动你的服务
micro run name

服务状态

# 检查状态
micro status

# 检查是否已注册
micro services

# 检查日志
micro logs helloworld

结束服务

micro kill helloworld

部署服务

# 将代码上传到 Github 才能完成部署

# 初始化 git
cd helloworld && git init && git add . && git commit -m "My helloworld service"

# 在 github 创建一个新的仓库并推送上去
# assuming you created it, add the remote origin
git remote add origin https://github.com/$user/helloworld.git

# 推送
git push origin master

# 设置环境为平台模式
micro env set platform

# 确保已经登陆到平台
micro login

# 现在可以运行了
micro run github.com/$user/helloworld

调用服务

检查服务在运行并调用该服务。另外因为是从源码构建的,可能需要几分钟才能启动 (后续我们会优化这个情况)

# 检查服务状态
micro status

# 检查服务注册情况
micro services

# 调用指定的服务
micro helloworld --name=Alice

注意调用服务的符号. Micro 支持动态的 CLI 命令,这意味着你的命名空间下的任何东西都将成为一个子命令.

micro [service] [endpoint] [args]

在终结点被提交的地方, 我们假设它是服务名称 + “呼叫” 方法, 例如 helloworld 成为 Helloworld. call 。如果这是一个问候方法,我们将假设 Helloworld. 问候与 c 在 c.micro helloworld greet

我们假设有一个服务名称 + “Call” 的方法是一个终结点。例如 helloworld 会是 Helloworld.Call. 如果是 Greet 方法我们会假设 Helloworld.Greet 对应的命令为 micro helloworld greet.

参数可以作为标志传递 --name 表示的就是 Name 字段参数.

如果你想要一个使用纯 json 和原始方法的更简单方式

micro call helloworld Helloworld.Call '{"name": "Alice"}'

Go-micro 框架应用

Greeter 服务

使用go-grpc创建了一个Greeter的微服务。

  • 原型如下:
syntax = "proto3";

package go.micro.srv.greeter;

service Say {
    
    
	rpc Hello(Request) returns (Response) {
    
    }
}

message Request {
    
    
	string name = 1;
}

message Response {
    
    
	string msg = 1;
}
  • 服务如下:
package main

import (
	"log"
	"time"

	hello "github.com/micro/examples/greeter/srv/proto/hello"
	"github.com/micro/go-grpc"
	"github.com/micro/go-micro"

	"golang.org/x/net/context"
)

type Say struct{
    
    }

func (s *Say) Hello(ctx context.Context, req *hello.Request, rsp *hello.Response) error {
    
    
	log.Print("Received Say.Hello request")
	rsp.Msg = "Hello " + req.Name
	return nil
}

func main() {
    
    
	service := grpc.NewService(
		micro.Name("go.micro.srv.greeter"),
		micro.RegisterTTL(time.Second*30),
		micro.RegisterInterval(time.Second*10),
	)

	// optionally setup command line usage
	service.Init()

	// Register Handlers
	hello.RegisterSayHandler(service.Server(), new(Say))

	// Run server
	if err := service.Run(); err != nil {
    
    
		log.Fatal(err)
	}
}

GRPC 网关

grpc网关使用与服务相同的协议,并增加一个http选项

syntax = "proto3";

package greeter;

import "google/api/annotations.proto";

service Say {
    
    
	rpc Hello(Request) returns (Response) {
    
    
		option (google.api.http) = {
    
    
			post: "/greeter/hello"
			body: "*"
		};
	}
}

message Request {
    
    
	string name = 1;
}

message Response {
    
    
	string msg = 1;
}

proto使用以下命令生成grpc stub和反向代理

protoc -I/usr/local/include -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --go_out=plugins=grpc:. \
  path/to/your_service.proto
protoc -I/usr/local/include -I. \
  -I$GOPATH/src \
  -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis \
  --grpc-gateway_out=logtostderr=true:. \
  path/to/your_service.proto

我们使用下面的代码创建了greeter服务的示例api。将写入类似的代码来注册其他端点。请注意,网关需要greeter服务的端口地址。

package main

import (
	"flag"
	"net/http"

	"github.com/golang/glog"
	"github.com/grpc-ecosystem/grpc-gateway/runtime"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	hello "github.com/micro/examples/grpc/gateway/proto/hello"
)

var (
	// the go.micro.srv.greeter address
	endpoint = flag.String("endpoint", "localhost:9090", "go.micro.srv.greeter address")
)

func run() error {
    
    
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	mux := runtime.NewServeMux()
	opts := []grpc.DialOption{
    
    grpc.WithInsecure()}

	err := hello.RegisterSayHandlerFromEndpoint(ctx, mux, *endpoint, opts)
	if err != nil {
    
    
		return err
	}

	return http.ListenAndServe(":8080", mux)
}

func main() {
    
    
	flag.Parse()

	defer glog.Flush()

	if err := run(); err != nil {
    
    
		glog.Fatal(err)
	}
}

运行示例

运行greeter服务。指定mdns,因为我们不需要发现。

go run examples/grpc/greeter/srv/main.go --registry=mdns --server_address=localhost:9090

运行网关。它将默认为端点localhost:9090的greeter服务。

go run examples/grpc/gateway/main.go

使用curl在(localhost:8080)网关上发起请求。

curl -d '{"name": "john"}' http://localhost:8080/greeter/hello

执行 proto 命令,生成当前pb文件的go实现:

protoc --go_out=plugins=micro:. ./proto/hello.proto

protoc  --go_out=. --micro_out=. ./proto/hello.proto

写一个 go 服务

  • 定义 API
    我们使用protobuf文件来定义服务API接口。这是一种非常方便的方式来严格定义API并为服务器和客户端提供具体的类型。

    // this is greeter.proto
    syntax = "proto3";
    
    service Greeter {
          
          
    	rpc Hello(HelloRequest) returns (HelloResponse) {
          
          }
    }
    
    message HelloRequest {
          
          
    	string name = 1;
    }
    
    message HelloResponse {
          
          
    	string greeting = 2;
    }
    

    在这里,我们定义了一个名为Greeter的服务处理程序,其中的方法Hello使用参数HelloRequest类型并返回HelloResponse。

  • 生成API接口
    使用protoc和protoc-gen-go为这个定义生成具体的go实现。

    protoc --go_out=plugins=micro:. greeter.proto
    
  • 写一个服务

    package main
    
    import (
            "log"
    
            "github.com/micro/go-micro"
            proto "github.com/micro/examples/service/proto"
    
            "golang.org/x/net/context"
    )
    
    type Greeter struct{
          
          }
    
    func (g *Greeter) Hello(ctx context.Context, req *proto.HelloRequest, rsp *proto.HelloResponse) error {
          
          
            rsp.Greeting = "Hello " + req.Name
            return nil
    }
    
    func main() {
          
          
            service := micro.NewService(
                    micro.Name("greeter"),
                    micro.Version("latest"),
            )
    
            service.Init()
    
            proto.RegisterGreeterHandler(service.Server(), new(Greeter))
    
            if err := service.Run(); err != nil {
          
          
                    log.Fatal(err)
            }
    }
    
  • 写一个客户端

    // create the greeter client using the service name and client
    greeter := proto.NewGreeterClient("greeter", service.Client())
    
    // request the Hello method on the Greeter handler
    rsp, err := greeter.Hello(context.TODO(), &proto.HelloRequest{
          
          
    	Name: "John",
    })
    if err != nil {
          
          
    	fmt.Println(err)
    	return
    }
    
    fmt.Println(rsp.Greeter)
    

服务间通讯

两个微服务之间的通信是基于C/S模型,即服务发请求方充当Client,服务接收方充当Server。
image

猜你喜欢

转载自blog.csdn.net/zd398900463/article/details/109208026