go-micro教程

1.micro介绍
{


1.micro简介
Micro由开源的库与工具组成,旨在辅助微服务开发。
go-micro - 基于Go语言的可插拔RPC微服务开发框架;包含服务发现、RPC客户/服务端、广播/订阅机制等等。
go-plugins - go-micro的插件有etcd、kubernetes、nats、rabbitmq、grpc等等。
micro - 微服务工具集包含传统的入口点(entry point);API 网关、CLI、Slack Bot、代理及Web UI。

Micro
Micro包括了工具集用于查询和访问微服务。
	API Gateway,API网关是独立的http入口。
	Web Dashboard,用于可视化管理微服务。
	CLI,命令行接口。
	Bot,面向Slack或HipChat访问微服务的工具。
	New,用于快整生成服务模板,快速开发。

Go Micro
Go Micro可以帮你编写微服务。
	Go Micro抽象出分布式系统
	集成服务发布、RPC、分发/订阅机制、消息编码
	超时容错、重试机制、负载均衡
	功能可扩展
	可插拔的后台交换技术

Go Config
Go Config可以管理复杂的配置
	动态管理 - 加载配置不需要重启
	可插拔 - 可以选择从哪个源加载配置:文件、环境变量、consul。
	可合并 - 针对多个配置源可以合并并重写。
	回退 - 可以指定当key不存在时设置值。
	可观察 - 可以查看配置的变动。

Go Plugins
	go-micro与micro的插件集
	包含了绝大多数的后端技术
	grpc, kubernetes, etcd, kafka等等
	经过生产环境验证


2.如何才能使用micro
使用go-micro编写服务。
使用micro工具集来访问这些服务。

3.服务发现、注册中心
除了Consul,可以使用其它的注册中心吗
etcd 
如果你想使用etcd那你只需要引用etcd包,然后在启动的注册方式上标明使用的是etcd就行了。
import (
        _ "github.com/micro/go-plugins/registry/etcd"
)
service --registry=etcd --registry_address=127.0.0.1:2379
零依赖
micro专门为零依赖配置内置有一个多路广播DNS服务注册中心。
如果要使用,只需要在程序启动指令上传上--registry=mdns或者MICRO_REGISTRY=mdns。

4.API、Web、SRV 服务之间的区别是什么
API、Web、SRV作为micro工具集的一部分,我们尝试着使用一些设计模式规划出弹性的架构,通过把API接口、Web管理控制台、SRV(SRV是service的简称,可理解为后台业务逻辑部分)
API 服务
micro api默认把go.micro.api作为API网关服务的命名空间,micro api遵从API网关模式

Web 服务
Web服务由micro web提供,默认命名空间是go.micro.web。我们坚信,web应用作为微服务中的一等公民,所以把构建web管理控制台作为微服务的一部分显得非常重要。micro web其实是一个反向代理,并把http请求基于路径解析到适当的web应用程序。

SRV 服务
SRV 服务是RPC服务的基础,也就是你常写的服务类型。我们一般把它称作RPC或后后端服务,因为它作为后台架构的一部分,不应该暴露在最外层。默认情况下,我们使用go.micro.srv作为它的命名空间,或者你可以使用像com.example.srv这样的名字

5.Micro与Go-Kit比较
Go-kit声称自己是一个微服务的标准库。像GO一样,go-kit提供独立的包,通过这些包,开发者可以用来组建自己的应用程序。Go-kit非常不错,基于Go-kit,你可以完全掌控你定义的服务。

Go-micro则是一个面向微服务的可插拔RPC框架。go-micro是一个只在特殊方向上努力的框架,它尝试简化分布式系统之间的通信,所以我们可以花更多的时间在我们需要关注的业务逻辑上。对于想快速启动,把程序跑起来,同时用拥有一些可插拔的能力从基础架构中断开的能力,而不用修改代码,那么go-micro也很不错。

Micro作为一个微服务工具库,好比一把瑞士军刀,在我们构建微服务时,可以提供传统的接入点,比如http api gateway,web ui,cli,slack bot等等。Micro使用工具来引导架构关注点之间逻辑上的隔离,推动开发者创建API层的服务来暴露对外的API接口,并且创建隔离于对外API的Web层微服务。

如果想全盘掌控,那么使用go-kit;但是如果想弄一个有想法框架,使用go-micro。


}

2.MICRO安装
{
1.注册中心安装:
consul:https://www.consul.io/downloads.html
etcd:https://github.com/etcd-io/etcd/releases

2.go-micro安装
Go Micro是基于Go语言用于开发的微服务的RPC框架。
go get -u -v  github.com/micro/go-micro

3.Protobuf
安装protoc-gen-micro,用于生成Protobuf的代码。
https://github.com/micro/protoc-gen-micro

4.Toolkit工具集
micro工具集可以辅助操作微服务
go get -u -v github.com/micro/micro

5.可以使用docker镜像安装
使用Docker安装
可以通过docker镜像来安装
docker pull microhq/micro

6.grpcgateway的安装参考:https://blog.csdn.net/Edu_enth/article/details/93164637
}

3.1. 初始化
{

可以使用micro.NewService创建服务
import "github.com/micro/go-micro"
service := micro.NewService() 

初始化时,也可以传入相关选项
service := micro.NewService(
        micro.Name("greeter"),
        micro.Version("latest"),
)
配置项:https://godoc.org/github.com/micro/go-micro#Option

Go Micro也提供通过命令行参数micro.Flags传递配置参数:
import (
        "github.com/micro/cli"
        "github.com/micro/go-micro"
)

service := micro.NewService(
        micro.Flags(
                cli.StringFlag{
                        Name:  "environment",
                        Usage: "The environment",
                },
        )
)

解析命令行标识参数可以使用service.Init,增加标识参数可以使用micro.Action选项:
service.Init(
        micro.Action(func(c *cli.Context) {
                env := c.StringFlag("environment")
                if len(env) > 0 {
                        fmt.Println("Environment set to", env)
                }
        }),
)

Go Micro提供预置的标识,service.Init执行时就会设置并解析这些参数。所有的标识参考.https://godoc.org/github.com/micro/go-micro/config/cmd
	
}


3.2. 定义API
{
protoc	https://github.com/protocolbuffers/protobuf
protoc-gen-go	https://github.com/golang/protobuf
protoc-gen-micro	https://github.com/micro/protoc-gen-micro

go get github.com/golang/protobuf/{proto,protoc-gen-go}
go get github.com/micro/protoc-gen-micro
protoc --proto_path=$GOPATH/src:. --micro_out=. --go_out=. greeter.proto
	
}
3.3. 编写Golang Function
Function是执行一次的服务。(译者按:这里Function并不等同与平常我们编写的函数,而是只执行一次的服务所以我没有直接翻译,以免引起误解)
https://micro.mu/blog/2016/03/20/micro.html。
{
先写一个Function
Function作为顶级的接口,它是go-micro中函数式编程模型主要组件。它封装服务接口,并提供执行一次函数的能力。	
https://github.com/micro/examples/tree/master/function
go get github.com/micro/protobuf/{proto,protoc-gen-go}
protoc --go_out=plugins=micro:. greeter.proto

}

3.4.容错
{
如果是命令行的方式,则可以方便使用内置的flag设置ttl值、间隔时间
micro --register_ttl=30 --register_interval=15 api

刚这个例子我们设置了30秒的TTL生存期,并设置了每15秒一次的重注册。
而对于使用go-micro机制,可以以在构造服务时把选项传进去,比如time.Duration*n
service := micro.NewService(
        micro.Name("com.example.srv.foo"),
        micro.RegisterTTL(time.Second*30),
        micro.RegisterInterval(time.Second*15),
)

负载均衡
微服务客户端通过选择器负载均衡,选择器可以把请求分到任意多的服务节点上。服务启动后,它使用唯一的地址与id组合向注册中心注册成服务节点。创建请求时,micro客户端会通过选择器决定向哪一个节点发送请求。选择器在服务注册信息中找到服务的节点,然后用负载均衡策略选择一个节点把请求发送出去,比如随机哈希、轮询。

使用方式
客户端负载均衡内置在go-micro客户端中,这是自动完成的。
重置可以通过命令行标记或代码选项在客户端传入。默认值是1,也即是一次请求尝试一回。

通过命令行flag传入
micro --client_retries=3
设置选项
client.Init(
    client.Retries(3),
)

服务发现缓存
服务发现是微服务的核心,但是如果架构设计不对,它也会变成故障节点。
服务发现缓存是指在客户端缓存服务发现的信息。
micro --selector=cache api
如果要调用Init方法,Go-micro服务也支持使用同样的命令行flag来传递该参数:
import (
    "github.com/micro/go-micro/client"
    "github.com/micro/go-micro/selector/cache"
)

service := micro.NewService(
    micro.Name("com.example.srv.foo"),
)

service.Client().Init(cache.NewSelector())

}

4. Micro Toolkit
{
micro工具库由以下几个部分组成:

API Gateway: API网关作为单一的http入口,它使用服务发现中查询的服务地址,把请求动态路由到具体服务。网关允许我们建立可伸缩的后台微服务架构,并且让工作在前端的公共API更健壮。Micro API基于服务发现拥有强大的路由能力,它可以处理http、gRPC、websocket、消息推送事件等等。

Interactive CLI: 交互式的命令行接口。CLI通过终端可以描述、查询、直接与平台和服务进行交互。CLI提供所有的命令让开发者明白微服务正在处理的事情。CLI也包含了交互模式。

Service Proxy: 服务代理,这是一个在Go Micro和MUCP协议之上构建的透明的代理服务。它将服务发现、负载均衡、消息编码、中间件、传输及代理插件卸载到单一位置。

可以单独运行或与服务一起运行。

Service Templates: 服务生成模板,目的是快速生成服务代码,让编写代码飞起来。Micro预置了一些模板用来编写服务。 保持相同的方式编写服务,提高效率。

SlackOps Bot: Slack小机器人插件,当它运行中服务中时,这个插件允许开发者通过Slack消息来操作平台。MicroBot插件提供聊天配置选项,这样就可以让团队可以通过向小机器人发送聊天消息来做一些我们希望它做的事,这里面当然也包含像动态发现服务一样创建slack命令。

Web Dashboard: Web管理控制台允许直接在Web页面上查看服务的运行情况,展示端点信息,请求与响应状态,甚至直接向服务进行查询。管理控制台也有CLI交互页面提供给开发者在线上处理,就像直接操作终端一样。

依赖
micro工具库有两个依赖:

Service Discovery - 用于服务名解析
Protobuf - 代码生成工具

	
}

4.1.模板生成代码
{
使用模板生成
下面演示使用micro new命令来快速生成一个示例服务

生成的服务会被放到$GOPATH的相对目录下:
micro new github.com/micro/example
然后使用protoc把proto方便生成go源码
protoc --proto_path=. --micro_out=. --go_out=. proto/example/example.proto

}

4.2 micro api
{
API参考了API网关模式为服务提供了一个单一的公共入口。基于服务发现,使得micro api可以提供具备http及动态路由的服务。
Micro的API基于HTTP协议。请求的API接口通过HTTP协议访问,并且路由是基于服务发现机制向下转发的。 Micro API在 go-micro之上开发,所以它集成了服务发现、负载均衡、编码及基于RPC的通信。

因为micro api内部使用了go-micro,所以它自身也是可插拔的。 参考go-plugins了解对gRPC、kubernetes、etcd、nats、及rabbitmq等支持。另外,api也使用了go-api,这样,接口handler也是可以配置的。

# 默认的端口是8080
micro api
ACME( Automatic Certificate Management Environment)是由Let’s Encrypt制定的安全协议。
MICRO_ENABLE_ACME=true micro api

可以选择是否配置白名单
MICRO_ENABLE_ACME=true \
MICRO_ACME_HOSTS=example.com,api.example.com \
micro api

API服务支持TLS证书
MICRO_ENABLE_TLS=true \
MICRO_TLS_CERT_FILE=/path/to/cert \
MICRO_TLS_KEY_FILE=/path/to/key \
micro api

设置命名空间
MICRO_NAMESPACE=com.example.api micro api

运行示例
先决条件:我们使用Consul作为默认的服务发现,所以请先确定它已经安装好了,并且已经运行,比如执行consul agent -dev这样子方式运行。
# 下载示例
git clone https://github.com/micro/examples

# 运行服务
go run examples/greeter/srv/main.go

# 运行api
go run examples/greeter/api/api.go

# 启动micro api
micro api

向micro api发起http请求
curl "http://localhost:8080/greeter/say/hello?name=John"

HTTP请求的路径/greeter/say/hello会被路由到服务go.micro.api.greeter的方法Say.Hello上。

绕开api服务并且直接通过rpc调用:


curl -d 'service=go.micro.srv.greeter' \
     -d 'method=Say.Hello' \
     -d 'request={"name": "John"}' \
     http://localhost:8080/rpc
	 
使用JSON的方式执行同一请求:
curl -H 'Content-Type: application/json' \
     -d '{"service": "go.micro.srv.greeter", "method": "Say.Hello", "request": {"name": "John"}}' \
     http://localhost:8080/rpc


micro api提供下面类型的http api接口
- /[service]/[method]   # HTTP路径式的会被动态地定位到服务上
- /rpc          # 显式使用后台服务与方法名直接调用


}


4.3 go-api
https://github.com/asim/go-api
Go API是micro api的基础。这里只是说明一下,该存储库已由所有者归档。 现在它是只读的,我们也不做介绍了。

4.4 模板生成代码
对于一些特殊操作比如namespace, type, fqdn和alias:
micro new --fqdn com.example.srv.foo github.com/micro/foo
micro new -h


4.5 小机器人来管理我们的服务
{
micro bot是一只藏在微服务中的小马蝇,有了它,我们可以在Slack、HipChat、XMPP等等聊天程序中与它对话,通过它来操控服务。
我们把消息发送给它,它基于这些消息模仿执行CLI,触发指定的接口功能。
现在支持的输入方式
Slack
HipChat
}

4.6 cli
{
micro cli是一个类命令行接口的工具

交互模式
CLI有带提示的交互模式:
micro cli
如果是在交互模式中时,下面的指令中的micro要删掉,非交互模式即直接命令行执行才需要。

非交互模式
列出服务	micro list services
获取服务	micro get service go.micro.srv.example
服务健康检测	micro health go.micro.srv.example
调用服务 micro call go.micro.srv.example Example.Call '{"name": "John"}'
注册/卸载服务	
micro register service '{"name": "foo", "version": "bar", "nodes": [{"id": "foo-1", "address": "127.0.0.1", "port": 8080}]}'
micro deregister service '{"name": "foo", "version": "bar", "nodes": [{"id": "foo-1", "address": "127.0.0.1", "port": 8080}]}'

代理远程的环境,可以使用micro proxy
如果针对远程环境进行开发时,可能无法直接访问服务,这使用CLI操作变更很不方便。micro proxy 提供了http代理解决这种使用场景。
在远程环境中运行,启动代理
micro proxy

在命令行中带上MICRO_PROXY_ADDRESS远程代理的地址,这样客户端的CLI就知道要连上这个代理
MICRO_PROXY_ADDRESS=staging.micro.mu:8081 micro list services


}

4.7 客户端代理
{
micro proxy 其实就是客户端的代理。
如果服务运行环境不能直接访问,那么就需要通过代理来访问,micro proxy就是来干这事的,它提供http api,这个api可以把客户端的请求转向那些没有直接暴露给客户端的服务。
Micro代理默认是运行在8081端口下。
micro proxy
服务默认使用ACME安全协议	MICRO_ENABLE_ACME=true micro proxy
可以选择性配置主机白名单	MICRO_ENABLE_ACME=true MICRO_ACME_HOSTS=example.com,api.example.com micro proxy 
Proxy CLI
命令行如果要指定代理,可以像下面这样设置:
MICRO_PROXY_ADDRESS=127.0.0.1:8081 micro list services
MICRO_PROXY_ADDRESS=127.0.0.1:8081 micro call greeter Say.Hello '{"name": "john"}'
}

4.8 web 
{
micro web
使用浏览器打开http://localhost:8082
Micro Web支持Let's Encrypt开发的ACME协议,它可以帮你的域名颁发证书。
micro --enable_acme web
可以指定白名单:
micro --enable_acme --acme_hosts=example.com,api.example.com web
管理控制台也支持使用TLS证书
micro --enable_tls --tls_cert_file=/path/to/cert --tls_key_file=/path/to/key web

}


5.实例
{
{
go run srv/main.go --server_address=127.0.0.1:9090 --registry=etcd

go run cli/main.go  --registry=etcd
{
        "msg": "Hello John"
}

micro --registry=etcd list services
{
go.micro.http.broker
go.micro.srv.greeter	
}

micro --registry=etcd get service go.micro.srv.greeter
{
	service  go.micro.srv.greeter

	version 2020.01.10.10.10

	ID      Address Metadata
	go.micro.srv.greeter-2c558087-8d1a-4eca-9f54-cbc168499ce4       127.0.0.1:9090broker=http,protocol=mucp,registry=etcd,server=mucp,transport=http

	Endpoint: Say.Hello

	Request: {
			name string
	}

	Response: {
			msg string
	}

}

micro --registry=etcd  call go.micro.srv.greeter Say.Hello '{"name": "John"}'
{
        "msg": "Hello John"
}


MICRO_API_HANDLER=rpc  MICRO_API_NAMESPACE=go.micro.srv micro --registry=etcd   api
MICRO_API_HANDLER http API的触发方法
MICRO_API_NAMESPACE API所属服务的命名空间�

curl -XPOST -H 'Content-Type: application/json' "http://localhost:8080/greeter/say/hello?name=John"
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    16  100    16    0     0   1333      0 --:--:-- --:--:-- --:--:--  1454{"msg":"Hello "}

-------------------
_, err = os.StartProcess("test.exe", nil, &os.ProcAttr{Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}})
Golang Cmd启动另外一个exe程序

goalng 手机号码 中间部分 替换为 * 星号
func MobileReplaceRepl(str string) string {
    re, _ := regexp.Compile("(\\d{3})(\\d{4})(\\d{4})")
    return re.ReplaceAllString(str, "$1****$3")
}

测试结果:
MobileReplaceRepl("18223270004")
182****7004


golang 时间转换,不注意将引发Gorm等mysql操作保存时间多8个小时
默认是没有时区
time.Parse("2006-01-02 15:04:05", "2017-06-20 18:16:15")

需要指定时区,再保存的时候才不会出现8小时差的情况
local, _ := time.LoadLocation("Local")
now, _ := time.ParseInLocation("2006-01-02 15:04:05", "2017-06-20 18:16:15", local)

switch e.Name {
        case "a", "b", "c":
            ...
        }

}
	
}
protoc --proto_path=. --go_out=. --micro_out=. proto/hello/hello.proto
go run main.go
6.环境变量 
{
MICRO_API_HANDLER设置http处理程序
MICRO_API_NAMESPACE设置服务名称空间
MICRO_REGISTRY=etcdv3 MICRO_TRANSPORT=nats MICRO_BROKER=kafka 	
MICRO_SERVER_ADDRESS=localhost:9090

MICRO_REGISTRY=etcd MICRO_CLIENT=grpc MICRO_SERVER=grpc  MICRO_REGISTRY_ADDRESS=127.0.0.1:9090
micro --client=grpc --server=grpc api

# 指定etcd不在同一主机上的地址。  MICRO_REGISTRY_ADDRESS=127.0.0.1:9090

1.getaway
etcd 
MICRO_REGISTRY=etcd MICRO_SERVER_ADDRESS=localhost:9090  go run srv.go
MICRO_REGISTRY=etcd  go run cli.go #测试服务是否可以连接
MICRO_REGISTRY=etcd  go run gateway.go #grpcgateway
#网页访问:http://127.0.0.1:8080/say/hello?name=xxx

go run srv.go --registry=etcd --server_address=127.0.0.1:9090

MICRO_REGISTRY=etcd  micro list services

MICRO_REGISTRY=etcd micro api --namespace=go.micro.srv.say
2.micro工具使用的gateway
MICRO_REGISTRY=etcd MICRO_SERVER_ADDRESS=localhost:9090  go run srv.go
MICRO_REGISTRY=etcd  go run api.go

MICRO_REGISTRY=etcd  MICRO_CLIENT=grpc MICRO_SERVER=grpc micro api

MICRO_REGISTRY=etcd  MICRO_CLIENT=./cli/cli MICRO_SERVER=./srv/srv micro api
}
--registry_address=registry:8500 --register_interval=5 --register_ttl=10

	micro-api   micro-web

a-api 	b-api 	a-web 	b-web 
		a-srv 	b-srv



添加插件 
{
如果要集成插件,只需将它们链接到一个单独的文件中并重建 创建一个plugins.go文件并导入所需的插件
{
package main

import (
        // consul registry
        _ "github.com/micro/go-plugins/registry/consul"
        // rabbitmq transport
        _ "github.com/micro/go-plugins/transport/rabbitmq"
        // kafka broker
        _ "github.com/micro/go-plugins/broker/kafka"
)	
}
go build -o service *.go
service --registry=etcdv3 --transport=nats --broker=kafka
或,最好使用环境变量
MICRO_REGISTRY=consul \
MICRO_TRANSPORT=rabbitmq \
MICRO_BROKER=kafka \
service
}




包装器
{
例子:服务处理程序包装器,用于记录传入的请求
服务
# 实现server.HandlerWrapper
func logWrapper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, rsp interface{}) error {
		fmt.Printf("[%v] server request: %s", time.Now(), req.Endpoint())
		return fn(ctx, req, rsp)
	}
}
可以在创建服务时进行初始化
service := micro.NewService(
	micro.Name("greeter"),
	// wrap the handler
	micro.WrapHandler(logWrapper),
)

客户端
{
type logWrapper struct {
	client.Client
}

func (l *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
	fmt.Printf("[wrapper] client request to service: %s endpoint: %s\n", req.Service(), req.Endpoint())
	return l.Client.Call(ctx, req, rsp)
}

// implements client.Wrapper as logWrapper
func logWrap(c client.Client) client.Client {
	return &logWrapper{c}
}	
service := micro.NewService(
	micro.Name("greeter"),
	// wrap the client
	micro.WrapClient(logWrap),
)
}
}



写项目时获取最稳定的go-micro
{
# enable go modules
export GO111MODULE=on
# initialise go modules in your app
go mod init
# now go get
go get ./...	
}





发布了264 篇原创文章 · 获赞 23 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/Edu_enth/article/details/103925223