原文連接:medium.com/@dnivra26/m…python
若是你剛接觸「Service Mesh「和「Envoy」,我這裏有一篇文章能夠幫你入門。nginx
這是Envoy service mesh下的可觀測性系列的第二篇文章,你能夠在這裏閱讀第一篇關於分佈式追蹤的文章。git
在微服務中談及監控時,你可不能被矇在鼓裏,至少要知道問題出在哪兒了。github
讓咱們看看Envoy是怎樣幫助咱們瞭解咱們的服務運行情況的。在service mesh下,全部的通訊都會經過mesh,這意味着沒有任何服務會與其它服務直接通訊,服務向Envoy發起調用請求,而後Envoy將調用請求路由到目標服務,因此Envoy將持有傳入和傳出流量的上下文。Envoy一般提供關於傳入請求、傳出請求和Envoy實例狀態的指標。redis
這是咱們將要構建的系統概覽。docker
Envoy支持經過兩到三種格式來暴露指標,但本文中咱們將使用statsd格式。shell
因此流程將是這樣,首先Envoy推送指標到statsd,而後咱們用prometheus(一個時序數據庫)從statsd拉取指標,最後經過grafana可視化這些指標。數據庫
在準備概覽圖中,我提到了statsd exporter而不是statsd,這是由於咱們並不會直接使用statsd,而是使用一個接收statsd格式數據,並將其以prometheus格式輸出的轉換器(服務)。下面讓咱們來搞定它吧。json
Envoy的指標主要分爲兩類:後端
讓咱們看一個包含stats sink的Envoy配置
---
admin:
access_log_path: "/tmp/admin_access.log"
address:
socket_address:
address: "127.0.0.1"
port_value: 9901
stats_sinks:
-
name: "envoy.statsd"
config:
tcp_cluster_name: "statsd-exporter"
prefix: front-envoy
static_resources:
listeners:
-
name: "http_listener"
address:
socket_address:
address: "0.0.0.0"
port_value: 80
filter_chains:
filters:
-
name: "envoy.http_connection_manager"
config:
use_remote_address: true
add_user_agent: true
access_log:
- name: envoy.file_access_log
config:
path: /dev/stdout
format: "[ACCESS_LOG][%START_TIME%] \"%REQ(:METHOD)% %REQ(X-ENVOY-ORIGINAL-PATH?:PATH)% %PROTOCOL%\" %RESPONSE_CODE% %RESPONSE_FLAGS% %BYTES_RECEIVED% %BYTES_SENT% %DURATION% %RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)% \"%REQ(X-FORWARDED-FOR)%\" \"%REQ(USER-AGENT)%\" \"%REQ(X-REQUEST-ID)%\" \"%REQ(:AUTHORITY)%\" \"%UPSTREAM_HOST%\" \"%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%\"\n"
stat_prefix: "ingress_443"
codec_type: "AUTO"
generate_request_id: true
route_config:
name: "local_route"
virtual_hosts:
-
name: "http-route"
domains:
- "*"
routes:
-
match:
prefix: "/"
route:
cluster: "service_a"
http_filters:
-
name: "envoy.router"
clusters:
-
name: "statsd"
connect_timeout: "0.25s"
type: "strict_dns"
lb_policy: "ROUND_ROBIN"
hosts:
-
socket_address:
address: "statsd_exporter"
port_value: 9125
-
name: "service_a"
connect_timeout: "0.25s"
type: "strict_dns"
lb_policy: "ROUND_ROBIN"
hosts:
-
socket_address:
address: "service_a_envoy"
port_value: 8786
複製代碼
第8-13行告訴Envoy咱們須要statsd格式的指標、咱們的統計信息前綴(一般是你的服務名)是什麼和statsd sink的地址。
第55-63行配置了咱們的環境中的statsd sink。
這就是讓Envoy輸出統計信息所須要的全部配置。如今讓咱們來看看第2-7行作了哪些事情:
你須要將相同的配置添加到系統中的其它Envoy sidecar上(是的,每一個服務都有本身的Envoy sidecar)。
這些服務自己是用go寫的,它們作的事情很簡單,僅僅是經過Envoy調用其它服務。你能夠在這裏查看服務和Envoy的配置。
如今,雖然咱們只有圖中的statsd exporter,但有了它,若是咱們運行docker容器(docker-compose build & docker-compose up),而後向Front Envoy(localhost:8080)發送一些流量,Envoy 將把這些流量的指標發送到statsd exporter,隨後statsd exporter會把這些指標轉換成prometheus格式,並將其暴露在9102端口。
Statsd exporter中的統計信息格式以下圖所示
這裏邊將有上百個指標,同時,在上面的截圖中咱們能看到Service A和Service B之間的通訊延遲指標。上圖的指標是遵循prometheus格式的
metric_name ["{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}"] value [ timestamp ]
複製代碼
你能夠在這裏瞭解更多。
咱們將使用Prometheus做爲時序數據庫來保存咱們的指標。Prometheus不只是一個時序數據庫,它自己仍是一個監控系統,但本文咱們只用它來存儲指標數據。須要注意的是,prometheus是一個經過主動拉取來獲取指標的系統,這意味着你必須告訴prometheus從何處拉取指標,在咱們的例子中是從statsd exporter處拉取。
將Prometheus添加到系統中很是簡單而又直接,咱們只須要將拉取目標(statsd exporter)做爲配置文件傳遞給Prometheus就能夠了。配置看起來是這樣的
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'statsd'
scrape_interval: 5s
static_configs:
- targets: ['statsd_exporter:9102']
labels:
group: 'services'
複製代碼
scrape_interval的值表示Prometheus從目標處拉取配置的頻率。
如今啓動Prometheus,裏面應該有一些數據了。讓咱們打開localhost:9090來看一看
如圖所示,能夠看到咱們的指標。你能作的可不單單是選擇已有的指標,從這裏能夠閱讀關於prometheus查詢語言的更多信息。它還能夠基於查詢結果繪製圖表,除此以外還有一個報警系統。
若是咱們打開prometheus的targets頁面,將能看到全部的拉取目標和它們的健康狀態
Grafana是一個很棒的監控可視化解決方案,它支持Prometheus,Graphite,InfluxDB,ElasticSearch等多種後端。
Grafana有兩大主要組件須要咱們配置
數據源(Datasource):指定grafana從哪一個後端獲取指標。你能夠經過配置文件來配置數據源,代碼以下所示
apiVersion: 1
datasources:
- name: prometheus
type: prometheus
access: Server
url: http://prometheus:9090
editable: true
isDefault:
複製代碼
儀表盤(Dashboard):你能夠從儀表盤查看來自數據源的指標。Grafana支持多種可視化元素,如Graphs,Single Stats,Heatmaps……你能夠繼承這些元素並使用插件來構造本身的元素。
我在使用Grafana時遇到的惟一一個問題是,缺乏一種標準的方法來用代碼開發那些儀表盤。所幸有一些第三方的庫提供了支持,咱們將使用來自weaveworks的grafanalib。
下面是咱們經過 python 代碼嘗試構建的一個儀表盤
from grafanalib.core import *
import os
dashboard = Dashboard(
title="Services Dashboard",
templating=Templating(
[
Template(
name="source",
dataSource="prometheus",
query="metrics(.*_cluster_.*_upstream_rq_2xx)",
regex="/(.*)_cluster_.*_upstream_rq_2xx/",
default="service_a"
),
Template(
name="destination",
dataSource="prometheus",
query="metrics(.*_cluster_.*_upstream_rq_2xx)",
regex="/.*_cluster_(.*)_upstream_rq_2xx/",
default="service_b"
)
]
),
rows=[
Row(
panels=[
Graph(
title="2XX",
transparent=True,
dataSource="prometheus",
targets=[
Target(
expr="[[source]]_cluster_[[destination]]_upstream_rq_2xx - [[source]]_cluster_[[destination]]_upstream_rq_2xx offset $__interval",
legendFormat="2xx"
)
]
),
Graph(
title="5XX",
transparent=True,
dataSource="prometheus",
targets=[
Target(
expr="[[source]]_cluster_[[destination]]_upstream_rq_5xx - [[source]]_cluster_[[destination]]_upstream_rq_5xx offset $__interval",
legendFormat="5xx"
),
]
),
Graph(
title="Latency",
transparent=True,
dataSource="prometheus",
targets=[
Target(
expr="[[source]]_cluster_[[destination]]_upstream_rq_time",
legendFormat="{{quantile}}"
)
]
)
]
),
]
).auto_panel_ids()
複製代碼
在這段代碼中,咱們爲2xx,5xx和延遲數據構建了圖表。其中第5-22行很重要,它從咱們的設置中提取可用的service names做爲grafana的變量,爲咱們建立一個動態的儀表盤,這意味着咱們可以選擇性地查看特定源服務和目標服務的統計數據。若是想了解更多關於變量的內容請參考這裏。
你須要經過grafanalib命令來從上述python文件生成儀表盤
generate-dashboard -o dashboard.json service-dashboard.py
複製代碼
注意這裏生成的dashboard.json可不容易閱讀。
因此,啓動Grafana時咱們只須要傳遞儀表盤和數據源就行了。當訪問http:localhost:3000時,你將看到:
如今你應該能看到2xx,5xx和延遲的圖表,同時還能看到一個下拉菜單,你能夠經過它選擇源服務和目標服務。關於Grafana還有許多內容咱們沒有討論到,包括強大的查詢編輯器和告警系統。更重要的是,這一切都是能夠經過插件和應用擴展的,能夠參考這裏的例子。若是你正想可視化常見服務如redis,rabbitmq等的指標,grafana有一個公共儀表盤庫,你只須要導入它們就能夠使用了。使用Grafana 還有一個好處,你能夠經過配置文件和代碼建立和管理全部東西,而不須要過多地經過UI來操做。
我建議你試用一下prometheus和grafana以瞭解更多信息。感謝閱讀,若有建議和意見,請寫在評論中。
在這裏能夠找到全部代碼和配置文件。