監(jiān)控新星 | 實戰(zhàn)Prometheus搭建監(jiān)控系統(tǒng)

Prometheus是一款基于時序數(shù)據(jù)庫的開源監(jiān)控告警系統(tǒng),說起Prometheus則不得不提SoundCloud,這是一個在線音樂分享的平臺,類似于做視頻分享的YouTube,由于他們在微服務(wù)架構(gòu)的道路上越走越遠,出現(xiàn)了成百上千的服務(wù),使用傳統(tǒng)的監(jiān)控系統(tǒng)StatsD和Graphite存在大量的局限性,于是他們在2012年開始著手開發(fā)一套全新的監(jiān)控系統(tǒng)。Prometheus的原作者是Matt T. Proud,他也是在2012年加入SoundCloud的,實際上,在加入SoundCloud之前,Matt一直就職于Google,他從Google的集群管理器Borg和它的監(jiān)控系統(tǒng)Borgmon中獲取靈感,開發(fā)了開源的監(jiān)控系統(tǒng)Prometheus,和Google的很多項目一樣,使用的編程語言是Go。
很顯然,Prometheus作為一個微服務(wù)架構(gòu)監(jiān)控系統(tǒng)的解決方案,它和容器也脫不開關(guān)系。早在2006年8月9日,Eric Schmidt在搜索引擎大會上首次提出了云計算(Cloud Computing)的概念,在之后的十幾年里,云計算的發(fā)展勢如破竹。在2013年,Pivotal的Matt Stine又提出了云原生(Cloud Native)的概念,云原生由微服務(wù)架構(gòu)、DevOps和以容器為代表的敏捷基礎(chǔ)架構(gòu)組成,幫助企業(yè)快速、持續(xù)、可靠、規(guī)模化地交付軟件。為了統(tǒng)一云計算接口和相關(guān)標(biāo)準(zhǔn),2015年7月,隸屬于Linux基金會的云原生計算基金會(CNCF,Cloud Native Computing Foundation)應(yīng)運而生。第一個加入CNCF的項目是Google的Kubernetes,而Prometheus是第二個加入的(2016 年)。
目前Prometheus已經(jīng)廣泛用于Kubernetes集群的監(jiān)控系統(tǒng)中,對Prometheus的歷史感興趣的同學(xué)可以看看SoundCloud的工程師Tobias Schmidt在2016年的PromCon大會上的演講:The History of Prometheus at SoundCloud。
一、Prometheus概述
A multi-dimensional data model, so that data can be sliced and diced at will, along dimensions like instance, service, endpoint, and method. Operational simplicity, so that you can spin up a monitoring server where and when you want, even on your local workstation, without setting up a distributed storage backend or reconfiguring the world. Scalable data collection and decentralized architecture, so that you can reliably monitor the many instances of your services, and independent teams can set up independent monitoring servers. Finally, a powerful query language that leverages the data model for meaningful alerting (including easy silencing) and graphing (for dashboards and for ad-hoc exploration).
多維度數(shù)據(jù)模型
方便的部署和維護
靈活的數(shù)據(jù)采集
強大的查詢語言

二、安裝Prometheus server
2.1 開箱即用
$ wget https://github.com/prometheus/prometheus/releases/download/v2.4.3/prometheus-2.4.3.linux-amd64.tar.gz$ tar xvfz prometheus-2.4.3.linux-amd64.tar.gz
cd prometheus-2.4.3.linux-amd64./prometheus --versionprometheus, version 2.4.3 (branch: HEAD, revision: 167a4b4e73a8eca8df648d2d2043e21bdb9a7449)build user: root@1e42b46043e9build date: 20181004-08:42:02go version: go1.11.1
./prometheus --config.file=prometheus.yml sudo docker run -d -p 9090:9090 prom/prometheus$ sudo docker run -d -p 9090:9090 \ -v ~/docker/prometheus/:/etc/prometheus/ \ prom/prometheus~/docker/prometheus/prometheus.yml,這樣可以方便編輯和查看,通過-v參數(shù)將本地的配置文件掛載到/etc/prometheus/位置,這是prometheus在容器中默認加載的配置文件位置。如果我們不確定默認的配置文件在哪,可以先執(zhí)行上面的不帶-v參數(shù)的命令,然后通過docker inspect命名看看容器在運行時默認的參數(shù)有哪些(下面的Args參數(shù)):$ sudo docker inspect 0c[]"Id": "0c4c2d0eed938395bcecf1e8bb4b6b87091fc4e6385ce5b404b6bb7419010f46","Created": "2018-10-15T22:27:34.56050369Z","Path": "/bin/prometheus","Args": ["--config.file=/etc/prometheus/prometheus.yml","--storage.tsdb.path=/prometheus","--web.console.libraries=/usr/share/prometheus/console_libraries","--web.console.templates=/usr/share/prometheus/consoles"],[]
2.3 配置Prometheus
--config.file來指定,配置文件格式為YAML。我們可以打開默認的配置文件prometheus.yml看下里面的內(nèi)容:/etc/prometheus $ cat prometheus.yml# my global configglobal:scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.# scrape_timeout is set to the global default (10s).# Alertmanager configurationalerting:alertmanagers:- static_configs:- targets:# - alertmanager:9093# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.rule_files:# - "first_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']
global塊:Prometheus的全局配置,比如
scrape_interval表示Prometheus多久抓取一次數(shù)據(jù),evaluation_interval表示多久檢測一次告警規(guī)則;alerting塊:關(guān)于Alertmanager的配置,這個我們后面再看;
rule_files塊:告警規(guī)則,這個我們后面再看;
scrape_config 塊:這里定義了Prometheus要抓取的目標(biāo),我們可以看到默認已經(jīng)配置了一個名稱為
prometheus的job,這是因為Prometheus在啟動的時候也會通過HTTP接口暴露自身的指標(biāo)數(shù)據(jù),這就相當(dāng)于Prometheus自己監(jiān)控自己,雖然這在真正使用Prometheus時沒啥用處,但是我們可以通過這個例子來學(xué)習(xí)如何使用Prometheus;可以訪問http://localhost:9090/metrics查看Prometheus暴露了哪些指標(biāo);
三、學(xué)習(xí)PromQL
http://localhost:9090/即可,它默認會跳轉(zhuǎn)到Graph頁面:
promhttp_metric_handler_requests_total,這個指標(biāo)表示/metrics頁面的訪問次數(shù),Prometheus就是通過這個頁面來抓取自身的監(jiān)控數(shù)據(jù)的。在Console標(biāo)簽中查詢結(jié)果如下:
scrape_interval參數(shù)是15s,也就是說Prometheus每15s訪問一次/metrics頁面,所以我們過15s刷新下頁面,可以看到指標(biāo)值會自增。在Graph標(biāo)簽中可以看得更明顯:
3.1 數(shù)據(jù)模型
promhttp_metric_handler_requests_total{code="200",instance="192.168.0.107:9090",job="prometheus"} 106promhttp_metric_handler_requests_total,并且包含三個標(biāo)簽code、instance和job,這條記錄的值為106。上面說過,Prometheus是一個時序數(shù)據(jù)庫,相同指標(biāo)相同標(biāo)簽的數(shù)據(jù)構(gòu)成一條時間序列。如果以傳統(tǒng)數(shù)據(jù)庫的概念來理解時序數(shù)據(jù)庫,可以把指標(biāo)名當(dāng)作表名,標(biāo)簽是字段,timestamp是主鍵,還有一個float64類型的字段表示值(Prometheus里面所有值都是按float64存儲)。Counter
Gauge
Histogram
Summary
3.2 PromQL入門
# 表示 Prometheus 能否抓取 target 的指標(biāo),用于 target 的健康檢查up
up{instance="192.168.0.107:9090",job="prometheus"} 1up{instance="192.168.0.108:9090",job="prometheus"} 1up{instance="192.168.0.107:9100",job="server"} 1up{instance="192.168.0.108:9104",job="mysql"} 0
up{job="prometheus"}=號,還可以使用!=、=~、!~,比如下面這樣:up{job!="prometheus"}up{job=~"server|mysql"}up{job=~"192\.168\.0\.107.+"}
=~ 是根據(jù)正則表達式來匹配,必須符合RE2的語法。http_requests_total[5m]Range vector,沒辦法在Graph上顯示成曲線圖,一般情況下,會用在Counter類型的指標(biāo)上,并和rate()或irate()函數(shù)一起使用(注意rate和irate的區(qū)別)。計算的是每秒的平均值,適用于變化很慢的 counterper-second average rate of increase, for slow-moving countersrate(http_requests_total[5m])# 計算的是每秒瞬時增加速率,適用于變化很快的 counterper-second instant rate of increase, for volatile and fast-moving countersirate(http_requests_total[5m])
count、sum、min、max、topk等 聚合操作,還支持rate、abs、ceil、floor等一堆的 內(nèi)置函數(shù),更多的例子,還是上官網(wǎng)學(xué)習(xí)吧。如果感興趣,我們還可以把PromQL和SQL做一個對比,會發(fā)現(xiàn)PromQL語法更簡潔,查詢性能也更高。3.3 HTTP API
GET /api/v1/query
GET /api/v1/query_range
GET /api/v1/series
GET /api/v1/label/<label_name>/values
GET /api/v1/targets
GET /api/v1/rules
GET /api/v1/alerts
GET /api/v1/targets/metadata
GET /api/v1/alertmanagers
GET /api/v1/status/config
GET /api/v1/status/flags
POST /api/v1/admin/tsdb/snapshot
POST /api/v1/admin/tsdb/delete_series
POST /api/v1/admin/tsdb/clean_tombstones
四、安裝 Grafana
docker run -d -p 3000:3000 grafana/grafanahttp://localhost:3000/進入Grafana的登陸頁面,輸入默認的用戶名和密碼(admin/admin)即可。

Name: prometheus
Type: Prometheus
URL: http://localhost:9090
Access: Browser
/api/datasources/proxy/),由Grafana的服務(wù)端來訪問數(shù)據(jù)源的URL,如果數(shù)據(jù)源是部署在內(nèi)網(wǎng),用戶通過瀏覽器無法直接訪問時,這種方式非常有用。

五、使用Exporter收集指標(biāo)
5.1 收集服務(wù)器指標(biāo)
$ wget https://github.com/prometheus/node_exporter/releases/download/v0.16.0/node_exporter-0.16.0.linux-amd64.tar.gz$ tar xvfz node_exporter-0.16.0.linux-amd64.tar.gz$ cd node_exporter-0.16.0.linux-amd64$ ./node_exporter
/metrics接口看看是否能正常獲取服務(wù)器指標(biāo):$ curl http://localhost:9100/metricsscrape_configs中:scrape_configs:- job_name: 'prometheus'static_configs:- targets: ['192.168.0.107:9090']- job_name: 'server'static_configs:- targets: ['192.168.0.107:9100']
HUP信號也可以讓Prometheus重新加載配置: killall -HUP prometheus
node_load1觀察服務(wù)器負載:
node exporter,有很多的面板模板可以直接使用,譬如:Node Exporter Server Metrics或者Node Exporter Full等。我們打開Grafana 的Import dashboard頁面,輸入面板的URL(https://grafana.com/dashboards/405)或者 ID(405)即可。
注意事項
docker run -d \--net="host" \--pid="host" \-v "/:/host:ro,rslave" \quay.io/prometheus/node-exporter \--path.rootfs /host
5.2 收集MySQL指標(biāo)
$ wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.11.0/mysqld_exporter-0.11.0.linux-amd64.tar.gz$ tar xvfz mysqld_exporter-0.11.0.linux-amd64.tar.gz$ cd mysqld_exporter-0.11.0.linux-amd64/
DATA_SOURCE_NAME,這被稱為DSN(數(shù)據(jù)源名稱),它必須符合DSN的格式,一個典型的DSN格式像這樣:user:password@(host:port)/。export DATA_SOURCE_NAME='root:123456@(192.168.0.107:3306)/'./mysqld_exporter另一種方式是通過配置文
~/.my.cnf,或者通過--config.my-cnf 參數(shù)指定: ./mysqld_exporter --config.my-cnf=".my.cnf"$ cat .my.cnf[client]host=localhostport=3306user=rootpassword=123456
注意事項
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'password' WITH MAX_USER_CONNECTIONS 3;GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
5.3 收集Nginx指標(biāo)
/status/format/json接口來將vts的數(shù)據(jù)格式轉(zhuǎn)換為Prometheus的格式。不過,在nginx-module-vts最新的版本中增加了一個新接口:/status/format/prometheus,這個接口可以直接返回Prometheus的格式,從這點這也能看出Prometheus的影響力,估計Nginx VTS exporter很快就要退役了(TODO:待驗證)。/nginx_status可以獲取一些比較簡單的指標(biāo)(需要開啟ngx_http_stub_status_module模塊);nginx_request_exporter通過syslog協(xié)議收集并分析Nginx的access log來統(tǒng)計HTTP請求相關(guān)的一些指標(biāo);nginx-prometheus-shiny-exporter和nginx_request_exporter類似,也是使用syslog協(xié)議來收集access log,不過它是使用Crystal語言寫的。還有vovolie/lua-nginx-prometheus基于Openresty、Prometheus、Consul、Grafana實現(xiàn)了針對域名和Endpoint級別的流量統(tǒng)計。5.4 收集JMX指標(biāo)
$ wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.3.1/jmx_prometheus_javaagent-0.3.1.jar-javaagent參數(shù)來加載:$ java -javaagent:jmx_prometheus_javaagent-0.3.1.jar=9404:config.yml -jar spring-boot-sample-1.0-SNAPSHOT.jarconfig.yml是JMX Exporter的配置文件,它的內(nèi)容可以參考JMX Exporter的配置說明 。然后檢查下指標(biāo)數(shù)據(jù)是否正確獲?。?/span>$ curl http://localhost:9404/metrics六、告警和通知
6.1 配置告警規(guī)則
rule_files:- "alert.rules"
alert.rules:groups:- name: examplerules: # Alert for any instance that is unreachable for >5 minutes.- alert: InstanceDownexpr: up == 0for: 5mlabels:severity: pageannotations:summary: "Instance {{ $labels.instance }} down"description: "{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes." # Alert for any instance that has a median request latency >1s.- alert: APIHighRequestLatencyexpr: api_http_request_latencies_second{quantile="0.5"} > 1for: 10mannotations:summary: "High request latency on {{ $labels.instance }}"description: "{{ $labels.instance }} has a median request latency above 1s (current value: {{ $value }}s)"InstanceDown和APIHighRequestLatency。顧名思義,InstanceDown表示當(dāng)實例宕機時(up === 0)觸發(fā)告警,APIHighRequestLatency表示有一半的API請求延遲大于1s時(api_http_request_latencies_second{quantile="0.5"} > 1)觸發(fā)告警。配置好后,需要重啟下Prometheus server,然后訪問http://localhost:9090/rules可以看到剛剛配置的規(guī)則:
http://localhost:9090/alerts可以看到根據(jù)配置的規(guī)則生成的告警:
PENDING,這表示已經(jīng)觸發(fā)了告警規(guī)則,但還沒有達到告警條件。這是因為這里配置的for參數(shù)是5m,也就是5分鐘后才會觸發(fā)告警,我們等5分鐘,可以看到這條alert的狀態(tài)變成了FIRING。6.2 使用Alertmanager發(fā)送告警通知
/alerts頁面可以看到所有的告警,但是還差最后一步:觸發(fā)告警時自動發(fā)送通知。這是由Alertmanager來完成的,我們首先 下載并安裝Alertmanager,和其他Prometheus的組件一樣,Alertmanager也是開箱即用的:$ wget https://github.com/prometheus/alertmanager/releases/download/v0.15.2/alertmanager-0.15.2.linux-amd64.tar.gz$ tar xvfz alertmanager-0.15.2.linux-amd64.tar.gz$ cd alertmanager-0.15.2.linux-amd64$ ./alertmanager
http://localhost:9093/來訪問,但是現(xiàn)在還看不到告警,因為我們還沒有把Alertmanager配置到Prometheus中,我們回到Prometheus的配置文件prometheus.yml,添加下面幾行:alerting:alertmanagers:- scheme: httpstatic_configs:- targets:- "192.168.0.107:9093"
http://192.168.0.107:9093。也可以使用命名行的方式指定Alertmanager:$ ./prometheus -alertmanager.url=http://192.168.0.107:9093
alertmanager.ym:global:resolve_timeout: 5mroute:group_by: ['alertname']group_wait: 10sgroup_interval: 10srepeat_interval: 1hreceiver: 'web.hook'receivers:- name: 'web.hook'webhook_configs:- url: 'http://127.0.0.1:5001/'inhibit_rules:- source_match:severity: 'critical'target_match:severity: 'warning'equal: ['alertname', 'dev', 'instance']
routes:- receiver: 'database-pager'group_wait: 10smatch_re:service: mysql|cassandra- receiver: 'frontend-pager'group_by: [product, environment]match:team: frontend
email_config
hipchat_config
pagerduty_config
pushover_config
slack_config
opsgenie_config
victorops_config
wechat_configs
webhook_config
七、學(xué)習(xí)更多
7.1 服務(wù)發(fā)現(xiàn)
7.2 告警配置管理
7.3 使用Pushgateway
總結(jié)
附錄:什么是時序數(shù)據(jù)庫?
增:需要頻繁的進行寫操作,而且是按時間排序順序?qū)懭?/span>
刪:不需要隨機刪除,一般情況下會直接刪除一個時間區(qū)塊的所有數(shù)據(jù)
改:不需要對寫入的數(shù)據(jù)進行更新
查:需要支持高并發(fā)的讀操作,讀操作是按時間順序升序或降序讀,數(shù)據(jù)量非常大,緩存不起作用
InfluxDB:https://influxdata.com/ Kdb+:http://kx.com/ Graphite:http://graphiteapp.org/ RRDtool:http://oss.oetiker.ch/rrdtool/ OpenTSDB:http://opentsdb.net/ Prometheus:https://prometheus.io/ Druid:http://druid.io/

