如何實時!主動監控你的網站接口,是否掛掉並及時報警


閱讀本文大概需要 10 分鍾。

最近我在公司負責的業務已經正式投入上線了,既然是線上環境,那么就需要保證其可用性。

我負責的業務其中就包括一個 Web Service,我需要保證 Service 的每個接口都是可用的,如果某個時間流量大了或者服務器掛掉了,那需要第一時間通知到我。

這時候可能我有這些需求:

1.定時測試和監控服務器每個接口是否是可用的,包括返回的數據、狀態碼是不是正確的。2.我可以隨時查看到每個接口的響應時間、可用率等信息,最好是有可視化的圖表呈現,一目了然。3.如果接口的錯誤率超過某一閾值一段時間,及時通知我,包括電話、短信或郵件。4.需要主動去監測接口的可用性,注意這里是主動監測而不是被動監測,不是等用戶用的時候報錯才提醒我。比如在沒有用戶用的時候,我也能及時知道每個接口的可用性。

其實,國內的一些服務商已經提供了這些功能,即主動型服務監控,比如「監控寶」,但我並不想用這些服務,一是需要額外花錢,二是數據上並不安全,三是我需要把我的服務集成到公司內部的監控體系下。

有了這些需求,我就結合公司內部現有的一些基礎設施先確定一個技術選型,然后實施就好了。

目前公司內部使用的一套監控體系是基於 Kubernetes + Prometheus + Grafana + Alert Manager 的,那么基於我的需求來分析下我怎樣利用這一套體系來搭建我想要的監控設施。

解決方案分析:

1.首先關於第四個需求比較特殊,現有的監控體系其實已經可以做到服務的被動監測,比如某個 Service 的 API 被調用了,那么相應的調用數據都會被匯總到 Prometheus 上面,Prometheus 里面會計算接口調用的可用率,如果一段時間內如果錯誤率超過一定閾值,那就報警,追錯誤的時候去查下 log 就好了。但其實這個不能做到主動監測,比如在凌晨三四點,當沒有用戶使用的時候,如果這時候服務器出現問題了,我也需要第一時間能知道,所以我需要有一個定時的主動監測程序來實時監測我的所有接口是否是可用的。要做到主動監控,那我一定需要一個接口監測程序定時運行並校驗每個接口的結果,這里我選用的就是開源的 JMeter,它大多數情況下是被用來做壓測的,但絕對能滿足接口調用和檢測的需求,只要我定時跑 JMeter 來檢測就好了。2.關於第一個需求,我需要監測我的每個接口都是可用的,包括返回的數據也需要是想要的結果。這時候我們可能想到直接跑一些 test case 之類的,但這些其實大多數都是在部署或運行時校驗的,如果我要實時跑或者 test case 有 update 了,也不太方便。另外為了寫接口測試的時候,如果沒有現成的工具,我們可能得寫一堆代碼,每個接口都寫一個,包括 GET 請求的 URL 參數、POST 請求的 Body 信息等等,然后校驗接口的返回結果是不是對的,也太麻煩了。所以我們需要找到一個可用的工具來幫助我們快速地完成這些功能。所以,我選擇的 JMeter 也提供了可視化界面,我只需要配置一些接口和參數即可,另外它還帶有定時器、斷言、動態參數、多線程等功能,這樣我們也可以做到並發測試、隨機等待、動態構造請求參數、返回結果判斷等功能了。3.其次再說第二個和第三個需求,其實用現有的 Prometheus + Grafana 就能解決了,這里最關鍵的則是我的接口監控結果能發給 Prometheus 才行。既然我選用了 JMeter,那么我怎樣把 JMeter 的數據發送給 Prometheus 呢?這里需要借助於 JMeter 的一個插件 jmeter-prometheus-plugin,https://github.com/johrstrom/jmeter-prometheus-plugin,利用它就能將 JMeter 變成一個 Data Exporter,Prometheus 來抓取就好了。

所以,綜上所述,我利用的一套服務監控體系就是 JMeter + Kubernetes + Prometheus + Grafana + Alert Manager,那么就開干吧。

這里先放一張圖,看下最終的監控 Grafana 面板吧:

監控面板

這里一些接口的名稱和 URL 我就打碼了,這里我可以在 Grafana 中每時每刻都看到每個接口的可用率、響應(包括平均、最快、最慢)時間、狀態碼等信息,這些信息就是 JMeter 定時檢測得到的結果,監控數據轉到 Prometheus 里面然后經過 Grafana 可視化出來,並能通過一些指標來實現報警機制。

感興趣的話,可以繼續往下看哈。

為了達成這些功能,我需要解決如下問題:

如何使用 JMeter 來測試每個接口的使用情況。JMeter 如何和 Prometheus 對接起來,即如何集成 jmeter-prometheus-plugin 到 JMeter。JMeter 怎樣去部署,部署到哪里。可視化數據怎樣來呈現。錯誤狀態怎樣來快速查看。出錯通知如何實現,比如打電話、發郵件等等。

下面我們就來一個個總結說一下。

由於內容比較多,整個流程我實踐下來然后測試通總共花了兩天左右的時間,在這里就不完全展開說了,只提關鍵點了。

JMeter 測試

第一步那就是用 JMeter 來完成接口的測試了,接口的調用形式肯定都有相應的規范的,比如 GET 請求設置啥參數,POST 請求發送什么數據,我們利用 JMeter 都能方便地配置。

JMeter 是有 GUI 的,我們在編寫的時候在 GUI 里面設置就好了,界面樣例如下所示:

JMeter界面(圖源:https://www.jianshu.com/p/0349441da3c4)

這里提示幾點可能用到的東西:

動態參數,JMeter 里面是支持動態參數設置的,比如循環測試 id 從 1 到 100,或者動態 POST 的數據替換,都是可以做到的,這個可以滿足你花樣測試接口的需求。定時器,JMeter 里面有很多 Timer,可以設置各種各樣的延時操作,比如每 3 分鍾測一次,隨機等待多少秒測一次都行。斷言,測試了接口之后,我們不僅要知道是否是可用的,同時也要判斷其結果是不是正確的,如果返回狀態碼是正確的但是結果不對,那也白搭,所以可以使用斷言來檢查返回結果。

關於 JMeter 的功能這里就不再展開講了,反正幾乎你想實現的任何測試功能都可以實現,具體的用法可以參考 JMeter 的官方文檔:https://jmeter.apache.org/usermanual/get-started.html。

嗯,寫好了之后,可以用 JMeter 在本地進行測試,測試好了時候,可以把 JMeter 的這個 Test Plan 存成一個 jmx 文件,留作后面備用。

對接 Prometheus

接下來就是如何把數據對接到 Prometheus 里面了。

默認情況下,JMeter 是能導出數據到諸如 InfluxDB 這樣的數據庫的,借助於它自帶的 Listener 即可實現。它並不帶導出到 Prometheus 的功能。

這里我們就需要借助於 jmeter-prometheus-plugin 這個插件了,其 GitHub 地址是 https://github.com/johrstrom/jmeter-prometheus-plugin,具體的用法可以參考其官方說明。

這里提示幾點:

jmeter-prometheus-plugin 安裝的時候把 jar 文件放到 JMeter 目錄下就好了,jar 文件可以直接看這里下載:https://github.com/johrstrom/jmeter-prometheus-plugin#programatically。安裝好這個插件之后,需要增加一個 Listener,然后配置各種導出字段和參數,可以參考這個 jmx 文件的配置:https://github.com/johrstrom/jmeter-prometheus-plugin/blob/master/docs/examples/simple_prometheus_example.jmx,可以把這個 jmx 打開,然后把 Listener 拷貝到你的 Test Plan 即可。jmeter-prometheus-plugin 這個插件會把 JMeter 變成一個 Data Exporter,而不是通過 Prometheus Push Gateway 來主動推送監控信息,所以它會在本地啟動一個端口,默認是 9270。

Listener 的配置示例如圖所示:

JMeter Listener

這里字段名如 jsr223_rt_as_summary 可以自行修改,比如這里我就統一修改為了 jmeter_test_xxx 這樣的字段。

配置完成之后,運行 JMeter 之后,我們就能在 http://localhost:9270 上看到 Exporter 的信息,如圖所示:

Exporter

這里面就包含了 JMeter 的一些接口測試結果,包括成功次數、失敗次數、狀態碼等等,另外還有 JVM、處理器等各種環境信息。

部署之后把對應的 URL 交由 Prometheus 就可以把監控數據收集到 Prometheus 里面了。

部署 JMeter

完成上述兩步,我們就能成功測試 Service 的每個接口並能生成測試結果的 Exporter 了。

那么 JMeter 寫好了,怎么來部署呢?可以用 crontab,放某台服務器上,不過這里最理想的方式當然是部署到 Kubernetes 里面了。

這里就需要把 JMeter 打包成一個鏡像了,GitHub 找來找去沒找到幾個合適的,另外也沒有把 jmeter-prometheus-plugin 包括進去,那只有自己來了。

我基於 https://github.com/justb4/docker-jmeter 進行了二次改寫,最后打包了一個鏡像,已經開源了,地址為:https://github.com/Germey/JMeterMonitor,鏡像名稱為 germey/jmeter,這里就不再展開講細節了,有點復雜。

運行所需要的 docker-compose 文件如下:

version: '3'
services:
  jmeter:
    restart: always
    image: 'germey/jmeter'
    volumes:
      - ./jmx:/app
    command:
      - sample.jmx
    ports:
      - "80:80"

這里我把本地的 jmx 文件夾 mount 到了 Docker 的 app 文件夾,所以這里在運行時需要在項目文件夾下新建 jmx 文件夾,用於存放 jmx 文件,把剛才寫好的 jmx 文件放過來就好了。

另外 command 就是 jmx 文件的名稱,這里需要修改成你的 jmx 文件。

另外部署到 Kubernetes 的話可以參考這里的 yml 文件:https://github.com/Germey/JMeterMonitor/tree/master/kubernetes。

Prometheus 收集數據

在成功部署 JMeter 之后呢,它肯定會提供一個 Web Service 來暴露 JMeter 的測試數據。

如果部署好了 Prometheus 之后,可以把它放在 Prometheus 的 scrape_configs,比如 Service 的 URL 為 jmeter-monitor.com,可以修改 prometheus.yml:

global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.


  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
    monitor: 'codelab-monitor'


# 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: 'jmeter-monitor'


    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s


    static_configs:
      - targets: ['jmeter-monitor.com']

其具體的配置字段可以參見:https://prometheus.io/docs/prometheus/latest/configuration/configuration/。

另外呢,這種方式其實並不怎么好,修改 Prometheus 挺麻煩的,推薦使用 Helm + Prometheus-Operator 來安裝 Prometheus,然后修改 values.yml 即可修改配置文件了,比如修改 https://github.com/helm/charts/blob/master/stable/prometheus-operator/values.yaml 里面的 additionalScrapeConfigs 即可。

Grafana 可視化

Prometheus 收集完數據之后,我們可以將其可視化出來了。

比如這里有些字段,jmeter_test_can_fail_success 代表成功請求的次數,jmeter_test_can_fail_total 代表總的測試次數。

那么就可以用一個表達式來計算 Error Rate 了:

1- jmeter_test_can_fail_success{instance="$instance"} / jmeter_test_can_fail_total{instance="$instance"}

效果如下:

配置面板

這里就能實時可視化展示出來錯誤率了,更多的一些配置可以自行修改這些表達式進行定制。

最后我配置成的一些監控面板如下所示:

監控面板

這樣我要是什么時候想看 Service 接口的情況,隨時上來看就好了。

報警

對於報警來說,可以使用兩種方式配置,一個是直接使用 Grafana 自帶的報警機制,另外是可以通過 Alert Manager,后者功能更加強大,推薦使用后者。

對於 Alert Manager 來說,其監控的規則這里推薦使用 Prometheus-Operator 里面自帶的 PrometheusRule 來實現,比如可以定義這么一個 PrometheusRule:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  labels:
    app: monitor
  name: monitor-rules
spec:
  groups:
  - name: monitor
    rules:
    - alert: ServiceErroring
      labels:
        severity: warning
      annotations:
        message: Service 連續5分鍾錯誤率過高。
      expr: |
        avg(1- jmeter_test_can_fail_success{job="service-monitor"} / jmeter_test_can_fail_total{job="service-monitor"}) > 0
      for: 5m

這樣配置好一個 PrometheusRule 之后,Prometheus 會自動應用這個 Rule 然后監控。

報警方式的話可以通過配置 Alert Manger 的 Receiver 來實現,包括打電話、郵件、短信等等,配置規則可以見:https://prometheus.io/docs/alerting/configuration/。

目前我是利用了組內已經提供的報警機制,組內已經對接好了電話、短信、郵件報警,並可以把每個人的信息進行管理和分組,然后應用到某個報警規則里面,這樣一旦有問題,就可以實現報警啦。

另外對於一些規則的管理,我們可以使用一些開源的 Dashboard 來管理,如 Krama,https://github.com/prymitive/karma,利用它我們可以方便配置、禁用和篩選一些報警規則,界面如下:

Krama

不過公司內部已經實現了一套了,對接了公司的員工賬號,更加方便,所以我就沒有再用這個了。

定時重啟

這里另外遇到了一個問題,就是 JMeter 導出的監控數據是不斷累積的,而監控的數據則是需要監控最近幾分鍾的數據,這樣一旦發生了 Error,那么 Error Rate 由於歷史數據的原因,在服務恢復之后永遠不會降為 0,這就導致一些問題。另外如果 JMeter 如果一直運行,其占用的內存會越來越大。

所以一個最好的方式就是定時將 JMeter 重啟,這樣可以定時清空歷史監控數據,保證在新的一段時間內測試獲取到最近的監控數據,而不是混雜歷史數據。

這里重啟就可以利用 Kubernetes 的 Cronjob,比如我們可以每隔 10 分鍾讓 JMeter 重啟一次,類似配置如下:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: jmeter-monitor
spec:
  successfulJobsHistoryLimit: 0
  failedJobsHistoryLimit: 0
  concurrencyPolicy: Replace
  schedule: "*/10 * * * *"
  jobTemplate:
    spec:
      template:
        metadata:
          labels:
            service: jmeter-monitor
        spec:
          containers:
            - args:
                - jmeter-monitor.jmx
              image: germey/jmeter:1
              name: jmeter-monitor
              volumeMounts:
                - mountPath: /app
                  name: jmeter-storage
              ports:
                - containerPort: 80
              imagePullPolicy: IfNotPresent
              resources:
                requests:
                  memory: "4Gi"
                  cpu: "250m"
                limits:
                  memory: "4Gi"
                  cpu: "250m"
          restartPolicy: OnFailure
          volumes:
            - name: jmeter-storage
              persistentVolumeClaim:
                claimName: jmeter

這里有幾個地方值得注意:

一個是 concurrencyPolicy,這里配置為 Replace,意思是重啟后新建的 Pod 會替換原來的 Pod,保證 JMeter 的 Pod 只有一個。另外一個是 imagePullPolicy 配置為 IfNotPresent,這樣可以每次重啟的時候不用重新拉鏡像。

這樣的話,就能避免發生錯誤的時候 Error Rate 無法降為 0 的狀態了。

好了,到此為止呢,我們就介紹完了使用 JMeter + Kubernetes + Prometheus + Grafana + Alert Manager 進行監控的整體思路了,希望對大家有幫助。

另外由於內容比較多,這里很多地方沒有展開講解,比如 JMeter 的配置、Grafana 的配置、Prometheus-Operator 的配置、Alert Manager 的配置等等,不知道大家感不感興趣,如果感興趣的話,后面可以繼續深入寫一個小系列來講解哈。

- END -

fin

開源項目Autotestplat,《自動化平台測試開發》作者

隱形字

個人公眾號:測試開發社區

長按識別二維碼關注


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM