引言

目前,几乎所有的研发人员每天都在跟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