应用性能监控通过周期性的统计数据,帮助开发者分析业务性能瓶颈,在性能优化、故障定位的时候非常有帮助。应用性能监控的指标包括 请求各个环节的时延、线程池使用情况、连接池使用情况、CPU和网络使用情况等。
统计数据是一个周期性时效数据,只在统计周期内具有意义。可以选择通过 REST
接口查询实时的统计数据,也可以通过日志开关,将 统计数据输出到日志文件里面,帮助分析性能问题。
使用应用性能监控非常简单, 只需要在应用中包含相关的依赖包,通过配置项开启和关闭相关功能。
开启应用性能监控功能, 需要引入下面的依赖:
``` <dependency> <groupId>org.apache.servicecomb</groupId> <artifactId>metrics-core</artifactId> </dependency> ```
通过在 microservice.yaml
中增加下面的配置项,就可以将性能统计数据输出到日志文件中。
``` servicecomb: metrics: window_time: 60000 invocation: latencyDistribution: 0,1,10,100,1000 Consumer.invocation.slow: enabled: true msTime: 1000 Provider.invocation.slow: enabled: true msTime: 1000 publisher.defaultLog: enabled: true endpoints.client.detail.enabled: true ```
上述配置开启了慢调用检测,如果存在慢调用,则会立即输出相应日志:
``` 2019-04-02 23:01:09,103\[WARN]\[pool-7-thread-74]\[5ca37935c00ff2c7-350076] - slow(40 ms) invocation, CONSUMER highway perf1.impl.syncQuery http method: GET url : /v1/syncQuery/{id}/ server : highway://192.168.0.152:7070?login=true status code: 200 total : 50.760 ms prepare : 0.0 ms handlers request : 0.0 ms client filters request : 0.0 ms send request : 0.5 ms get connection : 0.0 ms write to buf : 0.5 ms wait response : 50.727 ms wake consumer : 0.23 ms client filters response: 0.2 ms handlers response : 0.0 ms (SlowInvocationLogger.java:121) ```
其中 5ca37935c00ff2c7-350076 是 ${traceId}-${invocationId}
的结构,在log4j2 或 logback 的输出格式中通过 %marker 引用。
也可以通过 REST
接口查询性能统数据。使用浏览器访问http://ip:port/metrics 即可,将会得到类似下面格式的json数据:
``` { "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=connectCount,type=client)": 0.0, "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=disconnectCount,type=client)": 0.0, "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=connections,type=client)": 1.0, "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=bytesRead,type=client)": 508011.0, "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=bytesWritten,type=client)": 542163.0, "servicecomb.vertx.endpoints(address=192.168.0.124:7070,statistic=queueCount,type=client)": 0.0, "servicecomb.vertx.endpoints(address=0.0.0.0:7070,statistic=connectCount,type=server)": 0.0, "servicecomb.vertx.endpoints(address=0.0.0.0:7070,statistic=disconnectCount,type=server)": 0.0, "servicecomb.vertx.endpoints(address=0.0.0.0:7070,statistic=connections,type=server)": 1.0, "servicecomb.vertx.endpoints(address=0.0.0.0:7070,statistic=bytesRead,type=server)": 542163.0 ... ... } ```
Prometheus (普罗米修斯)是一个名字非常酷的开源监控系统。
它支持多维度的指标数据模型,服务端通过HTTP协议定时拉取数据后,通过灵活的查询语言,实现监控的目的。
servicecomb的应用性能监控功能支持对接Prometheus,首先需要在您的业务项目中加入如下依赖:
``` <dependency> <groupId>org.apache.servicecomb</groupId> <artifactId>metrics-prometheus</artifactId> </dependency> ```
然后在 microservice.yaml 中增加下面的配置项:
``` servicecomb: metrics: prometheus: address: ${ip}:${port} ```
该配置项是设置普罗米修斯框架监听的端口,您只需使用浏览器访问对应的ip地址加该端口即http://ip:port/metrics 就可以获得如下格式的监控数据:
``` # HELP ServiceComb_Metrics ServiceComb Metrics # TYPE ServiceComb_Metrics untyped threadpool_rejectedCount{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} 0.0 threadpool_rejectedCount{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} 0.0 threadpool_taskCount{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} 0.0 threadpool_currentThreadsBusy{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} NaN threadpool_taskCount{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} 0.0 threadpool_currentThreadsBusy{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} NaN threadpool_poolSize{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} NaN threadpool_poolSize{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} NaN threadpool_completedTaskCount{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="connectCount",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="disconnectCount",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="connections",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="bytesRead",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="bytesWritten",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="requests",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="latency",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:7070",statistic="rejectByConnectionLimit",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="connectCount",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="disconnectCount",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="connections",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="bytesRead",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="bytesWritten",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="requests",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="latency",type="server",} 0.0 servicecomb_vertx_endpoints{appId="springmvctest",address="0.0.0.0:8080",statistic="rejectByConnectionLimit",type="server",} 0.0 threadpool_completedTaskCount{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} 0.0 threadpool_maxThreads{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} NaN threadpool_maxThreads{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} NaN threadpool_queueSize{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} NaN threadpool_queueSize{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} NaN threadpool_corePoolSize{appId="springmvctest",id="cse.executor.groupThreadPool-group0",} NaN threadpool_corePoolSize{appId="springmvctest",id="cse.executor.groupThreadPool-group1",} NaN ```
注:默认端口是9696,您也可以根据实际业务要求进行修改。
配置项 | 默认值 | 含义 |
---|---|---|
servicecomb.metrics.window_time | 60000 | 统计周期,单位为毫秒 TPS、时延等等周期性的数据,每周期更新一次,在周期内获取到的值,实际是上一周期的值 |
servicecomb.metrics .invocation.latencyDistribution | 时延分布时间段定义,单位为毫秒 例如:0,1,10,100,1000 表示定义了下列时延段[0, 1),[1, 10),[10, 100),[100, 1000),[1000, ) | |
servicecomb.metrics .Consumer.invocation.slow.enabled | false | 是否开启Consumer端的慢调用检测 通过增加后缀.${service}.${schema}.${operation},可以支持4级优先级定义 |
servicecomb.metrics .Consumer.invocation.slow.msTime | 1000 | 时延超过配置值,则会立即输出日志,记录本次调用的stage耗时信息 通过增加后缀.${service}.${schema}.${operation},可以支持4级优先级定义 |
servicecomb.metrics .Provider.invocation.slow.enabled | false | 是否开启Provide端的慢调用检测 通过增加后缀.${service}.${schema}.${operation},可以支持4级优先级定义 |
servicecomb.metrics .Provider.invocation.slow.msTime | 1000 | 时延超过配置值,则会立即输出日志,记录本次调用的stage耗时信息 通过增加后缀.${service}.${schema}.${operation},可以支持4级优先级定义 |
servicecomb.metrics .prometheus.address | 0.0.0.0:9696 | prometheus监听地址 |
servicecomb.metrics.publisher.defaultLog .enabled | false | 是否输出默认的统计日志 |
servicecomb.metrics.publisher.defaultLog .endpoints.client.detail.enabled | false | 是否输出每一条client endpoint统计日志,因为跟目标的ip:port数有关,可能会有很多数据,所以默认不输出 |
1. 基于[netflix spectator](https://github.com/Netflix/spectator) 2. Foundation-metrics通过SPI机制加载所有MetricsInitializer实现,实现者可以通过MetricsInitializer中的getOrder规划执行顺序,order数字越小,越先执行。 3. Metrics-core实现3类MetricsInitializer: 1. DefaultRegistryInitializer: 实例化并注册spectator-reg-servo,设置较小的order,保证比下面2类MetricsInitializer先执行 2. Meters Initializer: 实现TPS、时延、线程池、jvm资源等等数据的统计 3. Publisher: 输出统计结果,内置了日志输出,以及通过RESTful接口输出 4. Metrics-prometheus提供与prometheus对接的能力
因为ServiceComb已经初始化了servo的registry,所以业务不必再创建registry。实现MetricsInitializer接口,定 义业务级的Meters,或实现定制的Publisher,再通过SPI机制声明自己的实现即可。
1.Meters
创建Meters能力均由spectator提供,可查阅[netflix spectator](https://github.com/Netflix/spectator)文档
2.Publisher
周期性输出的场景,比如日志场景,通过eventBus订阅org.apache.servicecomb.foundation.metrics.PolledEvent,PolledEvent.getMeters()即是本周期的统计结果 非周期性输出的场景,比如通过RESTful接口访问,通过globalRegistry.iterator()即可得到本周期的统计结果