背景
大数据集群的维护本身是充满挑战的,庞大的数据量、复杂的运算逻辑、关联的大数据组件、一个企业级的集群往往有PB 级的数据、成百上千和各式运算任务 在一套集群上运行。 所以运维如果想不是很被动的话,就必须做好各式监控,预防风险、发现风险、分析问题、进而针对性的处理问题。
因为大数据集群一旦出问题,往往就已经很难处理了 ,所以监控要前置,有趋势预测、有风险评估、才行。
针对这些,我们要从多个维度入手对大数据集群进行基础监控:
如下,我们对整个集群的基础监控主要分为三大维度:
- 底层服务监控:服务器底层的CPU、内存、IO、磁盘 等;
- Hadoop性能监控:各式组件各维度性能监控;
- Runtime 监控:自定义脚本轮训服务;
底层服务监控借助 Zabbix,这个很简单,不再详赘了。
这里主要说下第二个维度: 组件性能监控。
CDH 组件性能监控
对 CDH 组件的性能监控,如上图,我们借助 Prometheus + AlertManager + Grafana 的架构方式。
- 写一个 exporter ,从 Cloudera Manager 的 API 中取出各式组件的 Metrics 。
- 借助 Alertmanager 对需要的 metrics 进行告警。
- 写一个 钉钉告警API 供 Alertmanager 调用。
- 将 Prometheus data source 接入 Grafana 做报表展示。
这里具体的代码与实现细节,不展开了,否则太多,主要是将大概的思路和实现方式以及官网地址交待清楚:
一、明确要获取的 Metrics
首先我们要明确有哪些Metrics 可以供我们获取,或者说我们从哪里挑到 可以获取的 Metrics 列表。 这一步我们从 Cloudera Manager 官网可以看到:
https://docs.cloudera.com/documentation/enterprise/5-15-x/topics/cm_metrics.html
这里有所有的 CM 组件相关 Metrics,我们随便点一个进去,可以看到 组件的 Metrics 详细信息,有描述,也有单位等:
如果我们对这些 Metrics 还不是很懂的话,其实可以借助 Cloudera Manager 的图表生成器:
如上,其实这些 Metric 从 CM 的图标生成器也可以查到,并且有自动匹配功能和中文释义,非常方便。
二、Cloudera Manager 的 API 接口交互
与 Cloudera Manager 的接口交互当然也是看官方文档:http://cloudera.github.io/cm_api/apidocs/v19/
API 对应的官方文档里面有大量的接口调用方式,包括一些动作、状态、Metrics 获取等。这里我们暂时只关注 Metrics 获取,我们会发现,官方文档中所有的 Metrics 获取都建议我们走时序型接口:
如上,所有关于角色的 Metrics 建议我们走 时序型 API 去获取:
最简单的一个 Python 代码调用示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[root@aly-bigdata-hadoop-op-manager01 cdh_exporter]# cat test.py import os import requests import pdb import urllib import json import re,pdb uri = "http://admin:xxxxxxxxxx@10.x.x.x:7180/api/v11/timeseries?query=" cut_metrics_list = ['health_good_rate'] if __name__ == "__main__": for key in cut_metrics_list: url = "%sselect%s%s" % (uri, '%20', key) request = requests.get(url=url) jsondata = json.loads(request.text) print(jsondata) |
得到的结果如下:
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
{ 'items': [{ 'timeSeries': [{ 'metadata': { 'metricName': 'hive_init_total_count_dbs', 'entityName': 'Hive Metastore Server (xxxxxxxxxxx)', 'startTime': '2020-02-14T02:03:24.195Z', 'endTime': '2020-02-14T02:08:24.195Z', 'attributes': { 'serviceType': 'HIVE', 'clusterDisplayName': 'Cluster 1', 'hostId': '30445931-7e77-45c7-866b-c76570f23f68', 'active': 'true', 'serviceDisplayName': 'Hive', 'roleType': 'HIVEMETASTORE', 'serviceName': 'hive', 'version': 'CDH 5.15.1', 'hostname': 'xxxxxxxxxxxxxxxxxxxxxxxxxxx', 'entityName': 'hive-HIVEMETASTORE-c21650341c1d5e74b49a9322c129b687', 'clusterName': 'cluster', 'roleName': 'hive-HIVEMETASTORE-c21650341c1d5e74b49a9322c129b687', 'roleConfigGroup': 'Hive Metastore Server Default Group', 'category': 'ROLE', 'rackId': '/bx/A136' }, 'unitNumerators': ['databases'], 'unitDenominators': [], 'expression': 'SELECT hive_init_total_count_dbs WHERE entityName = "hive-HIVEMETASTORE-c21650341c1d5e74b49a9322c129b687" AND category = ROLE', 'metricCollectionFrequencyMs': 60000, 'rollupUsed': 'RAW' }, 'data': [{ 'timestamp': '2020-02-14T02:04:10.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:05:10.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:06:10.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:07:10.000Z', 'value': 77.0, 'type': 'SAMPLE' }] }, { 'metadata': { 'metricName': 'hive_init_total_count_dbs', 'entityName': 'Hive Metastore Server (xxxxxxxxxxxxxxxxxxxxxx)', 'startTime': '2020-02-14T02:03:24.195Z', 'endTime': '2020-02-14T02:08:24.195Z', 'attributes': { 'serviceType': 'HIVE', 'clusterDisplayName': 'Cluster 1', 'hostId': '50f09ed6-edbc-4c9c-9b58-1b12aede6dbe', 'active': 'true', 'serviceDisplayName': 'Hive', 'serviceName': 'hive', 'roleType': 'HIVEMETASTORE', 'version': 'CDH 5.15.1', 'hostname': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'entityName': 'hive-HIVEMETASTORE-79cc572c14eb65bedf5e1f761f0898bb', 'clusterName': 'cluster', 'roleName': 'hive-HIVEMETASTORE-79cc572c14eb65bedf5e1f761f0898bb', 'roleConfigGroup': 'Hive Metastore Server Default Group', 'category': 'ROLE', 'rackId': '/bx/A135' }, 'unitNumerators': ['databases'], 'unitDenominators': [], 'expression': 'SELECT hive_init_total_count_dbs WHERE entityName = "hive-HIVEMETASTORE-79cc572c14eb65bedf5e1f761f0898bb" AND category = ROLE', 'metricCollectionFrequencyMs': 60000, 'rollupUsed': 'RAW' }, 'data': [{ 'timestamp': '2020-02-14T02:03:36.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:04:36.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:05:36.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:06:36.000Z', 'value': 77.0, 'type': 'SAMPLE' }, { 'timestamp': '2020-02-14T02:07:36.000Z', 'value': 77.0, 'type': 'SAMPLE' }] }], 'warnings': [], 'timeSeriesQuery': 'select hive_init_total_count_dbs' }] } |
如上,就可以获取到对应 Metrics 相关值 。
三、自己写 Exporter 从 Cloudera Manager 获取 Metrics 数据
这里用 Python 写一个 Exporter ,获取数据,因为涉及到的 Metrics 很多,所以采取多线程并发的方式去获取。
这里主要借助 Python的这个库:https://github.com/prometheus/client_python#instrumenting
这个 Python 包里有大量 prometheus exporter client 方式,可以参考使用。
这块的代码就不再这里详细赘述了,总体来说,开 30个线程并发,取 几百个 Item,最终入Prometheus 的时候大概 几万个 Metric ,总共需要约 8 s 多。
四、搭建配置 AlertManager ,并实现自定义钉钉告警接口
数据入到 Prometheus 之后,我们当然要去设置针对一些Metrics 的告警阈值,这里借助和Prometheus 的告警插件 AlertManager,AlertManager 的安装很简单,这里不再详赘,之前的 Prometheus初探 一文中已经说过,这里主要说下配置相关:
关于相关配置可以参考官方文档:https://prometheus.io/docs/alerting/configuration/
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 |
[root@aly-bigdata-hadoop-op-monitor01 alertmanager-0.16.2.linux-amd64]# cat alertmanager.yml global: resolve_timeout: 5m route: group_by: ['alertname'] group_wait: 30s group_interval: 30s repeat_interval: 15m receiver: 'web.hook' routes: - match: severity: 'critical' receiver: 'web.hook' receivers: - name: 'web.hook' webhook_configs: - url: 'http://10.25.x.x:5000/ding_alert' send_resolved: true inhibit_rules: - source_match: severity: 'critical' target_match: severity: 'warning' equal: ['alertname', 'dev', 'instance'] |
如上,我们在 AlertManager 中加了这些配置,它的配置总体来说主要是包括 routes 告警转发路由,receiver 告警接收器,inhibit_rule 告警收敛规则 等。
如上,我们默认将报警都发给了我们自己实现的一个 http://10.25.x.x:5000/ding_alert webhook,其实是用 Python 写的一个钉钉告警接收器。
五、Flask 钉钉告警网关
正如上面所说,我们自己实现一个简单的钉钉告警接收器,用 Flask 实现,可以让 AlertManager 通过 5000 端口调用发送钉钉告警,这里主要是要注意处理发送与接收格式:
相关代码简要如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
alert_text = "### %s \n" % (alert_title,) +\ "- 告警名称: %s\n" % (alert_name) +\ "- 监控项目: %s\n" % (alert_key,) +\ "- 告警消息: %s\n" % (alert_message,) +\ "- 告警阈值: %s\n" % (alert_threshold,) +\ "- 当前数值: %s\n" % (alert_value,) +\ "- 告警时间: %s\n" % (alert_startime,) elif alert_status == 'resolved': alert_title = "CDH 集群监控: 恢复通知" alert_name = alert_item['labels']['alertname'] alert_message = alert_item['annotations']['summary'] alert_key = alert_item['annotations']['monitoritem'] alert_threshold = alert_item['annotations']['threshold'] alert_value = alert_item['annotations']['value'] alert_endtime = strtime(str(alert_item['endsAt'])) alert_text = "### %s \n" % (alert_title,) +\ "- 恢复名称: %s\n" % (alert_name) +\ "- 监控项目: %s\n" % (alert_key,) +\ "- 恢复消息: %s\n" % (alert_message,) +\ "- 告警阈值: %s\n" % (alert_threshold,) +\ "- 当前数值: %s\n" % (alert_value,) +\ "- 恢复时间: %s\n" % (alert_endtime,) |
六、Prometheus 中配置 AlertManager ,并添加配置告警项
前面的准备好之后,我们还需要配置 Prometheus 告诉它哪些需要告警,并且把AlertManager 加进去:
先是 Prometheus 的主配置文件:
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 50 51 |
[root@aly-bigdata-hadoop-op-monitor01 prometheus-2.13.1]# cat prometheus.yml # my global config global: scrape_interval: 30s # Set the scrape interval to every 15 seconds. Default is every 1 minute. evaluation_interval: 30s # Evaluate rules every 15 seconds. The default is every 1 minute. scrape_timeout: 30s # scrape_timeout is set to the global default (10s). external_labels: monitor: 'prometheus-monitor' # Alertmanager configuration alerting: alertmanagers: - static_configs: - targets: ['10.25.x.x:9093'] # 这里配置 AlertManager 的地址 # 这里配置的是告警规则 # Load rules once and periodically evaluate them according to the global 'evaluation_interval'. rule_files: - "rules/canary_alert_rules.yml" - "rules/cm_alert_rules.yml" - "rules/component_health_alert_rules.yml" - "rules/dns_alert_rules.yml" - "rules/hdfs_alert_rules.yml" - "rules/host_health_alert_rules.yml" - "rules/jvm_alert_rules.yml" - "rules/oom_alert_rules.yml" - "rules/yarn_alert_rules.yml" # 下面这些是 exporter # 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' scrape_interval: 5s static_configs: - targets: ['10.25.x.x:8091'] # 我们上面实现的 CDH 的 Exporter - job_name: 'cdh' scrape_interval: 60s static_configs: - targets: ['10.25.x.x:9990'] |
监控项我们放在单独的 rules 目录的文件下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
[root@aly-bigdata-hadoop-op-monitor01 rules]# ls canary_alert_rules.yml dns_alert_rules.yml host_health_alert_rules.yml yarn_alert_rules.yml cm_alert_rules.yml hdfs_alert_rules.yml jvm_alert_rules.yml component_health_alert_rules.yml hive_alert_rules.yml oom_alert_rules.yml [root@aly-bigdata-hadoop-op-monitor01 rules]# [root@aly-bigdata-hadoop-op-monitor01 rules]# [root@aly-bigdata-hadoop-op-monitor01 rules]# [root@aly-bigdata-hadoop-op-monitor01 rules]# cat canary_alert_rules.yml groups: - name: canary_duration_alert_rule rules: - alert: 'CDH 各canary持续时间报警' expr: canary_duration > 10000 for: 1m labels: severity: critical annotations: summary: "CDH 的{{ $labels.entityName }} canary持续时间恢复" description: "CDH 的{{ $labels.entityName }} canary持续时间超过10s." value: "{{ $value }}" threshold : "{{ $value }} > 10000时报警" monitoritem: "{{ $labels.__name__ }}" |
七、Grafana 接入 Prometheus
其实前六步昨晚之后,数据就已经入到我们的 Prometheus 了,可以在Prometheus 上查到:
如上图,我们点击 Graph ,然后输入 Metrics 名称或正则匹配就可以查到,点击 图片中间的 Graph还可以看到图形。
当然,我们配置的 Alert 也是可以在这里看到的:
甚至我们可以像 Zabbix一样看到告警相关的 Reports:
当然最重要的是也能收到相关的钉钉告警:
但是单纯的收到告警信息不行,我们需要一个炫酷的,有维度的监控展示。 Grafana 是很好的选择,我们只需要将 Prometheus 作为 Datasource 纳入 Grafana,即可构建丰富的报表展示:
总结
至此,我们就完成了我们的基础监控部分。 可以随着各式各样的需求逐步完善收集 Metrics 即可。 既有告警信息、又有丰富的图形展示,而且很灵活,方便调配。
但这只是基础监控,距离我们掌控运维好集群还有很大的距离,后续还要继续补充几个维度:
- 元数据监控。
- 业务运行日志与任务状态监控。
- 定时统计报表发送等。
其实每个维度想要做好都很难,会在后续的时间过程中持续更新此系列博客。