引言
目前,几乎所有的研发人员每天都在跟API打交道:后端为实现业务不停的生产API,前端为实现产品功能不停的调用API。API已经成为前端与后端、产品与产品、公司与公司之间技术沟通、业务合作的桥梁。
微服务中,API几乎是服务与外界的唯一交互渠道,API服务的稳定性、可靠性越来越成为不可忽略的部分。我们需要实时了解API的运行状况(请求次数、延时、失败等),需要通过对历史数据的分析了解哪些API存在瓶颈以便后期优化。所以,为了确保系统良好的提供服务,绝大多数的微服务框架也都集成了API监控组件。
本文将为算术运算服务增加API监控功能:Prometheus作为监控组件,Grafana作为可视化工具,两者均通过docker-compose部署运行。go-kit已经提供prometheus组件(metric/prometheus),因此集成工作变得非常容易。
本次实现基于service层的中间件 ServiceMiddleware
采集中间件
本示例使用go-kit中间件机制为Service添加Prometheus监控指标采集功能。在instrument.go下增加新的结构类型:
1
2
3
4
5
6
7
|
// metricMiddleware 定义监控中间件,嵌入Service
// 新增监控指标项:requestCount和requestLatency
type metricMiddleware struct {
Service
requestCount metrics.Counter
requestLatency metrics.Histogram
}
|
接下来创建为Service封装指标采集的方法Metric,采集请求次数和请求延迟两个指标项:
1
2
3
4
5
6
7
8
9
|
// Metrics 封装监控方法
func Metrics(requestCount metrics.Counter, requestLatency metrics.Histogram) ServiceMiddleware {
return func(next Service) Service {
return metricMiddleware{
next,
requestCount,
requestLatency}
}
}
|
然后跟限流、日志中间件的方式一致,由于嵌入了Service接口,需要依次实现该接口的方法.
- 每接收一次请求,请求次数每次加1;
- 通过请求结束时间减去请求开始的差值(单位秒)作为请求延时;
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
38
39
40
41
42
43
44
45
46
47
48
49
|
func (mw metricMiddleware) Add(a, b int) (ret int) {
defer func(beign time.Time) {
lvs := []string{"method", "Add"}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds())
}(time.Now())
ret = mw.Service.Add(a, b)
return ret
}
func (mw metricMiddleware) Subtract(a, b int) (ret int) {
defer func(beign time.Time) {
lvs := []string{"method", "Subtract"}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds())
}(time.Now())
ret = mw.Service.Subtract(a, b)
return ret
}
func (mw metricMiddleware) Multiply(a, b int) (ret int) {
defer func(beign time.Time) {
lvs := []string{"method", "Multiply"}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds())
}(time.Now())
ret = mw.Service.Multiply(a, b)
return ret
}
func (mw metricMiddleware) Divide(a, b int) (ret int, err error) {
defer func(beign time.Time) {
lvs := []string{"method", "Divide"}
mw.requestCount.With(lvs...).Add(1)
mw.requestLatency.With(lvs...).Observe(time.Since(beign).Seconds())
}(time.Now())
ret, err = mw.Service.Divide(a, b)
return
}
|
修改main.go
首先创建指标采集对象:请求次数采集和请求延时采集对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
fieldKeys := []string{"method"}
requestCount := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
Namespace: "test",
Subsystem: "arithmetic_service",
Name: "request_count",
Help: "Number of requests received.",
}, fieldKeys)
requestLatency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
Namespace: "test",
Subsystem: "arithemetic_service",
Name: "request_latency",
Help: "Total duration of requests in microseconds.",
}, fieldKeys)
|
使用Metrics方法对Service对象进行封装:
1
|
svc = Metrics(requestCount, requestLatency)(svc)
|
新增用于Prometheus轮循拉取监控指标的代码,开放API接口/metrics:
1
|
http.Handle("/metrics", promhttp.Handler())
|
至此,代码修改完成.
参考:https://juejin.im/post/5c6eb58a6fb9a049dd80e575