cover_image

流利说Prometheus监控系统实践

赵勇超 流利说技术团队
2021年05月26日 10:00

背景:

Prometheus是一种开源监控软件,由于 prometheus 易于定制告警,并且可以在不影响应用程序性能的情况下生成指标,所以在各个公司非常流行。同时,prometheus 监控消除了系统中的告警数量,仅仅发送匹配 Alerting rules 的告警,还可以通过配合 alertmanager 设置告警等级,只在发生指定等级的告警时,alertmanager 才推送告警,此外 prometheus 还根据不同监控场景(mysql,network,kafka等)衍生出多种 prometheus export,使得监控更加的灵活。
流利说 Prometheus 架构:

图片

差异:

  • 存储:我们将所有的 prometheus 的数据额外存储一份到 aliyun sls 中,这样不仅可以做到数据 backup,也可以方便 grafana 统一查询 prometheus 数据。

  • 服务发现:由于流利说拥有大量 aliyun ecs 机器,所以我们在 prometheus 原有的服务发现基础上开发了 ecs scrape 代码,以便监控ecs机器。

  • 告警:使用 pagerduty 以及正在开发的 goalert +流利说自研通知中心用于告警通知,并且支持告警调度以及告警升级。

 Gitops:

  1. 统一管理 Prometheus Config:由于流利说现有多个 prometheus 同时运行,由于每个 prometheus 所要监控的数据不同,所以需要分别配置相关 Recording rules && Alerting rules,但是如果分别管理每个prometheus config 就使得运维成本非常高。所以 infra 团队就将这些配置文件统一放到一个git仓库下,当某个 prometheus config 发生改变时,就会触发 prometheus reload,使变更立刻生效。这样我们只需管理一个配置“仓库”即可。

  2. 自动检测 Prometheus Config :由于 infra 团队会定制一些 metrics 用于告警,如果配置不准确会引起 prometheus 状态异常,所以当我们更新 prometheus config 时也会检测变更的 rule 或 metrics 是否正确,主要依靠 prometheus 自带检测工具 promtool 与流利说自研检测工具 prom-threshold 来检测。相关ci文件如下:

    stages:  - test check_rules:  stage: test  image: debian:jessie  script:    - find ./ -type f -name '*.yml' | grep -E 'alerting|recording' | grep -v 'threshold' | xargs ./bin/promtool-linux check rules  tags:    - docker check_threshold:  stage: test  image: prom-threshold:v0.1.1  script:    - find ./ -type d -name threshold | egrep '.*' || exit 0    - find ./ -type d -name threshold | xargs /prom_threshold -op check -path  tags:    - docker
  3. 自定义告警阈值:因为我们会配置一些通用的告警,但是由于业务差异,对一些告警的要求可能不同,所以我们就会给这些业务在通用告警的基础上,通过 metrics 的方式暴露业务专有指标(业务指定的告警阈值),然后通过 recordingRules 的方式修改其告警值,从而提高了告警的灵活性。

    ThresholdMetrics:- metric: http_4xx_ratio_threshold  threshold: 0.05  labels:    host: ****.com    path: /oauth/callback - metric: http_latency_95_seconds_threshold  threshold: 20  labels:    host: ****.com    path: / AlertingRule:- name: http/latency.customized  rules:  - alert: SlowHTTP    expr: service:kong_latency:quantile95_rate1m{type="request"} > on (host,path) group_left() (http_latency_95_seconds_threshold * 1000)
  4. 自研监控插件 Mercury:
    • 自动备份 AlertManagerSilence:alertmanager silence 是用户应对一些告警无法避免的情况下,对某些告警的屏蔽策略,但是 alertmanager 是在本地存储数据,为了降低 alertmanager 所在服务器的宕机风险,所以我们会实时的将 silence 数据备份一份到对象存储中。
    • 自动检查 AlertManagerSilence:由于我们的告警是按照特定规则发送到 pagerduty 然后通知给工程师的,当屏蔽告警的时候也需要按照特定规则去屏蔽,所以我们会定时去检测这些 silence 规则是否符合规范,如果不符合规范的话,就视为无效然后将其删除。
    • 自动同步生产测试环境中 Grafana Dashboard:流利说拥有两个环境的 prometheus 所以也就会对应两套 grafana,因为监控只有数据不同,但是 grafana dashboard 两个环境中可以复用,所以我们会定时同步两个环境下的 grafana dashboard,工程师只需对生产或测试环境某一个 grafana dashboard 做更改即可,从而减轻了运维成本。
    • 自动生成 AlertManagerConfig:由于我们的告警需用按照 app 或 team 发送到 pagerduty,而 pagerduty 是给每个 app 或 team 的告警生成一个 integrations(API接口),然后 alertmanager 通过这个特定的integrations,将告警发送给制定的告警策略中,由于需要告警的 app 和 team 非常多,所以在 alertmanager-config 中便会存在大量的 integrations。因此我们会在 pagerduty 生成一个 integrations 后,自动在alertmanager-config 生成相关配置。
  5. 云资源监控:
    • 流利说拥有各种各样的云资源,如果分别依靠云平台的监控系统,那么就与我们预期的统一监控不符,所以我们通过拉取云平台监控系统 api,将云资源相关指标暴露在 prometheus 中,对这些指标再针对性的配置 Recording rules && Alerting rules,从而使得云资源监控告警可以统一且灵活的配置。

      ExportCode:    switch collectType {    case "EsExporter":        es := exporter.EsExporter(newCmsClient())        prometheus.MustRegister(es)    case "HbaseExporter":        hbase := exporter.HbaseExporter(newCmsClient())        prometheus.MustRegister(hbase)    case "KafkaExporter":        kafka := exporter.KafkaExporter(newCmsClient())        prometheus.MustRegister(kafka)    case "KvstroeExporter":        kvstroe := exporter.KvstoreExporter(newDbClient())        prometheus.MustRegister(kvstroe)    case "NatExporter":        nat := exporter.NatExporter(newCmsClient())        prometheus.MustRegister(nat)    case "OssExporter":        oss := exporter.OssExporter(newCmsClient())        prometheus.MustRegister(oss)    case "RdsExporter":        rds := exporter.RdsExporter(newDbClient())        prometheus.MustRegister(rds)    case "SlbExporter":        slb := exporter.SlbExporter(newCmsClient())        prometheus.MustRegister(slb)    } AlertingRule:groups:- name: rds.rules  rules:  - alert: RdsConnectionOutOfUsage    expr: avg_over_time(cloudmonitor_rds_connection_usage[5m]) + on (instanceid) group_left(app,team,owner,name) avg_over_time(alicloud_rds_tags[1m]) >80    for: 3m    labels:      severity: critical      prometheus: prometheus      k8s_cluster: k8s      source: rds    annotations:      summary: "{{ $labels.app }} {{ $labels.name }} {{ $labels.instanceid }} rds connection_usage out of 80% for 3 minutes"      details: "{{ $labels.app }} {{ $labels.name }} {{ $labels.instanceid }} rds connection_usage is out of 80% for 3 minutes \n  Current value: {{ $value }}%"
    • 云平台提供的监控相关指标还满足不了我们的监控需求,所以我们还会额外生成一些 export,比如 mysql_export, node_export, blackbox_export, kafka_export,然后在再通过分析这些 export 暴露出来的指标,以满足我们的需求。
      0 */1 * * * bash /opt/cloudmonitor/cloudmonitor_cronjob.sh >> /opt/cloudmonitor/cronjob.log 2>&1

监控告警系统:

在流利说,一个服务会关联多种资源(数据库,kafka,kubernetes 等)所以相关的告警会有很多,如果由一个人负责处理这些告警的话,会非常繁琐,而且当工作繁忙时难免会忽略某个告警。为了避免这两种情况,我们对每个服务都配置了告警排班升级策略,使得告警变得更加灵活。
  • 告警升级策略:我们会为每个需要告警的 app,配置相关告警升级策略,升级策略分为多层,每一层对应一个或多个人,当告警通知到某一层,无人响应时,会升级到下一层中,从而使告警减少被忽略的情况。
  • 告警排班策略:对应告警升级策略中的某一层,如果这一层是多个人接受告警,可能会存在告警排班(多个人轮流接收告警)的情况,所以会配置相关的 schedule,某个人只在特定时间段内接收告警,减少工作冗余。
监控延伸:

服务可用性SLA:prometheus 的 Recording rules 功能非常的强大,所以流利说通过此规则延伸出了服务 SLA 监控,主要是通过 kong mertics 计算 HTTP SLA,通过 istio metrics 计算 GRPC SLA。

  • HTTP SLA:因为用户的所有请求都会经过 kong(网关),所以 kong 上可以记录下每个域名的 http_status,再通过相关的 Recording rules 计算出每个 http 请求的相关指标对应到 HTTP SLA。
  • GRPC SLA:流利说的服务基本都在 k8s 中运行,一个大型的服务又分为多个微服务,为了便于观察控制每个微服务,我们给 k8s 集群中接入了 istio 服务网格,因为 istio 可以记录并暴露出来微服务之间的调用指标,所以我们通过这些指标也计算出每个微服务的可用性,从而计算出 GRPC SLA。

展望:

存储:现在我们监控数据存储了一份到阿里云 SLS 时序存储中,后期为了以云原生存储为标准和降低云成本,我们会在保证业务稳定的情况下考虑 cortx 存储方案。
告警:后期我们会通过更改 goalert 代码,让 alertmanager 告警先发到 goalert,在 goalert 完成排班调度升级策略后,再发送到我们自己的通知中心,最终通过指定的通知方式通知给工程师。告警流程相关 call graph 如下:


图片


作者简介


赵勇超  技术部 cloud-infra 团队 后端工程师



继续滑动看下一个
流利说技术团队
向上滑动看下一个