云原生第十周——promethus简介(上)

发布时间 2023-08-22 17:32:39作者: 黑夜有约

监控简介:

监控的价值:

  • 长期趋势分析:通过对监控样本数据的持续收集和统计,对监控指标进行长期趋势分析。例如,通过对磁盘空间增长率的判断,我们可以提前预测在未来什么时间节点上需要对资源进行扩容。
  • 对照分析:两个版本的系统运行资源使用情况的差异如何?在不同容量情况下系统的并发和负载变化如何?通过监控能够方便的对系统进行跟踪和比较。
  • 告警:当系统出现或者即将出现故障时,监控系统需要迅速反应并通知管理员,从而能够对问题进行快速的处理或者提前预防问题的发生,避免出现对业务的影响。
  • 故障分析与定位:当问题发生后,需要对问题进行调查和处理。通过对不同监控监控以及历史数据的分析,能够找到并解决根源问题。
  • 数据可视化:通过可视化仪表盘能够直接获取系统的运行状态、资源使用情况、以及服务运行状态等直观的信息

监控的类型:
通过业务监控系统,全面掌握业务环境的运行状态,通过黑盒监控能够第一时间发现业务故障并通过告警通告运维人员进行紧急恢复,通过白盒监控能够提前预知业务瓶颈,从而将业务影响降到最低。

  • 黑盒监控,关注的是时时的状态,一般都是正在发生的事件,比如nginx web界面打开的是界面报错503、API接口超时、磁盘IO异常等,即黑盒监控重点在于能对当前正在发生的故障进行发现及发送通知告警。
  • 白盒监控,关注的是原因,也就是系统内部暴露的一些指标数据,比如nginx 后端服务器的响应时长、磁盘的I/O负载值等。

监控系统需要能够有效的支持白盒监控和黑盒监控,通过白盒能够了解其内部的实际运行状态,以及对监控指标的观察能够预判可能出现的潜在问题,从而对潜在的不确定因素进行提前优化并避免问题的发生,而通过黑盒监控,比如常见的如HTTP探针、TCP探针等,可以在系统或者服务在发生故障时能够快速通知相关的人员进行处理。

常见的监控工具:

  • Cacti:基于基于LAMP平台展现的网络流量监测及分析工具,https://www.cacti.net
  • Nagios:用来监视系统和网络的开源应用软件,利用其众多的插件实现对本机和远端服务的监控,https://www.nagios.org
  • Open-falcon: 小米公司开源出来的监控软件open-falcon(猎鹰),监控能力和性能较强,https://www.open-falcon.org
  • Nightingale:夜莺, 由滴滴基于open-falcon二次开发后开源出来的分布式监控系统,https://n9e.github.io
  • Zabbix:老牌的开源监控软件,可横向扩展、自定义监控项、支持多种监控方式、可监控网络与各种服务等,https://www.zabbix.com/cn
  • prometheus:CNCF毕业的云原生监控系统,对k8s的容器有良好的兼容性,https://prometheus.io

商业监控:

prometheus简介:

Prometheus是基于go语言开发的一套开源的监控、报警和时间序列数据库的组合,是由SoundCloud公司开发(2012年)的开源监控系统,Prometheus
于2016年加入CNCF(Cloud Native Computing Foundation,云原生计算基金会),2018年8月9日prometheus成为CNCF继kubernetes 之后毕业的第二
个项目,prometheus在容器和微服务领域中得到了广泛的应用,其主要优缺点如下:

  • 使用key-value的多维度(多个角度,多个层面,多个方面)格式保存数据
  • 数据不使用MySQL这样的传统数据库,而是使用时序数据库,目前是使用的TSDB
  • 支持第三方dashboard实现更绚丽的图形界面,如grafana(Grafana 2.5.0版本及以上)
  • 组件模块化
  • 不需要依赖存储,数据可以本地保存也可以远程保存
  • 平均每个采样点仅占3.5 bytes,且一个Prometheus server可以处理数百万级别的的metrics指标数据。
  • 支持服务自动化发现(基于consul等方式动态发现被监控的目标服务)
  • 强大的数据查询语句功(PromQL,Prometheus Query Language)
  • 数据可以直接进行算术运算
  • 易于横向伸缩
  • 众多官方和第三方的exporter(“数据”导出器)实现不同的指标数据收集

prometheus 架构图:

image

  • prometheus server:主服务,接受外部http请求、收集指标数据、存储指标数据与查询指标数据等。
  • prometheus targets: 静态发现目标后执行指标数据抓取。
  • service discovery:动态发现目标后执行数据抓取。
  • prometheus alerting:调用alertmanager组件实现报警通知。
  • push gateway:数据收集代理服务器(类似于zabbix proxy但仅限于client主动push数据至push gateway)。
  • Data visualization and export:数据可视化与数据导出(浏览器或其它client)。

prometheus数据采集流程:

  1. 基于静态配置文件或动态发现获取目标
  2. 向目标URL发起http/https请求
  3. 目标接受请求并返回指标数据
  4. prometheus server接受并数据并对比告警规则,如果触发告警则进一步执行告警动作并存储数据,不触发告警则只进行数据存储
  5. grafana进行数据可视化
    image

总结:promethus采集数据时是拉模型(pull).

TSDB简介

TSDB:Time Series Database , 简称 TSDB,存放时间序列数据的数据库 拥有以下特性。

  • 时间序列数据具有不变性、唯一性和按照时间排序的特性。
  • 持续周期性写入数据、高并发吞吐:每间隔一段时间,就会写入成千上万的节点的指标数据。
  • 写多读少:prometheus每间隔15s就会采集数十万或更多指标数据,但通常只查看最近比较重要的指标数据。
  • 数据按照时间排列:每次收集的指标数据,写入时都是按照当前时间往后进行写入,不会覆盖历史数据。
  • 数据量大:历史数据会有数百G甚至数百T或更多。
  • 时效性:只保留最近一段时间的数据,超出时效的数据会被删除。
  • 冷热数据分明:通常只查看最近的热数据,以往的冷数据很少查看。

默认情况下,prometheus将采集到的数据存储在本地的TSDB数据库中,路径默认为prometheus安装目录的data目录,数据写入过程为先把数据写入wal日志并放在内存,然后2小时后将内存数据保存至一个新的block块,同时再把新采集的数据写入内存并在2小时后再保存至一个新的block块,以此类推。

prometheus先将采集的指标数据保存到内存的chunk中,chunk是prometheus存储数据的最基本单元。

每间隔两个小时,将当前内存的多个chunk统一保存至一个block中并进行数据合并、压缩、并生成元数据文件index、meta.json和tombstones

image

部署promethus

docker-compose部署promethus

root@prometheus-server1:~# tar xvf docker-20.10.19-binary-install.tar.gz
root@prometheus-server1:~# bash docker-install.sh
root@prometheus-server1:~# git clone https://gitee.com/jiege-gitee/prometheus-docker-compose.git
root@prometheus-server1:~# cd prometheus-docker-compose
~/prometheus-docker-compose# vim config/prometheus/prometheus.yml #prometheus 配置文件
~/prometheus-docker-compose# docker-compose up -d #执行部署,需要在线下载镜像

image

该方式同时部署了promethus-server node-exporter grafana-server

image

image

image

其他服务安装node-exporter

docker run -it -p 9100:9100 prom/node-exporter

修改promethus.yml

image

可以看到promethus监控多台服务

image

grafana配置

初始用户密码 admin/admin 修改为admin/123456

添加数据源 将promethus和grafana绑定
image

image

导入监控模板

进入grafana官网 找到想导入的数据源 记录id号
https://grafana.com/grafana/dashboards/

image

进入create import
image

image

选择匹配的数据源 (由于已经导入过,这里提示sameid)
image

最终效果
image

也可以使用从官网下载的json文件 或 把json文件内容粘贴上去都可以导入,此处不在演示。

PromQL语句

PromQL查询数据类型:

Range Vector:范围向量/范围数据,是指在任何一个时间范围内,抓取的所有度量指标数据.比如最近一天的网卡流量趋势图、或最近5分钟的node节点内容可用字节数等,以下是查询node节点可用内存的范围向量表达式:

image

scalar:标量/纯量数据,是一个浮点数类型的数据值,使用node_load1获取到时一个瞬时向量后,在使用prometheus的内置函数scalar()将瞬时向量转换为标量,例如:scalar(sum(node_load1))

image

prometheus指标数据类型:

Counter:计数器 Counter类型代表一个累积的指标数据,在没有被重启的前提下只增不减,比如磁盘I/O总数、Nginx/API的请求总数、网卡流经的报文总数等。
Gauge: 仪表盘 Gauge类型代表一个可以任意变化的指标数据,值可以随时增高或减少,如带宽速率、CPU负载、内存利用率、nginx 活动连接数等。
Histogram:累积直方图 Histogram会在一段时间范围内对数据进行采样(通常是请求持续时间或响应大小等),假如每分钟产生一个当前的活跃连接数,那么一天24小时*60分钟=1440分钟就会产生1440个数据,查看数据的每间隔的绘图跨度为2小时,那么2点的柱状图(bucket)会包含0点到2点即两个小时的数据,而4点的柱状图(bucket)则会包含0点到4点的数据,而6点的柱状图(bucket)则会包含0点到6点的数据,可用于统计从当天零点开始到当前时间的数据统计结果,如http请求成功率、丢包率等,比如ELK的当天访问IP统计。
image
image
Summary:摘要 摘要图,也是一组数据,默认统计选中的指标的最近10分钟内的数据的分位数,可以指定数据统计时间范围,基于分位数(Quantile),亦称分位点,是指用分割点(cut point)将随机数据统计并划分为几个具有相同概率的连续区间,常见的为四分位,四分位数是将数据样本统计后分成四个区间,将范围内的数据进行百分比的占比统计,从0到1,表示是0%100%,(0%25%,%2550%,50%75%,75%~100%),利用四分位数,可以快速了解数据的大概统计结果。

node-exporter指标数据格式:

- 没有标签的 
metric_name metric_value
TYPE node_load15 gauge
node_load15 0.1

- 一个标签的
metric_name{label1_name="label1-value"} metric_value
TYPE node_network_receive_bytes_total counter
node_network_receive_bytes_total{device="eth0"} 1.44096e+07

- 多个标签的
metric_name{label1_name="label1-value","labelN_name="labelN-value} metric_value
TYPE node_filesystem_files_free gauge
node_filesystem_files_free{device="/dev/sda2",fstype="xfs",mountpoint="/boot"} 523984

PromQL查询指标数据示例:

node_memory_MemTotal_bytes #查询node节点总内存大小
node_memory_MemFree_bytes #查询node节点剩余可用内存
node_memory_MemTotal_bytes{instance="192.168.110.207:9100"} #基于标签查询指定节点的总内存
node_memory_MemFree_bytes{instance="192.168.110.207:9100"} #基于标签查询指定节点的可用内存
node_disk_io_time_seconds_total{device="sda"} #查询指定磁盘的每秒磁盘io
node_filesystem_free_bytes{device="/dev/sda1",fstype="xfs",mountpoint="/"} #查看指定磁盘的磁盘剩余空间

image

image

基于标签对指标数据进行匹配:

= :选择与提供的字符串完全相同的标签,精确匹配。
!= :选择与提供的字符串不相同的标签,去反。
=~ :选择正则表达式与提供的字符串(或子字符串)相匹配的标签。
!~ :选择正则表达式与提供的字符串(或子字符串)不匹配的标签。

node_load1{job="promethues-node",instance!="192.168.110.207:9100"}取反
image

node_load1{instance=~"192.168.110.*:9100$"} #包含正则且匹配

node_load1{instance!~"192.168.110.207:9100"} #包含正则且取反

PromQL 时间范围:

对指标数据进行时间范围指定:
s - 秒
m - 分钟
h - 小时
d - 天
w - 周
y - 年

瞬时向量表达式,选择当前最新的数据
node_memory_MemTotal_bytes{}

区间向量表达式,选择以当前时间为基准,查询所有节点
node_memory_MemTotal_bytes指标5分钟内的数据
node_memory_MemTotal_bytes{}[5m]

区间向量表达式,选择以当前时间为基准,查询指定节点
node_memory_MemTotal_bytes指标5分钟内的数据
node_memory_MemTotal_bytes{instance="192.168.110。207:9100"}[5m]

对指标数据进行数学运算:

  • 加法
  • 减法
  • 乘法
    / 除法
    % 模
    ^ 幂(N次方)
node_memory_MemFree_bytes/1024/1024 #将内存进行单位从字节转行为兆
node_disk_read_bytes_total{device="sda"} + node_disk_written_bytes_total{device="sda"} #计算磁盘读写数据量
(node_disk_read_bytes_total{device="sda"} + node_disk_written_bytes_total{device="sda"}) / 1024 / 1024 #单位转换

聚合运算

max() #最大值
min() #最小值
avg() #平均值

计算每个节点的最大的流量值:
max(node_network_receive_bytes_total) by (instance)
计算每个节点最近五分钟每个device的最大流量
max(rate(node_network_receive_bytes_total[5m])) by (device)
sum() #求数据值相加的和(总数)
sum(prometheus_http_requests_total)
{} 2495 #最近总共请求数为2495次,用于计算返回值的总数(如http请求次数)

count() #统计返回值的条数
count(node_os_version)
{} 2 #一共两条返回的数据,可以用于统计节点数、pod数量等
count_values() #对value的个数(行数)进行计数,并将value赋值给自定义标签,从而成为新的label
count_values("node_version",node_os_version) #统计不同的系统版本节点有多少
{node_version="20.04"} 2

对指标数据进行进行聚合运算:

abs() #返回指标数据的值
abs(sum(prometheus_http_requests_total{handler="/metrics"}))
absent() #如果监指标有数据就返回空,如果监控项没有数据就返回1,可用于对监控项设置告警通知(如果返回值等于1就触发告警通知)
absent(sum(prometheus_http_requests_total{handler="/metrics"}))

stddev() #标准差
stddev(prometheus_http_requests_total) #5+5=10,1+9=10,1+9这一组的数据差异就大,在系统是数据波动较大,不稳定

stdvar() #求方差
stdvar(prometheus_http_requests_total)

topk() #样本值排名最大的N个数据
#取从大到小的前6个
topk(6, prometheus_http_requests_total)
bottomk() #样本值排名最小的N个数据
#取从小到大的前6个
bottomk(6, prometheus_http_requests_total)

rate() #rate函数是专门搭配counter数据类型使用函数,rate会取指定时间范围内所有数据点,算出一组速率,然后取平均值作为结果,适合用于计算数据相对平稳的数据。
 rate(prometheus_http_requests_total[5m])
 rate(apiserver_request_total{code=~"^(?:2..)$"}[5m])
 rate(node_network_receive_bytes_total[5m])
 
irate() #函数也是专门搭配counter数据类型使用函数,irate取的是在指定时间范围内的最近两个数据点来算速率,适合计算数据变化比较大的数据,显示的数据相对比较准确,所以官网文档说:irate适合快速变化的计数器(counter),而rate适合缓慢变化的计数器(counter)。
 irate(prometheus_http_requests_total[5m])
 irate(node_network_receive_bytes_total[5m])
 irate(apiserver_request_total{code=~"^(?:2..)$"}[5m])
#by,在计算结果中,只保留by指定的标签的值,并移除其它所有的
sum(rate(node_network_receive_packets_total{instance=~".*"}[10m])) by (instance)
sum(rate(node_memory_MemFree_bytes[5m])) by (increase)

#without,从计算结果中移除列举的instance,job标签,保留其它标签
sum(prometheus_http_requests_total) without (instance,job)

pushgateway简介

当prometheus无法直接从目标服务拉取数据时,需要一个中介点,目标服务通过将数据push到pushgateway中,然后再由prometheus拉取。

pushgateway用于临时的指标数据收集。
pushgateway不支持数据拉取(pull模式),需要客户端主动将数据推送给pushgateway。
pushgateway可以单独运行在一个节点,然后需要自定义监控脚本把需要监控的主动推送给pushgateway的API接口,然后pushgateway再等待prometheus server抓取数据,即pushgateway本身没有任何抓取监控数据的功能,目前pushgateway只能被动的等待数据从客户端进行推送。

--persistence.file="" #数据保存的文件,默认只保存在内存中
--persistence.interval=5m #数据持久化的间隔时间

pushgateway 数据采集流程:

image

docker部署pushgateway

image

image

将pushgateway端口添加到promethus的job中
image

image

编写获取数据脚本 发送至pushgateway中

root@192:/usr/local/src/prometheus/prometheus-docker-compose# cat memory.sh 
#!/bin/bash
total_memory=$(free |awk '/Mem/{print $2}')
used_memory=$(free |awk '/Mem/{print $3}')
job_name="custom_memory_monitor"
instance_name=`ifconfig ens160 | grep -w inet | awk '{print $2}'`
pushgateway_server="http://192.168.110.207:9091/metrics/job"
cat <<EOF | curl --data-binary @- ${pushgateway_server}/${job_name}/instance/${instance_name}
#TYPE custom_memory_total gauge
custom_memory_total $total_memory
#TYPE custom_memory_used gauge
custom_memory_used $used_memory
EOF

bash -x memory.sh

登录promethus可以看到pushgateway获取的数据已生效

image

联邦集群

对于初创型公司或中小型公司而言,单机部署基本上已经满足需求。而对于大规模监控而言,如:两个数据中心,其内部服务器的内网并不互通,此时单机部署的情景是无法满足我们需求的,而如果你每个数据中心都部署一套完整的监控体系,那你的数据很难进行集中管理。一般像这种夸机房、夸数据中心的情况我们就会采用 prometheus 的联邦集群模式,来进行数据集中管理、监控及告警。

联邦集群部署

在192.168.110.208和209上部署prometheus
image

之后修改192.168.110.207的yml文件,使其从208,209两台promethus集群中获取信息
image

之后重启207的promethus,登录检查

image

cadvisor简介

cadvisor由谷歌开源,在kubernetes v1.11及之前的版本内置在kubelet中并监听在4194端口(https://github.com/kubernetes/kubernetes/pull/65707),从v1.12开始kubelet中的cadvisor被移除,因此需要单独通过daemonset等方式部署。

cadvisor(容器顾问)不仅可以收集一台机器上所有运行的容器信息,还提供基础查询界面和http接口,方便其他组件如Prometheus进行数据抓取,cAdvisor可以对节点机器上的容器进行实时监控和性能数据采集,包括容器的CPU使用情况、内存使用情况、网络吞吐量及文件系统使用情况。

daemonset部署cadvisor


root@192:/usr/local/src/3.prometheus-case-files/prometheus-files/case# cat case1-daemonset-deploy-cadvisor.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: cadvisor
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: cAdvisor
  template:
    metadata:
      labels:
        app: cAdvisor
    spec:
      tolerations:    #污点容忍,忽略master的NoSchedule
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
        - effect: NoSchedule
          key:  node.kubernetes.io/disk-pressure
            
      hostNetwork: true
      restartPolicy: Always   # 重启策略
      containers:
      - name: cadvisor
        image: registry.cn-hangzhou.aliyuncs.com/zhangshijie/cadvisor-amd64:v0.45.0
        imagePullPolicy: IfNotPresent  # 镜像策略
        securityContext:
          privileged: true
        ports:
        - containerPort: 8080
        volumeMounts:
          - name: root
            mountPath: /rootfs
            readOnly: true
          - name: run
            mountPath: /var/run
            #    readOnly: true
          - name: sys
            mountPath: /sys
            readOnly: true
          - name: docker
            mountPath: /var/lib/containerd
            readOnly: true
          - name: devdisk
            mountPath: /dev/disk
            readOnly: true
      volumes:
      - name: root
        hostPath:
          path: /
      - name: run
        hostPath:
          path: /var/run
      - name: sys
        hostPath:
          path: /sys
      - name: docker
        hostPath:
          path: /var/lib/containerd
      - name: devdisk
        hostPath:
          path: /dev/disk

image

登录192.168.110.208:8080 可以看到cadvisor监控pod内数据

image

修改207prometheus.yml
image

登录promethus可以看到已经可以查看cadvisor数据

image

登录192.168.110.207:3000进入grafana

导入cadvisor模板14282
image

可以看到数据

image

daemonset部署node-exporter

root@192:/usr/local/src/3.prometheus-case-files/prometheus-files/case# cat case2-daemonset-deploy-node-exporter.yaml 
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitoring 
  labels:
    k8s-app: node-exporter
spec:
  selector:
    matchLabels:
        k8s-app: node-exporter
  template:
    metadata:
      labels:
        k8s-app: node-exporter
    spec:
      tolerations:
        - effect: NoSchedule
          key: node-role.kubernetes.io/master
      containers:
      - image: prom/node-exporter:v1.3.1 
        imagePullPolicy: IfNotPresent
        name: prometheus-node-exporter
        ports:
        - containerPort: 9100
          hostPort: 9100
          protocol: TCP
          name: metrics
        volumeMounts:
        - mountPath: /host/proc
          name: proc
        - mountPath: /host/sys
          name: sys
        - mountPath: /host
          name: rootfs
        args:
        - --path.procfs=/host/proc
        - --path.sysfs=/host/sys
        - --path.rootfs=/host
      volumes:
        - name: proc
          hostPath:
            path: /proc
        - name: sys
          hostPath:
            path: /sys
        - name: rootfs
          hostPath:
            path: /
      hostNetwork: true
      hostPID: true
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    prometheus.io/scrape: "true"
  labels:
    k8s-app: node-exporter
  name: node-exporter
  namespace: monitoring 
spec:
  type: NodePort
  ports:
  - name: http
    port: 9100
    nodePort: 39100
    protocol: TCP
  selector:
    k8s-app: node-exporter


image

修改promtheus.yml

image

可以看到通过daemonset部署的exporter已经被监控
image

deployment部署prometheus server:

部署prometheus server:


创建configmap:
prometheus-files/case# kubectl apply -f case3-1-prometheus-cfg.yaml
configmap/prometheus-config created
#将prometheus运行在node3并,提前准备数据目录并授权
root@k8s-node1:~# mkdir -p /data/prometheusdata
# kubectl exec -it prometheus-server-7747ccb4b5-rdbmd sh -n monitoring /prometheus $ id nobody
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
#存储或宿主机数据目录授权
root@k8s-node1:~# chmod 777 /data/prometheusdata
root@k8s-node3:~# chown 65534.65534 /data/prometheusdata -R
创建监控账号:
# kubectl create serviceaccount monitor -n monitoring
serviceaccount/monitor created
对monitoring 账号授权:
# kubectl create clusterrolebinding monitor-clusterrolebinding -n monitoring --clusterrole=cluster-admin --serviceaccount=monitoring:monitor
clusterrolebinding.rbac.authorization.k8s.io/monitor-clusterrolebinding created
创建deployment控制器:
# kubectl apply -f case3-2-prometheus-deployment.yaml
deployment.apps/prometheus-server create

创建service:
# kubectl apply -f case3-3-prometheus-svc.yaml
service/prometheus created

image