微服务实例监控
1.现状&背景
1.1 背景
事故一:资料微服务,双节点实例,宕机了一个实例,已经宕机了24小时了,但并未发觉,到第二天高峰期时,单节点抗压不住,导致资料列表和详情接口报大量的缓慢。
事故二:计费服务,双节点实例,其中一个节点元空间溢出,节点假死,导致下载结算相关业务一直处于等待中,影响到了用户正常使用。
基于以上线上事故,我们缺乏一个对服务实例级别的监控,能够监控实例的存活状态,资源使用情况,在服务实例状态异常或者资源使用即将饱和时,能够提前进行预警,进行人工干预。
1.2 现状
目前我们是基于Prometheus进行指标收集,已经收集了JVM相关的指标,以及基于Consul监控了实例的健康状态,但是我们目前使用的却是Grafana告警,Grafana只能针对每一个具体的实例才能添加告警,并且不支持动态变量的方式,我们的面板都是通过变量的方式动态创建的,所以Grafana告警并不适用于我们,即使适用,我们的创建告警成本很高。为了对所有服务实例进行统一的一套实例级别的告警规则,所以采用Prometheus+AlertManager+Webhook的方式进行更灵活的的告警。
2.定义监测指标
(1)告警级别
告警级别暂分为:警告,严重。
(2)告警指标
服务存活监控:服务宕机时间持续1min,即触发告警(严重)。
JVM堆内存使用率:JVM堆内存使用率持续1min超过50%(警告),JVM堆内存使用率持续1min超过80%(严重)。
JVM元空间使用率:JVM元空间使用率持续1min超过80%(严重)。
系统CPU使用率:系统cpu使用率在连续5min内,超过80%(严重)。
3.系统架构
4.环境搭建
4.1 升级prometheus到2.31.1
cd /dataes/prometheus-2.31.1
touch start.sh
## prometheus的启动脚本
nohup ./prometheus --config.file=prometheus.yml --web.enable-lifecycle --web.max-connections=512 --storage.tsdb.retention.time=15d --query.timeout=2m --query.max-concurrency=20 --web.read-timeout=5m --web.external-url=http://10.1.25.34:9090 > ./logs/start.log 2>&1 &
## 访问地址
http://10.1.25.34:9090
## 配置重载
curl -v --request POST 'http://localhost:9090/-/reload'
4.2 升级grafana到8.3.2
cd /dataes/grafana-8.3.2
touch start.sh
## 启动grafana
nohup ./bin/grafana-server web > ./logs/start.log 2>&1 &
## 访问地址
http://10.1.25.34:3000
4.3 搭建alertmanager-0.20.0
cd /dataes/alertmanager-0.20.0
touch start.sh
## 启动告警服务
nohup ./alertmanager --config.file=alertmanager.yml > ./logs/start.log 2>&1 &
## 访问地址
http://10.1.25.34:9093/
## 配置重载
curl -v --request POST 'http://localhost:9093/-/reload'
4.4 搭建prometheus-webhook-dingtalk-1.4.0
cd /dataes/prometheus-webhook-dingtalk-1.4.0
touch start.sh
## 启动dingtalk
nohup ./prometheus-webhook-dingtalk > ./start.log 2>&1 &
5.实施步骤
5.1 promethues.yml配置告警管理器和consul服务发现
# my global config
global:
scrape_interval: 15s # 设置抓取数据时间间隔为15s,不设置的话默认一分钟
evaluation_interval: 15s # 设置分析数据时间间隔为15s,不设置的话默认一分钟
# scrape_timeout is set to the global default (10s).
# 告警配置
alerting:
alertmanagers:
- static_configs:
- targets:
- 10.1.25.34:9093
# 告警规则配置
rule_files:
- "rules/*.yml"
# - "second_rules.yml"
# 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"
# metrics_path defaults to '/metrics'
# scheme defaults to 'http'.
static_configs:
- targets: ["localhost:9090"]
# consul acl version for microservice 配置
- job_name: 'zxxk_consul_microservice_acl'
scrape_interval: 15s
consul_sd_configs:
- server: '10.1.25.52:9600'
token: cff6f144-aa79-319d-7632-f62922536137
datacenter: 'amc'
refresh_interval: 5s
relabel_configs:
- source_labels: [__metrics_path__]
regex: /metrics
target_label: __metrics_path__
replacement: /actuator/prometheus # 必须这样否则会404
action: replace
- source_labels: [__meta_consul_tags]
separator: ;
regex: (.*)(,contextPath=)(.*)(,dubbo.metadata)(.*)
target_label: __metrics_path__
replacement: $3/actuator/prometheus # 必须这样否则会404
action: replace
# 单独openapi-settlement-admin一个应用在使用该匹配,项目下线后即可删除以下label重写
- source_labels: [__meta_consul_tags]
separator: ;
regex: (.*)(,contextPath=/videoapi)(,)
target_label: __metrics_path__
replacement: /videoapi/actuator/prometheus # 必须这样否则会404
action: replace
- source_labels: [__meta_consul_tags]
regex: (,)(.*)(,tag=)(dsp|bsp|site|app|openapi)(,)(.*)
replacement: $4
target_label: product
- source_labels: [__meta_consul_tags]
regex: (,)(.*)(,secure=false,)(.*)
replacement: $2
target_label: product
- source_labels: [__meta_consul_dc]
target_label: idc
- source_labels: [__meta_consul_service]
target_label: service
- source_labels: [__meta_consul_service]
target_label: service
regex: .*consul.*
action: drop
- source_labels: [__meta_consul_service_address]
target_label: host
- source_labels: [__meta_consul_service_id]
target_label: job
# consul-self sever 配置
- job_name: 'zxxk_linux_consul'
scrape_interval: 30s
metrics_path: "/v1/agent/metrics"
params:
format: ['prometheus']
bearer_token: "026d869a-4d4c-91f9-e16e-4413d681d8d1"
static_configs:
- targets: ['10.1.1.25:9600','10.1.1.25:9500', '10.1.1.22:9600','10.1.1.22:9500','10.1.25.52:9600','10.1.1.36:9500']
5.2 编写告警规则app-rule.yml
groups:
- name: "app"
rules:
# 告警名称 alertname
- alert: "服务实例存活告警"
# 告警表达式,当表达式条件满足,即发送告警
expr: up{idc="amc"} == 0
# 等待时长,等待自动恢复的时间。
for: 1m
# 此label不同于 metric中的label,发送给alertmanager之后用于管理告警项,比如匹配到那个label即触发哪种告警
labels:
# key:value 皆可完全自定义
severity: 严重
# 定义发送告警的内容,注意此地的labels为metric中的label
annotations:
summary: "{{$labels.service}}"
description: "{{$labels.service}}-{{$labels.instance}}:已停止运行,持续时间已超过1min"
value: "已宕机"
- alert: "CPU 使用率超过80%"
expr: 100-(avg(rate(system_cpu_usage{idc="amc"}[5m])) by(host)* 100) > 80
for: 1m
labels:
severity: 严重
annotations:
summary: "{{$labels.host}}"
description: "{{$labels.host}} 宿主机5分钟内,CPU使用率超过80%,持续时间已超过1min"
value: "{{$value}} %"
- alert: "jvm堆内存使用率超过60%"
expr: jvm_memory_used_bytes{idc="amc",area="heap"} / jvm_memory_max_bytes{idc="amc",area="heap"} * 100 > 60
for: 1m
labels:
severity: 警告
annotations:
summary: "{{$labels.serveice}}"
description: "{{$labels.service}}-{{$labels.instance}} 堆内存使用率>60%, 持续时间已超过1min"
value: "{{$value}} %"
- alert: "jvm堆内存使用率超过80%"
expr: jvm_memory_used_bytes{idc="amc",area="heap"} / jvm_memory_max_bytes{idc="amc",area="heap"} * 100 > 80
for: 1m
labels:
severity: 严重
annotations:
summary: "{{$labels.serveice}}"
description: "{{$labels.service}}-{{$labels.instance}} 堆内存使用率>80%, 持续时间已超过1min"
value: "{{$value}} %"
- alert: "jvm元空间使用率超过80%"
expr: jvm_memory_used_bytes{idc="amc",area="nonheap",id="Metaspace"} / jvm_memory_max_bytes{idc="amc",area="nonheap",id="Metaspace"} * 100 > 80
for: 1m
labels:
severity: 警告
annotations:
summary: "{{$labels.serveice}}"
description: "{{$labels.service}}-{{$labels.instance}} 元空间使用率>80%, 持续时间已超过1min"
value: "{{$value}} %"
5.3 告警管理器alertmanager.yml配置
global:
resolve_timeout: 5m #每5分钟检查一次状态是否恢复
route:
group_by: ['alertname'] #采用哪个标签来作为分组依据
group_wait: 10s # 等待多长时间进行汇总发送
group_interval: 5m #相同组之间发生告警通知的时间间隔
repeat_interval: 10m #重复报警间隔时间
receiver: 'web.hook' #配置的默认的告警消息接受者信息,例如常用的 email、wechat、slack、webhook 等消息通知方式。
#子路由,子路由的配置会覆盖默认路由,默认路由的配置会被子路由继承
routes:
- receiver: app_dingding
# 接收人列表
receivers:
- name: 'app_dingding'
webhook_configs:
- send_resolved: true #警报被解决之后是否通知
url: 'http://localhost:8060/dingtalk/app-webhook/send'
# 例如:当另一个告警的级别并且告警标签中的instance值跟alertName相同,则进行抑制
inhibit_rules: # 抑制规则配置,当存在与另一组匹配的警报(源)时,抑制规则将禁用与一组匹配的警报(目标)。
- source_match:
alertName: 'alertName'
severity: 'critical'
target_match:
severity: 'critical'
equal: ['instance']
5.4 prometheus-webhook-dingtalk的config.yml配置
## Request timeout
# timeout: 5s
## Customizable templates path
templates:
- templates/app-dingding.tmpl
## Targets, previously was known as "profiles"
targets:
app-webhook:
url: https://oapi.dingtalk.com/robot/send?access_token=fe0bcdb63cb07a2946dc76fd094d081ef34c1a9961a546aaff5c72b4bf016b83
secret: SEC351f9035d8ac2129259bdf9369639757a43476b63813dadead09de5137967304
message:
# Use legacy template
#title: '{{ template "legacy.title" . }}'
text: '{{ template "app-dingding" . }}'
5.5 告警提示信息模板app-dingding.tmpl
{{ define "app-dingding" }}
{{ range $i, $alert :=.Alerts }}
【系统报警】
告警状态:{{ .Status }}
告警级别:{{ $alert.Labels.severity }}
告警应用:{{ $alert.Annotations.summary }}
告警详情:{{ $alert.Annotations.description }}
当前值:{{ $alert.Annotations.value }}
告警主机:{{ $alert.Labels.host }}
告警时间:{{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}
{{ end }}
{{ end }}
6. 效果展示
(1)Prometheus的规则展示
(2)Alertmanager告警展示
(3)钉钉群消息
7. 下一步计划
1.Prometheus指标丰富,增加更多的关键性指标,流量预警等。
2.告警路由细化,可以根据监控对象的业务标签,分组路由到不同的钉钉群。
3.钉钉通知自动化,可以自动通知项目组或者业务组的主要@负责人。