我是靠谱客的博主 开朗过客,这篇文章主要介绍Go Micro框架(v2.9.1)的使用,现在分享给大家,希望可以做个参考。

部署开发环境

  • Golang环境 安装

  • gRPC 安装

  • Micro

虽然Micro目前V3版本趋于稳定,还是有很多人使用V2版本进行学习和开发使用。

现在的消息,go-micro已经回到asim个人仓库,但其已经把开源项目的issue都关闭了(2021/5/27),只接受PR,且不会有maintainer的支持。(issue现在已开)。因为他觉得Github上的人只是去抱怨,而不去解决问题。然后他就把解决问题的人给解决了,这波操作在大气层。说实话,我觉得他真的太能折腾了,这个框架实在不建议使用了,maintainer想法太多了,有点伤。

有替代品吗?有的,而且就是国内的,工程性都做的比较好,推荐两个,go-kratos,go-zero。go-zero听说是要进入CNCF基金会了。go-kratos在腾讯的一些业务上有用到。
复制代码
1
2
3
4
5
6
## 安装go-microgo get github.com/micro/go-micro/v2## 安装microgo get github.com/micro/micro/v2 download protobuf for micro: go get -u github.com/golang/protobuf/proto go get -u github.com/golang/protobuf/protoc-gen-go go get github.com/micro/micro/v2/cmd/protoc-gen-micro
常见开发组件如何一键安装,使用docker进行环境部署,见组件环境。

查看Micro命令的Help,命令参数后跟上--help,例如:

Micro Handler介绍

在micro的系统中,有许多资源类型,作为框架对服务的一种抽象归类,比如常用的有:api、fnc(函数)、srv、web。其中经常需要使用的是api、srv、web,关于web,api,srv这三种服务的疑问,可以查看该Issue。

例如,在实际使用中,我的理解是,简化分类,使用web,srv作为整体架构,web处理HTTP请求,srv提供特定的服务,例如,登录,验证,访问数据等操作。

web框架代码生成:

复制代码
1
micro new --namespace=mu.micro.book --type=web --alias=order micro_learn/orders-web

service框架代码生成:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ micro new --namespace=mu.micro.book --type=service --alias=u12 user-test Creating service mu.micro.book.service.u12 in user-test . ├── main.go ├── generate.go ├── plugin.go ├── handler │   └── u12.go ├── subscriber │   └── u12.go ├── proto │   └── u12 │       └── u12.proto ├── Dockerfile ├── Makefile ├── README.md ├── .gitignore └── go.mod

删除subscriber目录,这是用于专门放订阅异步消息组件的目录,我们暂时用不到。

删除go mod文件,仅需要在项目最外层有统一的go mod。

删除Dockerfile, Makefile打包编程文件与README.md,可以选择性保留。


Micro Grpc代码生成:

复制代码
1
protoc --proto_path=. --go_out=. --micro_out=. u12.proto
这里有个小细节,生成代码时,如果想生成micro目录下的user服务,那就在micro的同级目录下,运行命令。

micro new --namespace=mu.micro.book --type=web --alias=order micro/user

这样生成,proto文件路径才不会出现路径问题。

Micro代理启动

启动api网关

micro api 即可启动api一个网关,默认的端口是8080

可以通过--address=0.0.0.0:8080flag或者设置环境MICRO_API_ADDRESS=0.0.0.0:8080来修改

设置命名空间

复制代码
1
micro --api_namespace=namespace api  或  MICRO_API_NAMESPACE=namespace micro api

注意启动api时设置的namespace必须与要访问的资源的namespace一致不然无法访问,Web管理控制台类似。

设置服务发现

Micro默认是使用Grpc Mdns的方式进行局域网的服务发现,使用--registry参数修改注册服务,consul、etcd等,micro --registry=etcd list services--registry_address修改默认ETCD注册地址。

复制代码
1
micro --registry=etcd --api_namespace=mu.micro.book.web api --handler=web

RPC使用网关访问

--enable_rpc参数是micro api的参数,默认为false,这个得注意,注意,再注意,因为看到网上很多教程没有提到要开启,显然是Micro更新过快的锅。。。。

复制代码
1
micro_v2.exe --registry=etcd api --enable_rpc

接下来就是访问了。

复制代码
1
2
3
4
5
6
7
8
9
10
curl --location --request POST 'http://localhost:8080/rpc'  --header 'Content-Type: application/json'  --data-raw '{     "service": "micro.xxx.service.process_route",     "method": "ProcessRoute.StoreProcessInfo",     "request": {         "xxxx": "xxx",         "xxx": "xxx",     } }'

servicemethod如何去确定,若没有经验的情况下,可以使用我的办法:

复制代码
1
2
3
micro --registry=etcd api --enable_rpc ./etcdctl get "" --prefix

随便找一个去看一下就好了。

PROTO文件兼容其他tag

使用工具:github.com/favadi/proto 。

复制代码
1
go get github.com/favadi/protoc-go-inject-tag

Example:

复制代码
1
2
3
4
5
6
7
8
9
// file: test.proto syntax = "proto3"; package pb; message IP {   // @inject_tag: valid:"ip"   string Address = 1; }

Generate with protoc command as normal.

复制代码
1
protoc --go_out=. test.proto

Run protoc-go-inject-tag with generated file test.pb.go.

复制代码
1
protoc-go-inject-tag -input=./test.pb.go

The custom tags will be injected to test.pb.go.

复制代码
1
2
3
4
type IP struct { // @inject_tag: valid:"ip" Address string `protobuf:"bytes,1,opt,name=Address,json=address" json:"Address,omitempty" valid:"ip"` }

使用Apollo配置中心

复制代码
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
import ( apollo "github.com/xxxmicro/go-micro-apollo-plugin" ) e := json.NewEncoder() if err := config.Load(apollo.NewSource( apollo.WithAddress("172.16.9.229"+":8080"), apollo.WithNamespace("application"), apollo.WithAppId("12345"), apollo.WithCluster("dev"), source.WithEncoder(e), )); err != nil { log.Error(err) } if err := config.Get("etcd").Scan(&etcdConfig); err != nil { log.Error(err) } if err := config.Get("mysql").Scan(&mysqlConfig); err != nil { log.Error(err) } if err := config.Get("redis").Scan(&redisConfig); err != nil { log.Error(err) } if err := config.Get("zap").Scan(&zapConfig); err != nil { log.Error(err) } if err := config.Get("jwt").Scan(&jwtConfig); err != nil { log.Error(err) }


OpenTrace设置

Trace ID 在入口函数设置后,后续均一样。Span ID则标识每一个服务实例。

其他服务,可通过此操作,从context中拿到trace,拿到后,可以使用Log,将一些信息打印到trace上。

Web端:

复制代码
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
// 分布式追踪链路 t, io, err := tracer.NewTracer("mu.micro.book.web.api.user", "") if err != nil { log.Fatal(err.Error()) } defer io.Close() opentracing.SetGlobalTracer(t) ....... //设置采样率 gin2micro.SetSamplingFrequency(50) router := gin.Default() r := router.Group("/user") //添加Tracer中间件 r.Use(gin2micro.TracerWrapper) func Login(c *gin.Context) { ctx, ok := gin2micro.ContextWithSpan(c) if ok == false { log.Error("get context err") } sp := opentracing.SpanFromContext(ctx) // Get request ID for context if sc, ok := sp.Context().(jaeger.SpanContext); ok { fmt.Println(sc.TraceID().String()) } ......          // 调用后台服务 rsp, err := userClient.QueryUserByName(ctx, &us.Request{ UserName: c.Request.Form.Get("userName"), }) }

Service端:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import ( "github.com/opentracing/opentracing-go" tarceLog "github.com/opentracing/opentracing-go/log" ) func (e *Service) QueryUserByName(ctx context.Context, req *s.Request, rsp *s.Response) error {     sp := opentracing.SpanFromContext(ctx)     if sc, ok := sp.Context().(jaeger.SpanContext); ok {         fmt.Println(sc.TraceID().String(), sc)     }     sp.LogFields(         tarceLog.String("event", "soft error"),         tarceLog.String("type", "cache timeout"),         tarceLog.Int("waited.millis", 1500))     ....... }

Web设置Prometheus监控

复制代码
1
2
3
4
5
6
7
8
promMonitor := monitor.NewPrometheusMonitor("user_web", "user") r.Use(promMonitor.PromMiddleware()) r.POST("/login", handler.Login) router.GET("/metrics", gin.WrapH(promhttp.Handler())) ....

获取其他服务的信息

复制代码
1
2
3
4
5
6
micReg registry.Registry services, err := micReg.GetService(appName) log.Info(services[0].Version) // level=info latest

etcd.go中:

复制代码
1
2
3
4
5
6
7
GetService(xxxxxxxxxxxxx) ..... rsp, err := e.client.Get(ctx, servicePath(name)+"/", clientv3.WithPrefix(), clientv3.WithSerializable()) if err != nil { return nil, err } ........

WithPrefix,将会把传入的name作为前缀的key全部取下来,所以GetService才会返回的是一个数组。

另外,ListServices则是把服务信息全部返回。

Micro工具获取服务信息:

复制代码
1
micro.exe --registry=etcd --registry_address="192.xx.xx.xxx:2379" get service "xxxxxxxxxxxx"

教程中的问题:

一、版本更迭,web handler无法使用

造成问题,micro api,POST /user/login HTTP/1.1" 500 0。问题是使用了最新的稳定版本micro。

micro 2.9.3没有web handler,开发组尚未解决。issue。 不是没有了,看代码,其实是cmd中没有添加而已。

现在的解决方法就是,虽然使用--type=web创建项目:

复制代码
1
micro new --namespace=mu.micro.book --type=web --alias=user micro/user-web

代码修改:

复制代码
1
2
3
4
5
默认 web.Name("mu.micro.book.web.user") 改为 web.Name("mu.micro.book.web.api.user")
注意,这里这个api是必须的,查看代码会发现api模式代理rpc、http、proxy、web等,默认创建的只有web,显然是V1版本时代的产物,这里可以修改生成代码器将其改掉。

micro启动命令:

复制代码
1
micro --registry=etcd --api_namespace=mu.micro.book.web api --handler=web
解决方法参考☞issue。

Web HTTP代理

micro api --handler=web

web handler是一个基于服务发现和web socket支持的http反向代理。
  • Content-Type: Any

  • Body: Any

  • 正向格式:HTTP反向代理,包括web sockets。

  • Path: /[service]

  • 解析器:路径用于解析服务名称。

  • 配置:Flag —handler=web 或 MICRO_API_HANDLER=web

上面这段需要怎么理解呢?

例如Service Name为micro.cloud.api.test

启动micro进行代理:micro_v2.exe --api_namespace=micro.cloud api --handler=web.

此时,凡是/test前缀的HTTP请求,均从此服务请求,同理,此服务其他不是/test前缀,通过Micro则访问不到。

此时这个service,不能是下划线形式,例如,test_one。

二、Trace部分HTTP2Micro无法使用

按照原生HTTP方式注入Trace,没有能够完整使用,使用Gin或者Echo第三方Web库,利用其插件形式进行使用,则可以正常使用Trace服务。

三、设置Prometheus监控

需上文提到的方式,设置Gin框架的监控,按照网上操作,无法监视到接口访问。

组件环境

ETCD:

复制代码
1
docker run -p 2379:2379 -p 2380:2380 --name etcd gcr.io/etcd-development/etcd:v3.4.13

MySQL:

复制代码
1
2
docker pull mysql docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

Redis:

复制代码
1
2
docker pull redis:latest docker run -itd --name redis -p 6379:6379 redis

Jaeger:

复制代码
1
docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 -p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 -p 16686:16686 -p 14268:14268 -p 9411:9411 jaegertracing/all-in-one:1.6

Promethes

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
prometheus.yml global:   scrape_interval:     15s # By default, scrape targets every 15 seconds.   # Attach these labels to any time series or alerts when communicating with   # external systems (federation, remote storage, Alertmanager).   external_labels:     monitor: 'codelab-monitor' # A scrape configuration containing exactly one endpoint to scrape: # Here it's Prometheus itself. scrape_configs:   # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.   - job_name: 'prometheus'     # Override the global default and scrape targets from this job every 5 seconds.     scrape_interval: 5s     static_configs:       - targets: ['10.2.43.4:8088'] targets : 作为拉取数据的地址。 docker run -d -p 9090:9090 -v C:/tmp/prometheus.yml:/etc/prometheus/prometheus.yml --name prometheus prom/prometheus

Grafana

复制代码
1
docker run -d -p 3000:3000 --name grafana grafana/grafana

Web和Srv的区别


web.NewService 和 micro.NewService有啥区别

功能上:web打开的Http服务,micro打开的RPC/API服务
联系:为了让web服务能像RPC/API一样融合到Micro的微服务体系中,web.Micro做了以下事情:
  1. 与RPC一样注册服务

  2. 可以复用Service的配置,声明micro.client调用RPC

  3. client为http.client,非micro.client,故而无法直接使用web.client调用micro.service

  4. web的Transport并非micro.Transport,所以micro的RPC服务无法直接调用web.service,需要使用http.client调用。
    一句话总结:web面向http,可以向异构服务提供服务,rpc则是纯内部服务。


最后

以上就是开朗过客最近收集整理的关于Go Micro框架(v2.9.1)的使用的全部内容,更多相关Go内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(1709)

评论列表共有 0 条评论

立即
投稿
返回
顶部