部署开发环境
- Golang环境 安装
- Micro
Micro目前V3版本未稳定,使用V2版本进行学习和开发使用。(经过了一段时间来看,V2之后V3和V4都没啥使用的必要)
## 安装go-micro
go get github.com/micro/go-micro/v2
## 安装micro
go 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进行环境部署,见组件环境。
--helpMicro Handler介绍
在micro的系统中,有许多资源类型,作为框架对服务的一种抽象归类,比如常用的有:api、fnc(函数)、srv、web。其中经常需要使用的是api、srv、web,关于web,api,srv这三种服务的疑问,可以查看该Issue。
例如,在实际使用中,我的理解是,简化分类,使用web,srv作为整体架构,web处理HTTP请求,srv提供特定的服务,例如,登录,验证,访问数据等操作。
web框架代码生成:
micro new --namespace=mu.micro.book --type=web --alias=order micro_learn/orders-webservice框架代码生成:
$ 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代码生成:
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--address=0.0.0.0:8080MICRO_API_ADDRESS=0.0.0.0:8080设置命名空间
micro --api_namespace=namespace api 或 MICRO_API_NAMESPACE=namespace micro api注意启动api时设置的namespace必须与要访问的资源的namespace一致不然无法访问,Web管理控制台类似。
设置服务发现
--registrymicro --registry=etcd list services--registry_addressmicro --registry=etcd --api_namespace=mu.micro.book.web api --handler=webRPC使用网关访问
--enable_rpcmicro apimicro_v2.exe --registry=etcd api --enable_rpc接下来就是访问了。
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",
}
}'servicemethodmicro --registry=etcd api --enable_rpc
./etcdctl get "" --prefix随便找一个去看一下就好了。
PROTO文件兼容其他tag
go get github.com/favadi/protoc-go-inject-tagExample:
// file: test.proto
syntax = "proto3";
package pb;
message IP {
// @inject_tag: valid:"ip"
string Address = 1;
}Generate with protoc command as normal.
protoc --go_out=. test.protoprotoc-go-inject-tagtest.pb.goprotoc-go-inject-tag -input=./test.pb.gotest.pb.gotype IP struct {
// @inject_tag: valid:"ip"
Address string `protobuf:"bytes,1,opt,name=Address,json=address" json:"Address,omitempty" valid:"ip"`
}使用Apollo配置中心
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端:
// 分布式追踪链路
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端:
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监控
promMonitor := monitor.NewPrometheusMonitor("user_web", "user")
r.Use(promMonitor.PromMiddleware())
r.POST("/login", handler.Login)
router.GET("/metrics", gin.WrapH(promhttp.Handler()))
....获取其他服务的信息
micReg registry.Registry
services, err := micReg.GetService(appName)
log.Info(services[0].Version)
// level=info latestetcd.goGetService(xxxxxxxxxxxxx)
.....
rsp, err := e.client.Get(ctx, servicePath(name)+"/", clientv3.WithPrefix(), clientv3.WithSerializable())
if err != nil {
return nil, err
}
........WithPrefixnameGetServiceListServicesMicro工具获取服务信息:
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。
web--type=webmicro new --namespace=mu.micro.book --type=web --alias=user micro/user-web代码修改:
默认
web.Name("mu.micro.book.web.user")
改为
web.Name("mu.micro.book.web.api.user")apimicro启动命令:
micro --registry=etcd --api_namespace=mu.micro.book.web api --handler=web解决方法参考☞issue。
Web HTTP代理
micro api --handler=webweb handler是一个基于服务发现和web socket支持的http反向代理。
/[service]—handler=webMICRO_API_HANDLER=web上面这段需要怎么理解呢?
micro.cloud.api.testmicro_v2.exe --api_namespace=micro.cloud api --handler=web/test/test此时这个service,不能是下划线形式,例如,test_one。
二、Trace部分HTTP2Micro无法使用
按照原生HTTP方式注入Trace,没有能够完整使用,使用Gin或者Echo第三方Web库,利用其插件形式进行使用,则可以正常使用Trace服务。
三、设置Prometheus监控
需上文提到的方式,设置Gin框架的监控,按照网上操作,无法监视到接口访问。
组件环境
ETCD:
docker run -p 2379:2379 -p 2380:2380 --name etcd gcr.io/etcd-development/etcd:v3.4.13MySQL:
docker pull mysql
docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysqlRedis:
docker pull redis:latest
docker run -itd --name redis -p 6379:6379 redisJaeger:
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.6Promethes
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/prometheusGrafana
docker run -d -p 3000:3000 --name grafana grafana/grafanaWeb和Srv的区别
web.NewService 和 micro.NewService有啥区别
功能上:web打开的Http服务,micro打开的RPC/API服务
联系:为了让web服务能像RPC/API一样融合到Micro的微服务体系中,web.Micro做了以下事情:
- 与RPC一样注册服务
- 可以复用Service的配置,声明micro.client调用RPC
- client为http.client,非micro.client,故而无法直接使用web.client调用micro.service
- web的Transport并非micro.Transport,所以micro的RPC服务无法直接调用web.service,需要使用http.client调用。
一句话总结:web面向http,可以向异构服务提供服务,rpc则是纯内部服务。