关于prometheus:prometheus-remotewrite解析二-源码解读

整体流程 remoteConfigs反对配置多个remoteStorage,每个remoteStorage应用1个QueueManager;wathcer将sample发送给QueueManager;1个QueueManager中治理多个shard,每个shard的容量为capactiy;每个shard会定时(batch_send_deadline)定量(max_samples_per_send)的向remote endpoint发送数据;代码入口入口:storage/remote/write.go次要工作是初始化QueueManager,而后调用start()让其干活。 // 依据配置初始化QueueManager,而后让QueueManager干活func (rws *WriteStorage) ApplyConfig(conf *config.Config) error { ..... newQueues := make(map[string]*QueueManager) newHashes := []string{} for _, rwConf := range conf.RemoteWriteConfigs { hash, err := toHash(rwConf) if err != nil { return err } // Don't allow duplicate remote write configs. if _, ok := newQueues[hash]; ok { return fmt.Errorf("duplicate remote write configs are not allowed, found duplicate for URL: %s", rwConf.URL) } // Set the queue name to the config hash if the user has not set // a name in their remote write config so we can still differentiate // between queues that have the same remote write endpoint. name := hash[:6] if rwConf.Name != "" { name = rwConf.Name } c, err := NewWriteClient(name, &ClientConfig{ URL: rwConf.URL, Timeout: rwConf.RemoteTimeout, HTTPClientConfig: rwConf.HTTPClientConfig, }) if err != nil { return err } queue, ok := rws.queues[hash] ...... endpoint := rwConf.URL.String() newQueues[hash] = NewQueueManager( ##初始化QueueManager newQueueManagerMetrics(rws.reg, name, endpoint), rws.watcherMetrics, rws.liveReaderMetrics, rws.logger, rws.walDir, ##这里是/prometheus,在walwatcher中会被初始化为/prometheus/wal rws.samplesIn, rwConf.QueueConfig, conf.GlobalConfig.ExternalLabels, rwConf.WriteRelabelConfigs, c, rws.flushDeadline, ) // Keep track of which queues are new so we know which to start. newHashes = append(newHashes, hash) } // Anything remaining in rws.queues is a queue who's config has // changed or was removed from the overall remote write config. for _, q := range rws.queues { q.Stop() } for _, hash := range newHashes { ##QueueManager干活 newQueues[hash].Start() } rws.queues = newQueues return nil}具体看一下QueueManager做的事件: ...

September 6, 2021 · 6 min · jiezi

关于prometheus:prometheus-remotewrite解析一-使用

prometheus没有提供近程存储,但提供了近程存储的接口: 近程存储只有实现这一接口,即可存储和读取prometheus的数据;这里仅剖析remote-write:笔者的prometheus被prometheus-operator部署在kubernetes中,kubernetes应用prometheus这个CRD治理配置,prometheus-operator监听到配置变动,将新配置apply到prometheus POD上。 prometheus CRD中的remote-write配置:remoteWrite: - url: "https://1.2.3.4/api/monitor/v1/prom/write" tlsConfig: insecureSkipVerify: trueapply当前,prometheus生成如下的配置: remote_write:- url: https://1.2.3.4/api/monitor/v1/prom/write remote_timeout: 30s tls_config: insecure_skip_verify: true queue_config: capacity: 500 max_shards: 1000 min_shards: 1 max_samples_per_send: 100 batch_send_deadline: 5s min_backoff: 30ms max_backoff: 100ms能够看到,它减少了queue_config,即传输过程中的队列配置。假如每个remoteStorage应用1个queue进行传输: queue中的初始shards数=min_shards,最大shards数=max_shards;每个shard的容量=capacity个sample;通过HTTP向remoteStorage发送数据时,若发送失败,则回退min_backoff;再次失败,则回退2*min_backoff,直到max_backoff; prometheus的remote-write数据协定prometheus的samples,通过protobuf的序列化,而后再通过snappy压缩,最初通过HTTP发送给remoteStorage;对应的源代码: // prometheus/storage/remote/queue_manager.gofunc buildWriteRequest(samples []prompb.TimeSeries, buf []byte) ([]byte, int64, error) { var highest int64 for _, ts := range samples { // At the moment we only ever append a TimeSeries with a single sample in it. if ts.Samples[0].Timestamp > highest { highest = ts.Samples[0].Timestamp } } req := &prompb.WriteRequest{ Timeseries: samples, } data, err := proto.Marshal(req) if err != nil { return nil, highest, err } // snappy uses len() to see if it needs to allocate a new slice. Make the // buffer as long as possible. if buf != nil { buf = buf[0:cap(buf)] } compressed := snappy.Encode(buf, data) return compressed, highest, nil}remoteStorage如何实现remote-write协定接口remoteStorage要实现remoteConfigs中定义的HTTP接口,这里次要参考influxdb的实现。HTTP接口: ...

September 6, 2021 · 2 min · jiezi

关于prometheus:Google-mtail配合Prometheus和Grafana实现自定义日志监控

前言mtail是一个Google开发的日志提取工具,相比ELK/EFK/Grafana Loki来说会更轻量。因为我遇到的需要只是为了采集生产日志中的数据,所以采纳更为简略的mtail配合Prometheus和Grafana实现自定义日志数据监控。 更新历史2021年08月04日 - 初稿 浏览原文 - https://wsgzao.github.io/post... 常见的日志监控解决方案开源的业务日志监控,我重点举荐以下3个 值得注意的是ELK目前有被EFK取代的趋势1:ELK-“ELK”是三个开源我的项目的首字母缩写,这三个我的项目别离是:Elasticsearch、Logstash 和 Kibana。 Elasticsearch 是一个搜寻和剖析引擎。 Logstash 是服务器端数据处理管道,可能同时从多个起源采集数据,转换数据,而后将数据发送到诸如 Elasticsearch 等“存储库”中。 Kibana 则能够让用户在 Elasticsearch 中应用图形和图表对数据进行可视化。 2:Loki,Grafana Labs 团队最新的开源我的项目,是一个程度可扩大,高可用性,多租户的日志聚合零碎。 3:mtail :它是一个google开发的日志提取工具,从应用程序日志中提取指标以导出到工夫序列数据库或工夫序列计算器, 用处就是: 实时读取应用程序的日志、 再通过本人编写的脚本进行剖析、 最终生成工夫序列指标。 工具适宜本人的才是最好的,无论是EFK还是Loki都是功能齐全的日志采集零碎,当然它们也有各自的劣势, Blog中记录了一些应用教训大家能够参考Scribe装置应用 - https://wsgzao.github.io/post... 应用ELK(Elasticsearch + Logstash + Kibana) 搭建日志集中剖析平台实际 - https://wsgzao.github.io/post... 开源日志治理计划ELK和EFK的区别 - https://wsgzao.github.io/post... Grafana Loki开源日志聚合零碎代替ELK或EFK - https://wsgzao.github.io/post... mtail简介mtail - extract whitebox monitoring data from application logs for collection into a timeseries database mtail is a tool for extracting metrics from application logs to be exported into a timeseries database or timeseries calculator for alerting and dashboarding. ...

August 12, 2021 · 5 min · jiezi

关于prometheus:prometheus-简单例子

1.node_exporter 用户明码验证拜访yum install httpd-toolshtpasswd -nB "prometheus"[root@node3 node_exporter]# htpasswd -nB "prometheus"New password: Re-type new password: prometheus:$2y$05$TsMfhNUmHVD8PYmrAvWcNO5lisOfL25.5ybV0Z7t4NF43Aq1IennOnode_exporter web.config.yaml basic_auth_users: prometheus: $2y$05$TsMfhNUmHVD8PYmrAvWcNxO5OxfL25x.5ybV0Z7t4NF43Aq1IennO启动node_exporter ./node_exporter --web.config=web.config.yaml 设置node_exporter.service [Unit]Descriptiong=node_exporterDocumentation=After=network.target[Service]WorkingDirectory=/opt/node_exporter/ExecStart=/opt/node_exporter/node_exporter --web.config=/opt/node_exporter/web.config.yamlExecStop=/bin/kill -KILL $MAINPIDType=simpleKillMode=control-groupRestartSec=3s[Install]WantedBy=multi-user.target从新加载systemd systemctl daemon-reload2.将node_exporter退出到prometheusprometheus.yml 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'] - job_name: 'node' basic_auth: username: prometheus password: 123456 static_configs: - targets: ['localhost:9100']查看配置文件是否正确 ...

July 31, 2021 · 1 min · jiezi

关于prometheus:Prometheus-Operator-监控-Traefik-V24

背景:traefik搭建形式如下:https://www.yuque.com/duiniwukenaihe/ehb02i/odflm7 。Prometheus-oprator搭建形式如下:https://www.yuque.com/duiniwukenaihe/ehb02i/tm6vl7。Prometheus的文档写了grafana增加了traefik的监控模板。然而当初认真一看。traefik的监控图是空的,Prometheus的 target也没有对应traefik的监控。当初配置下增加traefik服务发现以及验证一下grafana的图表。 1. Prometheus Operator 监控 Traefik V2.41.1. Traefik 配置文件设置 Prometheus参照https://www.yuque.com/duiniwukenaihe/ehb02i/odflm7。配置中默认开启了默认的Prometheus监控。https://doc.traefik.io/traefik/observability/metrics/prometheus/可参照traefik官网文档。 1.2、Traefik Service 设置标签1.2.1 查看traefik service$ kubectl get svc -n kube-systemNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEcilium-agent ClusterIP None <none> 9095/TCP 15detcd-k8s ClusterIP None <none> 2379/TCP 8dhubble-metrics ClusterIP None <none> 9091/TCP 15dhubble-relay ClusterIP 172.254.38.50 <none> 80/TCP 15dhubble-ui ClusterIP 172.254.11.239 <none> 80/TCP 15dkube-controller-manager ClusterIP None <none> 10257/TCP 8dkube-controller-manager-svc ClusterIP None <none> 10252/TCP 6dkube-dns ClusterIP 172.254.0.10 <none> 53/UDP,53/TCP,9153/TCP 15dkube-scheduler ClusterIP None <none> 10259/TCP 8dkube-scheduler-svc ClusterIP None <none> 10251/TCP 6dkubelet ClusterIP None <none> 10250/TCP,10255/TCP,4194/TCP 8dtraefik ClusterIP 172.254.12.88 <none> 80/TCP,443/TCP,8080/TCP 11d1.2.2、编辑该 Service 设置 Label kubectl edit service traefik -n kube-system设置 Label “app: traefik”参照的是traefik-deploy.yaml 中的app:traefik这个标签用了,当然了也能够本人定义下用下别的...... ...

July 6, 2021 · 1 min · jiezi

关于prometheus:号称下一代监控系统来看看它有多牛逼

Prometheus 是一款基于时序数据库的开源监控告警零碎,说起 Prometheus 则不得不提 SoundCloud,这是一个在线音乐分享的平台,相似于做视频分享的 YouTube,因为他们在微服务架构的路线上越走越远,呈现了成千盈百的服务,应用传统的监控零碎 StatsD 和 Graphite 存在大量的局限性。 于是他们在 2012 年开始着手开发一套全新的监控零碎。Prometheus 的原作者是 Matt T. Proud,他也是在 2012 年退出 SoundCloud 的,实际上,在退出 SoundCloud 之前,Matt 始终就任于 Google,他从 Google 的集群管理器 Borg 和它的监控零碎 Borgmon 中获取灵感,开发了开源的监控零碎 Prometheus,和 Google 的很多我的项目一样,应用的编程语言是 Go。 很显然,Prometheus 作为一个微服务架构监控零碎的解决方案,它和容器也脱不开关系。早在 2006 年 8 月 9 日,Eric Schmidt 在搜索引擎大会上首次提出了云计算(Cloud Computing)的概念,在之后的十几年里,云计算的倒退长驱直入。 在 2013 年,Pivotal 的 Matt Stine 又提出了云原生(Cloud Native)的概念,云原生由微服务架构、DevOps 和以容器为代表的麻利基础架构组成,帮忙企业疾速、继续、牢靠、规模化地交付软件。 为了对立云计算接口和相干规范,2015 年 7 月,隶属于 Linux 基金会的 云原生计算基金会(CNCF,Cloud Native Computing Foundation) 应运而生。第一个退出 CNCF 的我的项目是 Google 的 Kubernetes,而 Prometheus 是第二个退出的(2016 年)。 ...

June 29, 2021 · 9 min · jiezi

关于prometheus:Prometheus监控Canal

一、背景简略记录下,应用Prometheus对Canal进行监控。 二、实现步骤1、批改prometheus.yml配置文件vim /Users/huan/soft/prometheus/prometheus-2.25.0/prometheus.yml scrape_configs: - job_name: 'canal' scrape_interval: 30s static_configs: - targets: ['localhost:11112'] # 端口配置即为canal.properties中的canal.metrics.pull.port labels: nodename: 'canal'# 检测刚刚编写的 prometheus.yml 语法是否谬误./promtool check config prometheus.yml2、启动prometheusnohup /Users/huan/soft/prometheus/prometheus-2.25.0/prometheus \--config.file="/Users/huan/soft/prometheus/prometheus-2.25.0/prometheus.yml" \--web.listen-address="0.0.0.0:9080" \--web.enable-lifecycle \--storage.tsdb.retention.time="3d" \--log.level=debug \> logs/prometheus.out 2>&1 &3、查看prometheus是否胜利接入canal 4、canal原始指标解释指标阐明单位精度canal_instance_transactionsinstance接管transactions计数--canal_instanceinstance根本信息--canal_instance_subscriptionsinstance订阅数量--canal_instance_publish_blocking_timeinstance dump线程提交到异步解析队列过程中的阻塞工夫(仅parallel解析模式)msnscanal_instance_received_binlog_bytesinstance接管binlog字节数byte-canal_instance_parser_modeinstance解析模式(是否开启parallel解析)--canal_instance_client_packetsinstance client申请次数的计数--canal_instance_client_bytes向instance client发送数据包字节计数byte-canal_instance_client_empty_batches向instance client发送get接口的空后果计数--canal_instance_client_request_errorinstance client申请失败计数--canal_instance_client_request_latencyinstance client申请的响应工夫详情--canal_instance_sink_blocking_timeinstance sink线程put数据至store的阻塞工夫msnscanal_instance_store_produce_seqinstance store接管到的events sequence number--canal_instance_store_consume_seqinstance store胜利生产的events sequence number--canal_instance_storeinstance store根本信息--canal_instance_store_produce_meminstance store接管到的所有events占用内存总量byte-canal_instance_store_consume_meminstance store胜利生产的所有events占用内存总量byte-canal_instance_put_rowsstore put操作实现的table rows--canal_instance_get_rowsclient get申请返回的table rows--canal_instance_ack_rowsclient ack操作开释的table rows--canal_instance_traffic_delayserver与MySQL master的延时msmscanal_instance_put_delaystore put操作events的延时msmscanal_instance_get_delayclient get申请返回events的延时msmscanal_instance_ack_delayclient ack操作开释events的延时msms5、导入fana图表 图表json数据 { "__inputs": [ { "name": "DS_PROMETHEUS", "label": "prometheus", "description": "", "type": "datasource", "pluginId": "prometheus", "pluginName": "Prometheus" } ], "__requires": [ { "type": "grafana", "id": "grafana", "name": "Grafana", "version": "5.2.2" }, { "type": "panel", "id": "graph", "name": "Graph", "version": "5.0.0" }, { "type": "datasource", "id": "prometheus", "name": "Prometheus", "version": "5.0.0" } ], "annotations": { "list": [ { "builtIn": 1, "datasource": "-- Grafana --", "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", "name": "Annotations & Alerts", "type": "dashboard" } ] }, "editable": true, "gnetId": null, "graphTooltip": 0, "id": null, "iteration": 1536989235272, "links": [], "panels": [ { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }, "id": 30, "panels": [], "title": "Instance status", "type": "row" }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance 根本信息。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 0, "y": 1 }, "id": 24, "legend": { "alignAsTable": true, "avg": false, "current": false, "hideEmpty": false, "hideZero": false, "max": false, "min": false, "rightSide": true, "show": true, "sideWidth": 500, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "repeat": null, "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "canal_instance{destination=~\"$destination\"}", "format": "time_series", "instant": true, "intervalFactor": 1, "legendFormat": "Destination: {{destination}}", "refId": "A" }, { "expr": "canal_instance_parser_mode{destination=~\"$destination\"}", "format": "time_series", "instant": true, "intervalFactor": 1, "legendFormat": "Parallel parser: {{parallel}}", "refId": "B" }, { "expr": "canal_instance_store{destination=~\"$destination\"}", "format": "time_series", "instant": true, "intervalFactor": 1, "legendFormat": "Batch mode: {{batchMode}}", "refId": "C" }, { "expr": "canal_instance_store{destination=~\"$destination\"}", "format": "time_series", "instant": true, "intervalFactor": 1, "legendFormat": "Buffer size: {{size}}", "refId": "D" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Basic", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "transparent": true, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": false, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": false }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": false } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": { "inbound": "#bf1b00" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance 网络带宽占用。\ninbound: 读取MySQL binlog.\noutbound: 对Client端传输格式化binlog.", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 6, "y": 1 }, "id": 6, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_received_binlog_bytes{destination=~\"$destination\", parser=\"0\"}[2m]) / 1024", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "inbound", "refId": "A" }, { "expr": "rate(canal_instance_client_bytes{destination=~\"$destination\"}[2m]) / 1024", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "outbound", "refId": "B" }, { "expr": "rate(canal_instance_received_binlog_bytes{destination=~\"$destination\", parser=\"1\"}[2m]) / 1024", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "inbound-1", "refId": "C" }, { "expr": "rate(canal_instance_received_binlog_bytes{destination=~\"$destination\", parser=\"2\"}[2m]) / 1024", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "inbound-2", "refId": "D" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Network bandwith", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "KBs", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": { "ack": "#f29191", "get": "#cca300", "put": "#1f78c1" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "master: Canal server绝对于MySQL master的延时。通过master heartbeat机制能刷新idle状态下的延时。\nput: store put操作的工夫点为基准。\nget: client get操作的工夫点为基准。\nack: client ack操作的工夫点为基准。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 12, "y": 1 }, "id": 4, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "canal_instance_traffic_delay{destination=~\"$destination\"} / 1000", "format": "time_series", "hide": false, "interval": "15s", "intervalFactor": 2, "legendFormat": "master", "refId": "D" }, { "expr": "canal_instance_put_delay{destination=~\"$destination\"} / 1000", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "put", "refId": "A" }, { "expr": "canal_instance_get_delay{destination=~\"$destination\"} / 1000", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "get", "refId": "B" }, { "expr": "canal_instance_ack_delay{destination=~\"$destination\"} / 1000", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "ack", "refId": "C" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Delay", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "s", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "sink线程blocking占比;dump线程blocking占比(仅parallel mode)。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 18, "y": 1 }, "hideTimeOverride": false, "id": 2, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "clamp_max(rate(canal_instance_publish_blocking_time{destination=~\"$destination\", parser=\"0\"}[2m]), 1000) / 10", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "dump", "refId": "B" }, { "expr": "clamp_max(rate(canal_instance_sink_blocking_time{destination=~\"$destination\"}[2m]), 1000) / 10", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "sink", "refId": "A" }, { "expr": "clamp_max(rate(canal_instance_publish_blocking_time{destination=~\"$destination\", parser=\"1\"}[2m]), 1000) / 10", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "dump-1", "refId": "C" }, { "expr": "clamp_max(rate(canal_instance_publish_blocking_time{destination=~\"$destination\", parser=\"2\"}[2m]), 1000) / 10", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "dump-2", "refId": "D" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Blocking", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "percent", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 6 }, "id": 32, "panels": [], "title": "Throughput", "type": "row" }, { "aliasColors": { "rowDatas": "#7eb26d", "tableRows": "#c15c17" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Instance解决binlog的TPS(以master变更行数table rows为基准计算)。\nput: put操作TPS。\nget: get操作TPS。\nack: ack操作TPS。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 0, "y": 7 }, "id": 14, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_put_rows{destination=~\"$destination\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "put", "refId": "A" }, { "expr": "rate(canal_instance_get_rows{destination=~\"$destination\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "get", "refId": "B" }, { "expr": "rate(canal_instance_ack_rows{destination=~\"$destination\"}[2m])", "format": "time_series", "intervalFactor": 1, "legendFormat": "ack", "refId": "C" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "TPS(table rows)", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "iops", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": { "transactions": "#f9ba8f" }, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance 解决binlog的TPS,以MySQL transaction为单位计算。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 6, "y": 7 }, "id": 12, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_transactions{destination=~\"$destination\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "transactions", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "TPS(MySQL transaction)", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "iops", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 12 }, "id": 34, "panels": [], "title": "Client", "type": "row" }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance接管到的申请统计,后果按packet type分类。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 0, "y": 13 }, "id": 16, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "canal_instance_client_packets{destination=~\"$destination\"}", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "{{packetType}}", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Client requests", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "none", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "client 申请的GET与ACK包的QPS。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 6, "y": 13 }, "id": 38, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_client_packets{destination=~\"$destination\",packetType=\"GET\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "GET", "refId": "A" }, { "expr": "rate(canal_instance_client_packets{destination=~\"$destination\",packetType=\"CLIENTACK\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "ACK", "refId": "B" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Client QPS", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "server响应GET申请,但返回空包的占比。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 12, "y": 13 }, "id": 26, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_client_empty_batches{destination=~\"$destination\"}[2m])", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "empty", "refId": "A" }, { "expr": "rate(canal_instance_client_packets{destination=~\"$destination\", packetType=\"GET\"}[2m])", "format": "time_series", "intervalFactor": 1, "legendFormat": "nonempty", "refId": "B" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Empty packets", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "wps", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal client 申请响应工夫的详情。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 18, "y": 13 }, "id": 18, "legend": { "alignAsTable": false, "avg": false, "current": false, "max": false, "min": false, "rightSide": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [ { "alias": "25.0", "yaxis": 1 }, { "alias": "100.0", "yaxis": 1 } ], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "rate(canal_instance_client_request_latency_bucket{destination=~\"$destination\"}[2m])", "format": "time_series", "hide": false, "interval": "15s", "intervalFactor": 2, "legendFormat": "{{le}}ms", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Response time", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "transparent": false, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 18 }, "id": 36, "panels": [], "title": "Store", "type": "row" }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance ringbuffer内未开释的events数量。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 0, "y": 19 }, "id": 20, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "canal_instance_store_produce_seq{destination=~\"$destination\"} - canal_instance_store_consume_seq{destination=~\"$destination\"}", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "events", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Store remain events", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "decimals": null, "format": "none", "label": "", "logBase": 1, "max": null, "min": null, "show": true }, { "decimals": null, "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } }, { "aliasColors": {}, "bars": false, "dashLength": 10, "dashes": false, "datasource": "$datasource", "description": "Canal instance ringbuffer 内未开释events占用内存。", "fill": 1, "gridPos": { "h": 5, "w": 6, "x": 6, "y": 19 }, "id": 22, "legend": { "avg": false, "current": false, "max": false, "min": false, "show": true, "total": false, "values": false }, "lines": true, "linewidth": 1, "links": [], "nullPointMode": "null", "percentage": false, "pointradius": 5, "points": false, "renderer": "flot", "seriesOverrides": [], "spaceLength": 10, "stack": false, "steppedLine": false, "targets": [ { "expr": "(canal_instance_store_produce_mem{destination=~\"$destination\"} - canal_instance_store_consume_mem{destination=~\"$destination\"}) / 1024", "format": "time_series", "interval": "15s", "intervalFactor": 2, "legendFormat": "memsize", "refId": "A" } ], "thresholds": [], "timeFrom": null, "timeShift": null, "title": "Store remain mem", "tooltip": { "shared": true, "sort": 0, "value_type": "individual" }, "type": "graph", "xaxis": { "buckets": null, "mode": "time", "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "deckbytes", "label": null, "logBase": 1, "max": null, "min": null, "show": true }, { "format": "short", "label": null, "logBase": 1, "max": null, "min": null, "show": true } ], "yaxis": { "align": false, "alignLevel": null } } ], "refresh": false, "schemaVersion": 16, "style": "dark", "tags": [ "canal" ], "templating": { "list": [ { "current": { "text": "prometheus", "value": "prometheus" }, "hide": 0, "label": "datasource", "name": "datasource", "options": [], "query": "prometheus", "refresh": 1, "regex": "", "type": "datasource" }, { "allValue": null, "current": {}, "datasource": "$datasource", "hide": 0, "includeAll": false, "label": "destination", "multi": false, "name": "destination", "options": [], "query": "label_values(canal_instance, destination)", "refresh": 1, "regex": "", "sort": 0, "tagValuesQuery": "", "tags": [], "tagsQuery": "", "type": "query", "useTags": false } ] }, "time": { "from": "now-6h", "to": "now" }, "timepicker": { "refresh_intervals": [ "5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d" ], "time_options": [ "5m", "15m", "1h", "6h", "12h", "24h", "2d", "7d", "30d" ] }, "timezone": "", "title": "Canal instances", "uid": "8vh8NGpiz", "version": 103}三、参考链接1、https://github.com/alibaba/canal/wiki/Prometheus-QuickStart ...

June 5, 2021 · 13 min · jiezi

关于prometheus:prometheus指南采集k8s的原理和高可用存储实践

我的项目地址指南我的项目地址我的项目阐明这是一个收费的prometheus底层原理课程(当然是精简版的) 次要介绍两大块内容,这也是大家常见的问题 prometheus采集k8s的原理prometheus的高可用存储怎么做付费全方位教程如果想进一线互联网大厂从事监控运维/开发的工作(冲击35k+的月薪) 须要更全面的理解Prometheus底层原理,并有高可用实战项⽬教训。 能够购买上面的付费课程, 课程链接:prometheus全组件配置应用、底层原理解析、高可用实战 付费课程介绍学完这个课程,你能够能够搭建如下架构哦门课指标用户收益 一线运维人员:学习应用、相熟配置、把握调优、升职加薪 能够从头到尾相熟prometheus、各种exporter、alertmanager、grafana、m3db、loki等组件的应用配置相熟支流exporter(中间件、存储)的告警表达式配置同时能把握相干组件调优的教训运维开发人员:学习高性能原理,可助⼒斩获⼤⼚监控运维开发offer 从源码级别理解prometheus高性能的设计方案把握二次开发相干组件的能力理解分布式系统高可用革新计划筹备工作在k8s中部署prometheuskubectl apply -f prome_k8s_all_pod/kube-stats-metricskubectl apply -f prome_k8s_all_pod/在k8s中部署grafanakubectl apply -f grafana/k8s关注指标剖析k8s中组件简单,咱们次要专一的无外乎四大块指标:容器根底资源指标、k8s资源指标、k8s服务组件指标、部署在pod中业务埋点指标 指标类型采集源利用举例发现类型grafana截图容器根底资源指标kubelet 内置cadvisor metrics接口查看容器cpu、mem利用率等k8s_sd node级别间接拜访node_ip k8s资源指标kube-stats-metrics (简称ksm)具体能够看 看pod状态如pod waiting状态的起因 数个数如:查看node pod按namespace散布状况通过coredns拜访域名 k8s服务组件指标服务组件 metrics接口查看apiserver 、scheduler、etc、coredns申请提早等k8s_sd endpoint级别 部署在pod中业务埋点指标pod 的metrics接口根据业务指标场景k8s_sd pod级别,拜访pod ip的metricspath

June 2, 2021 · 1 min · jiezi

关于prometheus:PrometheusGrafana性能监控

前言前几年做性能测试监控部署了telegraf+infludb+grafana,不便查看和存档性能监控数据,随着K8s流行起来,Prometheus计划开始失去各大厂青眼,最近尝试部署Prometheus+Grafana,再配合各种exporter,丰盛性能测试监控伎俩。Prometheus简介概念Prometheus是由SoundCloud开发的开源监控报警零碎和时序列数据库(TSDB)。Prometheus应用Go语言开发,是Google BorgMon监控零碎的开源版本。2016年由Google发动Linux基金会旗下的原生云基金会(Cloud Native Computing Foundation), 将Prometheus纳入其下第二大开源我的项目。Prometheus目前在开源社区相当沉闷。Prometheus和Heapster(Heapster是K8S的一个子项目,用于获取集群的性能数据。)相比性能更欠缺、更全面。Prometheus性能也足够反对上万台规模的集群。官网地址:https://prometheus.io/特点多维度数据模型高效灵便的查问语句不依赖分布式存储,单个服务器节点是自主的通过基于HTTP的pull形式采集时序数据能够通过两头网关进行时序列数据推送通过服务发现或者动态配置来发现指标服务对象反对多种多样的图表和界面展现,比方Grafana等组件promethues server:次要获取和存储工夫序列数据exporters:次要作为agent收集数据发送到prometheus server,不同的数据收集由不同的exporters实现,如监控服务器有node-exporters,redis有redis-exporter。 更多exporters可参看EXPORTERS AND INTEGRATIONS对应端口号Default port allocations · prometheus/prometheus Wiki · GitHubpushgateway:容许短暂和批处理的jobs推送它们的数据到prometheus;因为这类工作的存在工夫不长,须要他们被动将数据推送到pushgateway,而后由pushgateway将数据发送给prometheus。alertmanager:实现prometheus的告警性能。架构 GrafanaGrafana是一个跨平台的开源的度量剖析和可视化工具,能够通过将采集的数据查问而后可视化的展现,并及时告诉。特点展现形式:疾速灵便的客户端图表,面板插件有许多不同形式的可视化指标和日志,官网库中具备丰盛的仪表盘插件,比方热图、折线图、图表等多种展现形式;数据源:Graphite,InfluxDB,OpenTSDB,Prometheus,Elasticsearch,CloudWatch和KairosDB等;告诉揭示:以可视形式定义最重要指标的警报规定,Grafana将一直计算并发送告诉,在数据达到阈值时通过Slack、PagerDuty等取得告诉;混合展现:在同一图表中混合应用不同的数据源,能够基于每个查问指定数据源,甚至自定义数据源;正文:应用来自不同数据源的丰盛事件正文图表,将鼠标悬停在事件上会显示残缺的事件元数据和标记;过滤器:Ad-hoc过滤器容许动态创建新的键/值过滤器,这些过滤器会主动利用于应用该数据源的所有查问装置部署prometheus手动下载,并依据yml配置文件启动服务download the latest releasewget https://github.com/prometheus/prometheus/releases/download/v*/prometheus-*.*-amd64.tar.gztar xvf prometheus-*.*-amd64.tar.gzcd prometheus-*nohup ./prometheus --config.file=./prometheus.yml &grafana手动下载,并依据yml配置文件启动服务download the latest releasewget https://dl.grafana.com/oss/release/grafana-7.5.6-1.x86_64.rpmsudo yum install grafana-7.5.6-1.x86_64.rpmdocker装置docker-compose对立装置prometheus及grafanacd /optmkdir -p prometheus/config/mkdir -p grafana/datachmod 777 grafana/datamkdir -p /data/prometheuschmod 777 /data/prometheus创立prometheus.yml配置文件cd /opt/prometheus/config/touch prometheus.yml编辑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: ['192.168.9.140:9090'] - job_name: "node" static_configs: - targets: ["192.168.9.140:9100"] - job_name: "qianmingyanqian" static_configs: - targets: ["11.12.108.226:9100","11.12.108.225:9100"] ## config for the multiple Redis targets that the exporter will scrape - job_name: "redis_exporter_targets" scrape_interval: 5s static_configs: - targets: - redis://192.168.9.140:6379 - redis://192.168.9.140:7001 - redis://192.168.9.140:7004 metrics_path: /scrape relabel_configs: - source_labels: [__address__] target_label: __param_target - source_labels: [__param_target] target_label: instance - target_label: __address__ replacement: 192.168.9.140:9121创立docker-compose_prometheus_grafana.yml配置文件cd /optmkdir docker-composetouch docker-compose_prometheus_grafana.yml编辑docker-compose_prometheus_grafana.yml文件并键入version: '2'networks: monitor: driver: bridgeservices: prometheus: image: prom/prometheus:latest container_name: prometheus hostname: prometheus restart: always volumes: - /opt/prometheus/config:/etc/prometheus - /data/prometheus:/prometheus ports: - "9090:9090" expose: - "8086" command: - '--config.file=/etc/prometheus/prometheus.yml' - '--log.level=info' - '--web.listen-address=0.0.0.0:9090' - '--storage.tsdb.path=/prometheus' - '--storage.tsdb.retention=15d' - '--query.max-concurrency=50' networks: - monitor grafana: image: grafana/grafana:latest container_name: grafana hostname: grafana restart: always volumes: - /opt/grafana/data:/var/lib/grafana ports: - "3000:3000" - "26:26" networks: - monitor depends_on: - prometheusdocker-compose运行docker容器docker-compose -p prometheus_grafana -f docker-compose_prometheus_grafana.yml up -d启动胜利通过浏览器http://192.168.9.140:9090/拜访prometheus服务 ...

May 28, 2021 · 4 min · jiezi

关于prometheus:使用VictoriaMetrics监控K8S集群

过来几年,Kubernetes曾经成为容器编排的规范,越来越多的公司开始在生产零碎应用Kubernetes。通常咱们应用Prometheus对K8S集群进行监控,但因为Prometheus本身单点的问题。不得不寻求一些联邦计划或者分布式高可用计划,社区热度比拟高的我的项目有Thanos,Cortex,VictoriaMetrics。本文就介绍应用VictoriaMetrics作为数据存储后端对K8S集群进行监控,k8s部署不再具体形容。 环境版本试验应用单节点k8s 网络组件应用cilium VictoriaMetrics存储应用localpv [root@cilium-1 victoria-metrics-cluster]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core)[root@cilium-bgp-1 victoria-metrics-cluster]# uname -r4.19.110-300.el7.x86_64[root@cilium-1 pvs]# kubectl get nodeNAME STATUS ROLES AGE VERSIONcilium-1.novalocal Ready master 28m v1.19.4次要监控指标master,node节点负载状态k8s 组件状态etcd状态k8s集群资源状态 (deploy,sts,pod...)用户自定义组件(次要通过pod定义prometheus.io/scrape主动上报target)...监控须要部署的组件VictoriaMetrics(storage,insert,select,agent,vmalert)promxykube-state-metricsnode-exporterkarmaalertmanagergrafana...部署VictoriaMetrics创立localpv为storage组件提供StorageClass 也能够应用其余网络存储 ---apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: vm-disksprovisioner: kubernetes.io/no-provisionerreclaimPolicy: RetainvolumeBindingMode: WaitForFirstConsumer---apiVersion: v1kind: PersistentVolumemetadata: name: vm-1spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Delete storageClassName: vm-disks local: path: /mnt/vmdata-1 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - cilium-1.novalocal---...[root@cilium-1 pvs]# kubectl get scNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGEvm-disks kubernetes.io/no-provisioner Retain WaitForFirstConsumer false 6m5s[root@cilium-1 pvs]# kubectl get pvNAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGEvm-1 10Gi RWO Delete Available vm-disks 92svm-2 10Gi RWO Delete Available vm-disks 92svm-3 10Gi RWO Delete Available vm-disks 92s应用helm 进行装置增加helm repo 拉取chart包并解压 ...

May 27, 2021 · 22 min · jiezi

关于prometheus:使用PrometheusGrafana监控Artifactory实践

在企业的零碎平台上运行artifactory可能每天有上百万个制品在一直流转,随着研发团队不断扩大,用户缓缓增多,并发量也相应的逐步增大,在保障高可用的同时,咱们对artifactory所在零碎及应用服务进行监控会显得尤其重要。那么如何实现零碎及利用的监控呢? 这篇文章形容如何通过prometheus、grafana实现对Artifactory的根底零碎及利用JVM监控。一、Prometheus Server端部署下载安装包并解压(以版本2.11.1为例)下载地址:https://prometheus.io/download/mkdir /opt/monitor/prometheus;cd /opt/monitor/prometheusunzip prometheus.zip ./tar zxf prometheus-2.11.1.linux-amd64.tar.gzmv prometheus-2.11.1.linux-amd64 prometheus-2.11.1 增加为零碎服务vim /usr/lib/systemd/system/prometheus-server.service[Unit]Description=prometheus-serverAfter=network.target [Service]Type=simpleUser=rootExecStart=/opt/monitor/prometheus/prometheus-2.11.1/prometheus --config.file=/opt/monitor/prometheus/prometheus-2.11.1/prometheus.ymlRestart=on-failure [Install]WantedBy=multi-user.target 启动并退出开机自启systemctl start prometheus-serversystemctl enable prometheus-server 拜访http://ip:9090 二、Prometheus Node端部署下载安装包并解压(以版本0.18.1为例)cd /opt/monitor/prometheusunzip prometheus.zip ./tar zxf node_exporter-0.18.1.linux-amd64.tar.gzmv node_exporter-0.18.1.linux-amd64 node_exporter-0.18.1 增加为零碎服务vim /usr/lib/systemd/system/prometheus-node.service[Unit]Description=prometheus-nodeAfter=network.target [Service]Type=simpleUser=rootExecStart=/opt/monitor/prometheus/node_exporter-0.18.1/node_exporterRestart=on-failure [Install]WantedBy=multi-user.target 启动并退出开机自启systemctl start prometheus-nodesystemctl enable prometheus-node 三、Grafana部署下载安装包并装置(以6.2.5.1为例)wget https://dl.grafana.com/oss/re... yum localinstall grafana-6.2.5-1.x86_64.rpm -y 启动systemctl start/stop/restart/enable grafana-server 拜访http://IP:3000默认用户名/明码:admin/admin 四、配置Artifactory节点系统监控配置prometheus在Artifactory各个节点装置好Prometheus Node后,批改/opt/monitor/prometheus-2.11.1/prometheus.yml,增加: job_name: 'artifactory'      static_configs:            - targets: ['IP1:9100','IP2:9100']重启prometheus-serversystemctl restart prometheus-server 查看监控状态及数据查问示例 应用grafana展现,模板可参考https://grafana.com/dashboard... 监控状态如下图 五、配置Artifactory节点JVM监控下载jmx_prometheus_javaagent-0.12.0.jar下载地址参考:https://repo1.maven.org/maven...Jar包门路:/opt/monitor/prometueus/jmx_prometheus_javaagent-0.12.0.jar增加配置文件 vim /opt/monitor/prometheus/jmx_config.yamllowercaseOutputLabelNames: truelowercaseOutputName: true rules: pattern: ".*"批改Artifactory tomcat配置文件vim $ARTIFACTORY_HOME/tomcat/bin/catalina.sh,增加:JAVA_OPTS="$JAVA_OPTS -javaagent:/opt/monitor/prometheus/jmx_prometheus_javaagent-0.12.0.jar=30013:/opt/monitor/prometheus/jmx_config.yaml" ...

May 21, 2021 · 1 min · jiezi

关于prometheus:KubeVela-KEDA为应用带来与生俱来的弹性伸缩能力

简介:在这篇博文中,咱们将简要解释须要思考的畛域,KEDA 如何使利用主动伸缩变得简略,以及为什么阿里云企业分布式应用服务(EDAS)在 KEDA 上齐全标准化。 联结作者 |  Yan Xun,阿里云 EDAS 团队高级工程师 Andy Shi,阿里云开发者倡导者 Tom Kerkhove,Codit 容器化业务负责人兼 Azure 架构师、KEDA 维护者、CNCF 大使 起源 | KubeVela 我的项目一起构建的。其总体架构如下图所示。 在生产上,EDAS 在阿里云上集成了 ARMS 监控服务,提供监控和利用的细粒度指标。EDAS 团队在 KEDA 我的项目中增加了一个 ARMS Scaler 来执行主动缩放。他们还增加了一些个性,并修复了 KEDA v1 版本中的一些 bug。包含: 当有多个触发器时,这些值将被求和,而不是作为独自的值留下。当创立 KEDA HPA 时,名称的长度将被限度为 63 个字符,以防止触发 DNS 投诉。不能禁用触发器,这可能会在生产中引起麻烦。EDAS 团队正在踊跃地将这些修复程序发送给上游 KEDA,只管其中一些曾经增加到 V2 版本中。 为什么阿里云将 KEDA 标准化为其利用的主动伸缩器当波及到主动扩大个性时,EDAS 最后应用上游 Kubernetes HPA 的 CPU 和内存作为两个指标。然而,随着用户群的增长和需要的多样化,EDAS 团队很快发现了上游 HPA 的局限性: 对定制指标的反对无限,特地是对应用程序级细粒度指标的反对。上游 HPA 次要关注容器级指标,比方 CPU 和内存,这些指标对于应用程序来说太毛糙了。反映应用程序负载的指标(如 RT 和 QPS)不受现成反对。是的,HPA 能够扩大。然而,当波及到应用程序级指标时,这种能力是无限的。EDAS 团队在尝试引入细粒度的应用程序级指标时,常常被迫分叉代码。不反对伸缩到零。当他们的微服务没有被应用时,许多用户都有将规模伸缩到零的需要。这一需要不仅限于 FaaS/无服务器工作负载。它为所有用户节省成本和资源。目前,上游 HPA 不反对此性能。不反对预约的伸缩。EDAS 用户的另一个强烈需要是预约的伸缩能力。同样,上游 HPA 不提供此性能,EDAS 团队须要寻找非供应商锁定的代替计划。基于这些需要,EDAS 团队开始布局 EDAS 主动伸缩个性的新版本。与此同时,EDAS 在 2020 年初引入了 OAM,对其底层外围组件进行了彻底改革。OAM 为 EDAS 提供了标准化的、可插入的利用程序定义,以取代其外部的 Kubernetes 应用程序 CRD。该模型的可扩展性使 EDAS 可能轻松地与 Kubernetes 社区的任何新性能集成。在这种状况下,EDAS 团队试图将对 EDAS 新的主动伸缩个性的需要与 OAM 主动伸缩个性的规范实现相结合。 基于用例,EDAS 团队总结了三个规范: ...

May 20, 2021 · 1 min · jiezi

关于prometheus:prometheus-rangequery源码解读和高基数判定依据querylog各阶段统计耗时原理

在时序数据库中的高基数问题能够看我之前写的文章高基数和prometheus中断定高基数的三种办法明天咱们解说下其中第二种断定办法的range_query 原理并且解说下query_log统计的原理总结range_query查问过程解析参数设置超时并设置opentracing依据queryEngine初始化query并解析promqlexec函数先设置 ExecTotalTimeexec函数进入队列排队 设置并计算 ExecQueueTimeexec函数 设置 EvalTotalTime 并执行execEvalStmt函数execEvalStmt函数 筹备存储上的querier+select series 设置并计算QueryPreparationTimeexecEvalStmt函数 设置InnerEvalTime,从存储拿到series后在本地内存中执行 evaluator.Eval(s.Expr)execEvalStmt函数设置并计算 ResultSortTimeprometheus query_log 配置配置# global段开启log即可global: query_log_file: /opt/logs/prometheus_query_logrange_query_log解析{ # 申请根底信息 "httpRequest":{ "clientIP":"192.168.43.114", "method":"POST", "path":"/api/v1/query_range" }, # 参数段 "params":{ "end":"2021-05-03T02:32:45.000Z", "query":"rate(node_disk_reads_completed_total{instance=~"192\\.168\\.43\\.114:9100"}[2m])", "start":"2021-05-03T02:17:45.000Z", "step":15 }, # 统计段 "stats":{ "timings":{ "evalTotalTime":0.000331799, "resultSortTime":0.000001235, "queryPreparationTime":0.000075478, "innerEvalTime":0.00024141, "execQueueTime":0.000012595, "execTotalTime":0.000354698 } }, # 申请工夫 "ts":"2021-05-03T02:32:49.876Z"}上面从源码层看下range_query的查问原理D:\nyy_work\go_path\pkg\mod\github.com\prometheus\prometheus@v1.8.2-0.20210220213500-8c8de46003d1\web\api\v1\api.go func (api *API) queryRange(r *http.Request) (result apiFuncResult) {}step1: 参数解析 // 解析start start, err := parseTime(r.FormValue("start")) if err != nil { return invalidParamError(err, "start") } // 解析end end, err := parseTime(r.FormValue("end")) if err != nil { return invalidParamError(err, "end") } // 判断end是否早于start if end.Before(start) { return invalidParamError(errors.New("end timestamp must not be before start time"), "end") } // 解析 step step, err := parseDuration(r.FormValue("step")) if err != nil { return invalidParamError(err, "step") } if step <= 0 { return invalidParamError(errors.New("zero or negative query resolution step widths are not accepted. Try a positive integer"), "step") }避免point过多 // 这里怎么了解? // For safety, limit the number of returned points per timeseries. // This is sufficient for 60s resolution for a week or 1h resolution for a year. if end.Sub(start)/step > 11000 { err := errors.New("exceeded maximum resolution of 11,000 points per timeseries. Try decreasing the query resolution (?step=XX)") return apiFuncResult{nil, &apiError{errorBadData, err}, nil, nil} }设置超时 ctx := r.Context() if to := r.FormValue("timeout"); to != "" { var cancel context.CancelFunc timeout, err := parseDuration(to) if err != nil { return invalidParamError(err, "timeout") } ctx, cancel = context.WithTimeout(ctx, timeout) defer cancel() }step2: 依据queryEngine初始化query并解析promqlfunc (ng *Engine) NewRangeQuery(q storage.Queryable, qs string, start, end time.Time, interval time.Duration) (Query, error) { expr, err := parser.ParseExpr(qs) if err != nil { return nil, err } if expr.Type() != parser.ValueTypeVector && expr.Type() != parser.ValueTypeScalar { return nil, errors.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type())) } qry, err := ng.newQuery(q, expr, start, end, interval) if err != nil { return nil, err } qry.q = qs return qry, nil}queryEngine从何而来? ...

May 6, 2021 · 4 min · jiezi

关于prometheus:高基数和prometheus中判定高基数的三种方法

写在最前prometheus断定高基数的三种办法prometheus tsdb的统计接口prometheus 能够依据query_log中的queryPreparationTime来定位prometheus 通过count by 统计什么是高基数 high-cardinality基数狭义上是指汇合中值的数量 在数据库畛域,基数是指数据库的特定列或字段中蕴含的惟一值的数量。 工夫序列数据集的基数通常由每个独自的索引列的基数的叉积定义 高基数示例:工业物联网设想一下一个IoT场景,其中某个采石场中有大量的重型设施在开采岩石,破碎岩石和分选岩石。假如有10,000件设施,每个设施带有100个传感器,运行10个不同的固件版本,散布在100个站点中:timestamp | temper | mem_f | equipm | senso | firmwar | sit | (lat,long) | ature | ree | ent_id | r_id | e_version | e_id |--------------------+-------+--------+-------------------+------+-----------2019-04-04 | 85.2 | 10.2 | 1 | 98 | 1.0 | 4 | (x,y) 09:00:00 | | | | | | | 2019-04-04 | 68.8 | 16.0 | 72 | 12 | 1.1 | 20 | (x1,y1)09:00:00 | | | | | | | 2019-04-04 | 100.0 | 0.0 | 34 | 58 | 2.1 | 55 | (x2,y2) 09:00:00 | | | | | | | 2019-04-04 | 84.8 | 9.8 | 12 | 75 | 1.4 | 81 | (x3,y3)09:00:00 | | | | | | | 2019-04-04 | 68.7 | 16.0 | 89 | 4 | 2.1 | 13 | (x4,y4)09:00:00 | | | | | | | ... | | | | | | | 而后,此数据集的最大基数变为10亿[10,000 x 100 x 10 x 100]。当初,假如设施也能够挪动,并且咱们想存储准确的GPS地位(纬度,经度),并将其用作索引的元数据进行查问。因为(lat,long)是一个间断字段(与诸如equipment_id之类的离散字段绝对),所以通过在地位上建设索引,此数据集的最大基数当初无限大(无界)。高基数查问艰深的说就是返回的series或者查问到的series数量过多查问体现进去返回工夫较长,对应调用服务端资源较多的查问数量多少算多 10w~100w个别咱们定义在1小时内的range_query 响应工夫超过3秒则认为较重了prometheus断定高基数的三种办法prometheus tsdb的统计接口prometheus 能够依据query_log中的queryPreparationTime来定位prometheus 通过count by 统计办法一 tsdb的统计接口http://192.168.43.114:9090/ts...接口地址 /api/v1/status/tsdb是基于内存中的倒排索引 算最大堆取 top1010个最多的metric_name排序 ...

May 6, 2021 · 2 min · jiezi

关于prometheus:别再乱用prometheus联邦了分享一个multiremoteread的方案来实现prometheus高可用

前言我看到很多人会这样应用联邦:联邦prometheus 收集多个采集器的数据切实看不下上来了,很多小白还在乱用prometheus的联邦其实很多人是想实现prometheus数据的可用性,数据分片保留,有个对立的查问中央(小白中的联邦prometheus)而且引入m3db等反对集群的tsdb可能比拟重 具体问题能够看我之前写的文章 m3db资源开销,聚合降采样,查问限度等注意事项m3db-node oom追踪和内存分配器代码查看明天写篇文章剖析下联邦的问题,并给出一个基于全副是prometheus的multi_remote_read计划架构图 联邦问题联邦文档地址联邦应用样例实质上就是采集级联说白了就是 a 从 b,c,d那里再采集数据过去能够搭配match指定只拉取某些指标上面就是官网文档给出的样例scrape_configs: - job_name: 'federate' scrape_interval: 15s honor_labels: true metrics_path: '/federate' params: 'match[]': - '{job="prometheus"}' - '{__name__=~"job:.*"}' static_configs: - targets: - 'source-prometheus-1:9090' - 'source-prometheus-2:9090' - 'source-prometheus-3:9090'看下面的样例配置怎么感觉是采集的配置呢不必狐疑就是,上面看看代码剖析一下 从上述配置能够看到采集的 path是 /federate // web.go 的 federate Handler router.Get("/federate", readyf(httputil.CompressionHandler{ Handler: http.HandlerFunc(h.federation), }.ServeHTTP))剖析下联邦函数 说白了就是读取本地存储数据处理func (h *Handler) federation(w http.ResponseWriter, req *http.Request) { // localstorage 的query q, err := h.localStorage.Querier(req.Context(), mint, maxt) defer q.Close() // 最终发送的Vector 数组 vec := make(promql.Vector, 0, 8000) hints := &storage.SelectHints{Start: mint, End: maxt} var sets []storage.SeriesSet set := storage.NewMergeSeriesSet(sets, storage.ChainedSeriesMerge) // 遍历存储中的full series for set.Next() { s := set.At() vec = append(vec, promql.Sample{ Metric: s.Labels(), Point: promql.Point{T: t, V: v}, }) for _, s := range vec { nameSeen := false globalUsed := map[string]struct{}{} protMetric := &dto.Metric{ Untyped: &dto.Untyped{}, } // Encode办法依据申请类型编码 if protMetricFam != nil { if err := enc.Encode(protMetricFam); err != nil { federationErrors.Inc() level.Error(h.logger).Log("msg", "federation failed", "err", err) return } } } protMetric.TimestampMs = proto.Int64(s.T) protMetric.Untyped.Value = proto.Float64(s.V) protMetricFam.Metric = append(protMetricFam.Metric, protMetric) } // if protMetricFam != nil { if err := enc.Encode(protMetricFam); err != nil { federationErrors.Inc() level.Error(h.logger).Log("msg", "federation failed", "err", err) } }}最终调用压缩函数压缩type CompressionHandler struct { Handler http.Handler}// ServeHTTP adds compression to the original http.Handler's ServeHTTP() method.func (c CompressionHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) { compWriter := newCompressedResponseWriter(writer, req) c.Handler.ServeHTTP(compWriter, req) compWriter.Close()}如果没有过滤那么只是一股脑把分片的数据集中到了一起,没意义很多时候是因为数据量太大了,扩散在多个采集器的数据是不能被一个联邦消化的正确应用联邦的姿态应用match加过滤,将采集数据分位两类 ...

April 29, 2021 · 2 min · jiezi

关于prometheus:Flagger-on-ASM基于Mixerless-Telemetry实现渐进式灰度发布系列-3-渐进式灰度发布

简介:作为CNCF[成员](https://landscape.cncf.io/car...[Weave Flagger](flagger.app)提供了继续集成和继续交付的各项能力。Flagger将渐进式公布总结为3类: - **灰度公布/金丝雀公布(Canary)**:用于渐进式切流到灰度版本(progressive traffic shifting) - **A/B测试(A/B Testing)**:用于依据申请信息将作为CNCF成员,Weave Flagger提供了继续集成和继续交付的各项能力。Flagger将渐进式公布总结为3类: 灰度公布/金丝雀公布(Canary):用于渐进式切流到灰度版本(progressive traffic shifting)A/B测试(A/B Testing):用于依据申请信息将用户申请路由到A/B版本(HTTP headers and cookies traffic routing)蓝绿公布(Blue/Green):用于流量切换和流量复制 (traffic switching and mirroring)本篇将介绍Flagger on ASM的渐进式灰度公布实际。 Setup Flagger1 部署Flagger执行如下命令部署flagger(残缺脚本参见:demo\_canary.sh)。 alias k="kubectl --kubeconfig $USER_CONFIG"alias h="helm --kubeconfig $USER_CONFIG"cp $MESH_CONFIG kubeconfigk -n istio-system create secret generic istio-kubeconfig --from-file kubeconfigk -n istio-system label secret istio-kubeconfig istio/multiCluster=trueh repo add flagger https://flagger.apph repo updatek apply -f $FLAAGER_SRC/artifacts/flagger/crd.yamlh upgrade -i flagger flagger/flagger --namespace=istio-system \ --set crd.create=false \ --set meshProvider=istio \ --set metricsServer=http://prometheus:9090 \ --set istio.kubeconfig.secretName=istio-kubeconfig \ --set istio.kubeconfig.key=kubeconfig2 部署Gateway在灰度公布过程中,Flagger会申请ASM更新用于灰度流量配置的VirtualService,这个VirtualService会应用到命名为public-gateway的Gateway。为此咱们创立相干Gateway配置文件public-gateway.yaml如下: ...

April 26, 2021 · 6 min · jiezi

关于prometheus:Flagger-on-ASM基于Mixerless-Telemetry实现渐进式灰度发布系列-1-遥测数据

简介:服务网格ASM的Mixerless Telemetry技术,为业务容器提供了无侵入式的遥测数据。遥测数据一方面作为监控指标被ARMPS/prometheus采集,用于服务网格可观测性;另一方面被HPA和flaggers应用,成为利用级扩缩容和渐进式灰度公布的基石。 本系列聚焦于遥测数据在利用级扩缩容和渐进式灰度公布上的实际,将分三篇介绍遥测数据(监控指标)、利用级扩缩容,和渐进式灰度公布。序服务网格ASM的Mixerless Telemetry技术,为业务容器提供了无侵入式的遥测数据。遥测数据一方面作为监控指标被ARMPS/prometheus采集,用于服务网格可观测性;另一方面被HPA和flaggers应用,成为利用级扩缩容和渐进式灰度公布的基石。 本系列聚焦于遥测数据在利用级扩缩容和渐进式灰度公布上的实际,将分三篇介绍遥测数据(监控指标)、利用级扩缩容,和渐进式灰度公布。 总体架构本系列的总体架构如下图所示: ASM下发Mixerless Telemetry相干的EnvoyFilter配置到各ASM sidecar(envoy),启用利用级监控指标的采集。业务流量通过Ingress Gateway进入,各ASM sidecar开始采集相干监控指标。Prometheus从各POD上采集监控指标。HPA通过Adapter从Prometheus查问相干POD的监控指标,并依据配置进行扩缩容。Flagger通过Prometheus查问相干POD的监控指标,并依据配置向ASM发动VirtualService配置更新。ASM下发VirtualService配置到各ASM sidecar,从而实现渐进式灰度公布。 Flagger渐进式公布流程Flagger官网形容了渐进式公布流程,这里翻译如下: 探测并更新灰度Deployment到新版本灰度POD实例数从0开始扩容期待灰度POD实例数达到HPA定义的最小正本数量灰度POD实例衰弱检测由flagger-loadtester实例发动acceptance-test验证灰度公布在验证失败时终止由flagger-loadtester实例发动load-test验证在配置流量复制时开始从生产全流量复制到灰度每分钟从Prometheus查问并检测申请成功率和申请提早等监控指标灰度公布在监控指标不符预期的数量达到阈值时终止达到配置中迭代的次数后进行流量复制开始切流到灰度POD实例更新生产Deployment到新版本期待生产Deployment滚动降级结束期待生产POD实例数达到HPA定义的最小正本数量生产POD实例衰弱检测切流回生产POD实例灰度POD实例缩容至0发送灰度公布剖析后果告诉原文如下: With the above configuration, Flagger will run a canary release with the following steps: detect new revision (deployment spec, secrets or configmaps changes)scale from zero the canary deploymentwait for the HPA to set the canary minimum replicascheck canary pods healthrun the acceptance testsabort the canary release if tests failstart the load testsmirror 100% of the traffic from primary to canarycheck request success rate and request duration every minuteabort the canary release if the metrics check failure threshold is reachedstop traffic mirroring after the number of iterations is reachedroute live traffic to the canary podspromote the canary (update the primary secrets, configmaps and deployment spec)wait for the primary deployment rollout to finishwait for the HPA to set the primary minimum replicascheck primary pods healthswitch live traffic back to primaryscale to zero the canarysend notification with the canary analysis result前提条件已创立ACK集群,详情请参见创立Kubernetes托管版集群。已创立ASM实例,详情请参见创立ASM实例。Setup Mixerless Telemetry本篇将介绍如何基于ASM配置并采集利用级监控指标(比方申请数量总数istio_requests_total和申请提早istio_request_duration等)。次要步骤包含创立EnvoyFilter、校验envoy遥测数据和校验Prometheus采集遥测数据。 ...

April 26, 2021 · 2 min · jiezi

关于k8s:干货丨如何进行容器管理平台监控k8s

转自@twt社区,作者:李志伟 随着容器化、分布式的一直倒退,业务零碎的逻辑变得复杂,定位问题越来越艰难,就须要从宿主机、容器治理平台和容器利用等多个层面进行监控,才能够定位性能问题、异样问题、平安问题等。本文介绍容器治理平台(k8s)的监控办法。 监控形式 容器类监控个别采纳Prometheus进行监控,反对默认的pull模式获取数据,这也是官网举荐的形式。然而如果一些网络或防火墙等起因无奈间接pull到数据的状况,就要借助Pushgateway让Prometheus转换为push形式获取数据;又比方咱们将prometheus搭建在外网去监控内网利用的状况下,因为内网有诸多平安限度使得无奈穿透,这时就要借助push模式来解决问题,还有就是监控的轮询监控大于被监控程序的执行工夫,比方5秒pull一次数据,然而被监控程序1秒就执行完了。如下为pull和push的通用比拟: Pull 实时性取决于定时工作;客户端是有状态,须要晓得拉取点,服务器端无状态,通常是短连贯;难点实时性和流量的取舍。 Push 实时性较好;客户端无状态,服务器端有状态,须要理解每个客户端的推送点;通常是长链接;难点客户端能力和push能力不匹配问题。 K8s集群监控 应用系统命令查看kubectl top pod --all-namespaces 应用prometheus查问语句 `sum(kube_pod_container_resource_limits{resource="cpu", unit="core",namespace="$Namespace"})` CPU usage / available CPU in cluster sum (rate (container_cpu_usage_seconds_total{namespace="$Namespace"}[1m])) / sum(machine_cpu_cores) * 100Kube_namespaces_cpu_used_percent >80% Kube_namespaces_memory_memused_bytes_percebt>80% Kube_namespaces_requests_cpu_percent>80% Kube_namespaces_requests_memory_percent>80% Pod监控项 资源限度 spec: containers: image: http://gcr.io/google_containers/serve_hostnameimagePullPolicy: Always name: kubernetes-serve-hostname resources: limits: cpu: "1" memory: 512Mi requests: cpu: "1" memory: 512Mi Pod Metrics 监控项举例: Kube_pod_container_limit_cpu_cores>2 Node节点监控及告警 命令Kubectl get nodes 间断5分钟node状态是非ready,与master节点失联,最大告警2次 先查看状态 Systemctl status kubelet ...

April 9, 2021 · 1 min · jiezi

关于rocketmq:基于-RocketMQ-Prometheus-Exporter-打造定制化-DevOps-平台

简介: 本文将对 RocketMQ-Exporter 的设计实现做一个简略的介绍,读者可通过本文理解到 RocketMQ-Exporter 的实现过程,以及通过 RocketMQ-Exporter 来搭建本人的 RocketMQ 监控零碎。RocketMQ 在线可交互教程现已登录知口头手实验室,PC 端登录 start.aliyun.com 即可中转。 作者 | 陈厚道  冯庆起源 | 阿里巴巴云原生公众号 导读:本文将对 RocketMQ-Exporter 的设计实现做一个简略的介绍,读者可通过本文理解到 RocketMQ-Exporter 的实现过程,以及通过 RocketMQ-Exporter 来搭建本人的 RocketMQ 监控零碎。RocketMQ 在线可交互教程现已登录知口头手实验室,PC 端登录 start.aliyun.com 即可中转。RocketMQ 云原生系列文章: 阿里的 RocketMQ 如何让双十一峰值之下 0 故障当 RocketMQ 遇上 Serverless,会碰撞出怎么的火花?云原生时代 RocketMQ 运维管控的利器 - RocketMQ Operator云原生时代消息中间件的演进路线基于 RocketMQ Prometheus Exporter 打造定制化 DevOps 平台(本文)RocketMQ-Exporter 我的项目的 GitHub 地址:https://github.com/apache/rocketmq-exporter 文章次要内容蕴含以下几个方面: RocketMQ 介绍Prometheus 简介RocketMQ-Exporter 的具体实现RocketMQ-Exporter 的监控指标和告警指标RocketMQ-Exporter 应用示例RocketMQ 介绍RocketMQ 是一个分布式音讯和流数据平台,具备低提早、高性能、高可靠性、万亿级容量和灵便的可扩展性。简略的来说,它由 Broker 服务器和客户端两局部组成,其中客户端一个是音讯发布者客户端(Producer),它负责向 Broker 服务器发送音讯;另外一个是音讯的消费者客户端(Consumer),多个消费者能够组成一个生产组,来订阅和拉取生产 Broker 服务器上存储的音讯。 ...

April 8, 2021 · 4 min · jiezi

关于prometheus:prometheus脑图梳理

[toc] prometheus脑图梳理官网grafanaprometheusnode_exporter官网脑图如下: 自我了解脑图:

February 7, 2021 · 1 min · jiezi

关于prometheus:VictoriaMetrics如何快照数TB的时序数据

VictoriaMetrics是一个疾速的工夫序列数据库。它反对Prometheus PromQL查问,其具备以下突出特点: 对高基数数据具备十分高的写入性能。无关详细信息,请参见本文。对大量数据时具备很高的查问性能。无关详细信息,请参见本文和此电子表格。对工夫序列数据具备高压缩率。在线即时快照,而不会影响数据库操作。让咱们钻研一下VictoriaMetrics反对下的即时快照如何工作。 简略介绍ClickHouseVictoriaMetrics将数据存储在相似于ClickHouse的 MergeTree表 数据结构中。它是用于剖析数据和其余事件流的最快的数据库。在典型的剖析查问上,它的性能要比PostgreSQL和MySQL等传统数据库高10到1000倍。这意味着单个ClickHouse服务器能够代替大量的惯例数据库。 ClickHouse的速度如此之快,这要归功于其MergeTree表引擎的架构。 什么是 MergeTree?MergeTree是面向列的表引擎,其建设在相似于Log Structured Merge Tree 的数据结构上。 MergeTree属性: 每列的数据别离存储。因为不须要在读取和跳过其余列的数据上破费资源,因而缩小了列扫描期间的开销。因为各个列通常蕴含类似的数据,因而这也进步了每列的压缩率。行按"主键"排序,该主键能够蕴含多列。主键没有惟一的束缚--多行可能具备雷同的主键。这样能够通过主键或其前缀疾速进行行查找和范畴扫描。另外,因为间断排序的行通常蕴含类似的数据,因而能够进步压缩率。行被分成中等大小的块。每个块由每个列的子块组成。每个块都是独立解决的。这意味着在多CPU零碎上具备靠近完满的可扩展性--只需为所有可用的CPU内核提供独立的块即可。能够配置块大小,然而倡议应用大小在64KB-2MB之间的子块,因而它们适宜CPU缓存。因为CPU缓存拜访比RAM拜访快得多,因而能够进步性能。另外,当必须从具备多行的块中仅拜访几行时,这会缩小开销。块合并为"parts"。这些parts相似于LSM树中的SSTables。 ClickHouse在后盾将较小的parts合并为较大的parts。与标准的LSM不同,MergeTree没有严格的part大小。合并过程进步了查问性能,因为每次查问都查看了较少的parts。另外,合并过程缩小了数据文件的数量,因为每个局部都蕴含与列数成比例的固定数量的文件。Parts合并还有另一个益处--更好的压缩率,因为它能够挪动更靠近已排序行的列数据。Parts通过"分区"分组到分区中。最后,ClickHouse容许在"Date"列上创立每月分区。当初,能够应用任意表达式来构建分区键。分区键的不同值导致不同的分区。这样能够疾速不便地按分区进行数据存档/删除。接下来真正介绍VictoriaMetrics中的即时快照。 VictoriaMetrics中的即时快照VictoriaMetrics将工夫序列数据存储在相似MergeTree的表中,因而它受害于上述性能。此外,它还存储了倒排索引,以便通过给定的工夫序列选择器进行疾速查找。倒排索引存储在mergeset中--一种数据结构,该数据结构建设在MergeTree思维的根底上,并针对倒排索引查找进行了优化。 MergeTree还有一个下面没有提到的重要属性--原子性。这意味着: 新减少的parts要么呈现在MergeTree中,要么无奈呈现。 MergeTree从不蕴含局部创立的parts。合并过程也是如此--parts要么齐全合并为新part,要么无奈合并。 MergeTree中没有局部合并的parts。MergeTree中的parts内容永不变。Parts是不可变的。合并到更大的Part后,才能够删除它们。这意味着MergeTree始终处于统一状态。 许多文件系统都提供诸如硬链接之类的"怪兽"。硬链接文件共享原始文件的内容。它与原始文件没有区别。硬链接不会在文件系统上占用额定的空间。删除原始文件后,硬链接文件将成为“原始文件”,因为它成为指向原始文件内容的惟一文件。无论文件大小如何,都会立刻创立硬链接。 VictoriaMetrics应用硬链接为工夫序列数据和倒排索引创立即时快照,因为它们都存储在相似MergeTree的数据结构中。它只是从原子上将所有parts的所有文件硬链接到快照目录。这是平安的,因为parts永远不会扭转。之后,能够应用任何适合的工具(例如,用于云存储的rsync或cp)将快照备份/存档到任何存储(例如,Amazon S3或Google Cloud Storage)。存档前无需进行快照压缩,因为它已蕴含高度压缩的数据--VictoriaMetrics为工夫序列数据提供了最佳的压缩率。 新创建的快照在文件系统上不占用额定的空间,因为其文件指向MergeTree表中的现有文件。即便快照大小超过10 TB也是如此!在原始MergeTree合并/删除从快照链接的局部之后,快照开始占用额定的空间。因而,不要遗记删除旧快照以开释磁盘空间。 论断VictoriaMetrics基于ClickHouse中MergeTree表引擎的杰出构想构建了即时快照。能够随时创立这些快照,而不会在VictoriaMetrics上造成任何停机工夫或失常操作的中断。 能够在单docker镜像或单服务器二进制文件上评估快照性能。可通过以下http处理程序应用: /snapshot/list — 列出所有可用的快照/snapshot/create — 创立一个新的快照/snapshot/delete?snapshot=… — 删除指定的快照创立的快照位于/<-storageDataPath>/snapshots目录下,其中-storageDataPath是命令行标记,其中蕴含VictoriaMetrics存储数据的文件系统门路。 PS: 本文属于翻译,原文

November 29, 2020 · 1 min · jiezi

关于prometheus:Prometheus监控告警浅析

前言最近有个新我的项目须要搞一套残缺的监控告警零碎,咱们应用了开源监控告警零碎Prometheus;其功能强大,能够很不便对其进行扩大,并且能够装置和应用简略;本文首先介绍Prometheus的整个监控流程;而后介绍如何收集监控数据,如何展现监控数据,如何触发告警;最初展现一个业务系统监控的demo。 监控架构Prometheus的整个架构流程能够参考如下图片:整个流程大抵分为收集数据,存储数据,展现监控数据,监控告警;外围组件包含:Exporters,Prometheus Server,AlertManager,PushGateway; Exporters:监控数据采集器,将数据通过Http的形式裸露给Prometheus Server;Prometheus Server:负责对监控数据的获取,存储以及查问;获取的监控数据须要是指定的Metrics 格局,这样能力解决监控数据;对于查问Prometheus提供了PromQL不便对数据进行查问汇总,当然Prometheus自身也提供了Web UI;AlertManager:Prometheus反对通过PromQL来创立告警规定,如果满足规定则创立一条告警,后续的告警流程就交给AlertManager,其提供了多种告警形式包含email,webhook等形式;PushGateway:失常状况下Prometheus Server可能间接与Exporter进行通信,而后pull数据;当网络需要无奈满足时就能够应用PushGateway作为中转站了;收集数据Exporter的次要性能就是收集数据,而后将数据通过http的形式裸露给Prometheus,而后Prometheus通过定期拉取的形式来获取监控数据;数据的起源多种多样包含:零碎级监控数据比方节点的cpu,io等,中间件比方mysql,mq等,过程级监控比方jvm等,业务监控数据等;除了监控的业务数据每个零碎可能不一样,除此之外其余的监控数据其实每个零碎都是大同小异的;所以在Exporter的起源分成了两类:社区提供的,用户自定义的; Exporter起源社区提供范畴罕用Exporter数据库MySQL Exporter, Redis Exporter, MongoDB Exporter等硬件Node Exporter等音讯队列Kafka Exporter, RabbitMQ Exporter等HTTP服务Apache Exporter, Nginx Exporter等存储HDFS Exporter等API服务Docker Hub Exporter, GitHub Exporter等其余JIRA Exporter, Jenkins Exporter, Confluence Exporter等官网提供的第三方Exporter:Exporters 用户自定义除了以上提供的第三方Exporter,用户也能够自定义Exporter,当然须要基于Prometheus提供的Client Library创立本人的Exporter程序,提供了对多种语言的反对包含:Go、Java/Scala、Python、Ruby等; Exporter运行形式从Exporter的运行形式上来讲,又能够分为:独立运行和集成到利用中; 独立运行像mysql,redis,mq这些中间件自身时不反对Prometheus,这时候就能够提供一个独立的Exporter,通过中间件对外提供的监控数据API,来获取监控数据,而后转换成Prometheus能够辨认的数据格式; 集成到利用中一些须要自定义监控指标的零碎,能够通过Prometheus提供的Client Library将监控数据在零碎外部提供给Prometheus; 数据格式Prometheus通过轮询的形式从Exporter获取监控数据,当然数据须要遵循肯定的格局,不然Prometheus也是无奈辨认的,这个格局就是 Metrics 格局. <metric name>{<label name>=<label value>, ...}次要分为三个局部 各个局部需合乎相干的正则表达式 metric name:指标的名称,次要反映被监控样本的含意 a-zA-Z_:*_label name: 标签 反映了以后样本的特色维度 [a-zA-Z0-9_]*label value: 各个标签的值,不限度格局能够看一个JVM的监控数据: # HELP jvm_memory_max_bytes The maximum amount of memory in bytes that can be used for memory management# TYPE jvm_memory_max_bytes gaugejvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Metaspace",} -1.0jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Eden Space",} 1.033895936E9jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Code Cache",} 2.5165824E8jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="nonheap",id="Compressed Class Space",} 1.073741824E9jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Survivor Space",} 2621440.0jvm_memory_max_bytes{application="springboot-actuator-prometheus-test",area="heap",id="PS Old Gen",} 2.09190912E9更多:data_model ...

November 6, 2020 · 4 min · jiezi

关于prometheus:prometheus在项目中的使用

Prometheus是什么 基于时序数据库的开源监控告警零碎,应用go语言最后由在线音乐分享的平台SoundCloud开源,2016年退出云原生计算基金会(CNCF,Cloud Native Computing Foundation)宽泛用于 Kubernetes 集群的监控零碎中时序数据的特点是: 增:须要频繁的进行写操作,而且是按工夫排序程序写入删:不须要随机删除,个别状况下会间接删除一个工夫区块的所有数据改:不须要对写入的数据进行更新查:须要反对高并发的读操作,读操作是按工夫程序升序或降序读,数据量十分大,缓存不起作用与监控数据地特点非常吻合 和mysql、redis相比,特点很显著: 多维度数据模型-由指标键值对标识的工夫序列数据组成(底层的数据结构是时序数列,能够对指标增加标签便于筛选)PromQL,一种灵便的查询语言。(在查问的时候组合条件进行筛选)不依赖分布式存储; 单个服务器节点是自治的。部署不便以HTTP形式,通过pull模式拉取工夫序列数据反对通过两头网关推送工夫序列数据通过服务发现或者动态配置,来发现指标服务对象反对多种多样的图表和界面展现目标: 目前的监控比拟少,现有的是健康检查,在portainer里看有没有失常的启用,还有在运行室配置的一些监控指标。并且大部分工夫服务都是失常运行的,不出事的话显得监控没什么意义,一旦出了问题,监控能够看呈现故障时刻的监控指标。交易数过多,内存,cpu的状况。事先预警,预先追踪性能优化架构: 组件: Prometheus server,用于抓取和存储工夫序列数据用于检测利用程序代码的client libraries用于反对短期jobs的push网关针对HAProxy,StatsD,Graphite等服务的特定exporters预警管理器来治理预警各种反对工具工作原理:客户端装置exporter,裸露监控指标的接口,prometheus定期从客户端pull数据,通过grafana或api clinet进行查问。 实用场景:记录任何纯数字工夫序列。 它实用于以机器为核心的监控以及高度动静的面向服务架构的监控。 在微服务的世界中,Prometheus的多维度数据收集和查问十分弱小。Prometheus是为服务的可靠性而设计的,当服务呈现故障时,它能够使你疾速定位和诊断问题。 每个Prometheus服务器都是独立的,不依赖于网络存储或其余近程服务。 当基础架构的其余局部损坏时,您能够依赖它,并且您不须要设置大量的基础架构来应用它。如果您须要100%的准确度,例如按申请计费,Prometheus不是一个好的抉择,因为收集的数据可能不够具体和残缺。 在这种状况下,您最好应用其余零碎来收集和剖析数据以进行计费,并应用Prometheus进行其余监控。 ExporterMySQL server exporter ElasticSearch exporterMongoDB exporterOracle DB ExporterRedis exporterRabbitMQ exporterNode exporterSNMP exporter 服务发现:azure、consul、dns、ec2、openstack、file、gce、kubernetes、marathon、triton、zookeeper(nerve、serverset) pull拉取采样点的端点服务称之为instance,通常对应一个过程(实例)。具备雷同目标的instance,例如,为可伸缩性或可靠性而复制的流程称为job。, 则形成了一个job 数据模型:从根本上存储的所有数据都是工夫序列: 具备工夫戳的数据流只属于单个度量指标和该度量指标下的多个标签维度。除了存储工夫序列数据外,Prometheus还能够生成长期派生的工夫序列作为查问的后果。每一个工夫序列数据由metric度量指标名称和它的标签labels键值对汇合惟一确定。这个metric度量指标名称指定监控指标零碎的测量特色(如:http_requests_total- 接管http申请的总计数)。 metric度量指标可能蕴含ASCII字母、数字、下划线和冒号,他必须配正则表达式a-zA-Z_:* 。labels开启了Prometheus的多维数据模型:对于雷同的度量名称,通过不同标签列表的联合, 会造成特定的度量维度实例。(例如:所有蕴含度量名称为/api/tracks的http申请,打上method=POST的标签,则造成了具体的http申请)。这个查询语言在这些度量和标签列表的根底上进行过滤和聚合。扭转任何度量上的任何标签值,则会造成新的工夫序列。 counter 是示意单个枯燥递增计数器的累积度量,其值只能在重启时减少或重置为零。Eg:申请数gauge是一个度量指标,它示意一个既能够递增, 又能够递加的值。Eg:cpu内存占用histogram,对察看后果进行采样(通常是申请持续时间或响应大小等),并将其计入可配置存储桶中。它还提供所有察看值的总和。summary是采样点分位图统计(通常是申请持续时间和响应大小等)。尽管它还提供察看的总数和所有观测值的总和,但它在滑动工夫窗口上计算可配置的分位数。Pull和push基于Http形式的pull模型提供了一下长处: 当开发变动时,能够运行监控如果指标实例挂掉,能够很容易地晓得能够手动指定一个指标,并通过浏览器查看该指标实例的监控情况在我的项目的利用: 服务的革新: 通过actuator和prometheus,对外裸露端点Security对裸露的端点进行爱护,每个服务增加filter,爱护/actuator/**并放行/actuator/health,以便健康检查能够通过。辨别mvc和webflux利用服务发现: 通过服务对外裸露的IP:port,多正本状况下无奈获取每个容器的指标通过eureka-consul进行服务发现,能够获取注册到eureka上的所有服务。须要将prometheus部署到服务网络,通过外部ip:port获取Prometheus server:监控SIT/QA/UAT环境: 通过一个prometheus监控不同环境,通过标签(job_name)进行辨别。不可行Push gateway,架构简单,须要保障pushgateway的高可用;无奈获取各个服务的状态每个环境均搭建prometheus ,grafana共用一个,在grafana通过选取不同的数据源展现不同环境的数据, Openapi服务 监控性能 Grafana中boot,Mysql,Redis的模板下载对应exporter,批改配置,Prometheus批改配置,增加exporter监控Grafana导入模板和时序数据库的区别:心愿部署和保护十分不便。 在微服务架构中,不同维度有不同的监控形式。 健康检查。健康检查是对利用自身健康状况的监控,查看服务是否还失常存活。日志。日志是排查问题的次要形式,日志能够提供丰盛的信息用于定位和解决问题。调用链监控。调用链监控能够残缺的呈现出一次申请的全副信息,包含服务调用链路、所耗时间等。指标监控。指标是一些基于工夫序列的离散数据点,通过聚合和计算后能反映出一些重要指标的趋势。应用服务监控根底监控数据次要是指应用服务实例的运行时状态、资源应用状况等度量指标。Micrometer默认提供了十分丰盛的利用度量指标,只有接入了Micrometer就能够间接采集到这些数据,次要包含: 零碎信息,包含运行工夫、CPU使用率、零碎负载等;内存应用状况,包含堆内存应用状况和非堆内存应用状况;线程应用状况,包含线程数、守护线程数、线程峰值等;类加载信息;GC信息,包含GC次数、GC耗费工夫等;HTTP申请状况,形容HTTP申请的性能指标,是十分重要的监控指标,在统计HTTP服务的QPS、响应工夫和成功率时必不可少。

November 2, 2020 · 1 min · jiezi

关于prometheus:第07期故障排查为什么发出的告警为已解决

本期作者:吴洋爱可生上海研发核心成员,研发工程师。 景象测试环境中呈现了一个异样的告警景象:一条告警通过 Thanos Ruler 的 HTTP 接口察看到继续处于 active 状态,然而从 AlertManager 这边看这条告警为已解决状态。依照 DMP 平台的设计,告警已解决指的是告警上设置的完结工夫曾经过了以后工夫。一条发送至 AlertManager 的告警为已解决状态有三种可能:1. 手动解决了告警2. 告警只产生了一次,第二次计算告警规定时会发送一个已解决的告警3. AlertManager 接管到的告警会带着一个主动解决工夫,如果还没达到主动解决工夫,则将该工夫重置为 24h 后首先,因为理解到测试环境没有手动解决过异样告警,排除第一条;其次,因为该告警继续处于 active 状态,所以不会是因为告警只产生了一次而接管到已解决状态的告警,排除第二条;最初,告警的告警的产生工夫与主动解决工夫相差不是 24h,排除第三条。那问题出在什么中央呢? 剖析上面咱们开始剖析这个问题。综合第一节的形容,初步的猜测是告警在达到 AlertManager 前的某些阶段的处理过程太长,导致告警达到 AlertManager 后就曾经过了主动解决工夫。咱们从剖析平台里一条告警的流转过程动手,找出告警在哪个解决阶段耗时过长。首先,一条告警的产生须要两方面的配合: metric 数据告警规定将 metric 数据输出到告警规定进行计算,如果符合条件则产生告警。DMP 平台集成了 Thanos 的相干组件,数据的提供和计算则会离开,数据还是由 Prometheus Server 提供,而告警规定的计算则交由 Thanos Rule(下文简称 Ruler)解决。下图是 Ruler 组件在集群中所处的地位: 看来,想要弄清楚现告警的产生到 AlertManager 之间的过程,须要先弄清除 Ruler 的大抵机制。官网文档对 Ruler 的介绍是:You can think of Rule as a simplified Prometheus that does not require a sidecar and does not scrape and do PromQL evaluation (no QueryAPI)。 ...

October 26, 2020 · 1 min · jiezi

关于prometheus:开源项目-promeshard-consulwatch动态分片实现Prometheus采集端高可用

开源我的项目地址:我的项目地址: https://github.com/ning1875/prome_shard

October 11, 2020 · 1 min · jiezi

关于prometheus:凤凰涅槃Cortex14-block-存储引擎

Cortex算得上反对prometheus的长久化存储的元老了,很早就退出到CNCF基金会,目前曾经处于孵化状态了。然而倒退却始终不温不火,反而thanos青出于蓝。细想其中的起因,其架构的复杂性无疑是一个重要的起因。上面是其chunk 存储模式的架构图: 波及到组件十几个,其chunk 模式,依赖两种存储,部署和保护艰难。 从瑜亮之争到双赢cortex和thanos 作为Prometheus长久化的两种计划,几乎就是瑜亮之争。各自有各自的劣势,不过貌似thanos倒退更好一些。 目前两种解决方案正在互相学习,逐渐补救本人的短处。乏味的是这两个计划,间接援用了对方的代码来补强性能。 对于thanos, 其变动体现在上面两个方面: 在写门路上,引入了receive组件,逐渐替换掉sidecar。在读门路上,引入了query-frontend 组件,用于split 大查问和缓存某些查问后果。对于cortex,其变动体现在引入block存储模式,简化了其架构模式。 实际上,在存储上,cortex向thanos学习更多一些。在读门路上,thanos向cortex学习更多一些。 上面咱们具体介绍一下cortex的block 存储引擎模式。 Block 存储引擎块存储是基于Prometheus TSDB的Cortex存储引擎:它将每个租户的工夫序列存储到本人的TSDB中,而后将其序列写到磁盘上的块中(默认为2h块范畴周期)。每个块由块文件(蕴含多个序列的工夫戳-值对)和索引组成,该索引将metrcis名称和labels索引到块文件中的工夫序列。 块存储反对的后端是: 亚马逊S3谷歌云存储Microsoft Azure存储本地文件系统(仅单节点)置信阿里云和腾讯云的对象存储也会很快反对。 架构运行Cortex块存储时,Cortex架构不会产生重大变动,因而惯例体系结构文档也实用于块存储。然而,运行块存储时还有两个其余的Cortex服务: Store-gatewayCompactor 能够看出compactor和store-gateway组件,显著学习了thanos。store-gateway负责查问chunk,并在查问时由查询器应用。抉择块存储模式时,须要store-gateway。compactor负责将较小的块合并和反复数据删除为较大的块,以缩小给定租户的长期存储中存储的块数量,并更无效地查问它们。compactor是可选的,然而在生产环境必不可少。 写门路Ingesters从distributors接管进来的sample。每个推送申请都属于一个租户,而ingester会将接管到的sample附加到存储在本地磁盘上的特定的每个租户TSDB。接管到的sample都保留在内存中,并写入到预写日志(WAL)中,并用于在内存忽然终止的状况下复原内存中的序列。一旦每个租户收到第一个sample,就会在每个租户中提早创立每个租户的TSDB。 创立新的TSDB块时,内存中的sample会定期刷新到磁盘,并且WAL会被截断,默认状况下,每2个小时会产生一次。而后,每个新创建的块都将上载到长期存储中,并保留在初始状态,直到配置的-blocks-storage.tsdb.retention-period到期为止,以便给予queriers 和 store-gateways足够的工夫来发现新块存储并下载其索引头。 为了无效地应用WAL并可能在忽然终止Inester后复原内存中的序列,WAL须要存储到一个永恒磁盘,该磁盘在产生Inester失败(例如AWS EBS卷或GCP)的状况下仍能够生存在云端运行时应用永恒磁盘)。例如,如果您在Kubernetes中运行Cortex集群,则能够将StatefulSet与长久化批量申明一起应用。文件系统上存储WAL的地位与存储本地TSDB块(从头压缩)的地位雷同,并且无奈解耦。 Distributor series 分片和复制Distributor 实现的series分片和复制不会依据存储引擎而扭转。请务必留神,因为复制因子为N(通常为3),因而与块存储不同的是,因为复制因子N,每个工夫序列均存储N个ingesters。因为每个实例都将其本人的块写入长期存储,因而这导致存储利用率是块存储的N倍。 Compactor通过将来自多个ingesters的块合并为一个块,并删除反复的sample来解决此问题。 读门路Queriers 和 store-gateways 定期在存储桶上进行迭代,以发现最近由ingesters上传的块。 对于每个发现的块,Queriers 仅下载块的meta.json文件(蕴含一些元数据,包含该块中sample的最小和最大工夫戳),而 store-gateways 下载meta.json以及索引头,这是一个store-gateways在查问时用于查找序列的块索引的一小部分。 Queriers应用块元数据来计算在查问时须要查问的块列表,并从保留所需块的store-gateways实例中获取匹配序列。 总结不过因为cortex 倒退比拟早,其组件更丰盛。也是将来thanos的倒退方向。例如cortex 封装了alertmanager,使其也反对多租户。 到底谁是赢家,不太好说。不过最终胜利的那个解决方案,身上肯定存满了另一个的影子。

October 8, 2020 · 1 min · jiezi

关于prometheus:第06期Prometheus-存储

Description: 本文是介绍了Prometheus的两种贮存类型和本地存储的原理 Author: 孙健,爱可生上海研发核心成员,研发工程师 一、前言Prometheus 提供了本地存储,本文次要讲述 Prometheus 自带的 tsdb 时序数据库。 二、本地存储(tsdb)1. 什么是时序数据库时序数据库全称为工夫序列数据库。工夫序列数据库次要用于指解决带工夫标签(依照工夫的程序变动,即工夫序列化)的数据,带工夫标签的数据也称为工夫序列数据。次要用于存储周期性的采集各种实时监控信息。 2. 特点垂直写,程度读 数据点写入扩散,且数据量微小热点数据显著 3.存储配置--storage.tsdb.path:数据存储目录。默认为 data/。--storage.tsdb.retention.time:数据过期清理工夫。默认为15天。--storage.tsdb.wal-compression:此标记启用预写日志(WAL)的压缩。依据您的数据,您能够预期WAL大小将缩小一半,而额定的CPU负载却很少。此标记在2.11.0中引入,默认状况下在2.20.0中启用。请留神,一旦启用,将Prometheus降级到2.11.0以下的版本将须要删除WAL。4.目录构造首先,block 在这里是一个数据块,每个数据块绝对独立,由一个目录组成,该目录里蕴含:一个或者多个 chunk 文件(保留 timeseries 数据)、一个 metadata文件、一个 index 文件(通过 metric name 和 labels 查找 timeseries 数据在 chunk 文件的地位)。 ./data├── 01BKGV7JBM69T2G1BGBGM6KB12│ └── meta.json├── 01BKGTZQ1SYQJTR4PB43C8PD98│ ├── chunks│ │ └── 000001│ ├── tombstones│ ├── index│ └── meta.json├── 01BKGTZQ1HHWHV8FBJXW1Y3W0K│ └── meta.json├── 01BKGV7JC0RY8A6MACW02A2PJD│ ├── chunks│ │ └── 000001│ ├── tombstones│ ├── index│ └── meta.json└── wal ├── 00000002 └── checkpoint.0000015.贮存原理(write) ...

September 29, 2020 · 1 min · jiezi

关于prometheus:Prometheus-监控系统的学习总结

APMAPM ( Application Performance Management ) 是利用性能治理的缩写,代表了服务的行为、可靠性、性能等的监控和治理。当利用产生故障,利用 APM 设施能够迅速检测并定位到产生故障的起因。 现在的后端服务大都是分布式、微服务化的,做好 APM 尤为重要。APM 包含许多方面工作,包含链路追踪(Tracing)、日志(Logging) 和 指标(Metrics)监控与报警 等,对应的开源基础设施也有很多,如 Jaeger/Zipkin (链路跟踪)、ELK (日志)、Prometheus/Zabbix/InfluxDB (指标监控零碎)、Grafana (监控展现前端) 等。 明天来说说什么是指标监控,以及总结一下最近学习 Prometheus 的心得,梳理一下常识网络。 Metrics 指标和 Prometheus咱们通常在应用程序中产生日志,日志往往代表的是一个利用或申请生命周期中的一个事件,它是离散的数据。而指标往往代表着应用程序中可量化可聚合剖析的数据,例如服务接管的申请量,申请量是一个一直减少的数据,咱们能够依据它和工夫的对应关系,计算出申请的增长率;再比方,服务的申请提早,咱们能够收集所有的提早时长,统计出不同的分位数,以掂量服务的整体提早体现;再比方音讯队列零碎的工作沉积状况、服务的内存占用、主机的 CPU 占用率等,这些是一个个高低浮动的数值,能够反馈一些实时情况,并且通过历史工夫的数据,反馈过来一段时间的数据稳定状况,以预测将来变动。 通过 Prometheus 咱们就能够进行这些指标数据的统计、收集、查问/聚合剖析、可视化展现、非正常指标的报警等工作。能够把 Prometheus 了解为一个指标收集器与时序数据库 (TSDB) 的汇合。 Prometheus 架构 Prometheus 采纳 PULL 的模式定期从应用程序中拉取指标数据。应用程序指标地址能够以动态配置的形式提供,也能够配置服务注册核心,动静的形式获取指标地址,见 文档。 组件Exporter 采集指标数据,为 Prometheus server 提供采集接口。Exporter 能够集成在业务代码中,也能够是一个独自的过程服务,来采集其余的服务指标。Pushgateway 是一个两头服务,短生命周期的 job 上传指标到 Pushgateway,server 从 Pushgateway 采集指标。TSDB 是 Prometheus server 内置的时序数据库,用来存储采集的指标数据,并且内置了一套用以查问数据的语法 PromQL。Alertmanager 是独立于 Prometheus server 的一个服务,用来解决报警。Prometheus server 只负责评估报警规定是否被触发,后续的报警告诉等工作交由 Alertmanager 解决。部署本地应用 Docker Compose 进行部署。 ...

September 14, 2020 · 2 min · jiezi

关于prometheus:开源项目-promeroute-使用反向代理实现prometheus分片

开源我的项目地址:我的项目地址: https://github.com/ning1875/prome-routePS: 这是一个仅用时半天就写完的我的项目 架构图 prometheus HAprometheus本地tsdb性能杰出,然而碍于其没有集群版本导致 实现伎俩留神这些伎俩都是要数据的对立存储 能够通过remote_write 到一个提供HA的tsdb存储中通过联邦收集到一个prometheus里问题来了,搞不定集中式的tsdb集群,或者集群挂了咋办本我的项目介绍原理介绍必定有一组prometheus 服务器和pod用来采集各式各样的数据那么采集器上本地的数据就是一个个分片,采集器自身也能够充当查问的角色而且每个采集器下面的指标通过一个特色标签比方cluster/app等辨别通常是定义global.external_labels中的 global: external_labels: cluster: a如果能有一个路由组件,晓得所有特色标签对应的采集器地址shard_addr_map = { "cluster_a": "1.1.1.1:9090", "cluster_b": "2.2.2.2:9090", "cluster_c": "3.3.3.3:9090", }而后依据申请中的expr获取到特色标签,将其替换掉因为在采集器本地存储的时候没有特色标签转发到指定的采集器申请数据后再返回给grafana即可须要适配的接口prometheus 3大查问接口instance_query : /api/v1/query 报警应用和以后点查问range_query : /api/v1/query_range 查问一段时间的曲线series : /api/v1/series 应用label_values查问变量对应在代码中实现 func Routes(r *gin.Engine) { qApi := r.Group("/") qApi.GET("/api/v1/query_range", promeRangequery) qApi.GET("/api/v1/query", promeInstancequery) qApi.GET("/api/v1/series", promeSeriesQuery) }查问状态码不同时返回数据结构不同这个很好解决,用interface即可 respBytes, err := ioutil.ReadAll(resp.Body) if err != nil { log.Error(err.Error()) c.String(http.StatusInternalServerError, fmt.Sprintf(`target prome %s error by %s=%s `, targetProme, keyName, labelName)) return } var respInterface interface{} _ = json.Unmarshal(respBytes, &respInterface) c.JSON(resp.StatusCode, respInterface)优缺点长处 ...

September 10, 2020 · 1 min · jiezi

关于prometheus:第05期使用-prometheus-监控-clickhouse-集群

一、前言本文介绍采纳 clickhouse-exporter + grafana + prometheus 搭建监控 clickhouse 单节点和集群的监控体系。 二、部署 exporter获取代码并编译mkdir -p $GO_PATH/src/github.com/Percona-Labcd $GO_PATH/src/github.com/Percona-Labgit clone https://github.com/Percona-Lab/clickhouse_exporter因为生产环境的零碎是基于 Linux,不能间接拜访外网。故在本人的 mac 零碎先编译成二进制,而后拷贝到生产环境。 在 mac 上编译 clickhouse_exporter,再下载到源代码目录。 cd $GO_PATH/src/github.com/Percona-LabGO111MODULE=off `CGO_ENABLED`=0 GOOS=linux GOARCH=amd64 go build clickhouse_exporter.go编译胜利会看到二进制文件,$ ./clickhouse_exporter -hUsage of ./clickhouse_exporter: -insecure Ignore server certificate if using https (default true) -log.level value Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal, panic]. -scrape_uri string URI to clickhouse http endpoint (default "http://localhost:8123/") -telemetry.address string Address on which to expose metrics. (default ":9116") -telemetry.endpoint string Path under which to expose metrics. (default "/metrics")配置比较简单,就是指定 scrape_uri=clickhouse_server_ip:port,  ...

September 10, 2020 · 1 min · jiezi

关于prometheus:Prometheus监控神器Kubernetes篇二

在Kubernetes中手动形式部署Statefulset的Grafana,并应用StorageClass来长久化数据,并且配置ingress-nginx拜访。本篇应用StorageClass来长久化数据,搭建Statefulset的Grafana,并且在Dashboard导入前配置后面曾经创立好的Prometheus的集群外部拜访地址,同时配置ingress-nginx内部拜访。 环境我的本地环境应用的 sealos 一键部署,次要是为了便于测试。 OSKubernetesHostNameIPServiceUbuntu 18.041.17.7sealos-k8s-m1192.168.1.151node-exporter prometheus-federate-0Ubuntu 18.041.17.7sealos-k8s-m2192.168.1.152node-exporter grafana alertmanager-0Ubuntu 18.041.17.7sealos-k8s-m3192.168.1.150node-exporter alertmanager-1Ubuntu 18.041.17.7sealos-k8s-node1192.168.1.153node-exporter prometheus-0 kube-state-metricsUbuntu 18.041.17.7sealos-k8s-node2192.168.1.154node-exporter prometheus-1Ubuntu 18.041.17.7sealos-k8s-node2192.168.1.155node-exporter prometheus-2部署 Grafana创立Grafana的SA文件 mkdir /data/manual-deploy/grafana/cat grafana-serviceaccount.yamlapiVersion: v1kind: ServiceAccountmetadata: name: grafana namespace: kube-system创立Grafana的sc配置文件 cat grafana-data-storageclass.yamlapiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: grafana-lpvprovisioner: kubernetes.io/no-provisionervolumeBindingMode: WaitForFirstConsumer创立Grafana的pv配置文件 cat grafana-data-pv.yamlapiVersion: v1kind: PersistentVolumemetadata: name: grafana-pv-0spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: grafana-lpv local: path: /data/grafana-data nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - sealos-k8s-m2在调度节点上创立pv目录与赋权 ...

September 9, 2020 · 6 min · jiezi

关于prometheus:Prometheus监控神器服务发现篇一

本章节次要讲主动发现应用场景介绍与Prometheus基于文件、DNS的主动发现配置当咱们应用各类exporter别离对系统、数据库和HTTP服务进行监控指标采集,对于所有监控指标对应的Target的运行状态和资源应用状况,都是用Prometheus的动态配置性能 static_configs 来手动增加主机IP和端口,而后重载服务让Prometheus发现。 对于一组比拟少的服务器的测试环境中,这种手动形式增加配置信息是最简略的办法。然而理论生产环境中,对于成千盈百的节点组成的大型集群又或者Kubernetes这样的大型集群,很显著,手动形式顾此失彼了。为此,Prometheus提前曾经设计了一套服务发现性能。 Prometheus 服务发现可能自动检测分类,并且可能辨认新节点和变更节点。也就是说,能够在容器或者云平台中,主动发现并监控节点或更新节点,动静的进行数据采集和解决。目前 Prometheus 曾经反对了很多常见的主动发现服务,比方 consul ec2 gce serverset_sd_config openStack kubernetes 等等。咱们罕用的就是sd_config、DNS、kubernetes、consul这些足够了。如果有须要其余配置的探讨,能够与我交换,我能够补上来。 本章节中会对Prometheus主动发现中的基于文件、DNS进行发现解说,consul 在前面会独自开展来讲,如何能够使其完满的解决以后场景下常见的各类服务发现监控。 为什么要用主动发现?在基于云(IaaS或者CaaS)的基础设施环境中用户能够像应用水、电一样按需应用各种资源(计算、网络、存储)。按需应用就意味着资源的动态性,这些资源能够随着需要规模的变动而变动。例如在AWS中就提供了专门的AutoScall服务,能够依据用户定义的规定动静地创立或者销毁EC2实例,从而使用户部署在AWS上的利用能够主动的适应拜访规模的变动。 这种按需的资源应用形式对于监控零碎而言就意味着没有了一个固定的监控指标,所有的监控对象(基础设施、利用、服务)都在动静的变动。对于Nagias这类基于Push模式传统监控软件就意味着必须在每一个节点上装置相应的Agent程序,并且通过配置指向核心的Nagias服务,受监控的资源与核心监控服务器之间是一个强耦合的关系,要么间接将Agent构建到基础设施镜像当中,要么应用一些自动化配置管理工具(如Ansible、Chef)动静的配置这些节点。当然理论场景下除了基础设施的监控需要以外,咱们还须要监控在云上部署的利用,中间件等等各种各样的服务。要搭建起这样一套中心化的监控系统实施老本和难度是不言而喻的。 而对于Prometheus这一类基于Pull模式的监控零碎,显然也无奈持续应用的static_configs的形式动态的定义监控指标。而对于Prometheus而言其解决方案就是引入一个两头的代理人(服务注册核心),这个代理人把握着以后所有监控指标的访问信息,Prometheus只须要向这个代理人询问有哪些监控指标控即可, 这种模式被称为服务发现。 在不同的场景下,会有不同的货色扮演者代理人(服务发现与注册核心)这一角色。比方在AWS私有云平台或者OpenStack的公有云平台中,因为这些平台本身把握着所有资源的信息,此时这些云平台本身就表演了代理人的角色。Prometheus通过应用平台提供的API就能够找到所有须要监控的云主机。在Kubernetes这类容器治理平台中,Kubernetes把握并治理着所有的容器以及服务信息,那此时Prometheus只须要与Kubernetes打交道就能够找到所有须要监控的容器以及服务对象。Prometheus还能够间接与一些开源的服务发现工具进行集成,例如在微服务架构的应用程序中,常常会应用到例如Consul这样的服务发现注册软件,Promethues也能够与其集成从而动静的发现须要监控的应用服务实例。除了与这些平台级的私有云、公有云、容器云以及专门的服务发现注册核心集成以外,Prometheus还反对基于DNS以及文件的形式动静发现监控指标,从而大大的缩小了在云原生,微服务以及云模式下监控施行难度。 如上所示,展现了Push零碎和Pull零碎的外围差别。相较于Push模式,Pull模式的长处能够简略总结为以下几点: 只有Exporter在运行,你能够在任何中央(比方在本地),搭建你的监控零碎;你能够更容易的查看监控指标实例的衰弱状态,并且能够疾速定位故障;更利于构建DevOps文化的团队;松耦合的架构模式更适宜于云原生的部署环境。基于文件的服务发现在Prometheus反对的泛滥服务发现的实现形式中,基于文件的服务发现是最通用的形式。这种形式不须要依赖于任何的平台或者第三方服务。对于Prometheus而言也不可能反对所有的平台或者环境。通过基于文件的服务发现形式下,Prometheus会定时从文件中读取最新的Target信息,因而,你能够通过任意的形式将监控Target的信息写入即可。用户能够通过JSON或者YAML格局的文件,定义所有的监控指标。例如,在上面的yaml文件中别离定义了2个采集工作,以及每个工作对应的Target列表: yaml格局 - targets: ['192.168.1.220:9100'] labels: app: 'app1' env: 'game1' region: 'us-west-2'- targets: ['192.168.1.221:9100'] labels: app: 'app2' env: 'game2' region: 'ap-southeast-1'json格局 [ { "targets": [ "192.168.1.221:29090"], "labels": { "app": "app1", "env": "game1", "region": "us-west-2" } }, { "targets": [ "192.168.1.222:29090" ], "labels": { "app": "app2", "env": "game2", "region": "ap-southeast-1" } }]同时还能够通过为这些实例增加一些额定的标签信息,例如应用env标签标示以后节点所在的环境,这样从这些实例中采集到的样本信息将蕴含这些标签信息,从而能够通过该标签依照环境对数据进行统计。 ...

August 25, 2020 · 2 min · jiezi

关于prometheus:Prometheus监控神器Alertmanager篇4

本章节次要解说Alertmanager高可用的搭建与配置的具体的常识内容。为了晋升Prometheus的服务可靠性,咱们会部署两个或多个的Prometheus服务,两个Prometheus具备雷同的配置(Job配、告警规定、等),当其中一个Down掉了当前,能够保障Prometheus继续可用。 AlertManager自带警报分组机制,即便不同的Prometheus别离发送雷同的警报给Alertmanager,Alertmanager也会主动把这些警报合并解决。 | 去重 | 分组 | 路由 | | :-----: | :----: |:----: | |Daduplicates|Groups|Route||将雷同的警报合并成一个|依据定义的分组|通过路由分发给指定的receiver| 尽管Alertmanager 可能同时解决多个雷同的Prometheus的产生的警报,如果部署的Alertmanager是单节点,那就存在显著的的单点故障危险,当Alertmanager节点down机当前,警报性能则不可用。 解决这个问题的办法就是应用传统的HA架构模式,部署Alertmanager多节点。然而因为Alertmanager之间关联存在不能满足HA的需要,因而会导致警报告诉被Alertmanager反复发送屡次的问题。 Alertmanager为了解决这个问题,引入了Gossip机制,为多个Alertmanager之间提供信息传递机制。确保及时的在多个Alertmanager别离承受到雷同的警报信息的状况下,不会发送反复的警报信息给Receiver. Gossip 机制要晓得什么是Gossip机制,必须理解分明Alertmanager中的每一次警报告诉是如何产生的,上面一图很具体的论述了警报个流程: 阶段形容Silence在这个阶段中Alertmanager会判断以后告诉是否匹配任何静默规定;如果没有则进入下一个阶段,否则会中断流程不发送告诉。WaitAlertmanager 会依据以后集群中所处在的程序[index],期待 index * 5s 的工夫。Dedup当期待完结实现,进入 Dedup 阶段,这时会判断以后Alertmanager TSDB中警报是否曾经发送,如果发送则中断流程,不发送警报。Send如果下面的未发送,则进入 Send 阶段,发送警报告诉。Gossip警报发送胜利当前,进入最初一个阶段 Gossip ,告诉其余Alertmanager节点,以后警报曾经发送胜利。其余Alertmanager节点会保留以后曾经发送过的警报记录。Gossip的俩个要害: Alertmanager 节点之间的Silence设置雷同,这样确保了设置为静默的警报都不会对外发送Alertmanager 节点之间通过Gossip机制同步警报告诉状态,并且在流程中标记Wait阶段,保障警报是顺次被集群中的Alertmanager节点读取并解决。搭建本地 Alertmanager 集群启动Alertmanager集群之前,须要理解一些集群相干的参数 参数阐明--cluster.listen-address="0.0.0.0:9094"集群服务监听端口--cluster.peer初始化关联其余节点的监听地址--cluster.advertise-address播送地址--cluster.gossip-interval集群音讯流传工夫,默认 200s--cluster.probe-interval各个节点的探测工夫距离# 间接复制之前曾经装置过的Alertmanager文件夹cp -r alertmanager/ /usr/local/alertmanager01cp -r alertmanager/ /usr/local/alertmanager02cp -r alertmanager/ /usr/local/alertmanager03# 复制实现当前,写入启动脚本,# Alertmanager01cat << EOF> /lib/systemd/system/alertmanager01.service[Unit]Description=alertmanagerDocumentation=https://prometheus.io/After=network.targetStartLimitIntervalSec=0[Service]Type=simpleUser=prometheusExecStart=/usr/local/alertmanager01/bin/alertmanager \--config.file=/usr/local/alertmanager01/conf/alertmanager.yml \--storage.path=/usr/local/alertmanager01/data \--web.listen-address=":19093" \--cluster.listen-address=192.168.1.220:19094 \--log.level=debugRestart=alwaysRestartSec=1[Install]WantedBy=multi-user.targetEOF# Alertmanager02cat << EOF> /lib/systemd/system/alertmanager02.service[Unit]Description=alertmanagerDocumentation=https://prometheus.io/After=network.targetStartLimitIntervalSec=0[Service]Type=simpleUser=prometheusExecStart=/usr/local/alertmanager02/bin/alertmanager \--config.file=/usr/local/alertmanager02/conf/alertmanager.yml \--storage.path=/usr/local/alertmanager02/data \--web.listen-address=":29093" \--cluster.listen-address=192.168.1.220:29094 \--cluster.peer=192.168.1.220:19094 \--log.level=debugRestart=alwaysRestartSec=1[Install]WantedBy=multi-user.targetEOF# Alertmanager03cat <<EOF > /lib/systemd/system/alertmanager03.service[Unit]Description=alertmanagerDocumentation=https://prometheus.io/After=network.targetStartLimitIntervalSec=0[Service]Type=simpleUser=prometheusExecStart=/usr/local/alertmanager03/bin/alertmanager \--config.file=/usr/local/alertmanager03/conf/alertmanager.yml \--storage.path=/usr/local/alertmanager03/data \--web.listen-address=":39093" \--cluster.listen-address=192.168.1.220:39094 \--cluster.peer=192.168.1.220:19094 \--log.level=debugRestart=alwaysRestartSec=1[Install]WantedBy=multi-user.targetEOF# 开启systemd脚本启动systemctl enable alertmanager01 alertmanager02 alertmanager03systemctl start alertmanager01 alertmanager02 alertmanager03启动实现后,就能够拜访http://192.168.1.220:19093能够看到以下集群状态了,我这里是为了测试,本地启动了多个端口,如果是理论生产环境中,是不同节点以及不同的IP,这些依据本人的需要设计即可。 ...

August 25, 2020 · 1 min · jiezi

关于prometheus:Prometheus监控神器Alertmanager篇3

本章次要对介绍什么是 Silences , 在哪些场景中应用、以及如何设置 警报长期静默 Silences。静默 Silences 是指让通过设置让警报在指定工夫临时不会发送警报的一种形式。通常静默个别用于解决重大生产故障问题时,因所破费的工夫过长,通过静默设置防止接管到过多的无用告诉。在已知的例行保护中,为了避免对例行保护的机器发送不必要的警报,能够在保护期间设置一个工夫范畴,长期敞开警报发送,期待保护实现,在将静默敞开,另外次要下本人的时区,这里应用的是UTC工夫做的测试。 设置 Silences的形式有俩种,始终是通过 WEB UI 配置,一种是通过 amtool 工具在命令行进行设置。 Silences 创立信息形容: | 名字 | 形容 || :-----: | :----: | |Start|静默的开始工夫||End|静默的完结工夫||Duration|主动计算静默工夫,就是说开始当前,残余的工夫会在此显示||Matches|应用Labels来辨认须要静默的警报,能够间接匹配,也能够应用正则表达式。||Creator|创建者名称||Comment|形容信息| 通过下面的形容其实能够很容易晓得须要制订的参数信息,当输出实现后,间接点击create创立即可,此时去触发警报就会发现,警报不会在告诉,上面是已创立好的Silences信息。 这个时候咱们能够应用 service process_exporter stop 来触发警报,查看静默是否失效,在浏览器咱们能够看到,触发的警报曾经呈现在咱们创立的 Silences 中了。 这个时候咱们能够假如保护,并没有实现,用 Expire 来模仿保护工夫达到,而后在 Alerts 中我就能够看到警报了,相干的告诉会发送到对应的Receiver中。

August 25, 2020 · 1 min · jiezi

关于prometheus:m3dbnode-oom追踪和内存分配器代码查看

m3dbnode oomoom时排查内存火焰图: 80G内存 bytes_pool_get_on_empty qps 很高db read qps增长 80%node cpu kernel 暴涨 看图论断 m3dbnode 内存oom过程很短,很激烈:总工夫不超过7分钟内存从27G增长到250G节点sys态cpu暴涨:因为大量的mem_alloca sys_call内存增长曲线和db_read_qps曲线和bytes_pool_get_on_empty曲线高度吻合内存火焰图: 27G的rpc 40G的pool.(*objectPool).tryFill查看代码,追踪火焰图中这个tryFill内存分配器目标很简略:本人治理内存,防止频繁的mem_allocate sys_call 晋升速度,空间换工夫 外围构造初始化时调用init 向池中注入type objectPool struct { opts ObjectPoolOptions values chan interface{} alloc Allocator size int refillLowWatermark int refillHighWatermark int filling int32 initialized int32 dice int32 metrics objectPoolMetrics} for i := 0; i < cap(p.values); i++ { p.values <- p.alloc() }从池中获取对象时池中还有残余则间接获取否则走各自的alloc调配同时设置bytes_pool_get_on_emptyfunc (p *objectPool) Get() interface{} { if atomic.LoadInt32(&p.initialized) != 1 { fn := p.opts.OnPoolAccessErrorFn() fn(errPoolGetBeforeInitialized) return p.alloc() } var v interface{} select { case v = <-p.values: default: v = p.alloc() p.metrics.getOnEmpty.Inc(1) } p.trySetGauges() return v}同时判断池水位,是否加油 if p.refillLowWatermark > 0 && len(p.values) <= p.refillLowWatermark { p.tryFill() }加油过程用CompareAndSwapInt32做并发管制标记位加油加到refillHighWatermarkfunc (p *objectPool) tryFill() { if !atomic.CompareAndSwapInt32(&p.filling, 0, 1) { return } go func() { defer atomic.StoreInt32(&p.filling, 0) for len(p.values) < p.refillHighWatermark { select { case p.values <- p.alloc(): default: return } } }()}默认池参数 defaultRefillLowWaterMark = 0.3 defaultRefillHighWaterMark = 0.6总结思考默认池低水位为什么不是0:因为 从水位判断到tryFill两头的并发申请使得最初tryFill开始时低水位可能低于0.3火焰图中的tryFill耗费了40G内存不是一次性的,类比右侧thriftrpc27,属于累加内存耗费值一次性的内存耗费必定没有这么多:每次加油时内存耗费低于初始化所以能够失去论断,oom是因为在过后byte_pool频繁的get耗费,而后tryFill频繁的加油导致内存调配所以根本原因还是查问导致的解决办法:限度query资源耗费爱护db批改m3coordinator参数 ...

August 13, 2020 · 1 min · jiezi

关于prometheus:m3dbnode-oom追踪和内存分配器代码查看

m3dbnode oomoom时排查内存火焰图: 80G内存 bytes_pool_get_on_empty qps 很高db read qps增长 80%node cpu kernel 暴涨 看图论断 m3dbnode 内存oom过程很短,很激烈:总工夫不超过7分钟内存从27G增长到250G节点sys态cpu暴涨:因为大量的mem_alloca sys_call内存增长曲线和db_read_qps曲线和bytes_pool_get_on_empty曲线高度吻合内存火焰图: 27G的rpc 40G的pool.(*objectPool).tryFill查看代码,追踪火焰图中这个tryFill内存分配器目标很简略:本人治理内存,防止频繁的mem_allocate sys_call 晋升速度,空间换工夫 外围构造初始化时调用init 向池中注入type objectPool struct { opts ObjectPoolOptions values chan interface{} alloc Allocator size int refillLowWatermark int refillHighWatermark int filling int32 initialized int32 dice int32 metrics objectPoolMetrics} for i := 0; i < cap(p.values); i++ { p.values <- p.alloc() }从池中获取对象时池中还有残余则间接获取否则走各自的alloc调配同时设置bytes_pool_get_on_emptyfunc (p *objectPool) Get() interface{} { if atomic.LoadInt32(&p.initialized) != 1 { fn := p.opts.OnPoolAccessErrorFn() fn(errPoolGetBeforeInitialized) return p.alloc() } var v interface{} select { case v = <-p.values: default: v = p.alloc() p.metrics.getOnEmpty.Inc(1) } p.trySetGauges() return v}同时判断池水位,是否加油 if p.refillLowWatermark > 0 && len(p.values) <= p.refillLowWatermark { p.tryFill() }加油过程用CompareAndSwapInt32做并发管制标记位加油加到refillHighWatermarkfunc (p *objectPool) tryFill() { if !atomic.CompareAndSwapInt32(&p.filling, 0, 1) { return } go func() { defer atomic.StoreInt32(&p.filling, 0) for len(p.values) < p.refillHighWatermark { select { case p.values <- p.alloc(): default: return } } }()}默认池参数 defaultRefillLowWaterMark = 0.3 defaultRefillHighWaterMark = 0.6总结思考默认池低水位为什么不是0:因为 从水位判断到tryFill两头的并发申请使得最初tryFill开始时低水位可能低于0.3火焰图中的tryFill耗费了40G内存不是一次性的,类比右侧thriftrpc27,属于累加内存耗费值一次性的内存耗费必定没有这么多:每次加油时内存耗费低于初始化所以能够失去论断,oom是因为在过后byte_pool频繁的get耗费,而后tryFill频繁的加油导致内存调配所以根本原因还是查问导致的解决办法:限度query资源耗费爱护db批改m3coordinator参数 ...

August 13, 2020 · 1 min · jiezi

关于prometheus:Prometheus监控神器Alertmanager篇2

本章次要对如何应用开源组件和Alertmanager组件集成警报告诉。Kubernetes的警报集成后续会间接在配置文件解说,原理大同小异,此处仅对相干警报告诉做集成。警报告诉接收器后面始终是在Web UI 查看警报信息,当初开始应用接收器与Alertmanager集成,发送警报信息到 Email、企业微信、钉钉机器人,对于警报要求比拟高的同学,能够依据上面提到的开源组件 【PrometheusAlert全家桶】 配置飞书、短信、语音电话等警报。 Email后面曾经讲过,Alertmanager默认反对配置Email,也是最一般的形式,在Alertmanager组件中内置了SMTP协定。间接能够把后面的Alertmanager.yml中的SMTP局部截取进去,而后进行调整与配置 global: resolve_timeout: 5m # smtp配置 smtp_from: "1234567890@qq.com" # 发送邮件主题 smtp_smarthost: 'smtp.qq.com:465' # 邮箱服务器的SMTP主机配置 smtp_auth_username: "1234567890@qq.com" # 登录用户名 smtp_auth_password: "auth_pass" # 此处的auth password是邮箱的第三方登录受权明码,而非用户明码,尽量用QQ来测试。 smtp_require_tls: false # 有些邮箱须要开启此配置,这里应用的是163邮箱,仅做测试,不须要开启此性能。route: receiver: ops group_wait: 30s # 在组内期待所配置的工夫,如果同组内,30秒内呈现雷同报警,在一个组内呈现。 group_interval: 5m # 如果组内内容不变动,合并为一条警报信息,5m后发送。 repeat_interval: 24h # 发送报警距离,如果指定工夫内没有修复,则从新发送报警。 group_by: [alertname] # 报警分组 routes: - match: team: operations group_by: [env,dc] receiver: 'ops' - receiver: ops # 路由和标签,依据match来指定发送指标,如果 rule的lable 蕴含 alertname, 应用 ops 来发送 group_wait: 10s match: team: operations# 接收器指定发送人以及发送渠道receivers:# ops分组的定义- name: ops email_configs: - to: '9935226@qq.com,xxxxx@qq.com' # 如果想发送多集体就以 ','做宰割,写多个邮件人即可。 send_resolved: true headers: from: "警报核心" subject: "[operations] 报警邮件" to: "小煜狼皇"配置实现后,间接重启Alertmanager组件,使配置失效,而后应用后面内存阈值触发一次警报来看下发送后果。 ...

August 7, 2020 · 4 min · jiezi

关于prometheus:Prometheus监控神器Rules篇

本章次要对如何应用Prometheus与Alertmanager组件集成配置,以及对警报规定 Rules 的俩种类型及其模板内容进行解说。与Alertmanager集成Prometheus把产生的警报发给Alertmanager进行解决时,须要在Prometheus应用的配置文件中增加关联Alertmanager的组件的对应配置信息。 alerting: alert_relabel_configs: [ - <relabel_config> ... ] alertmanagers: [ - <alertmanager_config> ... ]# alertmanagers 为 alertmanager_config 数组,配置范例: alerting: alert_relabel_configs: # 动静批改 alert 属性的规定配置。 - source_labels: [dc] regex: (.+)\d+ target_label: dc1 alertmanagers: - static_configs: - targets: ['127.0.0.1:9093'] # 单实例配置 #- targets: ['172.31.10.167:19093','172.31.10.167:29093','172.31.10.167:39093'] # 集群配置 - job_name: 'Alertmanager' # metrics_path defaults to '/metrics' # scheme defaults to 'http'. static_configs: - targets: ['localhost:19093']下面的配置中的 alert_relabel_configs是指警报从新标记在发送到Alertmanager之前利用于警报。 它具备与指标从新标记雷同的配置格局和操作,内部标签标记后利用警报从新标记,次要是针对集群配置。 这个设置的用处是确保具备不同内部label的HA对Prometheus服务端发送雷同的警报信息。 ...

August 7, 2020 · 3 min · jiezi

关于prometheus:第04期Prometheus-数据采集三

本期作者:罗韦 爱可生上海研发核心成员,研发工程师,次要负责 DMP 平台监控告警性能的相干工作。 Prometheus 的监控对象各式各样,没有统一标准。为了解决这个问题,Prometheus 制订了一套监控标准,合乎这个标准的样本数据能够被 Prometheus 采集并解析样本数据。Exporter 在 Prometheus 监控零碎中是一个采集监控数据并通过 Prometheus 监控标准对外提供数据的组件,针对不同的监控对象能够实现不同的 Exporter,这样就解决了监控对象规范不一的问题。从狭义上说,所有能够向 Prometheus 提供监控样本数据的程序都能够称为 Exporter,Exporter 的实例也就是咱们上期所说的"target"。 Exporter 的运行形式Exporter 有两种运行形式集成到利用中应用 Prometheus 提供的 Client Library,能够很不便地在应用程序中实现监控代码,这种形式能够将程序外部的运行状态裸露给 Prometheus,实用于须要较多自定义监控指标的我的项目。目前一些开源我的项目就减少了对 Prometheus 监控的原生反对,如 Kubernetes,ETCD 等。 独立运行在很多状况下,对象没法间接提供监控接口,可能起因有: 1. 我的项目公布工夫较早,并不反对 Prometheus 监控接口,如 MySQL、Redis; 2. 监控对象不能间接提供 HTTP 接口,如监控 Linux 零碎状态指标。 对于上述情况,用户能够抉择应用独立运行的 Exporter。除了用户自行实现外,Prometheus 社区也提供了许多独立运行的 Exporter,常见的有 Node Exporter、MySQL Server Exporter。更多详情能够到官网理解:https://prometheus.io/docs/in... Exporter 接口数据标准Exporter 通过 HTTP 接口以文本模式向 Prometheus 裸露样本数据,格局简略,没有嵌套,可读性强。每个监控指标对应的数据文本格式如下: # HELP <监控指标名称> <监控指标形容># TYPE <监控指标名称> <监控指标类型><监控指标名称>{ <标签名称>=<标签值>,<标签名称>=<标签值>...} <样本值1> <工夫戳><监控指标名称>{ <标签名称>=<标签值>,<标签名称>=<标签值>...} <样本值2> <工夫戳>...以 # 结尾的行,如果前面跟着"HELP",Prometheus 将这行解析为监控指标的形容,通常用于形容监控数据的起源;以 # 结尾的行,如果前面跟着"TYPE",Prometheus 将这行解析为监控指标的类型,反对的类型有:Counter、Gauge、Histogram、Summary、Untyped。在往期文章中介绍过 Prometheus 在存储数据时是不辨别数据类型的,所以当你在犹豫一个数据类型应该用 Counter 或 Gauge 时,能够试试 Untype;以 # 结尾的行,如果前面没有跟着"HELP"或"TYPE",则 Prometheus 将这行视为正文,解析时疏忽;如果一个监控指标有多条样本数据,那么每条样本数据的标签值组合应该是惟一的;每行数据对应一条样本数据;工夫戳应为采集数据的工夫,是可选项,如果 Exporter 没有提供工夫戳的话,Prometheus Server 会在拉取到样本数据时将工夫戳设置为以后工夫;Summary 和 Histogram 类型的监控指标要求提供两行数据别离示意该监控指标所有样本的和、样本数量,命名格局为:<监控指标名称>_sum、<监控指标名称>_count;Summary 类型的样本数据格式:1. 依据 Exporter 提供的分位点,样本会被计算后拆分成多行数据,每行应用标签"quantile"辨别,"quantile"的值包含 Exporter 提供的所有分位点。2. 数据的排列程序必须是依照标签"quantile"值递增;3. 举个栗子:一个名为x的监控指标,提供的分位点为:0.5, 0.9, 0.99,那么它裸露给 Prometheus 的接口数据格式如下:# HELP x balabala# TYPE x summaryx{quantile="0.5"} value1x{quantile="0.9"} value2x{quantile="0.99"} value3x_sum sum(values)x_count count(values)Histogram 类型的样本数据格式:1. 依据 Exporter 提供的 Bucket 值,样本会被计算后拆分成多行数据,每行应用标签"le"辨别,"le"为 Exporter 提供的 Buckets;2. 数据的排列程序必须是依照标签"le"值递增;3. 必须要有一行数据的标签 le="+Inf",值为该监控指标的样本总数;4. 举个栗子:一个名为 x 的监控指标,提供的 Buckets 为:20, 50, 70,那么它裸露给 Prometheus 的接口数据格式如下: ...

August 4, 2020 · 2 min · jiezi

关于prometheus:一步步教你用Prometheus搭建实时监控系统系列二详细分析拉取和推送两种不同模式

前言本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于本人的实时监控告警平台。 本系列受众对象为首次接触Prometheus的用户,大神勿喷,偏重于操作和实战,然而重要的概念也会精炼出提及下。系列次要分为以下几块 Prometheus各个概念介绍和搭建,如何抓取数据(一步步教你用Prometheus搭建实时监控零碎系列(一)——上帝之火,普罗米修斯的崛起)如何推送数据至Prometheus,推送和拉取别离用于什么样的场景(本次分享内容)Prometheus数据的构造以及查询语言PromQL的应用Java利用如何和Prometheus集成,如何启用服务发现,如果自定义业务指标Prometheus如何和Grafana可视化套件进行集成和设置告警教你如何手写一个集成了监控Dubbo各个指标的java套件理论案例分享,如何做各个业务端和零碎端的监控大盘抓取和推送拉取模式: Prometheus获取数据的形式只有拉取(PULL),即Prometheus会以固定频率去申请每个target所提供的http url来获取数据。这就须要每个服务端点提供http的接口来获取实时的数据。 推送模式: Prometheus也变相的实现了推送数据的形式。 为什么说是变相呢。因为Prometheus获取数据的形式始终是拉取形式,官网并没有提供推送数据的性能。然而官网为了兼容推送这种形式,减少了一个PushGateway组件。 这个组件相当于一个代理服务,独立部署。它没有数据抓取性能,只能被动的期待数据推送。利用把数据推送到PushGateway后,Prometheus再从PushGateway抓取。 推送模式要留神的点即使客户端推了全量的数据到了PushGateway,Prometheus也不是每次拉取这个期间用户推上来的所有数据。 事实上Prometheus只拉取用户最初一次push上来的数据。 在这个系列一的时候,已经提到过Prometheus其实并不需要每一个准确的数据,长期保留的是中等或者低精度的数据。它每次只抓取一个数据,在固定的频率下。也能造成某种数据的趋势。 如果客户端始终没有推送新的指标到PushGateway,那么Prometheus将始终拉取最初推送上的数据,直到指标隐没,默认是5分钟。 Pushgateway本意是不会存储指标的,然而为了让pushgateway意外重启一类的故障之后可能从新读取到原来的指标,增加了一个将指标临时存储到本地的性能,参数--persistence.interval=5m就是默认放弃5分钟,5分钟后,本地存储的指标会删除。能够通过调节这个值来修改发现异常的工夫。 通过单个Pushgateway监控多个实例时,Pushgateway有可能成为单点故障和潜在瓶颈 如果要用Pushgateway的话,倡议多点部署。而后后面通过nginx进行反向代理多个节点,进行负载平衡。 推送模式实用的场景Prometheus 采纳定时拉取模式,可能因为子网络或者防火墙的起因,不能间接拉取各个Target的指标数据,此时能够采纳各个Target往PushGateway上推送数据,而后Prometheus去PushGateway上定时拉取在监控各个业务数据时,须要将各个不同的业务数据进行对立汇总,此时也能够采纳PushGateway来对立收集,而后Prometheus来对立拉取搭建Pushgateway分docker装置和一般装置两种,这里才用一般装置 先上prometheus的github release主页 https://github.com/prometheus...依照须要下载对应的包,我这里是须要部署在linux服务器上,所以下载这个 下载好,解压。运行: nohup ./pushgateway &启动起来后,默认端口为9091 在浏览器上依据ip+port能够拜访到如下页面,就算启动胜利了: 除此之外还要在Prometheus的配置文件里设置Target: - job_name: 'pushgateway' scrape_interval: 10s # 每过10秒拉取一次 honor_labels: true static_configs: - targets: ['localhost:9091'] labels: instance: pushgateway设置结束后重启Prometheus,而后会在Target选项卡里看到状态为UP的Pushgateway。 设置阶段就实现了。 URL推送测试我这里用postman软件进行推送测试,推送url的格局为:/metrics/job/<JOBNAME>{/<LABEL_NAME>/<LABEL_VALUE>} 这个测试用例为意思是,推送一个指标aaa,标签为bbb=BBB,ccc=CCC,值为111.1到一个组上,这个组为job=pushgateway,instance=demo。 其实你能够简略的了解为这个指标aaa带有4个标签:job,instance,bbb,ccc。只是job和instance是属于组上的标签。 同一个组里的雷同的指标,Prometheus每次只取最新的,不同组内能够有雷同的指标。 对于数据结构和标签构造系列的下一篇文章会具体介绍。 总之,你提交这个POST申请后,能够在http://ip:9091上看到如下数据: 能够看到,aaa这个标签曾经胜利的被提交到Pushgateway里了。 接下来,咱们在Prometheus里查问这个指标: 能够看到,Prometheus也胜利的拉取到了这个指标。 Java端利用SDK进行推送尽管咱们在java服务端也能利用httpclient等工具进行提交,然而须要自行组装很多申请体。Prometheus官网提供了一个SDK。 首先在Maven中引入依赖包: <dependency> <groupId>io.prometheus</groupId> <artifactId>simpleclient_pushgateway</artifactId> <version>0.9.0</version></dependency>对Gauge,Timer,Counter,Summary四种常见的指标进行推送示例: ...

July 28, 2020 · 1 min · jiezi

关于prometheus:一步步教你用Prometheus搭建实时监控系统系列二详细分析拉取和推送两种不同模式

前言本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于本人的实时监控告警平台。 本系列受众对象为首次接触Prometheus的用户,大神勿喷,偏重于操作和实战,然而重要的概念也会精炼出提及下。系列次要分为以下几块 Prometheus各个概念介绍和搭建,如何抓取数据(一步步教你用Prometheus搭建实时监控零碎系列(一)——上帝之火,普罗米修斯的崛起)如何推送数据至Prometheus,推送和拉取别离用于什么样的场景(本次分享内容)Prometheus数据的构造以及查询语言PromQL的应用Java利用如何和Prometheus集成,如何启用服务发现,如果自定义业务指标Prometheus如何和Grafana可视化套件进行集成和设置告警教你如何手写一个集成了监控Dubbo各个指标的java套件理论案例分享,如何做各个业务端和零碎端的监控大盘抓取和推送拉取模式: Prometheus获取数据的形式只有拉取(PULL),即Prometheus会以固定频率去申请每个target所提供的http url来获取数据。这就须要每个服务端点提供http的接口来获取实时的数据。 推送模式: Prometheus也变相的实现了推送数据的形式。 为什么说是变相呢。因为Prometheus获取数据的形式始终是拉取形式,官网并没有提供推送数据的性能。然而官网为了兼容推送这种形式,减少了一个PushGateway组件。 这个组件相当于一个代理服务,独立部署。它没有数据抓取性能,只能被动的期待数据推送。利用把数据推送到PushGateway后,Prometheus再从PushGateway抓取。 推送模式要留神的点即使客户端推了全量的数据到了PushGateway,Prometheus也不是每次拉取这个期间用户推上来的所有数据。 事实上Prometheus只拉取用户最初一次push上来的数据。 在这个系列一的时候,已经提到过Prometheus其实并不需要每一个准确的数据,长期保留的是中等或者低精度的数据。它每次只抓取一个数据,在固定的频率下。也能造成某种数据的趋势。 如果客户端始终没有推送新的指标到PushGateway,那么Prometheus将始终拉取最初推送上的数据,直到指标隐没,默认是5分钟。 Pushgateway本意是不会存储指标的,然而为了让pushgateway意外重启一类的故障之后可能从新读取到原来的指标,增加了一个将指标临时存储到本地的性能,参数--persistence.interval=5m就是默认放弃5分钟,5分钟后,本地存储的指标会删除。能够通过调节这个值来修改发现异常的工夫。 通过单个Pushgateway监控多个实例时,Pushgateway有可能成为单点故障和潜在瓶颈 如果要用Pushgateway的话,倡议多点部署。而后后面通过nginx进行反向代理多个节点,进行负载平衡。 推送模式实用的场景Prometheus 采纳定时拉取模式,可能因为子网络或者防火墙的起因,不能间接拉取各个Target的指标数据,此时能够采纳各个Target往PushGateway上推送数据,而后Prometheus去PushGateway上定时拉取在监控各个业务数据时,须要将各个不同的业务数据进行对立汇总,此时也能够采纳PushGateway来对立收集,而后Prometheus来对立拉取搭建Pushgateway分docker装置和一般装置两种,这里才用一般装置 先上prometheus的github release主页 https://github.com/prometheus...依照须要下载对应的包,我这里是须要部署在linux服务器上,所以下载这个 下载好,解压。运行: nohup ./pushgateway &启动起来后,默认端口为9091 在浏览器上依据ip+port能够拜访到如下页面,就算启动胜利了: 除此之外还要在Prometheus的配置文件里设置Target: - job_name: 'pushgateway' scrape_interval: 10s # 每过10秒拉取一次 honor_labels: true static_configs: - targets: ['localhost:9091'] labels: instance: pushgateway设置结束后重启Prometheus,而后会在Target选项卡里看到状态为UP的Pushgateway。 设置阶段就实现了。 URL推送测试我这里用postman软件进行推送测试,推送url的格局为:/metrics/job/<JOBNAME>{/<LABEL_NAME>/<LABEL_VALUE>} 这个测试用例为意思是,推送一个指标aaa,标签为bbb=BBB,ccc=CCC,值为111.1到一个组上,这个组为job=pushgateway,instance=demo。 其实你能够简略的了解为这个指标aaa带有4个标签:job,instance,bbb,ccc。只是job和instance是属于组上的标签。 同一个组里的雷同的指标,Prometheus每次只取最新的,不同组内能够有雷同的指标。 对于数据结构和标签构造系列的下一篇文章会具体介绍。 总之,你提交这个POST申请后,能够在http://ip:9091上看到如下数据: 能够看到,aaa这个标签曾经胜利的被提交到Pushgateway里了。 接下来,咱们在Prometheus里查问这个指标: 能够看到,Prometheus也胜利的拉取到了这个指标。 Java端利用SDK进行推送尽管咱们在java服务端也能利用httpclient等工具进行提交,然而须要自行组装很多申请体。Prometheus官网提供了一个SDK。 首先在Maven中引入依赖包: <dependency> <groupId>io.prometheus</groupId> <artifactId>simpleclient_pushgateway</artifactId> <version>0.9.0</version></dependency>对Gauge,Timer,Counter,Summary四种常见的指标进行推送示例: ...

July 28, 2020 · 1 min · jiezi

关于prometheus:使用Prometheus监控Flink

这篇文章介绍了如何利用Apache Flink的内置指标零碎以及如何应用Prometheus来高效地监控流式应用程序。 为什么抉择Prometheus?随着深刻地理解Prometheus,你会发现一些十分好的性能: 服务发现使配置更加容易。Prometheus反对consul,etcd,kubernetes以及各家私有云厂商主动发现。对于监控指标动静发现,这点特地符合Cloud时代,利用动静扩缩的特点。咱们无奈设想,在Cloud时代,须要运维一直更改配置。开源社区建设了数百个exporter。基本上涵盖了所有基础设施和支流中间件。工具库可从您的应用程序获取自定义指标。基本上支流开发语言都有对应的工具库。它是CNCF旗下的OSS,是继Kubernetes之后的第二个毕业我的项目。Kubernetes曾经与Promethues深度联合,并在其所有服务中公开了Prometheus指标。Pushgateway,Alermanager等组件,基本上涵盖了一个残缺的监控生命周期。Flink官网曾经提供了对接Prometheus的jar包,很不便就能够集成。因为本系列文章重点在Flink on Kubernetes, 因而咱们所有的操作都是基于这点开展。 部署Prometheus对k8s不相熟的同学,能够查阅k8s相干文档。因为部署不是本博客的重点,所以咱们间接贴出yaml文件: --- apiVersion: v1 kind: ServiceAccount metadata: name: monitor namespace: kube-system labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: monitor labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile rules: - apiGroups: - "" resources: - pods verbs: - get - list - watch--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: monitor labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: monitor subjects: - kind: ServiceAccount name: monitor namespace: kube-system--- apiVersion: v1 kind: ConfigMap metadata: labels: app: monitor name: monitor namespace: kube-system data: prometheus.yml: |- global: scrape_interval: 10s evaluation_interval: 10s scrape_configs: - job_name: kubernetes-pods kubernetes_sd_configs: - role: pod relabel_configs: - action: keep regex: true source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_scrape - action: replace regex: (.+) source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_path target_label: __metrics_path__ - action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 source_labels: - __address__ - __meta_kubernetes_pod_annotation_prometheus_io_port target_label: __address__ - action: labelmap regex: __meta_kubernetes_pod_label_(.+) - action: replace source_labels: - __meta_kubernetes_namespace target_label: kubernetes_namespace - action: replace source_labels: - __meta_kubernetes_pod_name target_label: kubernetes_pod_name --- apiVersion: apps/v1 kind: StatefulSet metadata: labels: app: monitor name: monitor namespace: kube-system spec: serviceName: monitor selector: matchLabels: app: monitor replicas: 1 template: metadata: labels: app: monitor spec: containers: - args: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/data/prometheus - --storage.tsdb.retention.time=10d image: prom/prometheus:v2.19.0 imagePullPolicy: IfNotPresent name: prometheus ports: - containerPort: 9090 protocol: TCP readinessProbe: httpGet: path: /-/ready port: 9090 initialDelaySeconds: 30 timeoutSeconds: 30 livenessProbe: httpGet: path: /-/healthy port: 9090 initialDelaySeconds: 30 timeoutSeconds: 30 resources: limits: cpu: 1000m memory: 2018Mi requests: cpu: 1000m memory: 2018Mi volumeMounts: - mountPath: /etc/prometheus name: config-volume - mountPath: /data name: monitor-persistent-storage restartPolicy: Always priorityClassName: system-cluster-critical serviceAccountName: monitor initContainers: - name: "init-chown-data" image: "busybox:latest" imagePullPolicy: "IfNotPresent" command: ["chown", "-R", "65534:65534", "/data"] volumeMounts: - name: monitor-persistent-storage mountPath: /data subPath: "" volumes: - configMap: defaultMode: 420 name: monitor name: config-volume volumeClaimTemplates: - metadata: name: monitor-persistent-storage namespace: kube-system spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: gp2--- apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb labels: app: monitor name: monitor namespace: kube-system spec: ports: - name: http port: 9090 protocol: TCP targetPort: 9090 selector: app: monitor type: LoadBalancer这里咱们简略说下,因为咱们想利用Prometheus的Kubernetes的服务发现的形式,所以须要RBAC受权,受权prometheus 实例对集群中的pod有一些读取权限。 ...

July 27, 2020 · 3 min · jiezi

关于prometheus:使用Prometheus监控Flink

这篇文章介绍了如何利用Apache Flink的内置指标零碎以及如何应用Prometheus来高效地监控流式应用程序。 为什么抉择Prometheus?随着深刻地理解Prometheus,你会发现一些十分好的性能: 服务发现使配置更加容易。Prometheus反对consul,etcd,kubernetes以及各家私有云厂商主动发现。对于监控指标动静发现,这点特地符合Cloud时代,利用动静扩缩的特点。咱们无奈设想,在Cloud时代,须要运维一直更改配置。开源社区建设了数百个exporter。基本上涵盖了所有基础设施和支流中间件。工具库可从您的应用程序获取自定义指标。基本上支流开发语言都有对应的工具库。它是CNCF旗下的OSS,是继Kubernetes之后的第二个毕业我的项目。Kubernetes曾经与Promethues深度联合,并在其所有服务中公开了Prometheus指标。Pushgateway,Alermanager等组件,基本上涵盖了一个残缺的监控生命周期。Flink官网曾经提供了对接Prometheus的jar包,很不便就能够集成。因为本系列文章重点在Flink on Kubernetes, 因而咱们所有的操作都是基于这点开展。 部署Prometheus对k8s不相熟的同学,能够查阅k8s相干文档。因为部署不是本博客的重点,所以咱们间接贴出yaml文件: --- apiVersion: v1 kind: ServiceAccount metadata: name: monitor namespace: kube-system labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: monitor labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile rules: - apiGroups: - "" resources: - pods verbs: - get - list - watch--- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: monitor labels: kubernetes.io/cluster-service: "true" addonmanager.kubernetes.io/mode: Reconcile roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: monitor subjects: - kind: ServiceAccount name: monitor namespace: kube-system--- apiVersion: v1 kind: ConfigMap metadata: labels: app: monitor name: monitor namespace: kube-system data: prometheus.yml: |- global: scrape_interval: 10s evaluation_interval: 10s scrape_configs: - job_name: kubernetes-pods kubernetes_sd_configs: - role: pod relabel_configs: - action: keep regex: true source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_scrape - action: replace regex: (.+) source_labels: - __meta_kubernetes_pod_annotation_prometheus_io_path target_label: __metrics_path__ - action: replace regex: ([^:]+)(?::\d+)?;(\d+) replacement: $1:$2 source_labels: - __address__ - __meta_kubernetes_pod_annotation_prometheus_io_port target_label: __address__ - action: labelmap regex: __meta_kubernetes_pod_label_(.+) - action: replace source_labels: - __meta_kubernetes_namespace target_label: kubernetes_namespace - action: replace source_labels: - __meta_kubernetes_pod_name target_label: kubernetes_pod_name --- apiVersion: apps/v1 kind: StatefulSet metadata: labels: app: monitor name: monitor namespace: kube-system spec: serviceName: monitor selector: matchLabels: app: monitor replicas: 1 template: metadata: labels: app: monitor spec: containers: - args: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.path=/data/prometheus - --storage.tsdb.retention.time=10d image: prom/prometheus:v2.19.0 imagePullPolicy: IfNotPresent name: prometheus ports: - containerPort: 9090 protocol: TCP readinessProbe: httpGet: path: /-/ready port: 9090 initialDelaySeconds: 30 timeoutSeconds: 30 livenessProbe: httpGet: path: /-/healthy port: 9090 initialDelaySeconds: 30 timeoutSeconds: 30 resources: limits: cpu: 1000m memory: 2018Mi requests: cpu: 1000m memory: 2018Mi volumeMounts: - mountPath: /etc/prometheus name: config-volume - mountPath: /data name: monitor-persistent-storage restartPolicy: Always priorityClassName: system-cluster-critical serviceAccountName: monitor initContainers: - name: "init-chown-data" image: "busybox:latest" imagePullPolicy: "IfNotPresent" command: ["chown", "-R", "65534:65534", "/data"] volumeMounts: - name: monitor-persistent-storage mountPath: /data subPath: "" volumes: - configMap: defaultMode: 420 name: monitor name: config-volume volumeClaimTemplates: - metadata: name: monitor-persistent-storage namespace: kube-system spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi storageClassName: gp2--- apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/aws-load-balancer-type: nlb labels: app: monitor name: monitor namespace: kube-system spec: ports: - name: http port: 9090 protocol: TCP targetPort: 9090 selector: app: monitor type: LoadBalancer这里咱们简略说下,因为咱们想利用Prometheus的Kubernetes的服务发现的形式,所以须要RBAC受权,受权prometheus 实例对集群中的pod有一些读取权限。 ...

July 27, 2020 · 3 min · jiezi

关于prometheus:一步步教你用Prometheus搭建实时监控系统系列一上帝之火普罗米修斯的崛起

上帝之火本系列讲述的是开源实时监控告警解决方案Prometheus,这个单词很牛逼。每次我都能联想到带来上帝之火的希腊之神,普罗米修斯。而这个开源的logo也是火,集体挺喜爱这个logo的设计。 本系列着重介绍Prometheus以及如何用它和其周边的生态来搭建一套属于本人的实时监控告警平台。 本系列受众对象为首次接触Prometheus的用户,大神勿喷,偏重于操作和实战,然而重要的概念也会精炼出提及下。系列次要分为以下几块 Prometheus各个概念介绍和搭建,如何抓取数据(本次分享内容)如何推送数据至Prometheus,推送和拉取别离用于什么样的场景Prometheus数据的构造以及查询语言PromQL的应用Java利用如何和Prometheus集成,如何启用服务发现,如果自定义业务指标Prometheus如何和Grafana可视化套件进行集成和设置告警教你如何手写一个集成了监控Dubbo各个指标的java套件理论案例分享,如何做各个业务端和零碎端的监控大盘Prometheus以及时序数据库的基本概念Prometheus当初在Github有3w多的star,基本上过万星的开源工具,能够认为是社区里相对的支流,社区也相当沉闷,能够有大量的教训能够借鉴。在企业级零碎中,能够释怀的应用。 Prometheus 是由 SoundCloud 开发的开源监控报警零碎和时序列数据库。从字面上了解,Prometheus 由两个局部组成,一个是监控报警零碎,另一个是自带的时序数据库(TSDB)。 对于时序数据库(TSDB)这里要说下,咱们能够简略的了解为一个优化后用来解决工夫序列数据的数据库,并且数据中的数组是由工夫进行索引的。相比于传统的结构化数据库次要有几个益处: 工夫序列数据专一于海量数据的疾速摄取。时序数据库视数据的每一次变动为一条新的数据,从而能够去掂量变动:剖析过来的变动,监测当初的变动,以及预测将来将如何变动,传统结构化数据在数据量小的时候能做到,在数据量大的时候就须要破费大量的老本。高精度数据保留工夫较短,中等或更低精度的摘要数据保留工夫较长。对于实时监控来说,不肯定须要每一个精准的数据,而是固定工夫段时间数据的摘要。这对于结构化数据库来说就意味着要进行筛选,在保障大量的写入同时还要进行帅选,这是一个超出结构化数据库设计来解决的工作量。数据库自身必须间断计算来自高精度数据的摘要以进行长期存储。这些计算既包含一些简略的聚合,同时也有一些简单计算。传统数据库无奈接受那么大量的计算。因为必须去实时统计这些聚合和简单运算。开始搭建Prometheushttps://prometheus.io/在Prometheue官网Download标签页进行下载,这里以linux版本为例: 下载好之后,解压,运行 nohup /data/prometheus/prometheus --web.listen-address=0.0.0.0:9090 --config.file=/data/prometheus/prometheus.yml --web.enable-lifecycle --storage.tsdb.path=/data/prometheus/data --storage.tsdb.retention.time=15d &这样,就简略的搭建起来Prometheus服务端了。这时候,咱们能够在web上拜访 http://127.0.0.1:9090就能够拜访到治理页面 界面上几个标签阐明下: Alert:用来配置告警规定。之后咱们会用Grafana本身的告警界面配置来代替这个。 Graph:用来运行PromQL语句的一个控制台,并且能够把运行进去的语句用用图形化进行展现,此块咱们前面章节会介绍到。 Status:蕴含零碎信息,零碎状态,配置信息,指标节点的状态,服务发现状态等元信息的查看。 Prometheus整体架构以及生态 这张图是官网的整体架构图。米黄色局部是Prometheus本人的组件,绿色的为第三方的中间件和利用。 简略介绍下整个Prometheus的生态架构: Prometheus获取数据的形式只有一种,就是scrape,也称作pull,意为拉取。Prometheus每隔一段时间会从指标(target)这里以Http协定拉取指标(metrics),这些指标能够是利用,也能够是代理,缓存中间件,数据库等等一些中间件。拉取出来的数据Prometheus会存到本人的TSDB数据库。本人的WebUI控制台以及Grafana能够对其数据进行工夫范畴内的一直查问,绘制成实时图表工展示。Prometheus 反对例如zookeeper,consul之类的服务发现中间件,用以对指标(target)的主动发现。而不必一个个去配置target了。alertManager组件反对自定义告警规定,告警渠道也反对很多种拉取数据Prometheus次要是通过拉取的形式获取数据,说简略点,就是每隔固定工夫去拜访配置的target,target就是一个获取数据的url。 当初咱们就来模仿一个数据源,并让prometheus去拉取。 新建一个springboot的web我的项目,pom依赖加上 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId></dependency>application.properties里加上 server.port=8080anagement.endpoints.web.exposure.include=*启动结束后,咱们就能够在页面上拜访如下地址: http://127.0.0.1:8080/actuator/prometheus失去如下数据: 对于actuator如何监控利用指标以及自定义指标我会在之后的系列里独自剖析,这里只有了解成咱们启动了一个服务,提供了一个url能列出一些kv模式的指标就行了。 例如jvm_memory_max_bytes{area="heap",id="PS Old Gen",} 2.863661056E9这个指标,后面是key,前面为value。 其中key上又分key name和key labels,key name就是`jvm_memory_max_bytes,key labels`有2个。 这个指标提供了jvm的最大内存,其中area为heap,表明这是堆内存区域,id为PS Old Gen,表明这是老年代。综合起来看,这个指标就是jvm中老年代的最大值。数值类型是byte,换算下来大略是286M左右。 咱们有指标的数据源后,再在prometheus 的根目录下编辑prometheus.yml文件,增加如下配置: - job_name: 'test' scrape_interval: 5s metrics_path: '/actuator/prometheus' static_configs: - targets: ['localhost:8080'] labels: instance: demo这个配置示意:prometheue每隔5秒钟从http://localhost:8080/actuator/prometheus这个url拉取指标,并且为每个指标增加instance这个标签。 ...

July 22, 2020 · 1 min · jiezi

基于docker搭建Prometheus

prometheus 实质上是一个时序数据库, 再配以alermanager pushgateway等子组件, 便可搭建成一个监控平台, 目前曾经是比拟支流的做法, 本文次要介绍一下此组件的简略应用和能够利用到的场景.官网文档doc docker配置以docker-compose的模式进行配置prometheus根本配置在文件夹新建一个docker-compose.yml文件, 将以下内容填入. version: "3.7" services: pro_server: image: prom/prometheus # 官网镜像ports: - "9090:9090" volumes: - ./prometheus:/prometheus # 用于存储Prometheus的状态, 下次启动能够连续- ./docker/prometheus.yml:/etc/prometheus/prometheus.yml # 内部传入Prometheus配置解下来新建./这是prometheus文件夹, 新建./docker/prometheus.yml文件, 写入以下信息 # my global config global: 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 configuration alerting: #alertmanagers: #- static_configs: #- targets: #- pro_alert_manager: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'] prometheus的主体服务, docker-compose up的话, 就能够在浏览器进行Prometheus的初体验了. 这个配置文件是Prometheus的默认配置, 能够看到它本人申明了一个job: prometheus, 外面监听了本人的9090端口. 你能够自行察看 /metrics接口内的数据, 领会一下数据结构. ...

July 17, 2020 · 3 min · jiezi

关于prometheus:prometheus-本地存储解析及其使用的那些黑科技

本文代码基于prometheus 2.19.2剖析基本概念什么是tsdbTime Series DBMS are designed to efficiently collect, store and query various time series with high transaction volumesprometheus 基本概念sample 数据点type sample struct { t int64 v float64}sample代表一个数据点size:16byte: 蕴含 1个8byte int64工夫戳和1个8byte float64 value Label 标签type Label struct { Name, Value string}一对label 比方 job="ec2"Labels 标签组type Labels []Label 就是metric 一个指标的所有tag valuesvector 向量type Vector []Samplevector 向量,是samples的别名,然而所有sample具备雷同timestamp ,罕用作instance_query的后果Scalar 标量type Scalar struct { T int64 V float64}Scalar 标量 间接查个数字Series 数据流type Series struct { Metric labels.Labels `json:"metric"` Points []Point `json:"values"`}Series 是一个metric的数据流Matrix 矩阵type Matrix []SeriesMatrix是series的切片,个别的range_query返回的后果数据点压缩 ...

July 15, 2020 · 6 min · jiezi

关于prometheus:prometheus-本地存储解析及其使用的那些黑科技

本文代码基于prometheus 2.19.2剖析基本概念什么是tsdbTime Series DBMS are designed to efficiently collect, store and query various time series with high transaction volumesprometheus 基本概念sample 数据点type sample struct { t int64 v float64}sample代表一个数据点size:16byte: 蕴含 1个8byte int64工夫戳和1个8byte float64 value Label 标签type Label struct { Name, Value string}一对label 比方 job="ec2"Labels 标签组type Labels []Label 就是metric 一个指标的所有tag valuesvector 向量type Vector []Samplevector 向量,是samples的别名,然而所有sample具备雷同timestamp ,罕用作instance_query的后果Scalar 标量type Scalar struct { T int64 V float64}Scalar 标量 间接查个数字Series 数据流type Series struct { Metric labels.Labels `json:"metric"` Points []Point `json:"values"`}Series 是一个metric的数据流Matrix 矩阵type Matrix []SeriesMatrix是series的切片,个别的range_query返回的后果数据点压缩 ...

July 15, 2020 · 6 min · jiezi

钉钉prometheus模板

{{ define "__subject" }}[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}] {{ .GroupLabels.SortedPairs.Values | join " " }} {{ if gt (len .CommonLabels) (len .GroupLabels) }}({{ with .CommonLabels.Remove .GroupLabels.Names }}{{ .Values | join " " }}{{ end }}){{ end }}{{ end }}{{ define "__alertmanagerURL" }}{{ .ExternalURL }}/#/alerts?receiver={{ .Receiver }}{{ end }}{{ define "__text_alert_list" }}{{ range . }}**Labels**{{ range .Labels.SortedPairs }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}**Annotations**{{ range .Annotations.SortedPairs }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}**Source:** [{{ .GeneratorURL }}]({{ .GeneratorURL }}){{ end }}{{ end }}{{ define "default.__text_alert_list" }}{{ range . }}---**告警级别:** {{ .Labels.severity | upper }}**运营团队:** {{ .Labels.team | upper }}**触发时间:** {{ dateInZone "2006.01.02 15:04:05" (.StartsAt) "Asia/Shanghai" }}**事件信息:** {{ range .Annotations.SortedPairs }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}**事件标签:**{{ range .Labels.SortedPairs }}{{ if and (ne (.Name) "severity") (ne (.Name) "summary") (ne (.Name) "team") }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}{{ end }}{{ end }}{{ end }}{{ define "default.__text_alertresovle_list" }}{{ range . }}---**告警级别:** {{ .Labels.severity | upper }}**运营团队:** {{ .Labels.team | upper }}**触发时间:** {{ dateInZone "2006.01.02 15:04:05" (.StartsAt) "Asia/Shanghai" }}**结束时间:** {{ dateInZone "2006.01.02 15:04:05" (.EndsAt) "Asia/Shanghai" }}**事件信息:**{{ range .Annotations.SortedPairs }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}**事件标签:**{{ range .Labels.SortedPairs }}{{ if and (ne (.Name) "severity") (ne (.Name) "summary") (ne (.Name) "team") }}> - {{ .Name }}: {{ .Value | markdown | html }}{{ end }}{{ end }}{{ end }}{{ end }}{{/* Default */}}{{ define "default.title" }}{{ template "__subject" . }}{{ end }}{{ define "default.content" }}#### \[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}\] **[{{ index .GroupLabels "alertname" }}]({{ template "__alertmanagerURL" . }})**{{ if gt (len .Alerts.Firing) 0 -}}![警报 图标](https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3626076420,1196179712&fm=15&gp=0.jpg)**====侦测到故障====**{{ template "default.__text_alert_list" .Alerts.Firing }}{{- end }}{{ if gt (len .Alerts.Resolved) 0 -}}{{ template "default.__text_alertresovle_list" .Alerts.Resolved }}{{- end }}{{- end }}{{/* Legacy */}}{{ define "legacy.title" }}{{ template "__subject" . }}{{ end }}{{ define "legacy.content" }}#### \[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}\] **[{{ index .GroupLabels "alertname" }}]({{ template "__alertmanagerURL" . }})**{{ template "__text_alert_list" .Alerts.Firing }}{{- end }}{{/* Following names for compatibility */}}{{ define "ding.link.title" }}{{ template "default.title" . }}{{ end }}{{ define "ding.link.content" }}{{ template "default.content" . }}{{ end }}

June 29, 2020 · 2 min · jiezi

Prometheus-如何活学活用大牛总结的避坑指南来了

作者:徐亚松   原文:http://www.xuyasong.com/?p=1921监控系统的历史悠久,是一个很成熟的方向,而 Prometheus 作为新生代的开源监控系统,慢慢成为了云原生体系的事实标准,也证明了其设计很受欢迎。 本文主要分享在 Prometheus 实践中遇到的一些问题和思考,如果你对 K8S 监控体系或 Prometheus 的设计还不太了解,可以先看下容器监控系列。 几点原则: 监控是基础设施,目的是为了解决问题,不要只朝着大而全去做,尤其是不必要的指标采集,浪费人力和存储资源(To B商业产品例外)。需要处理的告警才发出来,发出来的告警必须得到处理。简单的架构就是最好的架构,业务系统都挂了,监控也不能挂。Google Sre 里面也说避免使用 Magic 系统,例如机器学习报警阈值、自动修复之类。这一点见仁见智吧,感觉很多公司都在搞智能 AI 运维。一、版本的选择Prometheus 当前最新版本为 2.16,Prometheus 还在不断迭代,因此尽量用最新版,1.X版本就不用考虑了。 2.16 版本上有一套实验 UI,可以查看 TSDB 的状态,包括Top 10的 Label、Metric. 二、Prometheus 的局限Prometheus 是基于 Metric 的监控,不适用于日志(Logs)、事件(Event)、调用链(Tracing)。Prometheus 默认是 Pull 模型,合理规划你的网络,尽量不要转发。对于集群化和水平扩展,官方和社区都没有银弹,需要合理选择 Federate、Cortex、Thanos等方案。监控系统一般情况下可用性大于一致性,容忍部分副本数据丢失,保证查询请求成功。这个后面说 Thanos 去重的时候会提到。Prometheus 不一定保证数据准确,这里的不准确一是指 rate、histogram_quantile 等函数会做统计和推断,产生一些反直觉的结果,这个后面会详细展开。二来查询范围过长要做降采样,势必会造成数据精度丢失,不过这是时序数据的特点,也是不同于日志系统的地方。三、K8S 集群中常用的 exporterPrometheus 属于 CNCF 项目,拥有完整的开源生态,与 Zabbix 这种传统 agent 监控不同,它提供了丰富的 exporter 来满足你的各种需求。你可以在这里看到官方、非官方的 exporter。如果还是没满足你的需求,你还可以自己编写 exporter,简单方便、自由开放,这是优点。 但是过于开放就会带来选型、试错成本。之前只需要在 zabbix agent里面几行配置就能完成的事,现在你会需要很多 exporter 搭配才能完成。还要对所有 exporter 维护、监控。尤其是升级 exporter 版本时,很痛苦。非官方exporter 还会有不少 bug。这是使用上的不足,当然也是 Prometheus 的设计原则。 ...

June 28, 2020 · 4 min · jiezi

第03期Prometheus-数据采集二

本期作者:罗韦爱可生上海研发中心成员,研发工程师,主要负责 DMP 平台监控告警功能的相关工作。 上篇文章(第02期:数据采集一)介绍了 Prometheus 数据采集的格式和分类,本文会对采集过程进行详细的介绍。 Prometheus 数据采集过程介绍Prometheus 从采集数据到将存储的过程中,会对采集目标及数据样本作一系列处理。了解这个过程有利于帮助我们更充分、合理的使用可配参数。 一、文章中使用的概念简介target:采集目标,Prometheus Server 会从这些目标设备上采集监控数据sample: Prometheus Server 从 targets 采集回来的数据样本meta label: 执行 relabel 前,target 的原始标签。可在 Prometheus 的 /targets 页面或发送 GET /api/v1/targets 请求查看。 二、数据采集流程 2.1 relabel (targets 标签修改/过滤)relabel 是 Prometheus 提供的一个针对 target 的功能,relabel 发生 Prometheus Server 从 target 采集数据之前,可以对 target 的标签进行修改或者使用标签进行 target 筛选。注意以下几点: Prometheus 在 relabel 步骤默认会为 target 新增一个名为 instance 的标签,并设置成 "__address__" 标签的值;在 relabel 结束后,以 "__" 开头的标签不会被存储到磁盘;meta label 会一直保留在内存中,直到 target 被移除。在 Prometheus 的 targets 页面,可以看到 target 在 relabel 之前的标签,如下图所示,在 relabel 之前,target 的标签有:"__address__","__metrics_path__","__schema__","job"。经过 relabel 之后我们最终看到的 targets 的标签为:instance、job。 ...

June 22, 2020 · 2 min · jiezi

HADOOPpromethues监控

安装jmx-exporter $ wget https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.13.0/jmx_prometheus_javaagent-0.13.0.jarmv jmx_prometheus_javaagent-0.13.0.jar /data/hdfs$ for i in {2..5};do scp /data/hdfs/jmx_prometheus_javaagent-0.13.0.jar hadoop-test-$i:/data/hdfs/;donehdfs $ vim /data/hdfs/nn.yamlstartDelaySeconds: 0hostPort: 192.168.233.65:1234 #master为本机IP(一般可设置为localhost);1234为想设置的jmx端口#jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:1234/jmxrmissl: falselowercaseOutputName: falselowercaseOutputLabelNames: false$ vim /data/hdfs/dn.yaml---startDelaySeconds: 0hostPort: 192.168.233.65:1244 #master为本机IP(一般可设置为localhost);1244为想设置的jmx端口(可设置为未被占用的端口)#jmxUrl: service:jmx:rmi:///jndi/rmi://127.0.0.1:1234/jmxrmissl: falselowercaseOutputName: falselowercaseOutputLabelNames: false$ vim etc/hadoop/hadoop-env.shexport HADOOP_NAMENODE_JMX_OPTS="-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=1234 -javaagent:/data/hdfs/jmx_prometheus_javaagent-0.13.0.jar=9211:/data/hdfs/nn.yaml"export HADOOP_DATANODE_JMX_OPTS="-Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.port=1244 -javaagent:/data/hdfs/jmx_prometheus_javaagent-0.13.0.jar=9212:/data/hdfs/dn.yaml"$ vim bin/hdfsif [ "$COMMAND" = "namenode" ] ; then CLASS='org.apache.hadoop.hdfs.server.namenode.NameNode' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_NAMENODE_OPTS $HADOOP_NAMENODE_JMX_OPTS" #添加namenode JMX环境变量elif [ "$COMMAND" = "zkfc" ] ; then CLASS='org.apache.hadoop.hdfs.tools.DFSZKFailoverController' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_ZKFC_OPTS"elif [ "$COMMAND" = "secondarynamenode" ] ; then CLASS='org.apache.hadoop.hdfs.server.namenode.SecondaryNameNode' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_SECONDARYNAMENODE_OPTS"elif [ "$COMMAND" = "datanode" ] ; then CLASS='org.apache.hadoop.hdfs.server.datanode.DataNode' HADOOP_OPTS="$HADOOP_OPTS $HADOOP_DATANODE_JMX_OPTS" #添加datanode jmx变量 if [ "$starting_secure_dn" = "true" ]; then HADOOP_OPTS="$HADOOP_OPTS -jvm server $HADOOP_DATANODE_OPTS" else HADOOP_OPTS="$HADOOP_OPTS -server $HADOOP_DATANODE_OPTS"$ stop-dfs.sh$ start-dfs.shyarn ...

June 18, 2020 · 2 min · jiezi

xprober-分布式cs-ping-http框架

## 我写的分布式c/s ping & http 探测代码## 地址 [https://github.com/ning1875/xprober](https://github.com/ning1875/xprober)  ## xprober特点 - 基于公有混合云ec2的ping监控,可以得到不同region之间的网络延迟 - 可以从不同region对http接口发起探测,可以trace 一个http请求的各个stage的耗时 - icmp target可由 存活agent上报 / 可以在配置文件中指定 - http target 在配置文件中指定 ## 预览图 ### http 探测结果 ### 互ping 结果 # 项目说明 xprober 是分布式c / s架构接口检测框架: Ping监控:基于不同区域之间的公共云混合云ec2检测Ping监视:根据代理启动来建立目标池,可以获取两个区域的Ping结果作为彼此的源和目标目标源:同时,它还支持服务器端配置文件以指定目标Http监视:它可以获取从不同区域到目标接口在不同http阶段花费的时间服务器端逻辑*   RPC接收代理agent IP报告 *   定时器将探测目标池刷新到本地缓存中 *   server 根据agent rpc信息返回给其探测目标池 *   rpc接收数据 *   更新到本地缓存 *   定时器数据处理 *   公开prome http指标建造$ git clone https://github.com/ning1875/xprober.git# build agent$ cd xprober/pkg/cmd/agent && go build -o xprober-agent main.go # build server$ cd ../server/ && go build -o xprober-server main.go` 启动服务# for server xprober-server --config.file=xprober.yml# for agent xprober-agent --grpc.server-address=$server_rpc_ip:6001与promtheus集成将以下文本添加到promtheus.yaml的scrape_configs部分 ...

June 11, 2020 · 1 min · jiezi

Prometheus-的-Metrics-与-PromQL-的使用参考

前段时间使用Prometheus,其中的PromQL还是很厉害的查询语法,现在总结下其中的数据查询规则。为了能够帮助用户理解和区分这些不同监控指标之间的差异,Prometheus定义了4种不同的指标类型(metric type):Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。返回的样本数据中,其注释中也包含了该样本的类型。例如: # HELP node_cpu Seconds the cpus spent in each mode.# TYPE node_cpu counternode_cpu{cpu="cpu0",mode="idle"} 362812.7890625Counter:只增不减的计数器Counter类型的指标其工作方式和计数器一样,只增不减(除非系统发生重置)。常见的监控指标,如http_requests_total,node_cpu都是Counter类型的监控指标。 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。 样记录值:每个时刻对应的总数,因此随着时间增加该值递增或不变。 Counter 的应用最近10分钟cpu时间增加量: increase(node_cpu_seconds_total[10m])最近10分钟cpu的增长率(增量/时间间隔): rate(node_cpu_seconds_total[10m])最近10分钟cpu的增长率(该时间段的最后两个值之差/时间间隔):i irate(node_cpu_seconds_total[10m])cpu时间排名前10的: topk(10,node_cpu_seconds_total)Gauge:可增可减的仪表盘与Counter不同,Gauge类型的指标侧重于反应系统的当前状态。因此这类指标的样本数据可增可减。常见指标如:node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)都是Gauge类型的监控指标。 样记录值:每个抓取时刻对应的设置值,因此没有设置值即0。 Gauge 的应用Gauge 用法比较单一,一般直接展示即可,也可做预测。 最近10分钟的变化情况: delta(node_load1[10m])预测系统磁盘空间在4个小时之后的剩余情况: predict_linear(node_filesystem_free{job="node"}[1h], 4 * 3600)Histogram 和 Summary 分析数据分布情况Histogram和Summary主用用于统计和分析样本的分布情况。 这两个指标类型拥有Counter的全部功能,都有_sum记录值之和, _count记录值的个数,其独特的功能是拥有获取数据分布情况的能力。 Histogram由 Prometheus server 计算分布,这也是使用 Histogram 的情况比 Summary 多的原因。分桶标签 ‘le’使用 quantile 函数查看分为数值metrics 样例 # HELP ts_http_seconds_bucket web http response time in seconds# TYPE ts_http_seconds_bucket histogramts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="1"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="2"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="4"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="8"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="16"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="32"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="64"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="128"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="512"} 0ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="1024"} 877ts_http_seconds_bucket_bucket{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200",le="+Inf"} 1062ts_http_seconds_bucket_sum{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200"} 1.19617e+06ts_http_seconds_bucket_count{error="false",method="put",path="/app/tri",serverName="Java-application",stage="beta",statusCode="200"} 1062Summary由 Prometheus client 计算分布分布标签 'quantile'metrics 样例 ...

June 8, 2020 · 1 min · jiezi

为-Prometheus-Node-Exporter-加上认证

这篇文章主要是为了庆祝 Node Exporter 终于迎来了 v1.0.0 版本。Prometheus 是最早由 SoundCloud 开源的监控告警解决方案。并已经成长为继 Kubernetes 之后,第二个从 CNCF 毕业的项目。伴随着云原生理念的普及和 Kubernetes 等技术的发展, Prometheus 在监控领域也有了长足的发展。 其主要组件包括 Prometheus,Alertmanager,Node Exporter,Blackbox Exporter 和 Pushgateway 等。 本文主要是为了庆祝 Node Exporter 终于迎来了 v1.0.0 版本, 所以重点主要放在一直被人诟病的安全性相关上,具体而言就是利用 TLS 和 Basic Auth 提升其安全性。 背景Node Exporter 是 Prometheus 官方发布的,用于采集节点的系统信息,比如 CPU,内存,磁盘和网络等信息。通常情况下,如果我们在使用 Prometheus 作为监控方案,那 Node Exporter 基本都会用到的。 在 Promethues 的监控体系中,社区中一直存在的一个观点是,Metrics 不包含过于私密的信息。所以你可以看到,大多数的 /metrics 接口都是直接暴露出来的,没什么特别的安全措施。 但随着 Prometheus 在生产中的大量应用,安全问题变得更加重要。 大家最先想到的解决办法就是,为 Prometheus 与监控目标之间的连接启用 TLS。 但由于各类 exporter 并不原生支持 TLS 连接,所以通常情况下我们会选择配合反向代理来完成。 这种方式能满足需求,但未免复杂了些。近期 Prometheus 对其安全模型做了修改 , 从 Node Exporter 开始到后续其他的组件,都将支持 TLS 和 basic auth, 同时也列出了最新的安全基准(默认情况下都支持 TLS v1.2 及以上) ...

May 27, 2020 · 4 min · jiezi

Prometheus-入门

文章首发于公众号《程序员果果》地址 : https://mp.weixin.qq.com/s/Bj...简介Prometheus 是一套开源的系统监控报警框架。它启发于 Google 的 borgmon 监控系统,由工作在 SoundCloud 的 google 前员工在 2012 年创建,作为社区开源项目进行开发,并于 2015 年正式发布。 特点作为新一代的监控框架,Prometheus 具有以下特点: 强大的多维度数据模型: 时间序列数据通过 metric 名和键值对来区分。所有的 metrics 都可以设置任意的多维标签。数据模型更随意,不需要刻意设置为以点分隔的字符串。可以对数据模型进行聚合,切割和切片操作。支持双精度浮点类型,标签可以设为全 unicode。灵活而强大的查询语句(PromQL):在同一个查询语句,可以对多个 metrics 进行乘法、加法、连接、取分数位等操作。易于管理: Prometheus server 是一个单独的二进制文件,可直接在本地工作,不依赖于分布式存储。高效:平均每个采样点仅占 3.5 bytes,且一个 Prometheus server 可以处理数百万的 metrics。使用 pull 模式采集时间序列数据,这样不仅有利于本机测试而且可以避免有问题的服务器推送坏的 metrics。 可以采用 push gateway 的方式把时间序列数据推送至 Prometheus server 端。可以通过服务发现或者静态配置去获取监控的 targets。有多种可视化图形界面。易于伸缩。组成及架构Prometheus 生态圈中包含了多个组件,其中许多组件是可选的: Prometheus Server: 用于收集和存储时间序列数据。Client Library: 客户端库,为需要监控的服务生成相应的 metrics 并暴露给 Prometheus server。当 Prometheus server 来 pull 时,直接返回实时状态的 metrics。Push Gateway: 主要用于短期的 jobs。由于这类 jobs 存在时间较短,可能在 Prometheus 来 pull 之前就消失了。为此,这次 jobs 可以直接向 Prometheus server 端推送它们的 metrics。这种方式主要用于服务层面的 metrics,对于机器层面的 metrices,需要使用 node exporter。Exporters: 用于暴露已有的第三方服务的 metrics 给 Prometheus。Alertmanager: 从 Prometheus server 端接收到 alerts 后,会进行去除重复数据,分组,并路由到对收的接受方式,发出报警。常见的接收方式有:电子邮件,pagerduty,OpsGenie, webhook 等。一些其他的工具。下图为 Prometheus 官方文档中的架构图: ...

June 25, 2019 · 2 min · jiezi

容器监控实践Cortex

一.概述cortex:一个支持多租户、水平扩展的prometheus服务。 当时调研cortex其实是因为看到了Weave Cloud这个商业产品中的监控模块介绍,weave也叫weave works,官方地址是:https://cloud.weave.works,是一个专注于容器微服务的paas平台。 WeaveCloud在监控模块最大化利用了Prometheus,并在其基础上添加了很多组件,实现了多租户管理、高可用的监控集群。其使用的核心监控组件就是cortex。 本文主要分享的是cortex的运行机制,关于Weave Cloud的产品定位和功能可以看下后续的文章:[商业方案-weave work]() Cortex是一个CNCF的沙盒项目,目前被几个线上产品使用:Weave Cloud、GrafanaCloud和FreshTracks.io 为什么不直接运行Prometheus,而用Cortex? ps:来自cortex kubecon大会演讲 作为服务,cortex提供了鉴权和访问控制数据永久保留,状态能够被管理提供持久化、高可用、伸缩性提供更好的查询效率,尤其是长查询二.主要功能针对以上需求,Cortex提供的主要功能或特色如下: 支持多租户:Prometheus本身没有的租户概念。这意味着,它无法对特定于租户的数据访问和资源使用配额,提供任何形式的细粒度控制。Cortex可以从多个独立的prometheus实例中获取数据,并按照租户管理。长期存储:基于远程写入机制,支持四种开箱即用的长期存储系统:AWS DynamoDB、AWS S3、Apache Cassandra和Google Cloud Bigtable。全局视图:提供所有prometheus server 整合后的时间序列数据的单一,一致的“全局”视图。高可用:提供服务实例的水平扩展、联邦集群等最大化利用了Prometheus相似的竞品: Prometheus + InfluxDB:使用InfluxDataPrometheus + Thanos:长期存储、全局视图Timbala:多副本、全局视图,作者是Matt BostockM3DB:自动扩缩容,来自uber产品形态ps:来自weave work上试用监控模块时的截图 1.安装监控的agent: 2.概览视图 3.资源监控面板 4.监控详情页面 5.添加监控 6.配置报警 在k8s集群中部署所需要的yaml列表为: [https://github.com/weaveworks...](https://github.com/weaveworks...) 部署的agent时的脚本内容是: #!/bin/shset -e# Create a temporary file for the bootstrap binaryTMPFILE="$(mktemp -qt weave_bootstrap.XXXXXXXXXX)" || exit 1finish(){ # Send only when this script errors out # Filter out the bootstrap errors if [ $? -ne 111 ] && [ $? -ne 0 ]; then curl -s >/dev/null 2>/dev/null -H "Accept: application/json" -H "Authorization: Bearer $token" -X POST -d \ '{"type": "onboarding_failed", "messages": {"browser": { "type": "onboarding_failed", "text": "Installation of Weave Cloud agents did not finish."}}}' \ https://cloud.weave.works/api/notification/external/events || true fi # Arrange for the bootstrap binary to be deleted rm -f "$TMPFILE"}# Call finish function on exittrap finish EXIT# Parse command-line argumentsfor arg in "$@"; do case $arg in --token=*) token=$(echo $arg | cut -d '=' -f 2) ;; esacdoneif [ -z "$token" ]; then echo "error: please specify the instance token with --token=<TOKEN>" exit 1fi# Notify installation has startedcurl -s >/dev/null 2>/dev/null -H "Accept: application/json" -H "Authorization: Bearer $token" -X POST -d \ '{"type": "onboarding_started", "messages": {"browser": { "type": "onboarding_started", "text": "Installation of Weave Cloud agents has started"}}}' \ https://cloud.weave.works/api/notification/external/events || true# Get distributionunamestr=$(uname)if [ "$unamestr" = 'Darwin' ]; then dist='darwin'elif [ "$unamestr" = 'Linux' ]; then dist='linux'else echo "This OS is not supported" exit 1fi# Download the bootstrap binaryecho "Downloading the Weave Cloud installer... "curl -Ls "https://get.weave.works/bootstrap?dist=$dist" >> "$TMPFILE"# Make the bootstrap binary executablechmod +x "$TMPFILE"# Execute the bootstrap binary"$TMPFILE" "--scheme=https" "--wc.launcher=get.weave.works" "--wc.hostname=cloud.weave.works" "--report-errors" "$@"三.实现原理Cortex与Prometheus的交互图: ...

May 27, 2019 · 2 min · jiezi

配置-spring-boot-2X-支持-prometheus-metrics

前言实际项目中,提供metrics接口,对接公司的监控系统,增加服务的可观察性,是一个基本的要求。在spring boot 1.X 中集成prometheus metrics,非常简单。但是spring boot 2.X 颇费周折。因为prometheus官方提供的prometheus-client-java不兼容spring boot 2.X 。需要借助micrometer。 步骤1:引入所需的包 在pom.xml文件中增加如下: <!-- Spring boot actuator to expose metrics endpoint --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- Micormeter core dependecy --> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>2: 增加相关配置 在 application.yml中增加如下设置: management: endpoints: web: exposure: include: ["metrics","prometheus"] endpoint: metrics: enabled: true prometheus: enabled: true metrics: export: prometheus: enabled: truePS: 如果想获取其他的metrics,可以设置include: ["*"] 3:运行查看metrics 运行项目,访问 http://localhost:8090/actuator,可看到如下: ...

April 30, 2019 · 4 min · jiezi

K8S 生态周报| 2019-04-15~2019-04-21

「K8S 生态周报」内容主要包含我所接触到的 K8S 生态相关的每周值得推荐的一些信息。欢迎订阅知乎专栏「k8s生态」。Prometheus v2.9.0 正式发布Prometheus 是 CNCF 毕业项目,可用于监控系统及服务状态。它整体是使用 Pull 的模式,在周期时间内采集目标的 metrics ,并且提供了 PromQL 的查询语言,以供对监控数据进行查询过滤等操作。并且可以通过配置规则来触发报警等。我首次接触 Prometheus 大概是在 2015 年 0.15.0 版本左右,当时 Prometheus 还处于比较早期的阶段,不过在进入 CNCF 后,Prometheus 基本就成为了 K8S 监控的实施标准了,并且多数软件也都增加了对 Prometheus metrics 的支持。 v2.9.0 的主要更新: 从 2.8 开始引入了的从 WAL 读取进行 remote write 有时候会丢数据的问题已经得到修复;Kubernetes 和 OpenStack 在服务发现时候增加了更多元数据;Consul 现在支持多 tag;添加了一个 honor_timestamps 的选项;TLS 证书会自动从磁盘加载;日志也变的更易读;其他更新请阅读 ReleaseNote Linkerd 2.3 正式发布Linkerd 是一个 service mesh 旨在提供平台范围的可观察性,可靠性和安全性,而无需用户更改代码。在本月初的周报推送中,推荐了一篇关于 Linkerd v2 从产品中吸取的教育和经验的文章,Linkerd v2 使用 Go 和 Rust 进行了重写,并因此获得了巨大的收益。 ...

April 22, 2019 · 1 min · jiezi

Prometheus Operator - 如何监控一个外部服务

原文地址:Prometheus Operator — How to monitor an external service本实践指南中我们将看到如何部署Prometheus Operator到Kubernetes集群中,以及如何增加一个外部服务到Prometheus的targets列表。 在我的上个项目中,我们决定使用Prometheus Operator作为我们的监控和报警工具。我们的应用运行于Kubernetes集群中,但是除此我们还有个外部应用 — 一个GPU机器。 Kubernetes根本感知不到这个服务,相关服务通过HTTP请求连接该服务。我想跟你们分享下我使用Prometheus Operator的经验以及如何定制它来监控外部服务。 什么是PrometheusPrometheus是最早由SoundCloud开发的一个开源系统监控及报警工具。自从它2012年创建以来,许多公司和组织使用。Prometheus及其社区有一个非常活跃的开发者群体和用户社区。它现在是一个独立的开源项目,独立于任何公司进行维护。company.Prometheus已经成为Kubernetes和Docker领域监控和报警的事实标准。它提供了到目前为止最详细和可操作的监控指标和分析。在最新的主要版本2.0版本(访问下载页面查看当前最新版)Prometheus的性能有了显著提升,并且现在它在高负载和并发下表现良好。除此以外你可以获得世界领先的开源项目的所有好处。Prometheus可以免费使用,并可以轻松覆盖很多使用场景。 Prometheus Operator2016年年末,CoreOs引入了Operator 模式,并发布了Prometheus Operator 作为Operator模式的工作示例。Prometheus Operator自动创建和管理Prometheus监控实例。 Prometheus Operator的任务是使得在Kubernetes运行Prometheus仅可能容易,同时保留可配置性以及使Kubernetes配置原生。 https://coreos.com/operators/...Prometheus Operator使我们的生活更容易——部署和维护。 它如何工作为了理解这个问题,我们首先需要了解Prometheus Operator得工作原理。 Prometheus Operator架构图. 来源:prometheus-operator 我们成功部署 Prometheus Operator后可以看到一个新的CRDs(Custom Resource Defination): Prometheus,定义一个期望的Prometheus deployment。ServiceMonitor,声明式指定应该如何监控服务组;Operator根据定义自动创建Prometheusscrape配置。Alertmanager,定义期望的Alertmanager deployment。当服务新版本更新时,将会常见一个新Pod。Prometheus监控k8s API,因此当它检测到这种变化时,它将为这个新服务(pod)创建一组新的配置。 ServiceMonitorPrometheus Operator使用一个CRD,叫做ServiceMonitor将配置抽象到目标。下面是是个ServiceMonitor的示例: apiVersion: monitoring.coreos.com/v1alpha1kind: ServiceMonitormetadata: name: frontend labels: tier: frontendspec: selector: matchLabels: tier: frontend endpoints: - port: web # works for different port numbers as long as the name matches interval: 10s # scrape the endpoint every 10 seconds这仅仅是定义一组服务应该如何被监控。现在我们需要定义一个包含了该ServiceMonitor的Prometheus实例到其配置: ...

April 22, 2019 · 2 min · jiezi

Prometheus hotspot监控指标解读

简介Prometheus 是一套开源的系统监控报警框架。它启发于 Google 的 borgmon 监控系统,由工作在 SoundCloud 的 google 前员工在 2012 年创建,作为社区开源项目进行开发,并于 2015 年正式发布。2016 年,Prometheus 正式加入 Cloud Native Computing Foundation,成为受欢迎度仅次于 Kubernetes 的项目。特性强大的多维度数据模型:时间序列数据通过 metric 名和键值对来区分。所有的 metrics 都可以设置任意的多维标签。数据模型更随意,不需要刻意设置为以点分隔的字符串。可以对数据模型进行聚合,切割和切片操作。支持双精度浮点类型,标签可以设为全 unicode。灵活而强大的查询语句(PromQL):在同一个查询语句,可以对多个 metrics 进行乘法、加法、连接、取分数位等操作。易于管理: Prometheus server 是一个单独的二进制文件,可直接在本地工作,不依赖于分布式存储。高效:平均每个采样点仅占 3.5 bytes,且一个 Prometheus server 可以处理数百万的 metrics。使用 pull 模式采集时间序列数据,这样不仅有利于本机测试而且可以避免有问题的服务器推送坏的 metrics。可以采用 push gateway 的方式把时间序列数据推送至 Prometheus server 端。可以通过服务发现或者静态配置去获取监控的 targets。有多种可视化图形界面。易于伸缩。架构相关概念hotspot 监控Java Hotspot虚拟机监控指标收集BufferPoolsExportsJVM缓冲区监控指标。 bufferPool指标是从MBean获取的,BufferPoolsExports构造函数:public BufferPoolsExports() { try { final Class<?> bufferPoolMXBeanClass = Class.forName(“java.lang.management.BufferPoolMXBean”); bufferPoolMXBeans.addAll(accessBufferPoolMXBeans(bufferPoolMXBeanClass)); getName = bufferPoolMXBeanClass.getMethod(“getName”); getMemoryUsed = bufferPoolMXBeanClass.getMethod(“getMemoryUsed”); getTotalCapacity = bufferPoolMXBeanClass.getMethod(“getTotalCapacity”); getCount = bufferPoolMXBeanClass.getMethod(“getCount”); } catch (ClassNotFoundException e) { LOGGER.fine(“BufferPoolMXBean not available, no metrics for buffer pools will be exported”); } catch (NoSuchMethodException e) { LOGGER.fine(“Can not get necessary accessor from BufferPoolMXBean: " + e.getMessage()); }}获取Mean类对象获取可访问的MBean实例并添加到成员变量中获取getName方法Method对象(缓冲池名称)获取getMemoryUsed方法的Method对象(估算的jvm已使用内存大小)获取getTotalCapacity方法的Method对象(预估的总的缓冲池大小)获取getCount方法的Method对象(缓冲池中大致的数量)collect()方法返回buffer pool指标收集器收集的所有指标信息。jvm_buffer_pool_used_bytesjvm缓冲区使用情况,包括Code Cache(编译后的代码缓存,不同版本的jvm默认大小不同)、PS Old Gen(老年代)、PS Eden Space(伊甸园)、PS Survivor Space(幸存者)、PS Perm Gen(永久代)。jvm_buffer_pool_capacity_bytes给定jvm的估算缓冲区大小。这个metrics数据没有收集到,可能和jvm的版本有关,部署服务器使用的是jdk 6。jvm_buffer_pool_used_buffers给定jvm的已使用缓冲区大小。这个metrics没有收集到,可能和jvm的版本有关,部署服务器使用的是jdk 6。ClassLoadingExports提供jvm类加载指标。jvm类加载指标数据由ClassLoadingMXBean提供。jvm_classes_loaded当前jvm已加载类数量。 jvm_classes_loaded_total从jvm运行开始加载的类的数量,这是一个Counter指标,递增。jvm_classes_unloaded_totaljvm运行后卸载的类数量,这是一个Counter指标。生产环境一直是0。GarbageCollectorExports提供jvm 垃圾收集器指标,指标数据有GarbageCollectorMXBean列表提供。jvm_gc_collection_seconds这是一个Summary指标,与Histogram类似,可以对指标数据进行采样。MemoryAllocationExports内存分配情况指标,这个指标因java版本不兼容而没有做监控。MemoryPoolsExportsjvm 内存区域指标。jvm_memory_bytes_usedjvm已用内存区域。jvm_memory_bytes_committedCommitted (bytes) of a given JVM memory areajvm_memory_bytes_maxjvm内存区域的最大字节数jvm_memory_bytes_initjvm内存区域的初始化字节数jvm_memory_pool_bytes_usedjvm内存池使用情况jvm_memory_pool_bytes_committedCommitted bytes of a given JVM memory pool.jvm_memory_pool_bytes_maxjvm内存池最大数jvm_memory_pool_bytes_initjvm内存池初始化数ThreadExportsjvm线程区域监控。jvm_threads_currentjvm当前线程数。jvm_threads_daemonjvm后台线程数。jvm_threads_peakjvm线程峰值jvm_threads_started_totaljvm总启动线程数量,Counter指标。jvm_threads_deadlocked死锁线程数量jvm_threads_deadlocked_monitorCycles of JVM-threads that are in deadlock waiting to acquire object monitorsjvm_threads_state当前线程的状态VersionInfoExportsjvm版本信息jvm_info版本信息,可以看到生产环境使用的是:1.6.0.29-b11StandardExports所有prometheus 客户端共有的标准指标。process_cpu_seconds_total用户和系统的总cpu使用时间process_start_time_secondsStart time of the process since unix epoch in secondsprocess_open_fds打开的文件描述符数量process_max_fds看支持打开的最大文件描述符数量PromQLtodo参考资料Prometheus 入门与实践 ...

April 20, 2019 · 1 min · jiezi

prometheus 集成dubbo

dubbo 自身的监控使用了dubbo 的拦截器,这里我们也使用dubbo 的拦截器来添加prometheus 监控首先需要dubbo 项目提供http的接口,为dubbo 项目添加 web依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>加入 micrometer prometheus <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-core</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency>实现dubbo 的filter 接口,添加 @Activate(group = Constants.PROVIDER)注解,声明拦截所有服务提供者@Activate(group = Constants.PROVIDER)public class PrometheusFilter implements Filter { private Logger logger = LoggerFactory.getLogger(PrometheusFilter.class); @Override public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { logger.info("—————-prometheus filter—————"); RequestTimeCollector requestTimeCollector = (RequestTimeCollector) ServiceBean.getSpringContext(). getBean(“dubboRequestTimeCollector”); RpcContext context = RpcContext.getContext(); boolean isProvider = context.isProviderSide(); String serviceName = invoker.getInterface().getName(); String methodName = RpcUtils.getMethodName(invocation); long start = System.currentTimeMillis(); try { // proceed invocation chain Result result = invoker.invoke(invocation); long duration = System.currentTimeMillis() - start; String status = “success”; if(result.getException()!=null){ status = result.getException().getClass().getSimpleName(); } requestTimeCollector.setValue(duration,serviceName,methodName,status); return result; } catch (RpcException e) { long duration = System.currentTimeMillis() - start; String result = “error”; if (e.isTimeout()) { result = “timeoutError”; } if (e.isBiz()) { result = “bisError”; } if (e.isNetwork()) { result = “networkError”; } if (e.isSerialization()) { result = “serializationError”; } requestTimeCollector.setValue(duration,serviceName,methodName,result); throw e; } }}配置拦截器扩展在 resourceMETA-INFdubbo 文件夹下创建com.alibaba.dubbo.rpc.Filter 文本文件添加 prometheus=com.rcplatform.livechat.dubbo.filter.PrometheusFilter文本启动项目访问/actuator/prometheus,即可看到监控项 ...

March 31, 2019 · 1 min · jiezi

Prometheus 监控 Nginx

前言Nginx官网有介绍各种监控方案,以前我们常用stub_status和Log日志来实现Nginx监控。本文主要介绍基于Prometheus的2种监控方案nginx-lua-prometheus和nginx-vts-exporter,在真实的生产环境中你可能需要研究和选择哪种方法才是适合你的,F5收购Nginx后的未来让我们一起拭目以待。Prometheus 监控 Nginx更新历史2019年03月25日 - 初稿阅读原文 - https://wsgzao.github.io/post…扩展阅读Monitoring NGINX - https://www.nginx.com/blog/mo...Nginx监控官网介绍的监控方案 - https://www.nginx.com/blog/mo...Prometheus 集成的 HTTP exporter 方案 - https://prometheus.io/docs/in…聊聊 Nginx 的监控 - https://zhuanlan.zhihu.com/p/…使用rpmbuild制作Nginx的RPM包 - https://wsgzao.github.io/post...Prometheus 监控 Nginxnginx-lua-prometheusNginx 需要添加 Lua 扩展https://github.com/knyar/ngin…# 下载redis_exporterhttps://github.com/knyar/nginx-lua-prometheus/releaseswget https://github.com/knyar/nginx-lua-prometheus/archive/0.20181120.tar.gztar xf 0.20181120.tar.gzcd nginx-lua-prometheus-0.20181120# 创建prometheus.lua目录mkdir -p /etc/nginx/lua/cp prometheus.lua /etc/nginx/lua/# 编辑nginx配置文件修改,注意修改lua_package_path “/etc/nginx/lua/prometheus.lua”;vim /etc/nginx/nginx.conflua_shared_dict prometheus_metrics 10M;lua_package_path “/etc/nginx/lua/prometheus.lua”;init_by_lua ’ prometheus = require(“prometheus”).init(“prometheus_metrics”) metric_requests = prometheus:counter( “nginx_http_requests_total”, “Number of HTTP requests”, {“host”, “status”}) metric_latency = prometheus:histogram( “nginx_http_request_duration_seconds”, “HTTP request latency”, {“host”}) metric_connections = prometheus:gauge( “nginx_http_connections”, “Number of HTTP connections”, {“state”})’;log_by_lua ’ metric_requests:inc(1, {ngx.var.server_name, ngx.var.status}) metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.server_name})’;# 创建nginx-lua-prometheusvim /etc/nginx/sites-available/nginx-lua-prometheusserver { listen 9145; location /metrics { content_by_lua ’ metric_connections:set(ngx.var.connections_reading, {“reading”}) metric_connections:set(ngx.var.connections_waiting, {“waiting”}) metric_connections:set(ngx.var.connections_writing, {“writing”}) prometheus:collect() ‘; }}# 创建软链接cd /etc/nginx/sites-enabled/ln -s ../sites-available/prometheus# 测试Nginx语法并reload测试metricsnginx -tnginx -s reloadcurl http://127.0.0.1:9145/metrics# iptables rule for Prometheus Nginx -A INPUT -s xxx -p tcp –dport 9145 -j ACCEPTnginx-vts-exporterhttps://github.com/hnlq715/ng…对方正在输入中Grafananginx-lua-prometheushttps://grafana.com/dashboard…nginx-vts-exporterhttps://grafana.com/dashboard…参考文献https://prometheus.io/docs/in… ...

March 26, 2019 · 1 min · jiezi

Prometheus 监控 Redis

前言Prometheus Exporter for Redis Metrics. Supports Redis 2.x, 3.x, 4.x, and 5.xPrometheus 监控 Redis更新历史2019年03月23日 - 初稿阅读原文 - https://wsgzao.github.io/post…扩展阅读redis_exporter - https://github.com/oliver006/...Redis export 安装和使用# 下载redis_exporterhttps://github.com/oliver006/redis_exporter/releasescd /tmpwget https://github.com/oliver006/redis_exporter/releases/download/v0.30.0/redis_exporter-v0.30.0.linux-amd64.tar.gz tar xf redis_exporter-v0.30.0.linux-amd64.tar.gz# 后台启动redis_exporternohup ./redis_exporter -redis.addr redis://<IP>:<PORT> &# iptables rule for Prometheus Redis -A INPUT -s xxx -p tcp –dport 9121 -j ACCEPT# 测试URL获取metricscurl http://<IP>:9121/metricsGrafanaMemory Usage 中 redis_config_maxmemory 如果无法获取到数据请自行定义 valuehttps://grafana.com/dashboard…参考文献https://prometheus.io/docs/in…

March 26, 2019 · 1 min · jiezi

【融云分析】从过剩存储资源到分布式时序数据库的长存储

背景介绍:作为一名 Infra,管理平台的各种基础组建以及基本的服务质量是必修的功课,而如何对复杂和繁多的基础平台,甚至包括上面运行的 Ops 系统、业务系统,其稳定性的各项指标都是衡量 Infra 是否称职的非常重要的标准。单纯离散的指标本身是没有实际意义的,只有将离散的指标通过某种方式进行存储,并支持对终端用户友好的查询以及聚合,才会真正的有意义。因此,一个性能足够的,分布式的,用户友好且方便下面 DevOps 团队进行部署的 TSDB ( Time Series Database )就成了一个不可缺少的系统。常见的 TSDB 包括 InfluxDB , OpenTSDB , Prometheus 等,其中,开源版本的 InfluxDB 虽然优秀,但并不支持集群部署,且 TICK Stack 本身对数据清洗的灵活性支持并不太好,直接使用开源版本,会有统计信息被收集并上报;而 OpenTSDB 由于基于 HBase ,在部署时成本过高,且本身并不是一套完整的监控系统,而基于 Prometheus 与 TiKV 进行开发的话,整个系统可在保持最简洁的同时,也有非常丰富的生态支持。因此,基于实际情况,融云最终选择 TiPrometheus 作为 Infra 部的监控平台存储方案。项目简介:上图为 Prometheus 的官方系统架构图,而实现 TiPrometheus ,用到了上图中没有体现到的一个 Prometheus 的功能:Remote Storage ,如其名所示,其主要功能是给 Prometheus 提供了远程写的能力,这个功能对于查询是透明的,主要用于长存储。而我们当时的 TiPrometheus 实现了基于 TiKV 以及 PD 实现的 Prometheus 的 Remote Storage 。核心实现Prometheus 记录的数据结构分为两部分 Label 及 Samples 。 Label 记录了一些特征信息,Samples 包含了指标数据和 Timestamp 。Label 和时间范围结合,可以查询到需要的 Value 。为了查询这些记录,需要构建两种索引 Label Index 和 Time Index ,并以特殊的 Key 存储 Value 。l Label Index每对 Label 为会以 index🏷️<name>#<latency> 为 key ,labelID 为 Value 存入。新的记录会 “,” 分割追加到 Value 后面。这是一种搜索中常用的倒排索引。l Time Index每个 Sample 项会以 index:timeseries:<labelID>:<splitTime> 为 Key,Timestamp 为 Value ,SplitTime 为时间切片的起始点。追加的 Timestamp 同样以",“分割。l Doc 存储我们将每一条 Samples 记录以 timeseries:doc:<labelID>:<timestamp> 为 Key 存入 TiKV ,其中 LabelID 是 Label 全文的散列值。下面做一个梳理:写入过程生成 labelID构建 time index,index:timeseries:<labelID>:<splitTime>“ts,ts"写入时序数据 timeseries:doc:<labelID>:<timestamp> “value"写入时序数据 timeseries:doc:<labelID>:<timestamp> “value"查询过程根据倒排索引查出 labelID 的集合,多对 Label 的查询会对 labelID 集合求交集。根据 labelID 和时间范围内的时间分片查询包含的 Timestamp 。根据 labelID 和 Timestamp 查出所需的 Value 。Why TiPrometheus该项目最初源于参加 PingCAP 组织的 Hackathon ,当时希望与参与者一起完成大家脑海里的想法,其实最重要的事情就是,做出来的东西并不是为了单纯的 Demo ,而是要做一个在实际工作中应用于生产环境的实际能力,且能解决生产中的问题。刚开始还有过各种奇思妙想,包括在 TiSpark 上做一套 ML ,Hadoop over TiKV 等,不过这些想法实现起来都有些过于硬核,对于只有两天工作时间就需要完成的项目来说,可能性太小;或者说,如果希望实现 Demo ,所需 Hack 的点过多。而 GEO 全文检索在融云现有的生产上,以及现有的系统中,也并没有需要去填补的大坑,因此,也就没有什么必要去在这方面花费力气去解决一个并不存在的问题。由于 IM 服务是一种计算密集型的服务,且服务质量是融云的核心竞争力;而目前存储资源呈现出零散分布的节点,且每个节点的存储资源使用率并不高,为了最大化利用现有的闲置资源,融云最终设计并实现了这套 TiPrometheus 系统。Result打通了 TiKV 与 Prometheus ,为基于 K , V 存储的时序数据库设计提供了一个可行的思路。为 Prometheus 的长存储提供了一套实用的解决方案。 ...

March 15, 2019 · 1 min · jiezi

CNCF案例研究:网易

网易如何利用Kubernetes支持全球互联网业务公司:网易地点:中国杭州行业:互联网技术挑战它的游戏业务是世界上最大的游戏业务之一,但这并不是网易为中国消费者提供的唯一服务。该公司还经营电子商务、广告、音乐流媒体、在线教育和电子邮件平台;最后一个通过163.com等网站为近十亿用户提供免费电子邮件服务。2015年,为所有这些系统提供基础设施的网易云团队,意识到他们的研发流程正在减缓开发者的速度。“我们的用户需要自己准备所有基础设施。”网易云和容器服务架构师Feng Changjian说。“我们渴望通过无服务器的容器服务,自动为我们的用户提供基础设施和工具。”解决方法在考虑建立自己的业务流程解决方案后,网易决定将其私有云平台建立在Kubernetes上。这项技术来自Google的事实让团队相信它可以跟上网易的规模。“经过2到3个月的评估,我们相信它可以满足我们的需求。”Changjian说。该团队在2015年开始使用Kubernetes,甚至在1.0之前。今天,网易内部云平台还利用了CNCF项目Prometheus、Envoy、Harbor、gRPC和Helm,在生产集群中运行10,000个节点,并且可以在一个集群中支持多达30,000个节点。基于其内部平台的经验,该公司向外部客户推出了基于Kubernetes的云和面向微服务的PaaS产品,网易轻舟微服务。影响网易团队报告说,Kubernetes使研发效率提高了100%以上。部署效率提高了280%。“在过去,如果我们想进行升级,我们需要与其他团队合作,甚至在其他部门工作。”Changjian说。“我们需要特殊的工作人员来准备一切,所以花了大约半个小时。现在我们可以在5分钟内完成。”新平台还允许使用GPU和CPU资源进行混合部署。“之前,如果我们将所有资源都用于GPU,我们就不会为CPU提供备用资源。但是现在我们通过混合部署得到了改进。”他说。这些改进也提高了资源的利用率。“该系统可以在一个集群中支持30,000个节点。在生产中,我们在单个集群中获得了10,000个节点的数据。整个内部系统正在使用该系统进行开发、测试和生产。” - Zeng Yuxing,网易架构师它的游戏业务是全球第五大,但这并非网易为消费者提供的唯一服务。该公司还在中国经营电子商务、广告、音乐流媒体、在线教育和电子邮件平台;其中最后一个通过163.com和126.com等热门网站为近十亿用户提供免费电子邮件服务。凭借这种规模,网易云团队为所有这些系统提供基础设施,在2015年发现他们的研发流程难以使开发者满足需求。“我们的用户需要自己准备所有基础设施。”网易云和容器服务架构师Feng Changjian说。“我们渴望通过无服务器的容器服务,自动为我们的用户提供基础设施和工具。”在考虑建立自己的业务流程解决方案后,网易决定将其私有云平台建立在Kubernetes上。这项技术来自Google的事实让团队相信它可以跟上网易的规模。“经过2到3个月的评估,我们相信它可以满足我们的需求。”Changjian说。“我们利用Kubernetes的可编程性,以便我们可以构建一个平台来满足内部客户的升级和部署需求。” - Feng Changjian,网易云和容器服务架构师该团队在2015年开始采用Kubernetes,甚至在1.0之前,因为它相对容易使用,并且让公司启用了DevOps。“我们放弃了Kubernetes的一些概念;我们只想使用标准化框架。”Changjian说。“我们利用Kubernetes的可编程性,以便我们可以构建一个平台来满足内部客户的升级和部署需求。”该团队首先专注于构建容器平台,以更好地管理资源,然后通过添加监控等内部系统,将注意力转向改进其对微服务的支持。这意味着整合CNCF项目Prometheus、Envoy、Harbor、gRPC和Helm。“我们努力提供简化和标准化的流程,因此我们的用户和客户可以利用我们的最佳实践。”Changjian说。团队正在继续改进。例如,企业的电子商务部分需要利用混合部署,这在过去需要使用两个独立的平台:基础架构即服务平台和Kubernetes平台。最近,网易创建了一个跨平台的应用程序,可以同时使用单命令部署。“只要公司拥有一支成熟的团队和足够的开发者,我认为Kubernetes是一种非常好的技术,可以帮助他们。” - Li Lanqing,网易Kubernetes开发者今天,网易内部云平台“可以在一个集群中支持30,000个节点。”架构师Zeng Yuxing说。“在生产中,我们在单个集群中获得了10,000个节点的数据。整个内部系统正在使用该系统进行开发、测试和生产。”网易团队报告说,Kubernetes使研发效率提高了100%以上。部署效率提高了280%。“在过去,如果我们想进行升级,我们需要与其他团队合作,甚至在其他部门工作。”Changjian说。“我们需要特殊的工作人员来准备一切,所以花了大约半个小时。现在我们可以在5分钟内完成。”新平台还允许使用GPU和CPU资源进行混合部署。“之前,如果我们将所有资源都用于GPU,我们就不会为CPU提供备用资源。但是现在我们通过混合部署得到了改进。”他说。这些改进也提高了资源的利用率。“通过与这个社区合作,我们可以从中获得一些经验,我们也可以从中受益。我们可以看到社区面临的问题和挑战,并参与其中。” - Li Lanqing,网易Kubernetes开发者基于使用其内部平台的结果和经验,该公司向外部客户推出基于Kubernetes的云和面向微服务的PaaS产品,网易轻舟微服务。“我们的想法是,我们可以找到我们的游戏和电子商务以及云音乐供应商遇到的问题,因此我们可以整合他们的经验,并提供一个平台来满足用户的需求。”Changjian说。无论是否使用网易产品,该团队都鼓励其他公司尝试Kubernetes。“只要公司拥有一支成熟的团队和足够的开发者,我认为Kubernetes是一种非常好的技术,可以帮助他们。”Kubernetes开发者Li Lanqing说。作为最终用户和供应商,网易已经更多地参与社区,向其他公司学习并分享他们所做的事情。该团队一直在为Harbor和Envoy项目做出贡献,并在网易规模测试技术时提供反馈。“我们是一个专注于解决微服务架构挑战的团队。”Changjian说。“通过与这个社区合作,我们可以从中获得一些经验,我们也可以从中受益。我们可以看到社区面临的问题和挑战,并参与其中。”KubeCon + CloudNativeCon + Open Source Summit大会日期:会议日程通告日期:2019 年 4 月 10 日会议活动举办日期:2019 年 6 月 24 至 26 日KubeCon + CloudNativeCon + Open Source Summit赞助方案KubeCon + CloudNativeCon + Open Source Summit多元化奖学金现正接受申请KubeCon + CloudNativeCon和Open Source Summit即将首次合体落地中国KubeCon + CloudNativeCon + Open Source Summit购票窗口,立即购票!CNCF邀请你加入最终用户社区

March 15, 2019 · 1 min · jiezi

TiKV 源码解析系列文章(四)Prometheus(下)

作者: Breezewish本文为 TiKV 源码解析系列的第四篇,接上篇继续为大家介绍 [rust-prometheus]。上篇 主要介绍了基础知识以及最基本的几个指标的内部工作机制,本篇会进一步介绍更多高级功能的实现原理。与上篇一样,以下内部实现都基于本文发布时最新的 rust-prometheus 0.5 版本代码,目前我们正在开发 1.0 版本,API 设计上会进行一些简化,实现上出于效率考虑也会和这里讲解的略微有一些出入,因此请读者注意甄别。指标向量(Metric Vector)Metric Vector 用于支持带 Label 的指标。由于各种指标都可以带上 Label,因此 Metric Vector 本身实现为了一种泛型结构体,[Counter]、[Gauge] 和 [Histogram] 在这之上实现了 [CounterVec]、[GaugeVec] 和 [HistogramVec]。Metric Vector 主要实现位于 src/vec.rs。以 [HistogramVec] 为例,调用 [HistogramVec::with_label_values] 可获得一个 [Histogram] 实例,而 [HistogramVec] 定义为:pub type HistogramVec = MetricVec<HistogramVecBuilder>;pub struct MetricVec<T: MetricVecBuilder> { pub(crate) v: Arc<MetricVecCore<T>>,}impl<T: MetricVecBuilder> MetricVec<T> { pub fn with_label_values(&self, vals: &[&str]) -> T::M { self.get_metric_with_label_values(vals).unwrap() }}因此 [HistogramVec::with_label_values] 的核心逻辑其实在 MetricVecCore::get_metric_with_label_values。这么做的原因是为了让 MetricVec 是一个线程安全、可以被全局共享但又不会在共享的时候具有很大开销的结构,因此将内部逻辑实现在 MetricVecCore,外层(即在 MetricVec)套一个 Arc<T> 后再提供给用户。进一步可以观察 MetricVecCore 的实现,其核心逻辑如下:pub trait MetricVecBuilder: Send + Sync + Clone { type M: Metric; type P: Describer + Sync + Send + Clone; fn build(&self, &Self::P, &[&str]) -> Result<Self::M>;}pub(crate) struct MetricVecCore<T: MetricVecBuilder> { pub children: RwLock<HashMap<u64, T::M>>, // Some fields are omitted.}impl<T: MetricVecBuilder> MetricVecCore<T> { // Some functions are omitted. pub fn get_metric_with_label_values(&self, vals: &[&str]) -> Result<T::M> { let h = self.hash_label_values(vals)?; if let Some(metric) = self.children.read().get(&h).cloned() { return Ok(metric); } self.get_or_create_metric(h, vals) } pub(crate) fn hash_label_values(&self, vals: &[&str]) -> Result<u64> { if vals.len() != self.desc.variable_labels.len() { return Err(Error::InconsistentCardinality( self.desc.variable_labels.len(), vals.len(), )); } let mut h = FnvHasher::default(); for val in vals { h.write(val.as_bytes()); } Ok(h.finish()) } fn get_or_create_metric(&self, hash: u64, label_values: &[&str]) -> Result<T::M> { let mut children = self.children.write(); // Check exist first. if let Some(metric) = children.get(&hash).cloned() { return Ok(metric); } let metric = self.new_metric.build(&self.opts, label_values)?; children.insert(hash, metric.clone()); Ok(metric) }}现在看代码就很简单了,它首先会依据所有 Label Values 构造一个 Hash,接下来用这个 Hash 在 RwLock<HashMap<u64, T::M>> 中查找,如果找到了,说明给定的这个 Label Values 之前已经出现过、相应的 Metric 指标结构体已经初始化过,因此直接返回对应的实例;如果不存在,则要利用给定的 [MetricVecBuilder] 构造新的指标加入哈希表,并返回这个新的指标。由上述代码可见,为了在线程安全的条件下实现 Metric Vector 各个 Label Values 具有独立的时间序列,Metric Vector 内部采用了 RwLock 进行同步,也就是说 with_label_values() 及类似函数内部是具有锁的。这在多线程环境下会有一定的效率影响,不过因为大部分情况下都是读锁,因此影响不大。当然,还可以发现其实给定 Label Values 之后调用 with_label_values() 得到的指标实例是可以被缓存起来的,只访问缓存起来的这个指标实例是不会有任何同步开销的,也绕开了计算哈希值等比较占 CPU 的操作。基于这个思想,就有了 Static Metrics,读者可以在本文的后半部分了解 Static Metrics 的详细情况。另外读者也可以发现,Label Values 的取值应当是一个有限的、封闭的小集合,不应该是一个开放的或取值空间很大的集合,因为每一个值都会对应一个内存中指标实例,并且不会被释放。例如 HTTP Method 是一个很好的 Label,因为它只可能是 GET / POST / PUT / DELETE 等;而 Client Address 则很多情况下并不适合作为 Label,因为它是一个开放的集合,或者有非常巨大的取值空间,如果将它作为 Label 很可能会有容易 OOM 的风险。这个风险在 Prometheus 官方文档中也明确指出了。整型指标(Integer Metric)在讲解 Counter / Gauge 的实现时我们提到,[rust-prometheus] 使用 CAS 操作实现 [AtomicF64] 中的原子递增和递减,如果改用 atomic fetch-and-add 操作则一般可以取得更高效率。考虑到大部分情况下指标都可以是整数而不需要是小数,例如对于简单的次数计数器来说它只可能是整数,因此 [rust-prometheus] 额外地提供了整型指标,允许用户自由地选择,针对整数指标情况提供更高的效率。为了增强代码的复用,[rust-prometheus] 实际上采用了泛型来实现 [Counter] 和 [Gauge]。通过对不同的 Atomic(如 [AtomicF64]、[AtomicI64])进行泛化,就可以采用同一份代码实现整数的指标和(传统的)浮点数指标。[Atomic] trait 定义如下(src/atomic64/mod.rs):pub trait Atomic: Send + Sync { /// The numeric type associated with this atomic. type T: Number; /// Create a new atomic value. fn new(val: Self::T) -> Self; /// Set the value to the provided value. fn set(&self, val: Self::T); /// Get the value. fn get(&self) -> Self::T; /// Increment the value by a given amount. fn inc_by(&self, delta: Self::T); /// Decrement the value by a given amount. fn dec_by(&self, delta: Self::T);}原生的 [AtomicU64]、[AtomicI64] 及我们自行实现的 [AtomicF64] 都实现了 [Atomic] trait。进而,[Counter] 和 [Gauge] 都可以利用上 [Atomic] trait:pub struct Value<P: Atomic> { pub val: P, // Some fields are omitted.}pub struct GenericCounter<P: Atomic> { v: Arc<Value<P>>,}pub type Counter = GenericCounter<AtomicF64>;pub type IntCounter = GenericCounter<AtomicI64>;本地指标(Local Metrics)由前面这些源码解析可以知道,指标内部的实现是原子变量,用于支持线程安全的并发更新,但这在需要频繁更新指标的场景下相比简单地更新本地变量仍然具有显著的开销(大约有 10 倍的差距)。为了进一步优化、支持高效率的指标更新操作,[rust-prometheus] 提供了 Local Metrics 功能。rust-prometheus 中 Counter 和 Histogram 指标支持 local() 函数,该函数会返回一个该指标的本地实例。本地实例是一个非线程安全的实例,不能多个线程共享。例如,[Histogram::local()] 会返回 [LocalHistogram]。由于 Local Metrics 使用是本地变量,开销极小,因此可以放心地频繁更新 Local Metrics。用户只需定期调用 Local Metrics 的 flush() 函数将其数据定期同步到全局指标即可。一般来说 Prometheus 收集数据的间隔是 15s 到 1 分钟左右(由用户自行配置),因此即使是以 1s 为间隔进行 flush() 精度也足够了。普通的全局指标使用流程如下图所示,多个线程直接利用原子操作更新全局指标:本地指标使用流程如下图所示,每个要用到该指标的线程都保存一份本地指标。更新本地指标操作开销很小,可以在频繁的操作中使用。随后,只需再定期将这个本地指标 flush 到全局指标,就能使得指标的更新操作真正生效。TiKV 中大量运用了本地指标提升性能。例如,TiKV 的线程池一般都提供 Context 变量,Context 中存储了本地指标。线程池上运行的任务都能访问到一个和当前 worker thread 绑定的 Context,因此它们都可以安全地更新 Context 中的这些本地指标。最后,线程池一般提供 tick() 函数,允许以一定间隔触发任务,在 tick() 中 TiKV 会对这些 Context 中的本地指标进行 flush()。Local Counter[Counter] 的本地指标 [LocalCounter] 实现很简单,它是一个包含了计数器的结构体,该结构体提供了与 [Counter] 一致的接口方便用户使用。该结构体额外提供了 flush(),将保存的计数器的值作为增量值更新到全局指标:pub struct GenericLocalCounter<P: Atomic> { counter: GenericCounter<P>, val: P::T,}pub type LocalCounter = GenericLocalCounter<AtomicF64>;pub type LocalIntCounter = GenericLocalCounter<AtomicI64>;impl<P: Atomic> GenericLocalCounter<P> { // Some functions are omitted. pub fn flush(&mut self) { if self.val == P::T::from_i64(0) { return; } self.counter.inc_by(self.val); self.val = P::T::from_i64(0); }}Local Histogram由于 [Histogram] 本质也是对各种计数器进行累加操作,因此 [LocalHistogram] 的实现也很类似,例如 observe(x) 的实现与 [Histogram] 如出一辙,除了它不是原子操作;flush() 也是将所有值累加到全局指标上去:pub struct LocalHistogramCore { histogram: Histogram, counts: Vec<u64>, count: u64, sum: f64,}impl LocalHistogramCore { // Some functions are omitted. pub fn observe(&mut self, v: f64) { // Try find the bucket. let mut iter = self .histogram .core .upper_bounds .iter() .enumerate() .filter(|&(_, f)| v <= *f); if let Some((i, _)) = iter.next() { self.counts[i] += 1; } self.count += 1; self.sum += v; } pub fn flush(&mut self) { // No cached metric, return. if self.count == 0 { return; } { let h = &self.histogram; for (i, v) in self.counts.iter().enumerate() { if *v > 0 { h.core.counts[i].inc_by(*v); } } h.core.count.inc_by(self.count); h.core.sum.inc_by(self.sum); } self.clear(); }}静态指标(Static Metrics)之前解释过,对于 Metric Vector 来说,由于每一个 Label Values 取值都是独立的指标实例,因此为了线程安全实现上采用了 HashMap + RwLock。为了提升效率,可以将 with_label_values 访问获得的指标保存下来,以后直接访问。另外使用姿势正确的话,Label Values 取值是一个有限的、确定的、小的集合,甚至大多数情况下在编译期就知道取值内容(例如 HTTP Method)。综上,我们可以直接写代码将各种已知的 Label Values 提前保存下来,之后可以以静态的方式访问,这就是静态指标。以 TiKV 为例,有 Contributor 为 TiKV 提过这个 PR:#2765 server: precreate some labal metrics。这个 PR 改进了 TiKV 中统计各种 gRPC 接口消息次数的指标,由于 gRPC 接口是固定的、已知的,因此可以提前将它们缓存起来:struct Metrics { kv_get: Histogram, kv_scan: Histogram, kv_prewrite: Histogram, kv_commit: Histogram, // …}impl Metrics { fn new() -> Metrics { Metrics { kv_get: GRPC_MSG_HISTOGRAM_VEC.with_label_values(&[“kv_get”]), kv_scan: GRPC_MSG_HISTOGRAM_VEC.with_label_values(&[“kv_scan”]), kv_prewrite: GRPC_MSG_HISTOGRAM_VEC.with_label_values(&[“kv_prewrite”]), kv_commit: GRPC_MSG_HISTOGRAM_VEC.with_label_values(&[“kv_commit”]), // … } }}使用的时候也很简单,直接访问即可:@@ -102,10 +155,8 @@ fn make_callback<T: Debug + Send + ‘static>() -> (Box<FnBox(T) + Send>, oneshot:impl<T: RaftStoreRouter + ‘static> tikvpb_grpc::Tikv for Service<T> { fn kv_get(&self, ctx: RpcContext, mut req: GetRequest, sink: UnarySink<GetResponse>) {- let label = “kv_get”;- let timer = GRPC_MSG_HISTOGRAM_VEC- .with_label_values(&[label])- .start_coarse_timer();+ const LABEL: &str = “kv_get”;+ let timer = self.metrics.kv_get.start_coarse_timer(); let (cb, future) = make_callback(); let res = self.storage.async_get(这样一个简单的优化可以为 TiKV 提升 7% 的 Raw Get 效率,可以说是很超值了(主要原因是 Raw Get 本身开销极小,因此在指标上花费的时间就显得有一些显著了)。但这个优化方案其实还有一些问题:代码繁琐,有大量重复的、或满足某些 pattern 的代码;如果还有另一个 Label 维度,那么需要维护的字段数量就会急剧膨胀(因为每一种值的组合都需要分配一个字段)。为了解决以上两个问题,[rust-prometheus] 提供了 Static Metric 宏。例如对于刚才的 TiKV 改进 PR #2765 来说,使用 Static Metric 宏可以简化为:make_static_metric! { pub struct GrpcMsgHistogram: Histogram { “type” => { kv_get, kv_scan, kv_prewrite, kv_commit, // … }, }}let metrics = GrpcMsgHistogram::from(GRPC_MSG_HISTOGRAM_VEC);// Usage:metrics.kv_get.start_coarse_timer();可以看到,使用宏之后,需要维护的繁琐的代码量大大减少了。这个宏也能正常地支持多个 Label 同时存在的情况。限于篇幅,这里就不具体讲解这个宏是如何写的了,感兴趣的同学可以观看我司同学最近在 FOSDEM 2019 上的技术分享 视频(进度条 19:54 开始介绍 Static Metrics)和 Slide,里面详细地介绍了如何从零开始写出一个这样的宏(的简化版本)。 ...

March 14, 2019 · 4 min · jiezi

容器监控实践—Prometheus存储机制

概述Prometheus提供了本地存储,即tsdb时序数据库,本地存储给Prometheus带来了简单高效的使用体验,prometheus2.0以后压缩数据能力也得到了很大的提升。可以在单节点的情况下满足大部分用户的监控需求。但本地存储也限制了Prometheus的可扩展性,带来了数据持久化等一系列的问题。为了解决单节点存储的限制,prometheus没有自己实现集群存储,而是提供了远程读写的接口,让用户自己选择合适的时序数据库来实现prometheus的扩展性。Prometheus 1.x版本的TSDB(V2存储引擎)基于LevelDB,并且使用了和Facebook Gorilla一样的压缩算法,能够将16个字节的数据点压缩到平均1.37个字节。Prometheus 2.x版本引入了全新的V3存储引擎,提供了更高的写入和查询性能以下所有内容均基于prometheus2.7版本本地存储存储原理Prometheus按2小时一个block进行存储,每个block由一个目录组成,该目录里包含:一个或者多个chunk文件(保存timeseries数据)、一个metadata文件、一个index文件(通过metric name和labels查找timeseries数据在chunk文件的位置)。最新写入的数据保存在内存block中,达到2小时后写入磁盘。为了防止程序崩溃导致数据丢失,实现了WAL(write-ahead-log)机制,启动时会以写入日志(WAL)的方式来实现重播,从而恢复数据。删除数据时,删除条目会记录在独立的tombstone文件中,而不是立即从chunk文件删除。通过时间窗口的形式保存所有的样本数据,可以明显提高Prometheus的查询效率,当查询一段时间范围内的所有样本数据时,只需要简单的从落在该范围内的块中查询数据即可。这些2小时的block会在后台压缩成更大的block,数据压缩合并成更高level的block文件后删除低level的block文件。这个和leveldb、rocksdb等LSM树的思路一致。这些设计和Gorilla的设计高度相似,所以Prometheus几乎就是等于一个缓存TSDB。它本地存储的特点决定了它不能用于long-term数据存储,只能用于短期窗口的timeseries数据保存和查询,并且不具有高可用性(宕机会导致历史数据无法读取)。内存中的block数据未写入磁盘时,block目录下面主要保存wal文件:./data/01BKGV7JBM69T2G1BGBGM6KB12./data/01BKGV7JBM69T2G1BGBGM6KB12/meta.json./data/01BKGV7JBM69T2G1BGBGM6KB12/wal/000002./data/01BKGV7JBM69T2G1BGBGM6KB12/wal/000001持久化的block目录下wal文件被删除,timeseries数据保存在chunk文件里。index用于索引timeseries在wal文件里的位置。./data/01BKGV7JC0RY8A6MACW02A2PJD./data/01BKGV7JC0RY8A6MACW02A2PJD/meta.json./data/01BKGV7JC0RY8A6MACW02A2PJD/index./data/01BKGV7JC0RY8A6MACW02A2PJD/chunks./data/01BKGV7JC0RY8A6MACW02A2PJD/chunks/000001./data/01BKGV7JC0RY8A6MACW02A2PJD/tombstones存储配置对于本地存储,prometheus提供了一些配置项,主要包括:–storage.tsdb.path: 存储数据的目录,默认为data/,如果要挂外部存储,可以指定该目录–storage.tsdb.retention.time: 数据过期清理时间,默认保存15天–storage.tsdb.retention.size: 实验性质,声明数据块的最大值,不包括wal文件,如512MB–storage.tsdb.retention: 已被废弃,改为使用storage.tsdb.retention.timePrometheus将所有当前使用的块保留在内存中。此外,它将最新使用的块保留在内存中,最大内存可以通过storage.local.memory-chunks标志配置。监测当前使用的内存量:prometheus_local_storage_memory_chunksprocess_resident_memory_bytes监测当前使用的存储指标:prometheus_local_storage_memory_series: 时间序列持有的内存当前块数量prometheus_local_storage_memory_chunks: 在内存中持久块的当前数量prometheus_local_storage_chunks_to_persist: 当前仍然需要持久化到磁盘的的内存块数量prometheus_local_storage_persistence_urgency_score: 紧急程度分数prometheus 2.0的存储升级prometheus 2.0于2017-11-08发布,主要是存储引擎进行了优化。性能的整体提高:与 Prometheus 1.8 相比,CPU使用率降低了 20% - 40%与 Prometheus 1.8 相比,磁盘空间使用率降低了 33% - 50%没有太多查询,平均负载的磁盘 I/O<1%在Kubernetes集群这样的动态环境中,prometheus的数据平面通常看起来是这种样式垂直维度表示所有存储的序列水平维度表示样本传播的时间如:requests_total{path="/status", method=“GET”, instance=“10.0.0.1:80”}requests_total{path="/status", method=“POST”, instance=“10.0.0.3:80”}requests_total{path="/", method=“GET”, instance=“10.0.0.2:80”}Prometheus定期为所有系列收集新数据点,这意味着它必须在时间轴的右端执行垂直写入。但是,在查询时,我们可能希望访问平面上任意区域的矩形(各种label条件)因此为了能够在大量数据中有效地查找查询序列,我们需要一个索引。在Prometheus 1.x存储层可以很好地处理垂直写入模式,但是随着规模增大,索引或出现一些问题,因此在2.0版本中重新设计了存储引擎和索引,主要改造是:样本压缩现有存储层的样本压缩功能在Prometheus的早期版本中发挥了重要作用。单个原始数据点占用16个字节的存储空间。但当普罗米修斯每秒收集数十万个数据点时,可以快速填满硬盘。但,同一系列中的样本往往非常相似,我们可以利用这一类样品(同样label)进行有效的压缩。批量压缩一系列的许多样本的块,在内存中,将每个数据点压缩到平均1.37字节的存储。这种压缩方案运行良好,也保留在新版本2存储层的设计中。具体压缩算法可以参考:Facebook的“Gorilla”论文中时间分片我们将新的存储层划分为块(block),每个块在一段时间内保存所有序列。每个块充当独立数据库。这样每次查询,仅检查所请求的时间范围内的块子集,查询执行时间自然会减少。这种布局也使删除旧数据变得非常容易(这在1.x的存储设计中是一个很耗时的操作)。但在2.x中,一旦块的时间范围完全落后于配置的保留边界,它就可以完全丢弃。索引一般prometheus的查询是把metric+label做关键字的,而且是很宽泛,完全用户自定义的字符,因此没办法使用常规的sql数据库,prometheus的存储层使用了全文检索中的倒排索引概念,将每个时间序列视为一个小文档。而metric和label对应的是文档中的单词。例如,requests_total{path="/status", method=“GET”, instance=“10.0.0.1:80”}是包含以下单词的文档:name=“requests_total"path="/status"method=“GET"instance=“10.0.0.1:80"基准测试cpu、内存、查询效率都比1.x版本得到了大幅度的提升具体测试结果参考:https://dzone.com/articles/pr…故障恢复如果您怀疑数据库中的损坏引起的问题,则可以通过使用storage.local.dirtyflag配置,来启动服务器来强制执行崩溃恢复。如果没有帮助,或者如果您只想删除现有的数据库,可以通过删除存储目录的内容轻松地启动:1.停止服务:stop prometheus.2.删除数据目录:rm -r <storage path>/*3.启动服务:start prometheus远程存储Prometheus默认是自己带有存储的,保存的时间为15天。但本地存储也意味着Prometheus无法持久化数据,无法存储大量历史数据,同时也无法灵活扩展。为了保证Prometheus的简单性,Prometheus并没有从自身集群的维度来解决这些问题,而是定义了两种接口,remote_write/remote_read,将数据抛出去,你自己处理。Prometheus的remote_storage 其实是一个adapter,至于在adapter的另一端是什么类型的时序数据库它根本不关心,如果你愿意,你也可以编写自己的adpater。如:存储的方式为:Prometheus —-发送数据—- > remote_storage_adapter —- 存储数据 —-> influxdb。prometheus通过下面两种方式来实现与其他的远端存储系统对接:Prometheus 按照标准的格式将metrics写到远端存储Prometheus 按照标准格式从远端的url来读取metrics远程读在远程读的流程当中,当用户发起查询请求后,Promthues将向remote_read中配置的URL发起查询请求(matchers,ranges),Adaptor根据请求条件从第三方存储服务中获取响应的数据。同时将数据转换为Promthues的原始样本数据返回给Prometheus Server。当获取到样本数据后,Promthues在本地使用PromQL对样本数据进行二次处理。远程写用户可以在Promtheus配置文件中指定Remote Write(远程写)的URL地址,一旦设置了该配置项,Prometheus将样本数据通过HTTP的形式发送给适配器(Adaptor)。而用户则可以在适配器中对接外部任意的服务。外部服务可以是真正的存储系统,公有云的存储服务,也可以是消息队列等任意形式。配置配置非常简单,只需要将对应的地址配置下就行remote_write: - url: “http://localhost:9201/write"remote_read: - url: “http://localhost:9201/read"社区支持现在社区已经实现了以下的远程存储方案AppOptics: writeChronix: writeCortex: read and writeCrateDB: read and writeElasticsearch: writeGnocchi: writeGraphite: writeInfluxDB: read and writeOpenTSDB: writePostgreSQL/TimescaleDB: read and writeSignalFx: write可以使用读写完整的InfluxDB,我们使用了多prometheus server同时远程读+写,验证了速度还是可以的。并且InfluxDB生态完整,自带了很多管理工具。容量规划在一般情况下,Prometheus中存储的每一个样本大概占用1-2字节大小。如果需要对Prometheus Server的本地磁盘空间做容量规划时,可以通过以下公式计算:磁盘大小 = 保留时间 * 每秒获取样本数 * 样本大小保留时间(retention_time_seconds)和样本大小(bytes_per_sample)不变的情况下,如果想减少本地磁盘的容量需求,只能通过减少每秒获取样本数(ingested_samples_per_second)的方式。因此有两种手段,一是减少时间序列的数量,二是增加采集样本的时间间隔。考虑到Prometheus会对时间序列进行压缩,因此减少时间序列的数量效果更明显。其他远程读写解决了Promtheus的数据持久化问题。使其可以进行弹性扩展。另外还支持联邦集群模式,用于解决横向扩展、网络分区的问题(如地域A+B+C的监控数据,统一汇总到D),联邦集群的配置将在后面的Promthues高可用文章中详细说明。附:kubecon2018上讲Prometheus 2.0的帅哥还有一本专门讲Prometheus的书:Prometheus: Up & Running(600多页…)国内没找到卖的,找到了一本英文pdf的,还在翻译理解中,有新的内容会继续同步在这个系列博客。。。又找到一本:https://www.prometheusbook.com/参考资料:https://prometheus.io/docs/pr…https://coreos.com/blog/prome...https://dzone.com/articles/pr...https://www.linuxidc.com/Linu...http://ylzheng.com/2018/03/06...https://www.cnblogs.com/vovli...https://files-cdn.cnblogs.com...https://www.bookstack.cn/read…本文为容器监控实践系列文章,完整内容见:container-monitor-book ...

March 12, 2019 · 1 min · jiezi

容器监控实践—Prometheus数据可视化

一. 概述Prometheus自带了一个web服务,包括一个默认的dashboard,可以使用表达式查询并进行图表可视化,默认服务的地址为:http://prometheus_ip:9090如下图:自带的web展示一般只用于表达式快速输入或者临时调试,因为默认服务没有鉴权,且图表表达能力有限,因此不会作为线上可视化方案,正式的监控数据可视化一般使用Grafana来配套prometheus可视化方案:自带web服务:在验证指标时是非常好用的,grafana虽然是作为可视化展示,但一般是先确认表达式,才去配置到grafana面板grafana可视化Console templates:官方给的一种选择,使用go templete来实现,使用难度较大,不太推荐promviz:开源项目,不算是监控图,可以做集群实时流量的可视化。二. Grafana可视化Grafana 是一个开源的图表可视化系统,简单说图表配置比较方便、生成的图表比较漂亮。并且模板众多,默认支持了prometheus作为数据源,也是prometheus官方推荐方案这里只对grafana做简单介绍,更多详细的内容参考展示-Grafana2.1 部署grafana是很成熟的(商业)项目,可以在官网下载客户端,或者在github主页自己build为镜像。主要的配置文件为conf文件夹下的defaults.ini文件,常用的配置可以配置在文件中,如果是docker运行或者在k8s中运行,可以使用env的方式,传入全局变量,将覆盖原有的defaults.ini配置。使用docker运行:docker run -d –name=grafana -p 3000:3000 grafana/grafana访问:http://127.0.0.1:3000账号:admin密码:admin2.2 配置第一步:配置数据源进入grafana后,第一步需要配置数据源,grafana默认支持prometheus作为数据源,因此Type直接选择PrometheusHttp的url地址为prometheus的服务地址,如果是同一个pod内,可以127.0.0.1:9090,不同pod的话,可以使用svc地址:http://prometheus.kube-system…:9090数据源配置后,点击save&test,可以验证数据源是否可用:第二步:配置面板:点击左侧的加号,可以添加面板(dashboard),并在该面板中添加各种类型的图表。对于面板,可以设置变量,用于下拉框筛选等场景,如设置机器变量:节点信息然后使用该变量,配置查询语句:得到各节点的cpu使用率面板demo配置完成后,可以出现类似图表,可以点击分享按钮,将本面板分享为json文件也可以筛选时间周期,设置自动刷新上图的json文件如下,仅供参考(需要安装node-exporter)json文件:https://raw.githubusercontent…本文为容器监控实践系列文章,完整内容见:container-monitor-book

March 12, 2019 · 1 min · jiezi

TiKV 源码解析系列文章(三)Prometheus(上)

作者:Breezewish本文为 TiKV 源码解析系列的第三篇,继续为大家介绍 TiKV 依赖的周边库 [rust-prometheus],本篇主要介绍基础知识以及最基本的几个指标的内部工作机制,下篇会介绍一些高级功能的实现原理。[rust-prometheus] 是监控系统 [Prometheus] 的 Rust 客户端库,由 TiKV 团队实现。TiKV 使用 [rust-prometheus] 收集各种指标(metric)到 Prometheus 中,从而后续能再利用 [Grafana] 等可视化工具将其展示出来作为仪表盘监控面板。这些监控指标对于了解 TiKV 当前或历史的状态具有非常关键的作用。TiKV 提供了丰富的监控指标数据,并且代码中也到处穿插了监控指标的收集片段,因此了解 [rust-prometheus] 很有必要。感兴趣的小伙伴还可以观看我司同学在 [FOSDEM 2019] 会议上关于 rust-prometheus 的技术分享。基础知识指标类别[Prometheus] 支持四种指标:Counter、Gauge、Histogram、Summary。[rust-prometheus] 库目前还只实现了前三种。TiKV 大部分指标都是 Counter 和 Histogram,少部分是 Gauge。Counter[Counter] 是最简单、常用的指标,适用于各种计数、累计的指标,要求单调递增。Counter 指标提供基本的 inc() 或 inc_by(x) 接口,代表增加计数值。在可视化的时候,此类指标一般会展示为各个时间内增加了多少,而不是各个时间计数器值是多少。例如 TiKV 收到的请求数量就是一种 Counter 指标,在监控上展示为 TiKV 每时每刻收到的请求数量图表(QPS)。Gauge[Gauge] 适用于上下波动的指标。Gauge 指标提供 inc()、dec()、add(x)、sub(x) 和 set(x) 接口,都是用于更新指标值。这类指标可视化的时候,一般就是直接按照时间展示它的值,从而展示出这个指标按时间是如何变化的。例如 TiKV 占用的 CPU 率是一种 Gauge 指标,在监控上所展示的直接就是 CPU 率的上下波动图表。Histogram[Histogram] 即直方图,是一种相对复杂但同时也很强大的指标。Histogram 除了基本的计数以外,还能计算分位数。Histogram 指标提供 observe(x) 接口,代表观测到了某个值。举例来说,TiKV 收到请求后处理的耗时就是一种 Histogram 指标,通过 Histogram 类型指标,监控上可以观察 99%、99.9%、平均请求耗时等。这里显然不能用一个 Counter 存储耗时指标,否则展示出来的只是每时每刻中 TiKV 一共花了多久处理,而非单个请求处理的耗时情况。当然,机智的你可能想到了可以另外开一个 Counter 存储请求数量指标,这样累计请求处理时间除以请求数量就是各个时刻平均请求耗时了。实际上,这也正是 Prometheus 中 Histogram 的内部工作原理。Histogram 指标实际上最终会提供一系列时序数据:观测值落在各个桶(bucket)上的累计数量,如落在 (-∞, 0.1]、(-∞, 0.2]、(-∞, 0.4]、(-∞, 0.8]、(-∞, 1.6]、(-∞, +∞) 各个区间上的数量。观测值的累积和。观测值的个数。bucket 是 Prometheus 对于 Histogram 观测值的一种简化处理方式。Prometheus 并不会具体记录下每个观测值,而是只记录落在配置的各个 bucket 区间上的观测值的数量,这样以牺牲一部分精度的代价大大提高了效率。Summary[Summary] 与 [Histogram] 类似,针对观测值进行采样,但分位数是在客户端进行计算。该类型的指标目前在 [rust-prometheus] 中没有实现,因此这里不作进一步详细介绍。大家可以阅读 Prometheus 官方文档中的介绍了解详细情况。感兴趣的同学也可以参考其他语言 Client Library 的实现为 [rust-prometheus] 贡献代码。标签Prometheus 的每个指标支持定义和指定若干组标签([Label]),指标的每个标签值独立计数,表现了指标的不同维度。例如,对于一个统计 HTTP 服务请求耗时的 Histogram 指标来说,可以定义并指定诸如 HTTP Method(GET / POST / PUT / …)、服务 URL、客户端 IP 等标签。这样可以轻易满足以下类型的查询:查询 Method 分别为 POST、PUT、GET 的 99.9% 耗时(利用单一 Label)查询 POST /api 的平均耗时(利用多个 Label 组合)普通的查询诸如所有请求 99.9% 耗时也能正常工作。需要注意的是,不同标签值都是一个独立计数的时间序列,因此应当避免标签值或标签数量过多,否则实际上客户端会向 Prometheus 服务端传递大量指标,影响效率。与 Prometheus [Golang client] 类似,在 [rust-prometheus] 中,具有标签的指标被称为 Metric Vector。例如 Histogram 指标对应的数据类型是 [Histogram],而具有标签的 Histogram 指标对应的数据类型是 [HistogramVec]。对于一个 [HistogramVec],提供它的各个标签取值后,可获得一个 [Histogram] 实例。不同标签取值会获得不同的 [Histogram] 实例,各个 [Histogram] 实例独立计数。基本用法本节主要介绍如何在项目中使用 [rust-prometheus] 进行各种指标收集。使用基本分为三步:定义想要收集的指标。在代码特定位置调用指标提供的接口收集记录指标值。实现 HTTP Pull Service 使得 Prometheus 可以定期访问收集到的指标,或使用 rust-prometheus 提供的 Push 功能定期将收集到的指标上传到 [Pushgateway]。注意,以下样例代码都是基于本文发布时最新的 rust-prometheus 0.5 版本 API。我们目前正在设计并实现 1.0 版本,使用上会进一步简化,但以下样例代码可能在 1.0 版本发布后过时、不再工作,届时请读者参考最新的文档。定义指标为了简化使用,一般将指标声明为一个全局可访问的变量,从而能在代码各处自由地操纵它。rust-prometheus 提供的各个指标(包括 Metric Vector)都满足 Send + Sync,可以被安全地全局共享。以下样例代码借助 [lazy_static] 库定义了一个全局的 Histogram 指标,该指标代表 HTTP 请求耗时,并且具有一个标签名为 method:#[macro_use]extern crate prometheus;lazy_static! { static ref REQUEST_DURATION: HistogramVec = register_histogram_vec!( “http_requests_duration”, “Histogram of HTTP request duration in seconds”, &[“method”], exponential_buckets(0.005, 2.0, 20).unwrap() ).unwrap();}记录指标值有了一个全局可访问的指标变量后,就可以在代码中通过它提供的接口记录指标值了。在“基础知识”中介绍过,[Histogram] 最主要的接口是 observe(x),可以记录一个观测值。若想了解 [Histogram] 其他接口或其他类型指标提供的接口,可以参阅 [rust-prometheus 文档]。以下样例在上段代码基础上展示了如何记录指标值。代码模拟了一些随机值用作指标,装作是用户产生的。在实际程序中,这些当然得改成真实数据 :)fn thread_simulate_requests() { let mut rng = rand::thread_rng(); loop { // Simulate duration 0s ~ 2s let duration = rng.gen_range(0f64, 2f64); // Simulate HTTP method let method = [“GET”, “POST”, “PUT”, “DELETE”].choose(&mut rng).unwrap(); // Record metrics REQUEST_DURATION.with_label_values(&[method]).observe(duration); // One request per second std:🧵:sleep(std::time::Duration::from_secs(1)); }}Push / Pull到目前为止,代码还仅仅是将指标记录了下来。最后还需要让 Prometheus 服务端能获取到记录下来的指标数据。这里一般有两种方式,分别是 Push 和 Pull。Pull 是 Prometheus 标准的获取指标方式,Prometheus Server 通过定期访问应用程序提供的 HTTP 接口获取指标数据。Push 是基于 Prometheus [Pushgateway] 服务提供的另一种获取指标方式,指标数据由应用程序主动定期推送给 [Pushgateway],然后 Prometheus 再定期从 Pushgateway 获取。这种方式主要适用于应用程序不方便开端口或应用程序生命周期比较短的场景。以下样例代码基于 [hyper] HTTP 库实现了一个可以供 Prometheus Server pull 指标数据的接口,核心是使用 [rust-prometheus] 提供的 [TextEncoder] 将所有指标数据序列化供 Prometheus 解析:fn metric_service(req: Request<Body>) -> Response<Body> { let encoder = TextEncoder::new(); let mut buffer = vec![]; let mf = prometheus::gather(); encoder.encode(&mf, &mut buffer).unwrap(); Response::builder() .header(hyper::header::CONTENT_TYPE, encoder.format_type()) .body(Body::from(buffer)) .unwrap()}对于如何使用 Push 感兴趣的同学可以自行参考 rust-prometheus 代码内提供的 Push 示例,这里限于篇幅就不详细介绍了。上述三段样例的完整代码可参见这里。内部实现以下内部实现都基于本文发布时最新的 rust-prometheus 0.5 版本代码,该版本主干 API 的设计和实现 port 自 Prometheus [Golang client],但为 Rust 的使用习惯进行了一些修改,因此接口上与 Golang client 比较接近。目前我们正在开发 1.0 版本,API 设计上不再主要参考 Golang client,而是力求提供对 Rust 使用者最友好、简洁的 API。实现上为了效率考虑也会和这里讲解的略微有一些出入,且会去除一些目前已被抛弃的特性支持,简化实现,因此请读者注意甄别。Counter / GaugeCounter 与 Gauge 是非常简单的指标,只要支持线程安全的数值更新即可。读者可以简单地认为 Counter 和 Gauge 的核心实现都是 Arc<Atomic>。但由于 Prometheus 官方规定指标数值需要支持浮点数,因此我们基于 [std::sync::atomic::AtomicU64] 和 CAS 操作实现了 [AtomicF64],其具体实现位于 src/atomic64/nightly.rs。核心片段如下:impl Atomic for AtomicF64 { type T = f64; // Some functions are omitted. fn inc_by(&self, delta: Self::T) { loop { let current = self.inner.load(Ordering::Acquire); let new = u64_to_f64(current) + delta; let swapped = self .inner .compare_and_swap(current, f64_to_u64(new), Ordering::Release); if swapped == current { return; } } }}另外由于 0.5 版本发布时 [AtomicU64] 仍然是一个 nightly 特性,因此为了支持 Stable Rust,我们还基于自旋锁提供了 [AtomicF64] 的 fallback,位于 src/atomic64/fallback.rs。注:[AtomicU64] 所需的 integer_atomics 特性最近已在 rustc 1.34.0 stabilize。我们将在 rustc 1.34.0 发布后为 Stable Rust 也使用上原生的原子操作从而提高效率。Histogram根据 Prometheus 的要求,Histogram 需要进行的操作是在获得一个观测值以后,为观测值处在的桶增加计数值。另外还有总观测值、观测值数量需要累加。注意,Prometheus 中的 Histogram 是累积直方图,其每个桶的含义是 (-∞, x],因此对于每个观测值都可能要更新多个连续的桶。例如,假设用户定义了 5 个桶边界,分别是 0.1、0.2、0.4、0.8、1.6,则每个桶对应的数值范围是 (-∞, 0.1]、(-∞, 0.2]、(-∞, 0.4]、(-∞, 0.8]、(-∞, 1.6]、(-∞, +∞),对于观测值 0.4 来说需要更新(-∞, 0.4]、(-∞, 0.8]、(-∞, 1.6]、(-∞, +∞) 四个桶。一般来说 observe(x) 会被频繁地调用,而将收集到的数据反馈给 Prometheus 则是个相对很低频率的操作,因此用数组实现“桶”的时候,我们并不将各个桶与数组元素直接对应,而将数组元素定义为非累积的桶,如 (-∞, 0.1)、[0.1, 0.2)、[0.2, 0.4)、[0.4, 0.8)、[0.8, 1.6)、[1.6, +∞),这样就大大减少了需要频繁更新的数据量;最后在上报数据给 Prometheus 的时候将数组元素累积,得到累积直方图,这样就得到了 Prometheus 所需要的桶的数据。当然,由此可见,如果给定的观测值超出了桶的范围,则最终记录下的最大值只有桶的上界了,然而这并不是实际的最大值,因此使用的时候需要多加注意。[Histogram] 的核心实现见 src/histogram.rs:pub struct HistogramCore { // Some fields are omitted. sum: AtomicF64, count: AtomicU64, upper_bounds: Vec<f64>, counts: Vec<AtomicU64>,}impl HistogramCore { // Some functions are omitted. pub fn observe(&self, v: f64) { // Try find the bucket. let mut iter = self .upper_bounds .iter() .enumerate() .filter(|&(, f)| v <= *f); if let Some((i, _)) = iter.next() { self.counts[i].inc_by(1); } self.count.inc_by(1); self.sum.inc_by(v); }}#[derive(Clone)]pub struct Histogram { core: Arc<HistogramCore>,}[Histogram] 还提供了一个辅助结构 [HistogramTimer],它会记录从它创建直到被 Drop 的时候的耗时,将这个耗时作为 [Histogram::observe()] 接口的观测值记录下来,这样很多时候在想要记录 Duration / Elapsed Time 的场景中,就可以使用这个简便的结构来记录时间:#[must_use]pub struct HistogramTimer { histogram: Histogram, start: Instant,}impl HistogramTimer { // Some functions are omitted. pub fn observe_duration(self) { drop(self); } fn observe(&mut self) { let v = duration_to_seconds(self.start.elapsed()); self.histogram.observe(v) }}impl Drop for HistogramTimer { fn drop(&mut self) { self.observe(); }}[HistogramTimer] 被标记为了 [must_use],原因很简单,作为一个记录流逝时间的结构,它应该被存在某个变量里,从而记录这个变量所处作用域的耗时(或稍后直接调用相关函数提前记录耗时),而不应该作为一个未使用的临时变量被立即 Drop。标记为 must_use 可以在编译期杜绝这种明显的使用错误。 ...

March 11, 2019 · 3 min · jiezi

CNCF参与Google Summer of Code 2019!感兴趣的学生现在是加入的最佳时机

Google Summer of Code(GSoC)是面向开源开发领域新贡献者的最知名和最受欢迎的计划之一,我们很高兴地宣布CNCF(Cloud Native Computing Foundation,云原生计算基金会)参与GSoC 2019!CNCF是过去几年(包括2017年和2018年)GSoC中最活跃的参与者之一,我们将在2019年继续这项工作,有近50个项目构想涉及13个CNCF项目。如果你是学生,计划参加GSoC 2019,现在是审查项目构想,并与导师开始讨论的最佳时机。这里分享一篇去年浙江大学研究生,在谐云实习的Jian Liu,有关“GSoC 18:Kata Containers对containerd的支持”的经验。Kubernetes项目构想Integrate kube-batch with pytorch-operator/mxnet-operatorImplement volume snapshotting support into the external Manila provisionerEnable full e2e tests for external Azure cloud providerCSI driver for AzureDiskCSI driver for AzureFileCSI driver for BlobfuseStreamline and simplify SASS for the Kubernetes websiteFully automate API and reference doc generationAdd support for Custom Resource Definitions to the DashboardAdd plugin mechanism to the DashboardPrometheus项目构想Benchmarks for TSDBContinue the work on PrombenchPersist Retroactive Rule ReevaluationsOptimize queries using regex matchers for set lookupsPackage for bulk importsOpen Policy Agent (OPA)项目构想IntelliJ plugin to experiment with and visualize policy evaluationInteractive website detailing OPA integrationsIntegration with IPTablesCoreDNS项目构想Support source-IP based query block/allowSupport Google Cloud DNS backendSupport Azure DNS backendTiKV项目构想Migrate to tower-grpcIntroduce other storage enginesBuild TiKV clients in different languagesAuto-tune RocksDBRook项目构想Upgrade Rook to a more advanced operator/controller frameworkStorage provider features and enhancementsEnable multiple network interfaces for Rook storage providersEnhance and extend the Rook framework for storage solutionsExpand coverage and scope of Rook’s continuous integration (CI) systemDynamic provisioning for portable workloadsLinkerd and Envoy项目构想Benchmarks for Linkerd and EnvoyVirtual Kubelet项目构想Conformance testing for Virtual KubeletLinkerd项目构想Cross-cloud integration testingAuto-UpdateConformance ValidationAlertmanager IntegrationKafka Introspectionrkt项目构想Add support for the OCI runtime spec by implementing a runc stage2Add native OCI image supportcontainerd项目构想Snapshotter implementation for block devicesp2p or remote blob store implementationFalco项目构想Improved Falco OutputsAdditional Event SourcesLayer 7 Inspection and DetectionFalco integration with AI/ML platformsPrometheus Metrics ExporterPerformance Analysis and OptimizationFalco rules profiles for applications and security benchmarksCortex项目构想Improve Ingester HandoverCentralized Rate LimitingUse etcd in Cortex请在CNCF的GitHub页面上查看2019年项目构想的完整列表,包括描述、推荐技巧和导师资料等。KubeCon + CloudNativeCon和Open Source Summit大会日期:会议日程通告日期:2019 年 4 月 10 日会议活动举办日期:2019 年 6 月 24 至 26 日KubeCon + CloudNativeCon和Open Source Summit赞助方案KubeCon + CloudNativeCon和Open Source Summit多元化奖学金现正接受申请KubeCon + CloudNativeCon和Open Source Summit即将首次合体落地中国KubeCon + CloudNativeCon和Open Source Summit购票窗口,立即购票! ...

March 6, 2019 · 2 min · jiezi

容器监控实践—Prometheus部署方案

一.单独部署二进制安装各版本下载地址:https://prometheus.io/download/Docker运行运行命令:docker run –name prometheus -d -p 127.0.0.1:9090:9090 prom/prometheus暴露服务: http://localhost:9090/二.在K8S中部署如果在Kubernetes中部署Prometheus,可以使用prometheus in kubernetes,含exporter、grafana等组件。安装方式:kubectl apply \ –filename https://raw.githubusercontent.com/giantswarm/kubernetes-prometheus/master/manifests-all.yaml卸载方式:kubectl delete namespace monitoring该方式为大多数用户和云厂商使用的方式,可以基于Prometheus的服务发现:在annotation中设置prometheus.io/scrape为true,就可以把K8S的所有服务都加入到监控中,但在使用的过程中会有一些问题:1.如果增加了新的exporter,如nginx-exporter,需要修改prometheus配置并重启2.服务本身和监控配置没有分离3.监控集群多实例的状态不好管理4.报警配置也包含在prometheus的配置中,监控与报警没有分离,添加规则麻烦以上问题一般的处理方式为:在prometheus上加一个控制台,来动态配置target、报警规则,并向后端server发起修改、重启操作。同时有权限控制、日志审计、整体配置过期时间等功能。但如果使用了Prometheus Operator,就可以将以上大多数操作抽象为k8s中的资源提交、修改,减少上层封装的工作量。三.Prometheus Operator部署Prometheus-Operator是一套为了方便整合prometheus和kubernetes的开源方案,使用Prometheus-Operator可以非常简单的在kubernetes集群中部署Prometheus服务,用户能够使用简单的声明性配置来配置和管理Prometheus实例,这些配置将响应、创建、配置和管理Prometheus监控实例。官方地址:https://github.com/coreos/pro…目前状态:beta状态,还不够完整,但向后兼容。将成为趋势前置条件:要求k8s的版本>=1.8.0(应该是因为metric api和CRD支持的限制)Operator的核心思想是将Prometheus的部署与它监控的对象的配置分离,做到部署与监控对象的配置分离之后,就可以轻松实现动态配置。使用Operator部署了Prometheus之后就可以不用再管Prometheus Server了,以后如果要添加监控对象或者添加告警规则,只需要编写对应的ServiceMonitor和Prometheus资源就可以,不用再重启Prometheus服务,Operator会动态的观察配置的改动,并将其生成为对应的prometheus配置文件其中Operator可以部署、管理Prometheus Service四种CRD作用如下:Prometheus: 由 Operator 依据一个自定义资源kind: Prometheus类型中,所描述的内容而部署的 Prometheus Server 集群,可以将这个自定义资源看作是一种特别用来管理Prometheus Server的StatefulSets资源。ServiceMonitor: 一个Kubernetes自定义资源(和kind: Prometheus一样是CRD),该资源描述了Prometheus Server的Target列表,Operator 会监听这个资源的变化来动态的更新Prometheus Server的Scrape targets并让prometheus server去reload配置(prometheus有对应reload的http接口/-/reload)。而该资源主要通过Selector来依据 Labels 选取对应的Service的endpoints,并让 Prometheus Server 通过 Service 进行拉取(拉)指标资料(也就是metrics信息),metrics信息要在http的url输出符合metrics格式的信息,ServiceMonitor也可以定义目标的metrics的url。Alertmanager:Prometheus Operator 不只是提供 Prometheus Server 管理与部署,也包含了 AlertManager,并且一样通过一个 kind: Alertmanager 自定义资源来描述信息,再由 Operator 依据描述内容部署 Alertmanager 集群。PrometheusRule:对于Prometheus而言,在原生的管理方式上,我们需要手动创建Prometheus的告警文件,并且通过在Prometheus配置中声明式的加载。而在Prometheus Operator模式中,告警规则也编程一个通过Kubernetes API 声明式创建的一个资源.告警规则创建成功后,通过在Prometheus中使用想servicemonitor那样用ruleSelector通过label匹配选择需要关联的PrometheusRule即可。安装方式:创建命名空间:monitoring执行yaml文件:https://github.com/coreos/pro…prometheus的target列表: grafana的自带监控图列表:常见问题:因为要operator中要支持聚合api,在某些版本的集群上可能需要一些配置,如下:安装cfssl证书生成工具:http://www.cnblogs.com/xuling…生成证书cfssl gencert -ca=/etc/kubernetes/pki/ca.pem -ca-key=/etc/kubernetes/pki/ca-key.pem -config=/etc/kubernetes/pki/ca-config.json -profile=jpaas metrics-server-csr.json | cfssljson -bare metrics-server{ “CN”: “aggregator”, “host”: [], “key”: { “algo”: “rsa”, “size”: 2048 }, “names”: [ { “C”: “CN”, “ST”: “BeiJing”, “L”: “BeiJing”, “O”: “k8s”, “OU”: “cloudnative” } ]}配置master组件参数,以支持metric-servervim /etc/systemd/system/kube-apiserver.service–requestheader-client-ca-file=/etc/kubernetes/pki/ca.pem --requestheader-allowed-names=“aggregator” --requestheader-extra-headers-prefix=“X-Remote-Extra-” --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --proxy-client-cert-file=/etc/kubernetes/pki/metrics-server.pem --proxy-client-key-file=/etc/kubernetes/pki/metrics-server-key.pem --runtime-config=api/all=true --enable-aggregator-routing=true \systemctl daemon-reloadsystemctl restart kube-apiserver.servicesystemctl status kube-apiserver.servicevim /etc/systemd/system/kube-controller.service–horizontal-pod-autoscaler-use-rest-clients=truesystemctl daemon-reloadsystemctl restart kube-controller.servicesystemctl status kube-controller.service启动成功后,prometheus的target中,kubelet没有值,401报错vim /etc/systemd/system/kubelet.service–authentication-token-webhook=true–authorization-mode=Webhooksystemctl daemon-reloadsystemctl restart kubelet.service参考文档:https://github.com/coreos/pro…https://www.yinjk.cn/2018/09/...http://www.servicemesher.com/…本文为容器监控实践系列文章,完整内容见:container-monitor-book ...

March 4, 2019 · 1 min · jiezi

Laravel接入Prometheus

在原有的基础上增加Counter计数器:namespace App\Http\Middleware;use Closure;use Illuminate\Http\Request;use traumferienwohnungen\PrometheusExporter\Middleware\AbstractResponseTimeMiddleware;class PrometheusMonitor extends AbstractResponseTimeMiddleware{ protected function getRouteNames() { $routeNames = []; foreach (\Route::getRoutes() as $route){ $routeNames[] = ‘/’.ltrim($route->uri(), ‘/’); } return $routeNames; } /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed / public function handle(Request $request, Closure $next) { if (defined(‘LARAVEL_START’)){ $start = LARAVEL_START; } elseif (defined(‘LUMEN_START’)){ $start = LUMEN_START; } else { $start = microtime(true); } $this->request = $request; /* @var \Illuminate\Http\Response $response */ $response = $next($request); $route_name = $this->getRouteName(); $method = $request->getMethod(); $status = $response->getStatusCode(); $duration = microtime(true) - $start; $duration_milliseconds = $duration * 1000.0; $this->countRequest($route_name, $method, $status, $duration_milliseconds); $this->initRequestMetrics($method, $status); return $response; } public function getRouteName(){ return request()->getRequestUri(); } public function initRequestMetrics($method, $status) { $namespace = config(‘prometheus_exporter.namespace_http_server’); $labelNames = $this->getRequestCounterLabelNames(); $name = ‘request_wuc’; $help = ‘http_requests count’; $counter = $this->registry->getOrRegisterCounter( $namespace, $name, $help, $labelNames ); $counter->incBy(1, [$this->getRouteName(), $method, $status]); }} ...

March 1, 2019 · 1 min · jiezi

使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集

本博客是深入研究Envoy Proxy和Istio.io 以及它如何实现更优雅的方式来连接和管理微服务系列文章的一部分。这是接下来几个部分的想法(将在发布时更新链接):断路器(第一部分)重试/超时(第二部分)分布式跟踪(第三部分)Prometheus的指标收集(第四部分)服务发现(第五部分)第四部分 - 使用Prometheus搜集envoy 指标envoy 配置和提供metrics方式在envoy1.9版本中,已经直接暴露了prometheus 格式的metrics,也就是prometheus可以直接去采集,无需再通过配置Statsd来收集metrics了,使用statsd的流程大致上是:首先Envoy推送指标到statsd,然后我们用prometheus(一个时序数据库)从statsd拉取指标。设置envoy 的配置文件中,有如下的设置:admin: access_log_path: “/dev/null” address: socket_address: address: 0.0.0.0 port_value: 9000 envoy 启动成功以后,访问localhost:9000/stats/prometheus,可以返回类似下面的参数:# TYPE envoy_listener_admin_http_downstream_rq_completed counterenvoy_listener_admin_http_downstream_rq_completed{envoy_http_conn_manager_prefix=“admin”} 3154# TYPE envoy_listener_admin_http_downstream_rq_xx counterenvoy_listener_admin_http_downstream_rq_xx{envoy_response_code_class=“1”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_listener_admin_downstream_cx_total counterenvoy_listener_admin_downstream_cx_total{} 146346envoy_listener_admin_http_downstream_rq_xx{envoy_response_code_class=“5”,envoy_http_conn_manager_prefix=“admin”} 0envoy_listener_admin_http_downstream_rq_xx{envoy_response_code_class=“3”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_listener_admin_downstream_pre_cx_timeout counterenvoy_listener_admin_downstream_pre_cx_timeout{} 0# TYPE envoy_listener_admin_no_filter_chain_match counterenvoy_listener_admin_no_filter_chain_match{} 0# TYPE envoy_listener_admin_downstream_cx_destroy counterenvoy_listener_admin_downstream_cx_destroy{} 146344envoy_listener_admin_http_downstream_rq_xx{envoy_response_code_class=“2”,envoy_http_conn_manager_prefix=“admin”} 3154envoy_listener_admin_http_downstream_rq_xx{envoy_response_code_class=“4”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_upstream_flow_control_paused_reading_total counterenvoy_cluster_upstream_flow_control_paused_reading_total{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_membership_change counterenvoy_cluster_membership_change{envoy_cluster_name=“hawkeye”} 1# TYPE envoy_cluster_ext_authz_denied counterenvoy_cluster_ext_authz_denied{envoy_cluster_name=“hawkeye”} 15# TYPE envoy_cluster_upstream_rq_completed counterenvoy_cluster_upstream_rq_completed{envoy_cluster_name=“hawkeye”} 255# TYPE envoy_cluster_upstream_rq_pending_failure_eject counterenvoy_cluster_upstream_rq_pending_failure_eject{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_connect_attempts_exceeded counterenvoy_cluster_upstream_cx_connect_attempts_exceeded{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_timeout counterenvoy_cluster_upstream_rq_timeout{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq counterenvoy_cluster_upstream_rq{envoy_response_code=“204”,envoy_cluster_name=“hawkeye”} 2# TYPE envoy_cluster_upstream_cx_connect_timeout counterenvoy_cluster_upstream_cx_connect_timeout{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_none_healthy counterenvoy_cluster_upstream_cx_none_healthy{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_pending_total counterenvoy_cluster_upstream_rq_pending_total{envoy_cluster_name=“hawkeye”} 6# TYPE envoy_cluster_internal_upstream_rq_completed counterenvoy_cluster_internal_upstream_rq_completed{envoy_cluster_name=“hawkeye”} 15envoy_cluster_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“hawkeye”} 209envoy_cluster_upstream_rq{envoy_response_code=“503”,envoy_cluster_name=“hawkeye”} 29# TYPE envoy_cluster_lb_local_cluster_not_ok counterenvoy_cluster_lb_local_cluster_not_ok{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_zone_routing_sampled counterenvoy_cluster_lb_zone_routing_sampled{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_connect_fail counterenvoy_cluster_upstream_cx_connect_fail{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_retry_success counterenvoy_cluster_upstream_rq_retry_success{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_bind_errors counterenvoy_cluster_bind_errors{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_total counterenvoy_cluster_upstream_cx_total{envoy_cluster_name=“hawkeye”} 6# TYPE envoy_cluster_lb_zone_number_differs counterenvoy_cluster_lb_zone_number_differs{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_original_dst_host_invalid counterenvoy_cluster_original_dst_host_invalid{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_zone_no_capacity_left counterenvoy_cluster_lb_zone_no_capacity_left{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_max_requests counterenvoy_cluster_upstream_cx_max_requests{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_per_try_timeout counterenvoy_cluster_upstream_rq_per_try_timeout{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_retry_overflow counterenvoy_cluster_upstream_rq_retry_overflow{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_external_upstream_rq counterenvoy_cluster_external_upstream_rq{envoy_response_code=“204”,envoy_cluster_name=“hawkeye”} 2envoy_cluster_external_upstream_rq{envoy_response_code=“503”,envoy_cluster_name=“hawkeye”} 29# TYPE envoy_cluster_upstream_cx_rx_bytes_total counterenvoy_cluster_upstream_cx_rx_bytes_total{envoy_cluster_name=“hawkeye”} 122326# TYPE envoy_cluster_upstream_cx_http1_total counterenvoy_cluster_upstream_cx_http1_total{envoy_cluster_name=“hawkeye”} 6# TYPE envoy_cluster_upstream_rq_pending_overflow counterenvoy_cluster_upstream_rq_pending_overflow{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_zone_routing_cross_zone counterenvoy_cluster_lb_zone_routing_cross_zone{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_subsets_created counterenvoy_cluster_lb_subsets_created{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_flow_control_backed_up_total counterenvoy_cluster_upstream_flow_control_backed_up_total{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_flow_control_drained_total counterenvoy_cluster_upstream_flow_control_drained_total{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_external_upstream_rq_xx counterenvoy_cluster_external_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“hawkeye”} 211# TYPE envoy_cluster_upstream_rq_cancelled counterenvoy_cluster_upstream_rq_cancelled{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_subsets_removed counterenvoy_cluster_lb_subsets_removed{envoy_cluster_name=“hawkeye”} 0envoy_cluster_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“hawkeye”} 15# TYPE envoy_cluster_retry_or_shadow_abandoned counterenvoy_cluster_retry_or_shadow_abandoned{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_tx_bytes_total counterenvoy_cluster_upstream_cx_tx_bytes_total{envoy_cluster_name=“hawkeye”} 179523# TYPE envoy_cluster_lb_zone_cluster_too_small counterenvoy_cluster_lb_zone_cluster_too_small{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_external_upstream_rq_completed counterenvoy_cluster_external_upstream_rq_completed{envoy_cluster_name=“hawkeye”} 240# TYPE envoy_cluster_internal_upstream_rq_xx counterenvoy_cluster_internal_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“hawkeye”} 15# TYPE envoy_cluster_lb_recalculate_zone_structures counterenvoy_cluster_lb_recalculate_zone_structures{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_destroy_with_active_rq counterenvoy_cluster_upstream_cx_destroy_with_active_rq{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_subsets_fallback counterenvoy_cluster_lb_subsets_fallback{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_xx counterenvoy_cluster_upstream_rq_xx{envoy_response_code_class=“5”,envoy_cluster_name=“hawkeye”} 29# TYPE envoy_cluster_upstream_rq_total counterenvoy_cluster_upstream_rq_total{envoy_cluster_name=“hawkeye”} 240# TYPE envoy_cluster_update_no_rebuild counterenvoy_cluster_update_no_rebuild{envoy_cluster_name=“hawkeye”} 18890# TYPE envoy_cluster_upstream_cx_destroy counterenvoy_cluster_upstream_cx_destroy{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_destroy_local counterenvoy_cluster_upstream_cx_destroy_local{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_rx_reset counterenvoy_cluster_upstream_rq_rx_reset{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_destroy_remote_with_active_rq counterenvoy_cluster_upstream_cx_destroy_remote_with_active_rq{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_flow_control_resumed_reading_total counterenvoy_cluster_upstream_flow_control_resumed_reading_total{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_update_attempt counterenvoy_cluster_update_attempt{envoy_cluster_name=“hawkeye”} 18891# TYPE envoy_cluster_upstream_rq_maintenance_mode counterenvoy_cluster_upstream_rq_maintenance_mode{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_update_failure counterenvoy_cluster_update_failure{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_ext_authz_ok counterenvoy_cluster_ext_authz_ok{envoy_cluster_name=“hawkeye”} 460envoy_cluster_external_upstream_rq_xx{envoy_response_code_class=“5”,envoy_cluster_name=“hawkeye”} 29# TYPE envoy_cluster_internal_upstream_rq counterenvoy_cluster_internal_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“hawkeye”} 15# TYPE envoy_cluster_update_empty counterenvoy_cluster_update_empty{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_zone_routing_all_directly counterenvoy_cluster_lb_zone_routing_all_directly{envoy_cluster_name=“hawkeye”} 0envoy_cluster_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“hawkeye”} 211# TYPE envoy_cluster_upstream_cx_http2_total counterenvoy_cluster_upstream_cx_http2_total{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_destroy_remote counterenvoy_cluster_upstream_cx_destroy_remote{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_retry counterenvoy_cluster_upstream_rq_retry{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_destroy_local_with_active_rq counterenvoy_cluster_upstream_cx_destroy_local_with_active_rq{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_overflow counterenvoy_cluster_upstream_cx_overflow{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_protocol_error counterenvoy_cluster_upstream_cx_protocol_error{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_tx_reset counterenvoy_cluster_upstream_rq_tx_reset{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_healthy_panic counterenvoy_cluster_lb_healthy_panic{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_idle_timeout counterenvoy_cluster_upstream_cx_idle_timeout{envoy_cluster_name=“hawkeye”} 0envoy_cluster_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“hawkeye”} 15envoy_cluster_external_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“hawkeye”} 209# TYPE envoy_cluster_lb_subsets_selected counterenvoy_cluster_lb_subsets_selected{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_update_success counterenvoy_cluster_update_success{envoy_cluster_name=“hawkeye”} 18891# TYPE envoy_cluster_upstream_cx_close_notify counterenvoy_cluster_upstream_cx_close_notify{envoy_cluster_name=“hawkeye”} 0envoy_cluster_upstream_cx_close_notify{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_tx_reset{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_local_cluster_not_ok{envoy_cluster_name=“ext-authz”} 0envoy_cluster_update_no_rebuild{envoy_cluster_name=“ext-authz”} 18890envoy_cluster_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“ext-authz”} 15envoy_cluster_upstream_cx_overflow{envoy_cluster_name=“ext-authz”} 0envoy_cluster_internal_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“ext-authz”} 460envoy_cluster_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“ext-authz”} 15envoy_cluster_upstream_flow_control_paused_reading_total{envoy_cluster_name=“ext-authz”} 0envoy_cluster_internal_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“ext-authz”} 460envoy_cluster_upstream_cx_tx_bytes_total{envoy_cluster_name=“ext-authz”} 142288envoy_cluster_update_empty{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_cancelled{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy_remote{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_timeout{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_retry{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_protocol_error{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy_local{envoy_cluster_name=“ext-authz”} 0envoy_cluster_update_attempt{envoy_cluster_name=“ext-authz”} 18891envoy_cluster_upstream_rq_retry_overflow{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_idle_timeout{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_zone_routing_sampled{envoy_cluster_name=“ext-authz”} 0envoy_cluster_original_dst_host_invalid{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_flow_control_resumed_reading_total{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_pending_failure_eject{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_per_try_timeout{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_max_requests{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_http2_total{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_zone_no_capacity_left{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_http1_total{envoy_cluster_name=“ext-authz”} 4envoy_cluster_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“ext-authz”} 460envoy_cluster_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“ext-authz”} 460envoy_cluster_update_success{envoy_cluster_name=“ext-authz”} 18891envoy_cluster_lb_subsets_fallback{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_healthy_panic{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_connect_fail{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_connect_attempts_exceeded{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_total{envoy_cluster_name=“ext-authz”} 4envoy_cluster_upstream_cx_rx_bytes_total{envoy_cluster_name=“ext-authz”} 80016envoy_cluster_internal_upstream_rq_completed{envoy_cluster_name=“ext-authz”} 475envoy_cluster_lb_zone_number_differs{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_zone_routing_all_directly{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_pending_total{envoy_cluster_name=“ext-authz”} 4envoy_cluster_lb_subsets_created{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_retry_success{envoy_cluster_name=“ext-authz”} 0envoy_cluster_internal_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“ext-authz”} 15envoy_cluster_upstream_rq_maintenance_mode{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_zone_routing_cross_zone{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_completed{envoy_cluster_name=“ext-authz”} 475envoy_cluster_upstream_flow_control_drained_total{envoy_cluster_name=“ext-authz”} 0envoy_cluster_membership_change{envoy_cluster_name=“ext-authz”} 1envoy_cluster_upstream_cx_none_healthy{envoy_cluster_name=“ext-authz”} 0envoy_cluster_bind_errors{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_rx_reset{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy_remote_with_active_rq{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_flow_control_backed_up_total{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_connect_timeout{envoy_cluster_name=“ext-authz”} 0envoy_cluster_update_failure{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_subsets_removed{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy_with_active_rq{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_subsets_selected{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_total{envoy_cluster_name=“ext-authz”} 475envoy_cluster_internal_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“ext-authz”} 15envoy_cluster_lb_recalculate_zone_structures{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_zone_cluster_too_small{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_rq_pending_overflow{envoy_cluster_name=“ext-authz”} 0envoy_cluster_retry_or_shadow_abandoned{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_destroy_local_with_active_rq{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_connect_timeout{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_pending_failure_eject{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_flow_control_paused_reading_total{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_flow_control_drained_total{envoy_cluster_name=“sso”} 0envoy_cluster_lb_local_cluster_not_ok{envoy_cluster_name=“sso”} 0envoy_cluster_lb_subsets_created{envoy_cluster_name=“sso”} 0envoy_cluster_lb_subsets_selected{envoy_cluster_name=“sso”} 0envoy_cluster_lb_zone_routing_cross_zone{envoy_cluster_name=“sso”} 0envoy_cluster_external_upstream_rq{envoy_response_code=“405”,envoy_cluster_name=“sso”} 1envoy_cluster_upstream_rq_timeout{envoy_cluster_name=“sso”} 0envoy_cluster_external_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“sso”} 8envoy_cluster_external_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“sso”} 13envoy_cluster_upstream_cx_overflow{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_per_try_timeout{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_max_requests{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_destroy_remote_with_active_rq{envoy_cluster_name=“sso”} 0envoy_cluster_retry_or_shadow_abandoned{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_close_notify{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_idle_timeout{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq{envoy_response_code=“415”,envoy_cluster_name=“sso”} 1envoy_cluster_upstream_cx_destroy_with_active_rq{envoy_cluster_name=“sso”} 0envoy_cluster_lb_zone_cluster_too_small{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_xx{envoy_response_code_class=“4”,envoy_cluster_name=“sso”} 8envoy_cluster_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“sso”} 6envoy_cluster_upstream_rq{envoy_response_code=“405”,envoy_cluster_name=“sso”} 1envoy_cluster_upstream_flow_control_backed_up_total{envoy_cluster_name=“sso”} 0envoy_cluster_external_upstream_rq{envoy_response_code=“401”,envoy_cluster_name=“sso”} 6envoy_cluster_external_upstream_rq{envoy_response_code=“415”,envoy_cluster_name=“sso”} 1envoy_cluster_upstream_rq_retry{envoy_cluster_name=“sso”} 0envoy_cluster_lb_zone_no_capacity_left{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_http1_total{envoy_cluster_name=“sso”} 7envoy_cluster_upstream_rq_total{envoy_cluster_name=“sso”} 21envoy_cluster_upstream_cx_protocol_error{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_tx_reset{envoy_cluster_name=“sso”} 0envoy_cluster_update_success{envoy_cluster_name=“sso”} 18891envoy_cluster_upstream_rq_completed{envoy_cluster_name=“sso”} 21envoy_cluster_external_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“sso”} 13envoy_cluster_upstream_cx_destroy{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_destroy_local{envoy_cluster_name=“sso”} 0envoy_cluster_lb_recalculate_zone_structures{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_tx_bytes_total{envoy_cluster_name=“sso”} 13072envoy_cluster_upstream_rq_pending_overflow{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_total{envoy_cluster_name=“sso”} 7envoy_cluster_lb_subsets_fallback{envoy_cluster_name=“sso”} 0envoy_cluster_original_dst_host_invalid{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_pending_total{envoy_cluster_name=“sso”} 7envoy_cluster_upstream_rq_cancelled{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_maintenance_mode{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_retry_success{envoy_cluster_name=“sso”} 0envoy_cluster_lb_healthy_panic{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_http2_total{envoy_cluster_name=“sso”} 0envoy_cluster_update_failure{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_connect_fail{envoy_cluster_name=“sso”} 0envoy_cluster_update_attempt{envoy_cluster_name=“sso”} 18891envoy_cluster_upstream_flow_control_resumed_reading_total{envoy_cluster_name=“sso”} 0envoy_cluster_update_empty{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_destroy_remote{envoy_cluster_name=“sso”} 0envoy_cluster_update_no_rebuild{envoy_cluster_name=“sso”} 18890envoy_cluster_bind_errors{envoy_cluster_name=“sso”} 0envoy_cluster_lb_subsets_removed{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_connect_attempts_exceeded{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_retry_overflow{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_xx{envoy_response_code_class=“2”,envoy_cluster_name=“sso”} 13envoy_cluster_lb_zone_number_differs{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_rx_bytes_total{envoy_cluster_name=“sso”} 12934envoy_cluster_lb_zone_routing_sampled{envoy_cluster_name=“sso”} 0envoy_cluster_lb_zone_routing_all_directly{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_destroy_local_with_active_rq{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_rx_reset{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_none_healthy{envoy_cluster_name=“sso”} 0envoy_cluster_membership_change{envoy_cluster_name=“sso”} 1envoy_cluster_external_upstream_rq_completed{envoy_cluster_name=“sso”} 21envoy_cluster_upstream_rq{envoy_response_code=“200”,envoy_cluster_name=“sso”} 13# TYPE envoy_http_downstream_rq_too_large counterenvoy_http_downstream_rq_too_large{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_protocol_error counterenvoy_http_downstream_cx_protocol_error{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_rq_timeout counterenvoy_http_downstream_rq_timeout{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_runtime_load_error counterenvoy_runtime_load_error{} 0# TYPE envoy_runtime_override_dir_not_exists counterenvoy_runtime_override_dir_not_exists{} 0# TYPE envoy_http_no_cluster counterenvoy_http_no_cluster{envoy_http_conn_manager_prefix=“async-client”} 0# TYPE envoy_server_watchdog_miss counterenvoy_server_watchdog_miss{} 0# TYPE envoy_http_downstream_rq_xx counterenvoy_http_downstream_rq_xx{envoy_response_code_class=“3”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_manager_cluster_removed counterenvoy_cluster_manager_cluster_removed{} 0# TYPE envoy_http_downstream_cx_upgrades_total counterenvoy_http_downstream_cx_upgrades_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_manager_update_merge_cancelled counterenvoy_cluster_manager_update_merge_cancelled{} 0# TYPE envoy_http_downstream_cx_overload_disable_keepalive counterenvoy_http_downstream_cx_overload_disable_keepalive{envoy_http_conn_manager_prefix=“admin”} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“1”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_destroy counterenvoy_http_downstream_cx_destroy{envoy_http_conn_manager_prefix=“admin”} 146344envoy_http_downstream_rq_xx{envoy_response_code_class=“5”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_tx_bytes_total counterenvoy_http_downstream_cx_tx_bytes_total{envoy_http_conn_manager_prefix=“admin”} 155797820# TYPE envoy_http_downstream_cx_drain_close counterenvoy_http_downstream_cx_drain_close{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_destroy_local_active_rq counterenvoy_http_downstream_cx_destroy_local_active_rq{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_destroy_active_rq counterenvoy_http_downstream_cx_destroy_active_rq{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_destroy_local counterenvoy_http_downstream_cx_destroy_local{envoy_http_conn_manager_prefix=“admin”} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“2”,envoy_http_conn_manager_prefix=“admin”} 3154# TYPE envoy_http_downstream_rq_http1_total counterenvoy_http_downstream_rq_http1_total{envoy_http_conn_manager_prefix=“admin”} 3155# TYPE envoy_http_rq_total counterenvoy_http_rq_total{envoy_http_conn_manager_prefix=“async-client”} 475# TYPE envoy_http_downstream_cx_total counterenvoy_http_downstream_cx_total{envoy_http_conn_manager_prefix=“admin”} 146346# TYPE envoy_runtime_load_success counterenvoy_runtime_load_success{} 0# TYPE envoy_filesystem_reopen_failed counterenvoy_filesystem_reopen_failed{} 0# TYPE envoy_http_downstream_rq_total counterenvoy_http_downstream_rq_total{envoy_http_conn_manager_prefix=“admin”} 3155# TYPE envoy_http_downstream_rq_rx_reset counterenvoy_http_downstream_rq_rx_reset{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_manager_cluster_modified counterenvoy_cluster_manager_cluster_modified{} 0# TYPE envoy_http_downstream_rq_idle_timeout counterenvoy_http_downstream_rq_idle_timeout{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_destroy_remote_active_rq counterenvoy_http_downstream_cx_destroy_remote_active_rq{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_ssl_total counterenvoy_http_downstream_cx_ssl_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_delayed_close_timeout counterenvoy_http_downstream_cx_delayed_close_timeout{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_manager_update_out_of_merge_window counterenvoy_cluster_manager_update_out_of_merge_window{} 0# TYPE envoy_http_downstream_flow_control_resumed_reading_total counterenvoy_http_downstream_flow_control_resumed_reading_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_listener_manager_listener_added counterenvoy_listener_manager_listener_added{} 1# TYPE envoy_http_downstream_rq_overload_close counterenvoy_http_downstream_rq_overload_close{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_http2_total counterenvoy_http_downstream_cx_http2_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_listener_manager_listener_create_failure counterenvoy_listener_manager_listener_create_failure{} 0# TYPE envoy_stats_overflow counterenvoy_stats_overflow{} 0# TYPE envoy_listener_manager_listener_create_success counterenvoy_listener_manager_listener_create_success{} 16# TYPE envoy_http_downstream_cx_http1_total counterenvoy_http_downstream_cx_http1_total{envoy_http_conn_manager_prefix=“admin”} 2# TYPE envoy_http_no_route counterenvoy_http_no_route{envoy_http_conn_manager_prefix=“async-client”} 0# TYPE envoy_cluster_manager_cluster_updated counterenvoy_cluster_manager_cluster_updated{} 0# TYPE envoy_http_downstream_cx_destroy_remote counterenvoy_http_downstream_cx_destroy_remote{envoy_http_conn_manager_prefix=“admin”} 146344# TYPE envoy_http_downstream_rq_non_relative_path counterenvoy_http_downstream_rq_non_relative_path{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_rs_too_large counterenvoy_http_rs_too_large{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_rq_tx_reset counterenvoy_http_downstream_rq_tx_reset{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_server_watchdog_mega_miss counterenvoy_server_watchdog_mega_miss{} 0# TYPE envoy_http_downstream_flow_control_paused_reading_total counterenvoy_http_downstream_flow_control_paused_reading_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_rx_bytes_total counterenvoy_http_downstream_cx_rx_bytes_total{envoy_http_conn_manager_prefix=“admin”} 795620# TYPE envoy_http_downstream_rq_completed counterenvoy_http_downstream_rq_completed{envoy_http_conn_manager_prefix=“admin”} 3154# TYPE envoy_listener_manager_listener_removed counterenvoy_listener_manager_listener_removed{} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“4”,envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_rq_direct_response counterenvoy_http_rq_direct_response{envoy_http_conn_manager_prefix=“async-client”} 0# TYPE envoy_filesystem_write_completed counterenvoy_filesystem_write_completed{} 3366# TYPE envoy_http_downstream_rq_ws_on_non_ws_route counterenvoy_http_downstream_rq_ws_on_non_ws_route{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_cluster_manager_cluster_updated_via_merge counterenvoy_cluster_manager_cluster_updated_via_merge{} 0# TYPE envoy_filesystem_flushed_by_timer counterenvoy_filesystem_flushed_by_timer{} 18495# TYPE envoy_filesystem_write_buffered counterenvoy_filesystem_write_buffered{} 3669# TYPE envoy_runtime_override_dir_exists counterenvoy_runtime_override_dir_exists{} 0# TYPE envoy_cluster_manager_cluster_added counterenvoy_cluster_manager_cluster_added{} 4# TYPE envoy_listener_manager_listener_modified counterenvoy_listener_manager_listener_modified{} 0# TYPE envoy_http_downstream_rq_http2_total counterenvoy_http_downstream_rq_http2_total{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_rq_response_before_rq_complete counterenvoy_http_downstream_rq_response_before_rq_complete{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_idle_timeout counterenvoy_http_downstream_cx_idle_timeout{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_rq_redirect counterenvoy_http_rq_redirect{envoy_http_conn_manager_prefix=“async-client”} 0# TYPE envoy_listener_http_downstream_rq_xx counterenvoy_listener_http_downstream_rq_xx{envoy_response_code_class=“1”,envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 0envoy_listener_http_downstream_rq_xx{envoy_response_code_class=“2”,envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 456envoy_listener_http_downstream_rq_xx{envoy_response_code_class=“4”,envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 30# TYPE envoy_listener_downstream_pre_cx_timeout counterenvoy_listener_downstream_pre_cx_timeout{envoy_listener_address=“0.0.0.0_8000”} 0# TYPE envoy_listener_no_filter_chain_match counterenvoy_listener_no_filter_chain_match{envoy_listener_address=“0.0.0.0_8000”} 0# TYPE envoy_listener_downstream_cx_total counterenvoy_listener_downstream_cx_total{envoy_listener_address=“0.0.0.0_8000”} 147370envoy_listener_http_downstream_rq_xx{envoy_response_code_class=“5”,envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 29envoy_listener_http_downstream_rq_xx{envoy_response_code_class=“3”,envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 0# TYPE envoy_listener_downstream_cx_destroy counterenvoy_listener_downstream_cx_destroy{envoy_listener_address=“0.0.0.0_8000”} 147369# TYPE envoy_listener_http_downstream_rq_completed counterenvoy_listener_http_downstream_rq_completed{envoy_http_conn_manager_prefix=“ingress_http”,envoy_listener_address=“0.0.0.0_8000”} 515envoy_http_downstream_cx_destroy{envoy_http_conn_manager_prefix=“ingress_http”} 147369envoy_http_downstream_rq_http1_total{envoy_http_conn_manager_prefix=“ingress_http”} 515envoy_http_downstream_cx_destroy_local_active_rq{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_flow_control_resumed_reading_total{envoy_http_conn_manager_prefix=“ingress_http”} 0# TYPE envoy_http_tracing_health_check counterenvoy_http_tracing_health_check{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_response_before_rq_complete{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_protocol_error{envoy_http_conn_manager_prefix=“ingress_http”} 2envoy_http_downstream_cx_destroy_remote{envoy_http_conn_manager_prefix=“ingress_http”} 147367envoy_http_no_route{envoy_http_conn_manager_prefix=“ingress_http”} 7envoy_http_rq_redirect{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_http1_total{envoy_http_conn_manager_prefix=“ingress_http”} 41# TYPE envoy_http_tracing_random_sampling counterenvoy_http_tracing_random_sampling{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_total{envoy_http_conn_manager_prefix=“ingress_http”} 147370envoy_http_downstream_cx_destroy_remote_active_rq{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_rs_too_large{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_idle_timeout{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_idle_timeout{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_rx_bytes_total{envoy_http_conn_manager_prefix=“ingress_http”} 306987envoy_http_downstream_rq_xx{envoy_response_code_class=“1”,envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_ws_on_non_ws_route{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“3”,envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_overload_disable_keepalive{envoy_http_conn_manager_prefix=“ingress_http”} 0# TYPE envoy_http_tracing_service_forced counterenvoy_http_tracing_service_forced{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_drain_close{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_tx_bytes_total{envoy_http_conn_manager_prefix=“ingress_http”} 227287envoy_http_downstream_cx_delayed_close_timeout{envoy_http_conn_manager_prefix=“ingress_http”} 2envoy_http_downstream_flow_control_paused_reading_total{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_timeout{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_rx_reset{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_destroy_local{envoy_http_conn_manager_prefix=“ingress_http”} 2# TYPE envoy_http_tracing_not_traceable counterenvoy_http_tracing_not_traceable{envoy_http_conn_manager_prefix=“ingress_http”} 0# TYPE envoy_http_cors_origin_invalid counterenvoy_http_cors_origin_invalid{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_no_cluster{envoy_http_conn_manager_prefix=“ingress_http”} 0# TYPE envoy_http_cors_origin_valid counterenvoy_http_cors_origin_valid{envoy_http_conn_manager_prefix=“ingress_http”} 485envoy_http_downstream_rq_completed{envoy_http_conn_manager_prefix=“ingress_http”} 515envoy_http_rq_total{envoy_http_conn_manager_prefix=“ingress_http”} 268envoy_http_downstream_rq_tx_reset{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_total{envoy_http_conn_manager_prefix=“ingress_http”} 515envoy_http_downstream_rq_overload_close{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_http2_total{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_destroy_active_rq{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_http2_total{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_upgrades_total{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_non_relative_path{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“4”,envoy_http_conn_manager_prefix=“ingress_http”} 30envoy_http_downstream_rq_xx{envoy_response_code_class=“5”,envoy_http_conn_manager_prefix=“ingress_http”} 29envoy_http_rq_direct_response{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_ssl_total{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_too_large{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_rq_xx{envoy_response_code_class=“2”,envoy_http_conn_manager_prefix=“ingress_http”} 456# TYPE envoy_http_tracing_client_enabled counterenvoy_http_tracing_client_enabled{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_cluster_upstream_cx_protocol_error{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_flow_control_paused_reading_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_http2_total{envoy_cluster_name=“cost”} 0envoy_cluster_lb_subsets_removed{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_http1_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_close_notify{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_cluster_too_small{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_max_requests{envoy_cluster_name=“cost”} 0envoy_cluster_membership_change{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy_local{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_cancelled{envoy_cluster_name=“cost”} 0envoy_cluster_update_no_rebuild{envoy_cluster_name=“cost”} 18872envoy_cluster_upstream_rq_timeout{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_rx_bytes_total{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_no_capacity_left{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy_local_with_active_rq{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_per_try_timeout{envoy_cluster_name=“cost”} 0envoy_cluster_bind_errors{envoy_cluster_name=“cost”} 0envoy_cluster_update_success{envoy_cluster_name=“cost”} 18872envoy_cluster_upstream_rq_retry{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_tx_reset{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_retry_success{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_connect_attempts_exceeded{envoy_cluster_name=“cost”} 0envoy_cluster_update_empty{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy_remote{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_tx_bytes_total{envoy_cluster_name=“cost”} 0envoy_cluster_original_dst_host_invalid{envoy_cluster_name=“cost”} 0envoy_cluster_update_failure{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_pending_overflow{envoy_cluster_name=“cost”} 0envoy_cluster_update_attempt{envoy_cluster_name=“cost”} 18872envoy_cluster_upstream_cx_connect_timeout{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_routing_all_directly{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_none_healthy{envoy_cluster_name=“cost”} 0envoy_cluster_retry_or_shadow_abandoned{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_flow_control_resumed_reading_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_connect_fail{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_retry_overflow{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_routing_cross_zone{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_pending_total{envoy_cluster_name=“cost”} 0envoy_cluster_lb_subsets_created{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_maintenance_mode{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_completed{envoy_cluster_name=“cost”} 0envoy_cluster_lb_healthy_panic{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_routing_sampled{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_flow_control_drained_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy_remote_with_active_rq{envoy_cluster_name=“cost”} 0envoy_cluster_lb_local_cluster_not_ok{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_flow_control_backed_up_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_rx_reset{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy_with_active_rq{envoy_cluster_name=“cost”} 0envoy_cluster_lb_subsets_fallback{envoy_cluster_name=“cost”} 0envoy_cluster_lb_zone_number_differs{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_idle_timeout{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_overflow{envoy_cluster_name=“cost”} 0envoy_cluster_lb_subsets_selected{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_total{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_destroy{envoy_cluster_name=“cost”} 0envoy_cluster_lb_recalculate_zone_structures{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_pending_failure_eject{envoy_cluster_name=“cost”} 0# TYPE envoy_listener_admin_downstream_pre_cx_active gaugeenvoy_listener_admin_downstream_pre_cx_active{} 0# TYPE envoy_listener_admin_downstream_cx_active gaugeenvoy_listener_admin_downstream_cx_active{} 2# TYPE envoy_cluster_upstream_cx_rx_bytes_buffered gaugeenvoy_cluster_upstream_cx_rx_bytes_buffered{envoy_cluster_name=“hawkeye”} 3402# TYPE envoy_cluster_membership_healthy gaugeenvoy_cluster_membership_healthy{envoy_cluster_name=“hawkeye”} 1# TYPE envoy_cluster_circuit_breakers_high_cx_open gaugeenvoy_cluster_circuit_breakers_high_cx_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_circuit_breakers_default_rq_pending_open gaugeenvoy_cluster_circuit_breakers_default_rq_pending_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_tx_bytes_buffered gaugeenvoy_cluster_upstream_cx_tx_bytes_buffered{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_circuit_breakers_high_rq_retry_open gaugeenvoy_cluster_circuit_breakers_high_rq_retry_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_lb_subsets_active gaugeenvoy_cluster_lb_subsets_active{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_circuit_breakers_default_cx_open gaugeenvoy_cluster_circuit_breakers_default_cx_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_max_host_weight gaugeenvoy_cluster_max_host_weight{envoy_cluster_name=“hawkeye”} 1# TYPE envoy_cluster_circuit_breakers_default_rq_retry_open gaugeenvoy_cluster_circuit_breakers_default_rq_retry_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_version gaugeenvoy_cluster_version{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_membership_total gaugeenvoy_cluster_membership_total{envoy_cluster_name=“hawkeye”} 1# TYPE envoy_cluster_circuit_breakers_high_rq_pending_open gaugeenvoy_cluster_circuit_breakers_high_rq_pending_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_circuit_breakers_default_rq_open gaugeenvoy_cluster_circuit_breakers_default_rq_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_circuit_breakers_high_rq_open gaugeenvoy_cluster_circuit_breakers_high_rq_open{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_cx_active gaugeenvoy_cluster_upstream_cx_active{envoy_cluster_name=“hawkeye”} 3# TYPE envoy_cluster_upstream_rq_pending_active gaugeenvoy_cluster_upstream_rq_pending_active{envoy_cluster_name=“hawkeye”} 0# TYPE envoy_cluster_upstream_rq_active gaugeenvoy_cluster_upstream_rq_active{envoy_cluster_name=“hawkeye”} 0envoy_cluster_membership_healthy{envoy_cluster_name=“ext-authz”} 1envoy_cluster_circuit_breakers_default_rq_pending_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_default_rq_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_membership_total{envoy_cluster_name=“ext-authz”} 1envoy_cluster_circuit_breakers_default_rq_retry_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_active{envoy_cluster_name=“ext-authz”} 4envoy_cluster_version{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_high_rq_pending_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_rx_bytes_buffered{envoy_cluster_name=“ext-authz”} 714envoy_cluster_upstream_rq_pending_active{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_high_cx_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_high_rq_retry_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_max_host_weight{envoy_cluster_name=“ext-authz”} 1envoy_cluster_upstream_rq_active{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_high_rq_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_upstream_cx_tx_bytes_buffered{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_default_cx_open{envoy_cluster_name=“ext-authz”} 0envoy_cluster_lb_subsets_active{envoy_cluster_name=“ext-authz”} 0envoy_cluster_circuit_breakers_default_rq_open{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_pending_active{envoy_cluster_name=“sso”} 0envoy_cluster_membership_healthy{envoy_cluster_name=“sso”} 1envoy_cluster_circuit_breakers_high_rq_pending_open{envoy_cluster_name=“sso”} 0envoy_cluster_circuit_breakers_high_rq_open{envoy_cluster_name=“sso”} 0envoy_cluster_circuit_breakers_high_rq_retry_open{envoy_cluster_name=“sso”} 0envoy_cluster_version{envoy_cluster_name=“sso”} 0envoy_cluster_circuit_breakers_high_cx_open{envoy_cluster_name=“sso”} 0envoy_cluster_membership_total{envoy_cluster_name=“sso”} 1envoy_cluster_upstream_cx_active{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_tx_bytes_buffered{envoy_cluster_name=“sso”} 0envoy_cluster_circuit_breakers_default_rq_pending_open{envoy_cluster_name=“sso”} 0envoy_cluster_lb_subsets_active{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_cx_rx_bytes_buffered{envoy_cluster_name=“sso”} 0envoy_cluster_circuit_breakers_default_cx_open{envoy_cluster_name=“sso”} 0envoy_cluster_upstream_rq_active{envoy_cluster_name=“sso”} 0envoy_cluster_max_host_weight{envoy_cluster_name=“sso”} 1envoy_cluster_circuit_breakers_default_rq_retry_open{envoy_cluster_name=“sso”} 0# TYPE envoy_filesystem_write_total_buffered gaugeenvoy_filesystem_write_total_buffered{} 0# TYPE envoy_http_downstream_cx_http1_active gaugeenvoy_http_downstream_cx_http1_active{envoy_http_conn_manager_prefix=“admin”} 2# TYPE envoy_listener_manager_total_listeners_warming gaugeenvoy_listener_manager_total_listeners_warming{} 0# TYPE envoy_runtime_num_keys gaugeenvoy_runtime_num_keys{} 0# TYPE envoy_http_downstream_cx_rx_bytes_buffered gaugeenvoy_http_downstream_cx_rx_bytes_buffered{envoy_http_conn_manager_prefix=“admin”} 845# TYPE envoy_runtime_admin_overrides_active gaugeenvoy_runtime_admin_overrides_active{} 0# TYPE envoy_server_version gaugeenvoy_server_version{} 3653592# TYPE envoy_cluster_manager_active_clusters gaugeenvoy_cluster_manager_active_clusters{} 4# TYPE envoy_server_live gaugeenvoy_server_live{} 1# TYPE envoy_http_downstream_cx_ssl_active gaugeenvoy_http_downstream_cx_ssl_active{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_http2_active gaugeenvoy_http_downstream_cx_http2_active{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_tx_bytes_buffered gaugeenvoy_http_downstream_cx_tx_bytes_buffered{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_cx_upgrades_active gaugeenvoy_http_downstream_cx_upgrades_active{envoy_http_conn_manager_prefix=“admin”} 0# TYPE envoy_http_downstream_rq_active gaugeenvoy_http_downstream_rq_active{envoy_http_conn_manager_prefix=“admin”} 1# TYPE envoy_listener_manager_total_listeners_active gaugeenvoy_listener_manager_total_listeners_active{} 1# TYPE envoy_server_parent_connections gaugeenvoy_server_parent_connections{} 0# TYPE envoy_cluster_manager_warming_clusters gaugeenvoy_cluster_manager_warming_clusters{} 0# TYPE envoy_http_downstream_cx_active gaugeenvoy_http_downstream_cx_active{envoy_http_conn_manager_prefix=“admin”} 2# TYPE envoy_listener_manager_total_listeners_draining gaugeenvoy_listener_manager_total_listeners_draining{} 0# TYPE envoy_server_total_connections gaugeenvoy_server_total_connections{} 1# TYPE envoy_server_concurrency gaugeenvoy_server_concurrency{} 16# TYPE envoy_server_memory_allocated gaugeenvoy_server_memory_allocated{} 4216000# TYPE envoy_server_hot_restart_epoch gaugeenvoy_server_hot_restart_epoch{} 0# TYPE envoy_server_uptime gaugeenvoy_server_uptime{} 94576# TYPE envoy_server_memory_heap_size gaugeenvoy_server_memory_heap_size{} 6291456# TYPE envoy_server_days_until_first_cert_expiring gaugeenvoy_server_days_until_first_cert_expiring{} 2147483647# TYPE envoy_listener_downstream_cx_active gaugeenvoy_listener_downstream_cx_active{envoy_listener_address=“0.0.0.0_8000”} 1# TYPE envoy_listener_downstream_pre_cx_active gaugeenvoy_listener_downstream_pre_cx_active{envoy_listener_address=“0.0.0.0_8000”} 0envoy_http_downstream_cx_tx_bytes_buffered{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_upgrades_active{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_ssl_active{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_active{envoy_http_conn_manager_prefix=“ingress_http”} 1envoy_http_downstream_cx_http1_active{envoy_http_conn_manager_prefix=“ingress_http”} 1envoy_http_downstream_cx_http2_active{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_http_downstream_cx_rx_bytes_buffered{envoy_http_conn_manager_prefix=“ingress_http”} 403envoy_http_downstream_rq_active{envoy_http_conn_manager_prefix=“ingress_http”} 0envoy_cluster_upstream_rq_pending_active{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_default_cx_open{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_default_rq_pending_open{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_rq_active{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_high_rq_pending_open{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_default_rq_open{envoy_cluster_name=“cost”} 0envoy_cluster_max_host_weight{envoy_cluster_name=“cost”} 1envoy_cluster_membership_total{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_high_cx_open{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_default_rq_retry_open{envoy_cluster_name=“cost”} 0envoy_cluster_membership_healthy{envoy_cluster_name=“cost”} 0envoy_cluster_version{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_active{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_high_rq_retry_open{envoy_cluster_name=“cost”} 0envoy_cluster_circuit_breakers_high_rq_open{envoy_cluster_name=“cost”} 0envoy_cluster_lb_subsets_active{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_tx_bytes_buffered{envoy_cluster_name=“cost”} 0envoy_cluster_upstream_cx_rx_bytes_buffered{envoy_cluster_name=“cost”} 0配置prometheus 采集envoy由于我实际测试过程中,envoy是部署在k8s当中,所以,利用prometheus对pod 自动发现的能力,没有在prometheus做静态配置。自动发现的好处,就是当pod hpa的时候,不需要去更改配置文件。要采集envoy metrics,在 envoy deployment当中要加入如下注解:kind: DeploymentapiVersion: apps/v1metadata: name: gateway labels: app: gatewayspec: replicas: 2 selector: matchLabels: app: gateway template: metadata: labels: app: gateway annotations: prometheus.io/scrape: ’true’ prometheus.io/path: ‘/stats/prometheus’ prometheus.io/port: ‘9000’ spec: volumes: - name: config configMap: name: gateway-cm containers: - name: gateway image: ’envoyproxy/envoy:v1.9.0’ env: - name: ‘CPUS’ value: ‘1’ - name: ‘SERVICE_NAME’ value: ‘-gateway’ resources: limits: cpu: ‘1’ memory: 1Gi requests: cpu: ‘1’ memory: 1Gi volumeMounts: - name: config mountPath: /etc/envoy/ imagePullPolicy: Always 注意如下的注解: annotations: prometheus.io/scrape: ’true’ prometheus.io/path: ‘/stats/prometheus’ prometheus.io/port: ‘9000’然后查看prometheus的管理界面,查询一下metrics:prometheus已经成功采集metrics。grafana展示grafana dashbord中,已经有两个做好的模板。大家引入就可以了。具体是envoy global看板(7253)和 Envoy Service Dashboard(7250)。最后效果如下: ...

February 28, 2019 · 6 min · jiezi

Prometheus 500 Internal Privoxy Error 异常解决

Prometheus 500 Internal Privoxy Error 异常解决访问Prometheus web-ui时异常Privoxy encountered an error while processing your request:Could not load template file no-server-data or one of its included components.Please contact your proxy administrator.If you are the proxy administrator, please put the required file(s)in the (confdir)/templates directory. The location of the (confdir) directory is specified in the main Privoxy config file. (It’s typically the Privoxy install directory).解决方案翻墙软件因开全局代理导致异常,将全局代理修改为自动代理就解决

February 27, 2019 · 1 min · jiezi

CNCF案例研究:蚂蚁金服

蚂蚁金服利用Kubernetes的高速增长策略公司:蚂蚁金服地点:中国杭州行业:金融服务挑战蚂蚁金服于2014年10月正式成立,源自2004年推出的全球最大的在线支付平台支付宝。该公司还利用技术创新提供众多其他服务。随着支付宝处理其全球9亿多用户(通过其本地和全球合作伙伴)的交易量 - 在2017年双十一的高峰期每秒256,000笔交易,以及2018年双十一的总商品价值310亿美元 - 更不用说其他服务,蚂蚁金服面临着“全新的数据处理挑战”,负责存储和计算产品管理的Haojie Hang说。“我们看到了在这种规模下运营的三个主要问题:如何提供实时计算、存储和处理能力,例如为欺诈检测提供实时建议;如何在这些数据之上提供智能,因为数据太多,我们没有获得足够的洞察力;以及如何在应用程序级别,中间件级别,系统级别甚至芯片级别提供安全性。”为了向其客户提供可靠和一致的服务,蚂蚁金服在2014年初拥抱了容器,很快就需要为数据中心的数万个节点集群提供一个编排解决方案。解决方法在调查了几项技术后,该团队选择了Kubernetes作容器编排,以及其他一些CNCF项目,包括Prometheus、OpenTracing、etcd和CoreDNS。“2016年底,我们认为Kubernetes将成为事实上的标准,”Haojie说。“回顾过去,我们在合适的技术上做出了正确的选择。但是,我们需要将生产工作量从遗留基础设施转移到最新的Kubernetes平台,这需要一些时间,因为我们在可靠性和一致性方面非常谨慎。”所有核心财务系统都在2017年11月容器化,正在迁移到Kubernetes。影响“我们已经看到使用云原生技术在运营方面至少提高了十倍,这意味着你的产出可以增加十倍,”Haojie说。蚂蚁也为全球的业务合作伙伴提供完全集成的金融云平台,希望通过在服务创新和技术专业知识方面的丰富经验为下一代数字银行提供支持。Haojie表示,该团队还没有开始关注优化Kubernetes平台:“因为我们还处于超高速增长阶段,我们还没有采用节约成本的模式。”“2016年底,我们认为Kubernetes将成为事实上的标准。回顾过去,我们在合适的技术上做出了正确的选择。” - Haojie Hang,产品管理,蚂蚁金服作为跨国集团阿里巴巴的分拆公司,蚂蚁金服拥有1500亿美元的估值以及相匹配的规模。该金融科技创业公司于2014年成立,由全球最大的在线支付平台支付宝以及利用技术创新的众多其他服务组成。 支付宝为全球超过9亿用户(通过其本地和全球合作伙伴)处理的交易量惊人:2017年双11高峰期每秒256,000次,2018年双11总商品价值310亿美元。蚂蚁金服以“为世界带来更多平等的机会”为使命,致力于通过技术创新创建开放、共享的信用体系和金融服务平台。再加上其他业务的运营 - 如花呗在线信贷系统、借呗贷款服务以及3.5亿用户的蚂蚁森林绿色能源移动应用程序 - 蚂蚁金服面临着“全新的数据处理挑战”,负责存储和计算产品管理的Haojie Hang说。“我们看到了在这种规模下运营的三个主要问题:如何提供实时计算、存储和处理能力,例如为欺诈检测提供实时建议;如何在这些数据之上提供智能,因为数据太多,我们没有获得足够的洞察力;以及如何在应用程序级别,中间件级别,系统级别甚至芯片级别提供安全性。”为了应对这些挑战,为其客户提供可靠和一致的服务,蚂蚁金服在2014年采用了Docker容器化。但他们很快意识到需要为公司数据中心的数万个节点集群提供编排解决方案。“在今年的双11上,我们有很多节点运行Kubernetes,但与基础设施的整体规模相比,这仍然在进行中。” - Ranger Yu,全球技术合作伙伴关系与发展,蚂蚁金服该团队研究了几种技术,包括Docker Swarm和Mesos。“我们做了很多POC,但我们在生产系统方面非常谨慎,因为我们希望确保不会丢失任何数据。”Haojie说。“你不能让服务停工一分钟,甚至一秒钟也会产生非常非常大的影响。我们每天都在为中国和全球的消费者和企业提供可靠、一致的服务的前提下运营。”最终,Haojie说蚂蚁选择了Kubernetes,因为它满足了所有需求方框:一个强大的社区、“将在未来三到五年内是相关的技术”,以及与公司工程人才的良好匹配。“2016年底,我们认为Kubernetes将成为事实上的标准。”Haojie说。“回顾过去,我们在合适的技术上做出了正确的选择。但是,我们需要将生产工作量从遗留基础设施转移到最新的Kubernetes平台。我们花了很多时间学习,然后培训我们的员工在Kubernetes上很好地构建应用程序。”所有核心财务系统都在2017年11月进行了容器化,正在迁移到Kubernetes。蚂蚁的平台还利用了许多其他CNCF项目,包括Prometheus、OpenTracing、etcd和CoreDNS。“在今年的双11,我们有很多节点运行Kubernetes,但与基础设施的整体规模相比,这仍然在进行中。”全球技术合作伙伴关系与发展的Ranger Yu说。“我们非常感谢CNCF和这项令人惊叹的技术,这是我们在全球不断扩展所需要的。我们肯定会在未来更拥抱社区和开源。” - Haojie Hang,产品管理,蚂蚁金服这已经产生了影响。“云原生技术使我们在效率方面受益匪浅。”Haojie说。“总的来说,我们希望确保我们的基础设施敏捷和灵活,足以应对明天可能发生的工作。这就是目标。借助云原生技术,我们已经看到运营改进至少十倍,这意味着您可以将产出提高十倍。假设您正在一个人操作10个节点。使用云原生,明天你可以有100个节点。”蚂蚁也为世界各地的合作伙伴提供其金融云平台,希望通过在服务创新和技术专业知识方面的丰富经验为下一代数字银行提供支持。Haojie说团队还没有开始专注于优化Kubernetes平台,“因为我们还处于超高速增长阶段,我们还没有采用节约成本的模式。”在蚂蚁金服迁移到云原生期间,CNCF社区也是一项宝贵的资产。“如果你正在应用一项新技术,那么有一个社区与其他用户讨论技术问题是非常好的。”Haojie说。“我们非常感谢CNCF和这项令人惊叹的技术,这是我们在全球不断扩展所需要的。我们肯定会在未来更拥抱社区和开源。”“在中国,我们是金融和其他相关服务创新方面的北极星。我们肯定希望通过我们对技术的投资,确保在未来5到10年内保持领先地位。” - Haojie Hang,产品管理,蚂蚁金服事实上,该公司已经开始开源一些云原生中间件。“我们将非常积极主动,”Ranger说。“CNCF提供了一个平台,让每个人都可以加入或贡献组件。这是非常好的开源治理。”展望未来,蚂蚁团队将继续评估许多其他CNCF项目。该团队在中国建立了服务网络社区,汇集了许多中国公司和开发者,共同探讨该技术的潜力。“对于中国开发者和最终用户来说,服务网络非常吸引,因为我们现在有很多遗留系统在运行,它是一个理想的中间层,可以将所有内容粘合在一起,包括新旧系统。”Haojie说。“对于新技术,我们会密切关注它们是否会持久。”在蚂蚁,Kubernetes以优异的成绩通过了测试,团队希望其他公司也会效仿。“在中国,我们是金融和其他相关服务创新方面的北极星。”Haojie说。“我们肯定希望通过我们对技术的投资,确保在未来5到10年内保持领先地位。”KubeCon + CloudNativeCon中国论坛提案征集(CFP)2月22日截止KubeCon + CloudNativeCon 论坛让用户、开发人员、从业人员汇聚一堂,面对面进行交流合作。与会人员有 Kubernetes、Prometheus 及其他云原生计算基金会 (CNCF) 主办项目的领导,和我们一同探讨云原生生态系统发展方向。Open Source Summit中国提案征集(CFP)2月22日截止在Open Source Summit中国,与会者将共同合作及共享信息,了解最新和最有趣的开源技术,包括Linux、IoT、区块链、AI、网络等;并获得如何在开源社区中导向和引领的信息。大会日期:提案征集截止日期:太平洋标准时间 2 月 22 日,星期五,晚上 11:59提案征集通知日期:2019 年 4 月 8 日会议日程通告日期:2019 年 4 月 10 日会议活动举办日期:2019 年 6 月 24 至 26 日提醒:这是一场社区会议。因此,让我们尽量避开公然推销产品和/或供应商销售宣传。KubeCon + CloudNativeCon和Open Source Summit赞助方案出炉KubeCon + CloudNativeCon和Open Source Summit多元化奖学金现正接受申请KubeCon + CloudNativeCon和Open Source Summit即将首次合体落地中国 ...

February 14, 2019 · 1 min · jiezi

k8s与HPA--通过 Prometheus adaptor 来自定义监控指标

k8s与HPA–通过 Prometheus adaptor 来自定义监控指标自动扩展是一种根据资源使用情况自动扩展或缩小工作负载的方法。 Kubernetes中的自动缩放有两个维度:Cluster Autoscaler处理节点扩展操作,Horizontal Pod Autoscaler自动扩展部署或副本集中的pod数量。 Cluster Autoscaling与Horizontal Pod Autoscaler一起用于动态调整计算能力以及系统满足SLA所需的并行度。虽然Cluster Autoscaler高度依赖托管您的集群的云提供商的基础功能,但HPA可以独立于您的IaaS / PaaS提供商运营。Horizontal Pod Autoscaler功能最初是在Kubernetes v1.1中引入的,并且从那时起已经发展了很多。 HPA缩放容器的版本1基于观察到的CPU利用率,后来基于内存使用情况。在Kubernetes 1.6中,引入了一个新的API Custom Metrics API,使HPA能够访问任意指标。 Kubernetes 1.7引入了聚合层,允许第三方应用程序通过将自己注册为API附加组件来扩展Kubernetes API。 Custom Metrics API和聚合层使Prometheus等监控系统可以向HPA控制器公开特定于应用程序的指标。Horizontal Pod Autoscaler实现为一个控制循环,定期查询Resource Metrics API以获取CPU /内存等核心指标和针对特定应用程序指标的Custom Metrics API。以下是为Kubernetes 1.9或更高版本配置HPA v2的分步指南。您将安装提供核心指标的Metrics Server附加组件,然后您将使用演示应用程序根据CPU和内存使用情况展示pod自动扩展。在本指南的第二部分中,您将部署Prometheus和自定义API服务器。您将使用聚合器层注册自定义API服务器,然后使用演示应用程序提供的自定义指标配置HPA。在开始之前,您需要安装Go 1.8或更高版本并在GOPATH中克隆k8s-prom-hpa repo。cd $GOPATHgit clone https://github.com/stefanprodan/k8s-prom-hpa部署 Metrics Serverkubernetes Metrics Server是资源使用数据的集群范围聚合器,是Heapster的后继者。度量服务器通过汇集来自kubernetes.summary_api的数据来收集节点和pod的CPU和内存使用情况。摘要API是一种内存高效的API,用于将数据从Kubelet / cAdvisor传递到度量服务器。在HPA的第一个版本中,您需要Heapster来提供CPU和内存指标,在HPA v2和Kubernetes 1.8中,只有在启用horizontal-pod-autoscaler-use-rest-clients时才需要指标服务器。默认情况下,Kubernetes 1.9中启用了HPA rest客户端。 GKE 1.9附带预安装的Metrics Server。在kube-system命名空间中部署Metrics Server:kubectl create -f ./metrics-server一分钟后,度量服务器开始报告节点和pod的CPU和内存使用情况。查看nodes metrics:kubectl get –raw “/apis/metrics.k8s.io/v1beta1/nodes” | jq .结果如下:{ “kind”: “NodeMetricsList”, “apiVersion”: “metrics.k8s.io/v1beta1”, “metadata”: { “selfLink”: “/apis/metrics.k8s.io/v1beta1/nodes” }, “items”: [ { “metadata”: { “name”: “ip-10-1-50-61.ec2.internal”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/nodes/ip-10-1-50-61.ec2.internal”, “creationTimestamp”: “2019-02-13T08:34:05Z” }, “timestamp”: “2019-02-13T08:33:38Z”, “window”: “30s”, “usage”: { “cpu”: “78322168n”, “memory”: “563180Ki” } }, { “metadata”: { “name”: “ip-10-1-57-40.ec2.internal”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/nodes/ip-10-1-57-40.ec2.internal”, “creationTimestamp”: “2019-02-13T08:34:05Z” }, “timestamp”: “2019-02-13T08:33:42Z”, “window”: “30s”, “usage”: { “cpu”: “48926263n”, “memory”: “554472Ki” } }, { “metadata”: { “name”: “ip-10-1-62-29.ec2.internal”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/nodes/ip-10-1-62-29.ec2.internal”, “creationTimestamp”: “2019-02-13T08:34:05Z” }, “timestamp”: “2019-02-13T08:33:36Z”, “window”: “30s”, “usage”: { “cpu”: “36700681n”, “memory”: “326088Ki” } } ]}查看pods metrics:kubectl get –raw “/apis/metrics.k8s.io/v1beta1/pods” | jq .结果如下:{ “kind”: “PodMetricsList”, “apiVersion”: “metrics.k8s.io/v1beta1”, “metadata”: { “selfLink”: “/apis/metrics.k8s.io/v1beta1/pods” }, “items”: [ { “metadata”: { “name”: “kube-proxy-77nt2”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-proxy-77nt2”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:00Z”, “window”: “30s”, “containers”: [ { “name”: “kube-proxy”, “usage”: { “cpu”: “2370555n”, “memory”: “13184Ki” } } ] }, { “metadata”: { “name”: “cluster-autoscaler-n2xsl”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/cluster-autoscaler-n2xsl”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:12Z”, “window”: “30s”, “containers”: [ { “name”: “cluster-autoscaler”, “usage”: { “cpu”: “1477997n”, “memory”: “54584Ki” } } ] }, { “metadata”: { “name”: “core-dns-autoscaler-b4785d4d7-j64xd”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/core-dns-autoscaler-b4785d4d7-j64xd”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:08Z”, “window”: “30s”, “containers”: [ { “name”: “autoscaler”, “usage”: { “cpu”: “191293n”, “memory”: “7956Ki” } } ] }, { “metadata”: { “name”: “spot-interrupt-handler-8t2xk”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/spot-interrupt-handler-8t2xk”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:04Z”, “window”: “30s”, “containers”: [ { “name”: “spot-interrupt-handler”, “usage”: { “cpu”: “844907n”, “memory”: “4608Ki” } } ] }, { “metadata”: { “name”: “kube-proxy-t5kqm”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-proxy-t5kqm”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:08Z”, “window”: “30s”, “containers”: [ { “name”: “kube-proxy”, “usage”: { “cpu”: “1194766n”, “memory”: “12204Ki” } } ] }, { “metadata”: { “name”: “kube-proxy-zxmqb”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube-proxy-zxmqb”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:06Z”, “window”: “30s”, “containers”: [ { “name”: “kube-proxy”, “usage”: { “cpu”: “3021117n”, “memory”: “13628Ki” } } ] }, { “metadata”: { “name”: “aws-node-rcz5c”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/aws-node-rcz5c”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:15Z”, “window”: “30s”, “containers”: [ { “name”: “aws-node”, “usage”: { “cpu”: “1217989n”, “memory”: “24976Ki” } } ] }, { “metadata”: { “name”: “aws-node-z2qxs”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/aws-node-z2qxs”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:15Z”, “window”: “30s”, “containers”: [ { “name”: “aws-node”, “usage”: { “cpu”: “1025780n”, “memory”: “46424Ki” } } ] }, { “metadata”: { “name”: “php-apache-899d75b96-8ppk4”, “namespace”: “default”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/default/pods/php-apache-899d75b96-8ppk4”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:08Z”, “window”: “30s”, “containers”: [ { “name”: “php-apache”, “usage”: { “cpu”: “24612n”, “memory”: “27556Ki” } } ] }, { “metadata”: { “name”: “load-generator-779c5f458c-9sglg”, “namespace”: “default”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/default/pods/load-generator-779c5f458c-9sglg”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:34:56Z”, “window”: “30s”, “containers”: [ { “name”: “load-generator”, “usage”: { “cpu”: “0”, “memory”: “336Ki” } } ] }, { “metadata”: { “name”: “aws-node-v9jxs”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/aws-node-v9jxs”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:00Z”, “window”: “30s”, “containers”: [ { “name”: “aws-node”, “usage”: { “cpu”: “1303458n”, “memory”: “28020Ki” } } ] }, { “metadata”: { “name”: “kube2iam-m2ktt”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube2iam-m2ktt”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:11Z”, “window”: “30s”, “containers”: [ { “name”: “kube2iam”, “usage”: { “cpu”: “1328864n”, “memory”: “9724Ki” } } ] }, { “metadata”: { “name”: “kube2iam-w9cqf”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube2iam-w9cqf”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:03Z”, “window”: “30s”, “containers”: [ { “name”: “kube2iam”, “usage”: { “cpu”: “1294379n”, “memory”: “8812Ki” } } ] }, { “metadata”: { “name”: “custom-metrics-apiserver-657644489c-pk8rb”, “namespace”: “monitoring”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/monitoring/pods/custom-metrics-apiserver-657644489c-pk8rb”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:04Z”, “window”: “30s”, “containers”: [ { “name”: “custom-metrics-apiserver”, “usage”: { “cpu”: “22409370n”, “memory”: “42468Ki” } } ] }, { “metadata”: { “name”: “kube2iam-qghgt”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/kube2iam-qghgt”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:11Z”, “window”: “30s”, “containers”: [ { “name”: “kube2iam”, “usage”: { “cpu”: “2078992n”, “memory”: “16356Ki” } } ] }, { “metadata”: { “name”: “spot-interrupt-handler-ps745”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/spot-interrupt-handler-ps745”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:10Z”, “window”: “30s”, “containers”: [ { “name”: “spot-interrupt-handler”, “usage”: { “cpu”: “611566n”, “memory”: “4336Ki” } } ] }, { “metadata”: { “name”: “coredns-68fb7946fb-2xnpp”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/coredns-68fb7946fb-2xnpp”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:12Z”, “window”: “30s”, “containers”: [ { “name”: “coredns”, “usage”: { “cpu”: “1610381n”, “memory”: “10480Ki” } } ] }, { “metadata”: { “name”: “coredns-68fb7946fb-9ctjf”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/coredns-68fb7946fb-9ctjf”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:13Z”, “window”: “30s”, “containers”: [ { “name”: “coredns”, “usage”: { “cpu”: “1418850n”, “memory”: “9852Ki” } } ] }, { “metadata”: { “name”: “prometheus-7d4f6d4454-v4fnd”, “namespace”: “monitoring”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/monitoring/pods/prometheus-7d4f6d4454-v4fnd”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:00Z”, “window”: “30s”, “containers”: [ { “name”: “prometheus”, “usage”: { “cpu”: “17951807n”, “memory”: “202316Ki” } } ] }, { “metadata”: { “name”: “metrics-server-7cdd54ccb4-k2x7m”, “namespace”: “kube-system”, “selfLink”: “/apis/metrics.k8s.io/v1beta1/namespaces/kube-system/pods/metrics-server-7cdd54ccb4-k2x7m”, “creationTimestamp”: “2019-02-13T08:35:19Z” }, “timestamp”: “2019-02-13T08:35:04Z”, “window”: “30s”, “containers”: [ { “name”: “metrics-server-nanny”, “usage”: { “cpu”: “144656n”, “memory”: “5716Ki” } }, { “name”: “metrics-server”, “usage”: { “cpu”: “568327n”, “memory”: “16268Ki” } } ] } ]}基于CPU和内存使用情况的Auto Scaling您将使用基于Golang的小型Web应用程序来测试Horizontal Pod Autoscaler(HPA)。将podinfo部署到默认命名空间:kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yaml使用NodePort服务访问podinfo,地址为http:// <K8S_PUBLIC_IP>:31198。接下来定义一个至少维护两个副本的HPA,如果CPU平均值超过80%或内存超过200Mi,则最多可扩展到10个:apiVersion: autoscaling/v2beta1kind: HorizontalPodAutoscalermetadata: name: podinfospec: scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: podinfo minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu targetAverageUtilization: 80 - type: Resource resource: name: memory targetAverageValue: 200Mi创建这个hpa:kubectl create -f ./podinfo/podinfo-hpa.yaml几秒钟后,HPA控制器联系度量服务器,然后获取CPU和内存使用情况:kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEpodinfo Deployment/podinfo 2826240 / 200Mi, 15% / 80% 2 10 2 5m为了增加CPU使用率,请使用rakyll / hey运行负载测试:#install heygo get -u github.com/rakyll/hey#do 10K requestshey -n 10000 -q 10 -c 5 http://<K8S_PUBLIC_IP>:31198/您可以使用以下方式监控HPA事件:$ kubectl describe hpaEvents: Type Reason Age From Message —- —— —- —- ——- Normal SuccessfulRescale 7m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target Normal SuccessfulRescale 3m horizontal-pod-autoscaler New size: 8; reason: cpu resource utilization (percentage of request) above target 暂时删除podinfo。稍后将在本教程中再次部署它:kubectl delete -f ./podinfo/podinfo-hpa.yaml,./podinfo/podinfo-dep.yaml,./podinfo/podinfo-svc.yaml部署 Custom Metrics Server要根据自定义指标进行扩展,您需要拥有两个组件。一个组件,用于从应用程序收集指标并将其存储在Prometheus时间序列数据库中。第二个组件使用collect(k8s-prometheus-adapter)提供的指标扩展了Kubernetes自定义指标API。您将在专用命名空间中部署Prometheus和适配器。创建monitoring命名空间:kubectl create -f ./namespaces.yaml在monitoring命名空间中部署Prometheus v2:kubectl create -f ./prometheus生成Prometheus适配器所需的TLS证书:make certs生成以下几个文件:# ls outputapiserver.csr apiserver-key.pem apiserver.pem部署Prometheus自定义指标API适配器:kubectl create -f ./custom-metrics-api列出Prometheus提供的自定义指标:kubectl get –raw “/apis/custom.metrics.k8s.io/v1beta1” | jq .获取monitoring命名空间中所有pod的FS使用情况:kubectl get –raw “/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitoring/pods//fs_usage_bytes” | jq .查询结果如下:{ “kind”: “MetricValueList”, “apiVersion”: “custom.metrics.k8s.io/v1beta1”, “metadata”: { “selfLink”: “/apis/custom.metrics.k8s.io/v1beta1/namespaces/monitoring/pods/%2A/fs_usage_bytes” }, “items”: [ { “describedObject”: { “kind”: “Pod”, “namespace”: “monitoring”, “name”: “custom-metrics-apiserver-657644489c-pk8rb”, “apiVersion”: “/v1” }, “metricName”: “fs_usage_bytes”, “timestamp”: “2019-02-13T08:52:30Z”, “value”: “94253056” }, { “describedObject”: { “kind”: “Pod”, “namespace”: “monitoring”, “name”: “prometheus-7d4f6d4454-v4fnd”, “apiVersion”: “/v1” }, “metricName”: “fs_usage_bytes”, “timestamp”: “2019-02-13T08:52:30Z”, “value”: “24576” } ]}基于custom metrics 自动伸缩在默认命名空间中创建podinfo NodePort服务和部署:kubectl create -f ./podinfo/podinfo-svc.yaml,./podinfo/podinfo-dep.yamlpodinfo应用程序公开名为http_requests_total的自定义指标。 Prometheus适配器删除_total后缀并将度量标记为计数器度量标准。从自定义指标API获取每秒的总请求数:kubectl get –raw “/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods//http_requests” | jq .{ “kind”: “MetricValueList”, “apiVersion”: “custom.metrics.k8s.io/v1beta1”, “metadata”: { “selfLink”: “/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/http_requests” }, “items”: [ { “describedObject”: { “kind”: “Pod”, “namespace”: “default”, “name”: “podinfo-6b86c8ccc9-kv5g9”, “apiVersion”: “/__internal” }, “metricName”: “http_requests”, “timestamp”: “2018-01-10T16:49:07Z”, “value”: “901m” }, { “describedObject”: { “kind”: “Pod”, “namespace”: “default”, “name”: “podinfo-6b86c8ccc9-nm7bl”, “apiVersion”: “/__internal” }, “metricName”: “http_requests”, “timestamp”: “2018-01-10T16:49:07Z”, “value”: “898m” } ]}建一个HPA,如果请求数超过每秒10个,将扩展podinfo部署:apiVersion: autoscaling/v2beta1kind: HorizontalPodAutoscalermetadata: name: podinfospec: scaleTargetRef: apiVersion: extensions/v1beta1 kind: Deployment name: podinfo minReplicas: 2 maxReplicas: 10 metrics: - type: Pods pods: metricName: http_requests targetAverageValue: 10 在默认命名空间中部署podinfo HPA:kubectl create -f ./podinfo/podinfo-hpa-custom.yaml几秒钟后,HPA从指标API获取http_requests值:kubectl get hpaNAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGEpodinfo Deployment/podinfo 899m / 10 2 10 2 1m在podinfo服务上应用一些负载,每秒25个请求:#install heygo get -u github.com/rakyll/hey#do 10K requests rate limited at 25 QPShey -n 10000 -q 5 -c 5 http://<K8S-IP>:31198/healthz几分钟后,HPA开始扩展部署:kubectl describe hpaName: podinfoNamespace: defaultReference: Deployment/podinfoMetrics: ( current / target ) “http_requests” on pods: 9059m / 10Min replicas: 2Max replicas: 10Events: Type Reason Age From Message —- —— —- —- ——- Normal SuccessfulRescale 2m horizontal-pod-autoscaler New size: 3; reason: pods metric http_requests above target按照当前的每秒请求速率,部署永远不会达到10个pod的最大值。三个复制品足以使每个吊舱的RPS保持在10以下。负载测试完成后,HPA会将部署缩到其初始副本:Events: Type Reason Age From Message —- —— —- —- ——- Normal SuccessfulRescale 5m horizontal-pod-autoscaler New size: 3; reason: pods metric http_requests above target Normal SuccessfulRescale 21s horizontal-pod-autoscaler New size: 2; reason: All metrics below target您可能已经注意到自动缩放器不会立即对使用峰值做出反应。默认情况下,度量标准同步每30秒发生一次,只有在最后3-5分钟内没有重新缩放时才能进行扩展/缩小。通过这种方式,HPA可以防止快速执行冲突的决策,并为Cluster Autoscaler提供时间。结论并非所有系统都可以通过单独依赖CPU /内存使用指标来满足其SLA,大多数Web和移动后端需要基于每秒请求进行自动扩展以处理任何流量突发。对于ETL应用程序,可以通过作业队列长度超过某个阈值等来触发自动缩放。通过使用Prometheus检测应用程序并公开正确的自动缩放指标,您可以对应用程序进行微调,以更好地处理突发并确保高可用性。 ...

February 13, 2019 · 6 min · jiezi

CNCF案例研究:奇虎360

公司:奇虎360地点:中国北京行业:计算机软件挑战中国软件巨头奇虎360科技的搜索部门,so.com是中国第二大搜索引擎,市场份额超过35%。该公司一直在使用传统的手动操作来部署环境,随着项目数量的不断增加,管理层希望提高服务器资源的利用率。“我们希望解决为大量项目构建运营环境的效率问题。”搜索云平台项目发起人之一郭少巍说。解决方法大约三年前,360开始规划容器云服务。该公司现在拥有完整的PaaS解决方案,该解决方案围绕Kubernetes编排、Prometheus监控、gRPC、CoreDNS和Harbor仓库,此外还使用Wayne(开源)部署项目。“我们主要在搜索部门的开发和交付过程中推广容器技术,以提供业务效率和服务质量。”郭说。影响自从切换到由Kubernetes管理容器,开发者开始编写新项目的业务需求代码的设置时间从2-6小时减少到10-30分钟。将应用程序部署到容器云环境后,服务器成本是最初在360使用的物理机解决方案的55%,以及之前传统虚拟化解决方案(VPS)的82%,同时确保相同的性能和可用性。此外,最近在一个小时内完成了大规模的计算机房迁移,这个迁移以前需要一周才能完成。“Kubernetes提供了完整和高度集成的功能组件,我们只需少量的开发工作即可满足业务需求。”郭少巍,奇虎360搜索云平台项目发起人中国软件巨头奇虎360科技的搜索部门,so.com是中国第二大搜索引擎,市场份额超过35%。 该公司一直在使用传统的手动操作来部署环境,随着项目数量的不断增加,管理层希望提高服务器资源的利用率。“我们希望解决为大量项目构建运营环境的效率问题。”搜索云平台项目发起人之一郭少巍说。大约三年前,360开始规划容器云系统。“我们评估了三种编排技术,最终选择了Kubernetes,因为它提供了完整和高度集成的功能组件,”郭说,“我们只需要少量的开发工作就能满足业务需求。”“将服务容器化并投入我们的云平台之后,完成两个计算机房的迁移只需一个小时左右,这是效率的极大提升。”郭少巍,奇虎360搜索云平台项目发起人该公司现在拥有完整的PaaS解决方案,该解决方案围绕Kubernetes编排、Prometheus监控、Harbor仓库和Wayne(开源)部署项目构建。该平台在很大程度上依赖于开源组件,包括CNCF项目gRPC和CoreDNS,以及InfluxDB、Kafka和Ceph。“我们主要在搜索部门的开发和交付过程中推广容器技术,以提供业务效率和服务质量。”郭说。事实上,这些云原生技术带来了更高的效率。自从切换到由Kubernetes管理容器,开发者开始编写新项目的业务需求代码的设置时间已从2-6小时减少到10-30分钟。应用程序部署到容器云环境后,服务器成本是最初在360使用的物理机解决方案的55%,以及之前传统虚拟化解决方案(VPS)的82%,同时确保相同的性能和可用性。“过去两年,我们的部门经历了两次大规模的计算机房迁移。过去,对于运营和开发而言,这是非常痛苦的,因为他们必须密切合作一周左右才能完成整个在线服务的迁移。”郭少巍,奇虎360搜索云平台项目发起人此外,最近在一个小时内完成了大规模的计算机房迁移,这个迁移以前需要一周才能完成。“我们的部门在过去两年里经历了两次大规模的计算机房迁移,”郭说。“过去,对于运营和开发而言,这是非常痛苦的,因为他们必须密切合作一周左右才能完成整个在线服务的迁移。但是,在将服务容器化并投入云平台之后,完成两个房间的迁移只需要一个小时左右,这是效率的极大提升。”云平台仍处于早期阶段。“我们仍在推动FaaS的实施和业务应用,预计将有10-20%的业务迁移到平台。”郭说。“对于初创公司或技术实力较弱的公司,我认为选择成熟的开源解决方案将使公司能够专注于业务需求,避免在基本平台开发的早期投入太多资源。”郭少巍,奇虎360搜索云平台项目发起人最后,该公司开源其平台项目Wayne。Wayne基于Kubernetes,以满足企业管理需求。该团队也非常乐意与其他想要沿着云原生路径前进的组织分享其经验和建议。“对于创业公司或技术实力较弱的公司,我认为选择成熟的开源解决方案将使公司能够专注于业务需求,避免在基本平台开发的早期投入太多资源,”郭说。最终,努力是值得的。对于360,“业务效率大大提高。”KubeCon + CloudNativeCon中国论坛提案征集(CFP)2月22日截止KubeCon + CloudNativeCon 论坛让用户、开发人员、从业人员汇聚一堂,面对面进行交流合作。与会人员有 Kubernetes、Prometheus 及其他云原生计算基金会 (CNCF) 主办项目的领导,和我们一同探讨云原生生态系统发展方向。中国开源峰会提案征集(CFP)2月22日截止在中国开源峰会上,与会者将共同合作及共享信息,了解最新和最有趣的开源技术,包括Linux、IoT、区块链、AI、网络等;并获得如何在开源社区中导向和引领的信息。大会日期:提案征集截止日期:太平洋标准时间 2 月 22 日,星期五,晚上 11:59提案征集通知日期:2019 年 4 月 8 日会议日程通告日期:2019 年 4 月 10 日会议活动举办日期:2019 年 6 月 24 至 26 日提醒:这是一场社区会议。因此,让我们尽量避开公然推销产品和/或供应商销售宣传。KubeCon + CloudNativeCon + Open Source Summit赞助方案出炉啦KubeCon + CloudNativeCon + Open Source Summit多元化奖学金现正接受申请

February 11, 2019 · 1 min · jiezi

Prometheus 联邦及高可用详解

Prometheus 联邦及高可用详解以下所有操作都是在k8s集群中完成,如果你是VM或者物理机在配置方面不会有太大区别;Prometheus 高可用当Exporter或者采集信息需要越来越多时就会考虑高可用,高可用优点不会因为集群中某个节点down而导致Prometheus不可用,可以让算力下沉; 缺点是A-Prometheus和B-Prometheus这两个实例会定时去scrape数据,并且存储在各本地,这样导致数据会存储两份;高可用配置将Prometheus启动两个实例,配置一样只需要暴露的service的端口不同,‘Nginx Controller’配置session-affinity的service名称;Prometheus 联邦在多个数据中心部署Prometheus需要将多数据中心数据合在一起管理,使用联邦模式非常合适,如果担心数据单点,可以在联邦的基础上再扩展高可用; 优点集中式管理数据,报警,不需要为每个Prometheus实例管理数据,如有些敏感节点报警要求高可以在Prometheus数据节点上加报警信息,可以按功能环境划分启动多个Prometheus采集实例; 缺点数据集中化,网络可能会延时,数据单点等问题;终级解决方案Prometheus 是支持远程读写TSDB数据库,请看官方网站支持哪些数据库的读写,因为有些数据只支持写而不支持读,你内网搭建TSDB集群,你所有启动的Prometheus实例都把数据写入到远程数据库,再使用高可用方案支持查询,只支持远程读,这样就可无限扩展采集实例和查询实例,非常的爽,作者没有实践过只是YY中;采集的Metrics远程写入TSDBPrometheus远程读TSDB文章会持续更新,文章中有不好之处欢迎留言

January 18, 2019 · 1 min · jiezi

pushgateway on k8s 部署yaml

pushgateway on k8s 部署yamlprometheus pushgateway部署的yaml文件pushgateway的deployment文件内容apiVersion: apps/v1beta2kind: Deploymentmetadata: namespace: kube-ops name: pushgateway-ttt labels: app: pushgateway-ttt annotations: prometheus.io/scrape: “true” prometheus.io/port: “8080"spec: replicas: 1 revisionHistoryLimit: 0 selector: matchLabels: app: pushgateway-ttt strategy: type: RollingUpdate rollingUpdate: maxSurge: “25%” maxUnavailable: “25%” template: metadata: name: pushgateway-ttt labels: app: pushgateway-ttt spec: containers: - name: pushgateway-ttt image: prom/pushgateway:v0.7.0 imagePullPolicy: IfNotPresent livenessProbe: initialDelaySeconds: 600 periodSeconds: 10 successThreshold: 1 failureThreshold: 10 httpGet: path: / port: 9091 ports: - name: “app-port” containerPort: 9091 resources: limits: memory: “1000Mi” cpu: 1 requests: memory: “1000Mi” cpu: 1prom/pushgateway可以在hub.docker.io查到dockerfile文件及部署说明pushgateway的service文件内容apiVersion: v1kind: Servicemetadata: name: pushgateway-ttt namespace: kube-ops labels: app: pushgateway-tttspec: selector: app: pushgateway-ttt #type: NodePort ports: - name: pushgateway-ttt port: 9091 targetPort: 9091pushgateway的ingress文件内容apiVersion: extensions/v1beta1kind: Ingressmetadata: name: pushgateway-ingress namespace: kube-ops annotations: kubernetes.io/ingress.class: nginxspec: rules: - host: push-prometheus.ttt.mucang.cn http: paths: - path: / backend: serviceName: pushgateway-ttt servicePort: 9091在Prometheus中配置pushgateway及pull pushgateway数据配置# prometheus配置文件中配置pull pushgateway组件配置- job_name: ‘pushgateway’ scrape_interval: 60s metrics_path: /metrics static_configs: - targets: [“push-prometheus.xxx.xx.xx]# prometheus的deployment配置文件配置环境变量,这样prometheus才会去pull pushgateway缓存的数据env: - name: PUSH_GATEWAY value: “http://push-prometheus.ttt.mucang.cn” ...

January 9, 2019 · 1 min · jiezi

Prometehus自动发现Docker Swarm Overlay网络中的容器

原文地址介绍如何使用Prometheus的dns service discovery机制,自动发现并抓取Docker swarm overlay网络中的容器所提供的指标。使用docker service create/docker stack deploy能够很方便管理多个docker host,并且对应用做扩缩容。那么我们如何抓取这些动态创建的容器应用所提供的指标呢?在《使用Prometheus+Grafana监控JVM》一文里我们使用了static_config静态配置指标抓取目标,这显然在docker swarm环境里是不合适的。我们需要一种动态发现容器的方法。解决思路如下:使用《一种生产环境Docker Overlay Network的配置方案》提到的方法配置overlay网络,并且把docker service、stack、standalone container都挂到这个overlay网络里。把Prometheus也挂到这个overlay网络里。使用Prometheus的DNS service discovery机制,半自动的发现容器。本文所提到的脚本可以在这里下载下面构建一个实验环境以说明方法。第一步:构建overlay network根据《一种生产环境Docker Overlay Network的配置方案》里提到的方法,创建Docker swarm,和一个overlay网络,名字叫做test-overlay:docker network create -d overlay –attachable test-overlay第二步:启动容器为了方便起见,使用prometheus-mock-data来模拟一个提供指标的应用,这样就能够避免繁琐的jmx-exporter。1) 新建一个目录,名字叫做docker-swarm-demo2) 新建一个文件scrape-data.txt,这个文件就是我们要提供的假指标,内容如下:# HELP x mock metric# TYPE x gaugex 1—# HELP x mock metric# TYPE x gaugex 2—# HELP x mock metric# TYPE x gaugex 3—# HELP x mock metric# TYPE x gaugex 43) 为了演示docker service和standalone container都能被采集到,会启动这两种形式的容器:4) 使用docker service create启动一个service,replicas=3(注意–name参数):docker service create \ –name mock \ –replicas 3 \ –network test-overlay \ –limit-memory 96M \ –mount type=bind,src=$(pwd)/scrape-data.txt,dst=/home/java-app/etc/scrape-data.txt \ chanjarster/prometheus-mock-data:latest4) 使用docker run启动一个standalone container(注意–name参数):docker run -d \ -v $(pwd)/scrape-data.txt:/home/java-app/etc/scrape-data.txt \ –network test-overlay \ –name standalone-mock \ chanjarster/prometheus-mock-data:latest第三步:启动Prometheus1) 在之前新建目录docker-swarm-demo里创建文件prom-config.yml,内容如下:scrape_configs: - job_name: ‘swarm-service’ scrape_interval: 30s dns_sd_configs: - names: - tasks.mock - standalone-mock type: A port: 8080 relabel_configs: - source_labels: [’__meta_dns_name’] target_label: ‘service’注意到上面的两个关键配置:设定了两个DNS A记录,tasks.mock和standalone-mock。tasks.mock是Docker自动为docker service mock创建的,而standalone-mock就是容器名。文章最开始说到的半自动就是这个意思,我们得事先知道DNS A记录有哪些,然后让Prometheus去发现这些DNS A记录背后对应的容器有哪些。把__meta_dns_name的值设置到指标的service 这个label里。2) 启动Prometheus:docker run -d \ –name=prometheus \ –network test-overlay \ -p 9090:9090 \ -v $(pwd):/prometheus-config \ -v $(pwd)/prom-data:/prometheus \ prom/prometheus –config.file=/prometheus-config/prom-config.yml3) 访问 http://localhost:9090 看看Prometheus是否启动成功,在输入框里输入x然后执行,应该可以看到如下图的结果:其中3个instance是属于tasks.mock的,还有一个则是standalone container(如果没有看到4个instance,那么等一会儿再试)。 ...

January 9, 2019 · 1 min · jiezi

使用prometheus operator监控envoy

kubernetes集群三步安装概述prometheus operator应当是使用监控系统的最佳实践了,首先它一键构建整个监控系统,通过一些无侵入的手段去配置如监控数据源等故障自动恢复,高可用的告警等。。不过对于新手使用上还是有一丢丢小门槛,本文就结合如何给envoy做监控这个例子来分享使用prometheus operator的正确姿势至于如何写告警规则,如何配置prometheus查询语句不是本文探讨的重点,会在后续文章中给大家分享,本文着重探讨如何使用prometheus operatorprometheus operator安装sealyun离线安装包内已经包含prometheus operator,安装完直接使用即可配置监控数据源原理:通过operator的CRD发现监控数据源service启动envoyapiVersion: apps/v1kind: Deploymentmetadata: name: envoy labels: app: envoyspec: replicas: 1 selector: matchLabels: app: envoy template: metadata: labels: app: envoy spec: volumes: - hostPath: # 为了配置方便把envory配置文件挂载出来了 path: /root/envoy type: DirectoryOrCreate name: envoy containers: - name: envoy volumeMounts: - mountPath: /etc/envoy name: envoy readOnly: true image: envoyproxy/envoy:latest ports: - containerPort: 10000 # 数据端口 - containerPort: 9901 # 管理端口,metric是通过此端口暴露—kind: ServiceapiVersion: v1metadata: name: envoy labels: app: envoy # 给service贴上标签,operator会去找这个servicespec: selector: app: envoy ports: - protocol: TCP port: 80 targetPort: 10000 name: user - protocol: TCP # service暴露metric的端口 port: 81 targetPort: 9901 name: metrics # 名字很重要,ServiceMonitor 会找端口名envoy配置文件:监听的地址一定需要修改成0.0.0.0,否则通过service获取不到metric/root/envoy/envoy.yamladmin: access_log_path: /tmp/admin_access.log address: socket_address: protocol: TCP address: 0.0.0.0 # 这里一定要改成0.0.0.0,而不能是127.0.0.1 port_value: 9901static_resources: listeners: - name: listener_0 address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 10000 filter_chains: - filters: - name: envoy.http_connection_manager config: stat_prefix: ingress_http route_config: name: local_route virtual_hosts: - name: local_service domains: ["*"] routes: - match: prefix: “/” route: host_rewrite: sealyun.com cluster: service_google http_filters: - name: envoy.router clusters: - name: service_sealyun connect_timeout: 0.25s type: LOGICAL_DNS # Comment out the following line to test on v6 networks dns_lookup_family: V4_ONLY lb_policy: ROUND_ROBIN hosts: - socket_address: address: sealyun.com port_value: 443 tls_context: { sni: sealyun.com }使用ServiceMonitorenvoyServiceMonitor.yaml:apiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: labels: app: envoy name: envoy namespace: monitoring # 这个可以与service不在一个namespace中spec: endpoints: - interval: 15s port: metrics # envoy service的端口名 path: /stats/prometheus # 数据源path namespaceSelector: matchNames: # envoy service所在namespace - default selector: matchLabels: app: envoy # 选择envoy servicecreate成功后我们就可以看到envoy的数据源了:然后就可以看到metric了:然后就可以在grafana上进行一些配置了,promethues相关使用不是本文讨论的对象告警配置alert manager配置[root@dev-86-201 envoy]# kubectl get secret -n monitoringNAME TYPE DATA AGEalertmanager-main Opaque 1 27d我们可以看到这个secrect,看下里面具体内容:[root@dev-86-201 envoy]# kubectl get secret alertmanager-main -o yaml -n monitoringapiVersion: v1data: alertmanager.yaml: Imdsb2JhbCI6IAogICJyZXNvbHZlX3RpbWVvdXQiOiAiNW0iCiJyZWNlaXZlcnMiOiAKLSAibmFtZSI6ICJudWxsIgoicm91dGUiOiAKICAiZ3JvdXBfYnkiOiAKICAtICJqb2IiCiAgImdyb3VwX2ludGVydmFsIjogIjVtIgogICJncm91cF93YWl0IjogIjMwcyIKICAicmVjZWl2ZXIiOiAibnVsbCIKICAicmVwZWF0X2ludGVydmFsIjogIjEyaCIKICAicm91dGVzIjogCiAgLSAibWF0Y2giOiAKICAgICAgImFsZXJ0bmFtZSI6ICJEZWFkTWFuc1N3aXRjaCIKICAgICJyZWNlaXZlciI6ICJudWxsIg==kind: Secretbase64解码一下:“global”: “resolve_timeout”: “5m"“receivers”:- “name”: “null"“route”: “group_by”: - “job” “group_interval”: “5m” “group_wait”: “30s” “receiver”: “null” “repeat_interval”: “12h” “routes”: - “match”: “alertname”: “DeadMansSwitch” “receiver”: “null"所以配置alertmanager就非常简单了,就是创建一个secrect即可如alertmanager.yaml:global: smtp_smarthost: ‘smtp.qq.com:465’ smtp_from: ‘474785153@qq.com’ smtp_auth_username: ‘474785153@qq.com’ smtp_auth_password: ‘xxx’ # 这个密码是开启smtp授权后生成的,下文有说怎么配置 smtp_require_tls: falseroute: group_by: [‘alertmanager’,‘cluster’,‘service’] group_wait: 30s group_interval: 5m repeat_interval: 3h receiver: ‘fanux’ routes: - receiver: ‘fanux’receivers:- name: ‘fanux’ email_configs: - to: ‘474785153@qq.com’ send_resolved: truedelete掉老的secret,根据自己的配置重新生成secret即可kubectl delete secret alertmanager-main -n monitoringkubectl create secret generic alertmanager-main –from-file=alertmanager.yaml -n monitoring邮箱配置,以QQ邮箱为例开启smtp pop3服务 照着操作即可,后面会弹框一个授权码,配置到上面的配置文件中然后就可以收到告警了:告警规则配置prometheus operator自定义PrometheusRule crd去描述告警规则[root@dev-86-202 shell]# kubectl get PrometheusRule -n monitoringNAME AGEprometheus-k8s-rules 6m直接edit这个rule即可,也可以再自己去创建个PrometheusRulekubectl edit PrometheusRule prometheus-k8s-rules -n monitoring如我们在group里加一个告警:spec: groups: - name: ./example.rules rules: - alert: ExampleAlert expr: vector(1) - name: k8s.rules rules:重启prometheuspod:kubectl delete pod prometheus-k8s-0 prometheus-k8s-1 -n monitoring然后在界面上就可以看到新加的规则:探讨可加QQ群:98488045公众号: ...

January 3, 2019 · 2 min · jiezi

Prometheus range query中的step参数

GH Page地址Prometheus有两种query:instant query、range query。本文要讲的就是range query中的step参数。range query是非常常见的一种query,看看它有哪些参数:query=<string>: PromQL表达式。start=<rfc3339 | unix_timestamp>: 时间范围的开始。end=<rfc3339 | unix_timestamp>: 时间范围的结束。step=<duration | float>: 查询解析度(query resolution)。timeout=<duration>: 执行超时。这个参数是可选的。在Prometheus expression browser里看到的是这样的:注意到上图中的Res框里没有给值,没有给的话Prometheus会自动给一个值,这个值在图示右上角可以看到。step对于查询结果的影响Prometheues在对PromQL表达式求值的逻辑是这样的(详见这个issue里的回答):对于[start, end]时间区间,从start开始,以step为长度,把时间区间分成若干段对每个段进行求值举例:start=10,end=20,step=2,那么就会有ts=10,ts=12,ts=14,ts=16,ts=18,ts=206段,然后为这6个段进行求值。求值方式视乎表达式中Time series selector的类型而定。PromQL有两种Time series selector:instant vector selector和range vector selector。下面将分别讲解:Instant vector selector形如下面的就是Instant vector selector,x是metric的名字。xPrometheus在对每段Instant vector selector求值的逻辑是这样的:从该段的timestamp(含)往前找,取第一个找到的data point的值。如果有一个data point的timestamp==该段的timestamp,则直接使用该data point。如果该段timestamp往前的5分钟范围内没有找到任何data point,则该段无值。下面这张图解释了上面逻辑:图中的绿点是Prometheus实际存储的数据,按照时间轴从左到右排列。蓝点是根据step参数的求值结果。当data point间隔比step更大的时候会发生下图这种情况:可以看到有两个段的求值结果来自于同一个data point。Range vector selector形如下面的就是Range vector selector,x是metric的名字,方括号里的是range duration。x[5m]range vector select返回的是当前timestamp之前的range duration内的所有data point。range vector是不能直接用做绘图的,你得用某些function把range vector转换成instant vector才行,比如rate()。下图解释了是如何对Range vector selector进行分段求值的:step和rate durationstep和range duration是独立的两个参数,在某些情况下两者的值存在某种限制条件,这里例举rate()来说明。rate()的作用是获得一个range-vector的每秒平均增长率。如果step=10m而range duration=5m,那么rate在计算的时候会丢失一半的数据,两个分段之间的data point有一半没有被纳入计算。前面那张图就存在数据丢失的情况,有一个data point被漏掉了。因此在使用rate()时,range duration得大于等于step。而如果是irate(),这个限制则是range duration不得大于step(详见Brian Brazil的Presentation)。Grafana中的step参数在Grafana中并没有直接提供step参数,而是这两个参数:min step和resolution(文档在这里)。min step故名思义设定的是step的最小值,那么resolution是什么呢?大家都知道Grafana都是用来画图的,比如下面这张图Y轴是值,X轴则是时间线,因此在X轴方向的每个像素都代表了一个timestamp。resolution就是用来根据像素来计算step的一个参数。下面用6个像素以及它们的timestamp来说明:x=1,ts=0; x=2,ts=5; x=3,ts=10; x=4,ts=15; x=5,ts=20; x=6,ts=25resolution=1/1时,那么step就是相邻像素所代表的timestamp的差,即5;resolution=1/2时,那么step就是相隔1个像素的两个像素的timestamp的差,即10;resolution=1/3时,那么step就是相隔2个像素的两个像素的timestamp的差,即15;以此类推而每个像素所代表的timestamp受两个因素影响:查询所定义的时间范围Graph的宽度(单位:像素)所以在Grafana发起的查询中step参数是动态的。其实这也是很合理的,因为只有这样才能够在Graph宽度小的时候绘图更粗糙(即step更大),Graph宽度大的时候绘图更精细(即step更小,但是不能小于min step)。实际发起的请求的step参数你可以在Graph的Query Inspector里看到:但是我们之前不说过了rate()的range duration不能小于step吗?那么把range duration给固定值的化就不太好了,怎么办呢?你可以使用Grafana提供的内置变量$__interval,它代表的Grafana就是计算出来的step的值。比如这样就能够将range duration和step保持一致了(更多内置变量可以见这里):rate(x[$__interval])所以,你想自己实验一把如果你想自己动手实验,但是又苦于无法制造干净的假数据,那么可以参考这篇文章推荐的方法。 ...

December 28, 2018 · 1 min · jiezi

给Prometheus造假数据的方法

GH Page地址学习Prometheus各种函数的时候最好能够造一些我们想要的数据来测试,但是Prometheus没有提供直接操作其数据库的功能,所以在这里安利一个工具。下面讲一下步骤:提供假指标数据我做了一个提供假指标的工具prometheus-mock-data。利用这个工具我们可以提供给Prometheus我们想提供给它的指标,这样便于后面的测试。新建一个文件scrape-data.txt,内容见gist,这个文件里定义了每次Prometheus抓指标的时候所能抓到的值,这个工具会依次提供这些指标(当然你也可以写自己的假数据)。运行:docker run -d –rm \ –name=mock-metrics \ -v $(pwd)/scrape-data.txt:/home/java-app/etc/scrape-data.txt \ -p 8080:8080 \ chanjarster/prometheus-mock-data:latest用浏览器访问:http://localhost:8080/metrics,刷新几次,能够看到指标数据在循环显示。启动Prometheus新建配置文件:scrape_configs: - job_name: ‘mock’ scrape_interval: 15s static_configs: - targets: - ‘<docker-host-machine-ip>:8080’注意:Data point的间隔通过scrape_interval参数控制。启动:docker run -d \ –name=prometheus \ -p 9090:9090 \ -v $(pwd)/prom-config.yml:/prometheus-config/prom-config.yml \ prom/prometheus –config.file=/prometheus-config/prom-config.yml打开http://localhost:9090看看是不是抓到指标了。启动Grafanadocker run -d \ –name=grafana \ -p 3000:3000 \ grafana/grafana在Grafana里配置Prometheus数据源,然后作图。

December 28, 2018 · 1 min · jiezi

Cortex:多租户、可横向扩展的Prometheus即服务

作者:Luc PerkinsPrometheus是用于监控和可观察性的标准开源解决方案之一。 Prometheus于2012年起源于SoundCloud,迅速获得广泛采用,后来成为首批CNCF项目之一,第二个毕业项目(仅次于Kubernetes)。它被许多具有前瞻性思维的公司用于生产,包括DigitalOcean、Fastly和Weaveworks等重量级公司,并拥有自己的年度会议PromCon。Prometheus:强大但有意地限制Prometheus之所以成功,部分原因是核心Prometheus服务器及其各种补充程序,如Alertmanager、Grafana和导出生态系统,形成了一个引人注目的端到端解决方案,解决了一个至关重要的难题。但是,Prometheus并没有提供你期望从一个成熟的“即服务”平台中获得的一些功能,例如多租户、身份验证和授权以及内置的长期存储。Cortex于9月作为沙箱项目加入CNCF,是一个开源的Prometheus即服务平台,旨在填补这些空白,从而提供完整、安全、多租户的Prometheus体验。我会在以下说很多关于Cortex的,首先,让我们短暂地游览更熟悉的Prometheus世界。为何选择Prometheus?作为CNCF开发者的倡导者,我有机会熟悉Prometheus社区和Prometheus作为工具(主要研究文档和Prometheus Playground)。由于各种原因,它的巨大成功对我来说并不奇怪:Prometheus实例易于部署和管理。我特别喜欢近乎即时的配置重新加载,以及所有Prometheus组件都提供静态二进制文件。Prometheus提供了简单易用的指标展示格式,可以轻松编写自己的指标导出器。这种格式甚至通过OpenMetrics项目(最近也加入了CNCF沙箱)变成了开放标准。Prometheus提供了简单,但功能强大的基于标签的查询语言PromQL,用于处理时间序列数据。我觉得PromQL非常直观。为何选择Prometheus即服务?早期,Prometheus的核心工程师做出明智的决定,让Prometheus保持简洁和可组合。从一开始,Prometheus设计成可以很好地完成一小部分工作,并与其他可选组件无缝协作(而不是让Prometheus负担过重,增加了一系列硬编码功能和集成)。以下是Prometheus设计范围外的一些内容:长期存储 - 单个Prometheus实例提供持久存储时间序列数据,但它们不能作为分布式数据存储系统,不提供像具有跨节点复制和自动修复等功能。这意味着,耐久性保证仅限于单台机器。幸运的是,Prometheus提供了一个远程写入API,可用于将时间序列数据传输到其他系统。全局数据视图 - 如上面要点所述,Prometheus实例充当隔离数据存储单元。Prometheus实例可以联邦,但这会给Prometheus设置增加很多复杂性,而且Prometheus不是设计为分布式数据库。这意味着,没有简单的途径来实现时间序列数据的单一,一致的“全局”视图。多租户 - Prometheus本身没有的租户概念。这意味着,它无法对特定于租户的数据访问和资源使用配额等事物,提供任何形式的细粒度控制。为何选择Cortex?作为Prometheus即服务平台,Cortex充分填补所有这些关键缺口,为即使是最苛刻的监控和可观察性使用案例,提供了完整的开箱即用解决方案。它支持四种开箱即用的长期存储系统:AWS DynamoDB、AWS S3、Apache Cassandra和Google Cloud Bigtable。它提供了Prometheus时间序列数据的全局视图,其中包括长期存储中的数据,极大地扩展了PromQL用于分析目的的有用性。它的核心支持多租户。通过Cortex的所有Prometheus指标都与特定租户相关联。Cortex的架构Cortex具有基于服务的设计,其基本功能分为单个用途组件,可以独立扩展:Distributor - 使用Prometheus的远程写入API处理由Prometheus实例写入Cortex的时间序列数据。传入数据会自动复制和分片,并且并行发送到多个Cortex Ingester。Ingester - 从distributor节点接收时间序列数据,然后将该数据写入长期存储后端,压缩数据到Prometheus块以提高效率。Ruler - 执行规则并生成警报,将它们发送到Alertmanager(Cortex安装包括Alertmanager)。Querier - 处理来自客户端(包括Grafana仪表板)的PromQL查询,对短期时间序列数据和长期存储中的样本进行抽象。这些组件每一个都可以独立管理,这是Cortex可扩展性和运营的关键。你可以在下面看到Cortex及与其交互的系统的基本图表:如图所示,Cortex“完成”Prometheus监控系统。要适应现有的Prometheus安装,你只需重新配置Prometheus实例以远程写入Cortex群集,Cortex将处理其余部分。多租户单租户系统往往适用于小型用例和非生产环境,但对于拥有大量团队、用例和环境的大型组织而言,这些系统变得站不住脚(没有双关语意)。为了满足这些大型组织的严格要求,Cortex不是作为附加组件或插件提供多租户,而是作为头等功能。多租户被编织到Cortex的结构中。从Prometheus实例到达Cortex的所有时间序列数据,都在请求元数据中标记所属于的特定租户。从那里,该数据只能由同一个租户查询。警报也是多租户,每个租户都可以使用Alertmanager配置设定自己的警报。从本质上讲,每个租户都有自己的系统“视图”,其自身以Prometheus为中心的世界。如果你以单租户的方式使用Cortex,你可以随时扩展到无限大的租户群。用例经过几年的发展,Cortex的用户倾向于分为两大类:服务供应商构建托管的管理平台,提供监控和可观察性组件。例如,如果你正在构建像Heroku或Google App Engine这样的平台即服务产品,Cortex使你能够为平台上运行的每个应用程序,提供Prometheus提供的全部功能,并处理每个应用程序( 或者每个帐户或客户)作为系统的单独租户。Weave Cloud和Grafana Labs使用Cortex使客户能够充分利用Prometheus,他们是综合云平台的示例。企业拥有许多内部客户,运行自己的应用程序、服务和“堆栈”。EA和StorageOS是受益于Cortex的大型企业的例子。Cortex、Prometheus的生态系统和CNCFCortex有一些非常引人注目的技术特性,但在当前的行业氛围下,我也认为指出其开源特性也很重要:Cortex使用Apache 2.0许可授权,并由CNCF支持。它仅与其他Apache 2.0 CNCF项目紧密耦合,没有与闭源、专有或特定于供应商技术的强链接。项目合作者包括像Goutham Veeramachaneni和Tom Wilkie这样的Prometheus核心维护者,来自Weaveworks、Grafana Labs、Platform9等公司的工程师,以及其他大量投资于监控和可观察性领域的工程师。Cortex已经投入生产,为Weave Cloud和Grafana Cloud提供支持,这两个云产品(和核心贡献者)的成功关键取决于Cortex未来的发展轨迹。通过在CNCF沙箱中添加Cortex,现在CNCF保护伞下有三个与Prometheus相关的项目(包括Prometheus本身和OpenMetrics)。我们知道监控和可观察性是云原生范式的重要组成部分,我们很高兴看到围绕Prometheus社区有机出现的一些核心基础的持续融合。Cortex项目正在大力推进这项工作,我很兴奋Prometheus生态系统的Prometheus即服务分支成型。

December 21, 2018 · 1 min · jiezi

如何在多Kubernetes集群和多租户环境中使用Prometheus监控

过去十年里,我一直在虚拟化和云计算领域工作,在VMware、Mercury Interactive和Oracle领导产品管理工作,并格外关注DevOps方向。直到2014年,我开始认真关注并研究容器。当2015年Kubernetes面向大众推出时,我强烈地感受到,企业需要一种更简单的方法来在其内部环境中部署容器。那时,我创立了Qubeship.io,提供企业级的容器的CI / CD工具。然而——尽管我们尽了全力应对这一问题——管理Kubernetes集群仍然是一个巨大的挑战。而Rancher,解决了这个复杂的问题。它从最初的容器编排引擎,迅速发展成为多集群、多租户Kubernetes管理平台,并解决了全球成千上万家企业在重要的生产环境中落地Kubernetes的难题。Rancher 2.2进一步推动了这一发展。Rancher 2.2中将包含许多新功能和错误修复,本文中我将重点分享:新的Alpha版本发布流程为Rancher所管理的集群提供的开箱即用的监控解决方案。Alpha版本发布流程从Rancher 2.2.0开始,Rancher Labs计划在最终2.2 GA发布之前发布一系列alpha版本。这将为用户提供足够的时间来试验新功能,并帮助发现一些潜在问题。Alpha版本无疑是最新最前沿的,它可能包含新功能、增强功能和错误修复。但我们不建议用户将任何alpha版本部署于生产环境,并且Rancher也不提供升级到alpha版本或从alpha版本升级的测试或支持。如果某个特定的alpha版本中有某些格外值得注意的功能或修复,我们会在release note里将它们着重标记出来。重要的已知问题我们也会标记。我们会做到尽量详细,不过这一清单也并非详尽无遗。无比希望大家能够尽可能多地向Rancher团队提供您在使用alpha版本时的反馈/意见/建议,这也是在产品正式GA之前帮助我们最大程度地优化产品的绝佳途径!多集群、多租户环境中Prometheus监控的黑科技Rancher Labs正式宣布了将在Rancher 2.2中引入对Prometheus的里程碑级别的增强支持,从而增强所有Kubernetes集群的可见性,同时确保不同项目与用户之间的隔离。Rancher也因此成为唯一一个在多集群、多租户环境中支持Prometheus的解决方案。在Rancher 2.2,使用Prometheus监控Rancher管理的Kubernetes环境,只需要两个步骤:选择集群一键启动监控搞定!我们可以做到这一点,因为Rancher 2.2配备了完全集成的Prometheus和Grafana。使用教程:登陆并选择您要监控的集群。需要注意的是,CPU利用率、内存利用率和Pods图表显示的是系统的当前状态。这些指标尽管很有用,但仅显示现在正在发生的事情。点开工具选项卡,然后选择“监控”选项。单击“Prometheus”按钮。关于数据留存以及端口,您都可以使用默认配置。关于存储Prometheus和Grafana数据的问题,这里也有添加持久化存储的选项。如果您要启用它,请立即选择它。在本文的这个演示中,我没有选中它们。保存更改。导航回集群,此时你就能看到更多其他内容了,包括集群指标、Etcd指标、Kubernetes组件指标和Rancher日志指标。展开每个指标后,就能查看到该指标下一层新指标。将鼠标悬停在图表上,还能查看到更多信信息。使用时间序列下拉列表,你还可以进一步放大并查看系统在不同时间段的性能变化。单击Grafana图标以查看仪表板:下面我们来看看项目级监控。项目级监控在Rancher中,项目是一种强大的方式来让多个团队在同一个集群上拥有自己的多租户工作区(或项目)。选择带有工作负载的项目,然后导航到工具→监控。如果监控尚未启用,可以选择Prometheus监控按钮来启用它。导航回Workload选项卡并展开现在可用的“Workload Metrics”部分,以查看所有利用率和I / O指标。将鼠标悬停在任意图表上可查看更多详细信息,使用时间序列下拉列表则可以进一步放大并查看特定时间段的情况。您还可以继续深入研究Pod甚至容器级指标。只需单击您想要观察的组件,然后参照执行和上文中一样的步骤,就可以查看到Pod指标和容器指标了。 结 论希望通过本文,您能了解到如何通过Rancher 2.2中开箱即用的Prometheus和Grafana监控解决方案,来简单快速地完成对多Kubernetes集群、多租户环境的统一监控。现已有多个Alpha版本可供您体验使用,具体可以参照这里:https://github.com/rancher/ra…一如既往,我们无比期待您的使用反馈。产品的beta版本将很快与您见面,GA时间计划为2019年初,敬请保持关注!Keep Rancher-ing!

December 19, 2018 · 1 min · jiezi

Rancher Labs引入全球首个多集群、多租户的Prometheus支持!

近日,Rancher Labs宣布加强对Prometheus的支持,提高Kubernetes集群的可见度。Rancher也因此成为唯一一个在多集群、多租户环境中支持Prometheus的解决方案。Prometheus正迅速成为监控云原生应用的最流行、最必不可少的工具之一,Rancher独特的多集群、多租户管理的功能,让用户可以更安全、更高效地在所有Kubernetes集群上部署Prometheus。——Rancher Labs联合创始人及CEO梁胜Rancher是业界首个且唯一一个可以管理所有云上、所有发行版、所有Kubernetes集群的企业级Kubernetes管理平台,此次和Prometheus的增强集成,将为跨多个Kubernetes集群和多个隔离租户环境提供更高的可见性。本次发布的对Prometheus的增强支持功能如下:每当添加一个新的Kubernetes集群到Rancher中,Rancher都将在集群中部署一个Prometheus operator,然后在集群中创建一个Prometheus部署。集群范围内的Prometheus部署将被用于存储集群指标(如CPU节点和内存消耗),并存储从单个用户部署的应用程序中收集的项目级指标。项目级的Grafana与Prometheus的通信将通过安全代理完成,该代理可为Prometheus实现多租户。安全代理工具PromQL语句可确保仅能通过用户项目的命名空间进行查询。此次Rancher对Prometheus的增强支持,将可确保为所有Kubernetes集群、所有项目和所有用户进行高效的部署和有效的监测。安全代理确保不在多租户之间重复共享数据,并且对多租户进行隔离。除此之外,Rancher还收集使用Prometheus处理的数据公开端点的任意自定义指标。所有指标均可用于Rancher内部的告警和决策,通过通知用户的Slack及PagerDuty进行简单操作,通过启动工作负载的横向扩展最终增加负载进行复杂操作。Rancher现在还拥有完全安全隔离和RBAC的集群级和项目级的指标和仪表盘。我们将Rancher当作单一窗格的玻璃,在多个集群中运行具有企业级控制和可见性的关键任务应用程序,检测这些应用程序的健康状况非常重要,我们十分期待Rancher增强对Prometheus的支持,它可以让我们进一步看到我们Kubernetes集群的更多指标。——Cardlytics IT和SRE总监Greg Cordell自成立之日起,Rancher便致力于建立以帮助容器技术落地实施为核心的开放的容器生态系统,和各大公有云、操作系统、存储、安全等厂商均保持着密切的合作关系,包括Docker、AWS、谷歌、微软、华为、阿里云、腾讯云、Ubuntu等业界巨头。增强对Prometheus支持的beta版即将提供试用,并将于2019年初GA。

December 18, 2018 · 1 min · jiezi

使用Prometheus+Alertmanager告警JVM异常情况

原文地址在前一篇文章中提到了如何使用Prometheus+Grafana来监控JVM。本文介绍如何使用Prometheus+Alertmanager来对JVM的某些情况作出告警。本文所提到的脚本可以在这里下载。摘要用到的工具:Docker,本文大量使用了Docker来启动各个应用。Prometheus,负责抓取/存储指标信息,并提供查询功能,本文重点使用它的告警功能。Grafana,负责数据可视化(本文重点不在于此,只是为了让读者能够直观地看到异常指标)。Alertmanager,负责将告警通知给相关人员。JMX exporter,提供JMX中和JVM相关的metrics。Tomcat,用来模拟一个Java应用。先讲一下大致步骤:利用JMX exporter,在Java进程内启动一个小型的Http server配置Prometheus抓取那个Http server提供的metrics。配置Prometheus的告警触发规则heap使用超过最大上限的50%、80%、90%instance down机时间超过30秒、1分钟、5分钟old gc时间在最近5分钟里超过50%、80%配置Grafana连接Prometheus,配置Dashboard。配置Alertmanager的告警通知规则告警的大致过程如下:Prometheus根据告警触发规则查看是否触发告警,如果是,就将告警信息发送给Alertmanager。Alertmanager收到告警信息后,决定是否发送通知,如果是,则决定发送给谁。第一步:启动几个Java应用1) 新建一个目录,名字叫做prom-jvm-demo。2) 下载JMX exporter到这个目录。3) 新建一个文件simple-config.yml内容如下:—blacklistObjectNames: [":"]4) 运行以下命令启动3个Tomcat,记得把<path-to-prom-jvm-demo>替换成正确的路径(这里故意把-Xmx和-Xms设置的很小,以触发告警条件):docker run -d \ –name tomcat-1 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms32m -Xmx32m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6060:6060 \ -p 8080:8080 \ tomcat:8.5-alpinedocker run -d \ –name tomcat-2 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms32m -Xmx32m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6061:6060 \ -p 8081:8080 \ tomcat:8.5-alpinedocker run -d \ –name tomcat-3 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms32m -Xmx32m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6062:6060 \ -p 8082:8080 \ tomcat:8.5-alpine5) 访问http://localhost:8080|8081|8082看看Tomcat是否启动成功。6) 访问对应的http://localhost:6060|6061|6062看看JMX exporter提供的metrics。备注:这里提供的simple-config.yml仅仅提供了JVM的信息,更复杂的配置请参考JMX exporter文档。第二步:启动Prometheus1) 在之前新建目录prom-jvm-demo,新建一个文件prom-jmx.yml,内容如下:crape_configs: - job_name: ‘java’ static_configs: - targets: - ‘<host-ip>:6060’ - ‘<host-ip>:6061’ - ‘<host-ip>:6062’# alertmanager的地址alerting: alertmanagers: - static_configs: - targets: - ‘<host-ip>:9093’# 读取告警触发条件规则rule_files: - ‘/prometheus-config/prom-alert-rules.yml'2) 新建文件prom-alert-rules.yml,该文件是告警触发规则:# severity按严重程度由高到低:red、orange、yello、bluegroups: - name: jvm-alerting rules: # down了超过30秒 - alert: instance-down expr: up == 0 for: 30s labels: severity: yellow annotations: summary: “Instance {{ $labels.instance }} down” description: “{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 30 seconds.” # down了超过1分钟 - alert: instance-down expr: up == 0 for: 1m labels: severity: orange annotations: summary: “Instance {{ $labels.instance }} down” description: “{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 1 minutes.” # down了超过5分钟 - alert: instance-down expr: up == 0 for: 5m labels: severity: blue annotations: summary: “Instance {{ $labels.instance }} down” description: “{{ $labels.instance }} of job {{ $labels.job }} has been down for more than 5 minutes.” # 堆空间使用超过50% - alert: heap-usage-too-much expr: jvm_memory_bytes_used{job=“java”, area=“heap”} / jvm_memory_bytes_max * 100 > 50 for: 1m labels: severity: yellow annotations: summary: “JVM Instance {{ $labels.instance }} memory usage > 50%” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [heap usage > 50%] for more than 1 minutes. current usage ({{ $value }}%)” # 堆空间使用超过80% - alert: heap-usage-too-much expr: jvm_memory_bytes_used{job=“java”, area=“heap”} / jvm_memory_bytes_max * 100 > 80 for: 1m labels: severity: orange annotations: summary: “JVM Instance {{ $labels.instance }} memory usage > 80%” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [heap usage > 80%] for more than 1 minutes. current usage ({{ $value }}%)” # 堆空间使用超过90% - alert: heap-usage-too-much expr: jvm_memory_bytes_used{job=“java”, area=“heap”} / jvm_memory_bytes_max * 100 > 90 for: 1m labels: severity: red annotations: summary: “JVM Instance {{ $labels.instance }} memory usage > 90%” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [heap usage > 90%] for more than 1 minutes. current usage ({{ $value }}%)” # 在5分钟里,Old GC花费时间超过30% - alert: old-gc-time-too-much expr: increase(jvm_gc_collection_seconds_sum{gc=“PS MarkSweep”}[5m]) > 5 * 60 * 0.3 for: 5m labels: severity: yellow annotations: summary: “JVM Instance {{ $labels.instance }} Old GC time > 30% running time” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [Old GC time > 30% running time] for more than 5 minutes. current seconds ({{ $value }}%)” # 在5分钟里,Old GC花费时间超过50% - alert: old-gc-time-too-much expr: increase(jvm_gc_collection_seconds_sum{gc=“PS MarkSweep”}[5m]) > 5 * 60 * 0.5 for: 5m labels: severity: orange annotations: summary: “JVM Instance {{ $labels.instance }} Old GC time > 50% running time” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [Old GC time > 50% running time] for more than 5 minutes. current seconds ({{ $value }}%)” # 在5分钟里,Old GC花费时间超过80% - alert: old-gc-time-too-much expr: increase(jvm_gc_collection_seconds_sum{gc=“PS MarkSweep”}[5m]) > 5 * 60 * 0.8 for: 5m labels: severity: red annotations: summary: “JVM Instance {{ $labels.instance }} Old GC time > 80% running time” description: “{{ $labels.instance }} of job {{ $labels.job }} has been in status [Old GC time > 80% running time] for more than 5 minutes. current seconds ({{ $value }}%)“3) 启动Prometheus:docker run -d \ –name=prometheus \ -p 9090:9090 \ -v <path-to-prom-jvm-demo>:/prometheus-config \ prom/prometheus –config.file=/prometheus-config/prom-jmx.yml4) 访问http://localhost:9090/alerts应该能看到之前配置的告警规则:如果没有看到三个instance,那么等一会儿再试。第三步:配置Grafana参考使用Prometheus+Grafana监控JVM第四步:启动Alertmanager1) 新建一个文件alertmanager-config.yml:global: smtp_smarthost: ‘<smtp.host:ip>’ smtp_from: ‘<from>’ smtp_auth_username: ‘<username>’ smtp_auth_password: ‘<password>’# The directory from which notification templates are read.templates: - ‘/alertmanager-config/*.tmpl’# The root route on which each incoming alert enters.route: # The labels by which incoming alerts are grouped together. For example, # multiple alerts coming in for cluster=A and alertname=LatencyHigh would # be batched into a single group. group_by: [‘alertname’, ‘instance’] # When a new group of alerts is created by an incoming alert, wait at # least ‘group_wait’ to send the initial notification. # This way ensures that you get multiple alerts for the same group that start # firing shortly after another are batched together on the first # notification. group_wait: 30s # When the first notification was sent, wait ‘group_interval’ to send a batch # of new alerts that started firing for that group. group_interval: 5m # If an alert has successfully been sent, wait ‘repeat_interval’ to # resend them. repeat_interval: 3h # A default receiver receiver: “user-a”# Inhibition rules allow to mute a set of alerts given that another alert is# firing.# We use this to mute any warning-level notifications if the same alert is # already critical.inhibit_rules:- source_match: severity: ‘red’ target_match_re: severity: ^(blue|yellow|orange)$ # Apply inhibition if the alertname and instance is the same. equal: [‘alertname’, ‘instance’]- source_match: severity: ‘orange’ target_match_re: severity: ^(blue|yellow)$ # Apply inhibition if the alertname and instance is the same. equal: [‘alertname’, ‘instance’]- source_match: severity: ‘yellow’ target_match_re: severity: ^(blue)$ # Apply inhibition if the alertname and instance is the same. equal: [‘alertname’, ‘instance’]receivers:- name: ‘user-a’ email_configs: - to: ‘<user-a@domain.com>‘修改里面关于smtp_*的部分和最下面user-a的邮箱地址。备注:因为国内邮箱几乎都不支持TLS,而Alertmanager目前又不支持SSL,因此请使用Gmail或其他支持TLS的邮箱来发送告警邮件,见这个issue2) 新建文件alert-template.tmpl,这个是邮件内容模板:{{ define “email.default.html” }}<h2>Summary</h2> <p>{{ .CommonAnnotations.summary }}</p><h2>Description</h2><p>{{ .CommonAnnotations.description }}</p>{{ end}}3) 运行下列命令启动:docker run -d \ –name=alertmanager \ -v <path-to-prom-jvm-demo>:/alertmanager-config \ -p 9093:9093 \ prom/alertmanager –config.file=/alertmanager-config/alertmanager-config.yml4) 访问http://localhost:9093,看看有没有收到Prometheus发送过来的告警(如果没有看到稍等一下):第五步:等待邮件等待一会儿(最多5分钟)看看是否收到邮件。如果没有收到,检查配置是否正确,或者docker logs alertmanager看看alertmanager的日志,一般来说都是邮箱配置错误导致。 ...

October 26, 2018 · 5 min · jiezi

使用Prometheus+Grafana监控JVM

原文地址摘要用到的工具:Docker,本文大量使用了Docker来启动各个应用。Prometheus,负责抓取/存储指标信息,并提供查询功能。Grafana,负责数据可视化。JMX exporter,提供JMX中和JVM相关的信息。Tomcat,用来模拟一个Java应用。先讲一下大致步骤:利用JMX exporter,在Java进程内启动一个小型的Http server配置Prometheus抓取那个Http server提供的数据。配置Grafana连接Prometheus,配置Dashboard。第一步:启动几个Java应用1) 新建一个目录,名字叫做prom-jvm-demo。2) 下载JMX exporter到这个目录3) 新建一个文件simple-config.yml内容如下:—blacklistObjectNames: [":"]4) 运行以下命令启动3个Tomcat,记得把<path-to-prom-jvm-demo>替换成正确的路径:docker run -d \ –name tomcat-1 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms64m -Xmx128m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6060:6060 \ -p 8080:8080 \ tomcat:8.5-alpinedocker run -d \ –name tomcat-2 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms64m -Xmx128m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6061:6060 \ -p 8081:8080 \ tomcat:8.5-alpinedocker run -d \ –name tomcat-3 \ -v <path-to-prom-jvm-demo>:/jmx-exporter \ -e CATALINA_OPTS="-Xms64m -Xmx128m -javaagent:/jmx-exporter/jmx_prometheus_javaagent-0.3.1.jar=6060:/jmx-exporter/simple-config.yml" \ -p 6062:6060 \ -p 8082:8080 \ tomcat:8.5-alpine5) 访问http://localhost:8080|8081|8082看看Tomcat是否启动成功。6) 访问对应的http://localhost:6060|6061|6062看看JMX exporter提供的metrics。备注:这里提供的simple-config.yml仅仅提供了JVM的信息,更复杂的配置请参考JMX exporter文档。第二步:启动Prometheus1) 在之前新建目录prom-jvm-demo,新建一个文件prom-jmx.yml,内容如下:crape_configs: - job_name: ‘java’ static_configs: - targets: - ‘<host-ip>:6060’ - ‘<host-ip>:6061’ - ‘<host-ip>:6062'2) 启动Prometheus:docker run -d \ –name=prometheus \ -p 9090:9090 \ -v <path-to-prom-jvm-demo>:/prometheus-config \ prom/prometheus –config.file=/prometheus-config/prom-jmx.yml3) 访问http://localhost:9090看看Prometheus是否启动成功,在输入框里输入jvm_info然后执行,应该可以看到如下图的结果:如果没有看到三个instance,那么等一会儿再试。第三步:配置Grafana1) 启动Grafana:docker run -d –name=grafana -p 3000:3000 grafana/grafana2) 访问http://localhost:3000,使用admin/admin登录。3) 添加Prometheus数据源,如下图所示到添加数据源页面:4) 配置数据源信息:Name:随便取Type:PrometheusURL:http://<host-ip>:9090其余不要设置,点击Save & Test,应该会返回成功结果5) 导入Dashboard。我们不需要重头自己做Dashboard,用现成的就行,按下图所示进入导入页面6) 使用我制作的JVM Dashboard,页面右侧出现的ID号是8563,记住这个号,填在如下图所示的位置:7) 然后鼠标点击别处稍等一下,出现下图,选择一下数据源就可以了8) 最后打开刚刚导入的Dashboard,如下图: ...

October 25, 2018 · 1 min · jiezi