Micro
- Micro 概述
-
- API
- Web
- Sidecar
- Bot
- CLI
- Go-Micro
-
- Registry
- Selector
- Broker
- Transport
- Codec
- Plugins
- Server
- Client
- 安装与应用
-
- 安装
-
- Micro
- Go-Micro
- protobuf
- gRPC 网关
-
- protobuf
- 安装插件
- 测试服务
- Micro CLI 应用
-
- 创建服务
- 启动、运行服务
- 服务状态
- 结束服务
- 部署服务
- 调用服务
- Go-micro 框架应用
-
- Greeter 服务
- GRPC 网关
- 运行示例
- 写一个 go 服务
- 服务间通讯
Micro 概述
Micro is a platform for cloud native development.
Micro是一个微服务工具包,包括:
API
提供并将HTTP请求路由到相应微服务的API网关。它充当微服务访问的单一入口,将HTTP请求转换为RPC并转发给相应的服务也可以用作反向代理。
Web
UI是go-micro的web版本,允许通过UI交互访问环境。在未来,它也将是一种聚合微型Web服务的方式。它包含一种Web应用程序的代理方式。将/[name]通过注册表路由到相应的服务。Web UI将前缀“go.micro.web。”(可以配置)添加到名称中,在注册表中查找它,然后将进行反向代理。
Sidecar
go-micro的HTTP接口版本。这是将非Go应用程序集成到微环境中的一种方式。
Bot
Hubot风格的bot,位于您的微服务平台中,可以通过Slack,HipChat,XMPP等进行交互。它通过消息传递提供CLI的功能。可以添加其他命令来自动执行常见的操作任务。
CLI
一个直接的命令行界面来与你的微服务进行交互,它提供了一种观察和与运行环境交互的方式。
Go-Micro
用于在Go中编写微服务的插件式RPC框架。它提供了用于服务发现,客户端负载平衡,编码,同步和异步通信库。go-micro 是一个独立的库,可以独立于其他工具包使用。
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。