華爾街見聞基於istio的服務網格實踐

距離2017 年的見聞技術架構調整接近 2 年,隨着業務線的發展,見聞技術部的項目數量、項目架構類型、基礎設施規模、服務變動頻率都在不斷地增加,帶給 SRE 的挑戰是如何能更快地助力於開發人員更快更穩定地部署服務,保障線上服務的穩定。前端

咱們的後端開發團隊仍然以 Golang 爲主,不一樣業務線的技術選型不盡相同,同時存在 Python,Java 服務,這就須要 SRE 提供更易接入的微服務基礎組件,常見的方案就是爲每種語言提供適配的微服務基礎組件,但痛點是基礎組件更新維護的成本較高。git

爲了解決痛點,咱們將目光放到服務網格,它能利用基礎設施下沉解決多語言基礎庫依賴問題,不一樣的語言不須要再引入各類不一樣的服務發現、監控等依賴庫,只需簡單的配置並運行在給定的環境下,就能享有以上功能,同時網絡做爲最重要的通訊組件,能夠基於它實現不少複雜的功能,譬如根據不一樣可用區進行的智能路由、服務熔斷降級等。github

爲此,咱們調研了一些服務網格方案,包括IstioLinkerd,基於咱們的當前的後端架構特色:golang

  • 服務通訊協議主要基於 gRPC、HTTP
  • 基於 Kubernetes 的 Docker 部署
  • 擁抱開源,使用了 Prometheus、Grafana 做爲監控,Zipkin 做爲鏈路追蹤等

對比下來,Istio 擁有更多活躍的開源貢獻者,迭代速度快,以及 Istio 架構可行性討論,咱們選擇 Istio 做爲實踐方案。docker

架構

Service Mesh

這張圖介紹了見聞典型的服務網格架構,左半圖介紹了一個用戶請求是如何處理,右半圖介紹運維繫統是如何監控服務,若無特殊說明,服務都是部署在騰訊雲託管 Kubernetes。數據庫

組件一覽

  • Go(1.11) 後端語言。
  • Docker(17.12.1-ce) 容器技術。
  • Kubernetes(1.10.5,託管於騰訊雲容器平臺) 容器編排工具。
  • Istio(1.0.0) 服務網格開源方案,支持與 Kubernetes 集成。
    • Ingress, Proxy(Istio 1.0.0) 服務流量轉發、智能代理,基於Envoy實現,Istio 二次開發Proxy
    • Pilot Discovery(Istio 1.0.5) 負責服務發現,經過監聽 Kubernetes 中ServicePod等資源維護服務映射表。
    • Mixer Policy(Istio 1.0.5) 管理服務之間訪問權限,提供 gRPC 形式的 Check 接口。
    • Mixer Telemetry(Istio 1.0.5) 負責接收服務指標數據,提供 gRPC 形式的 Report 接口。
    • Citadel 負責管理代理證書。
  • Dashboard 基於Kubernetes Dashboard二次開發的Istio Dashboard,負責管理 Istio 服務發佈,配置變動等。
  • Grafana 負責監控數據可視化。
  • Prometheus 時序數據庫,經常使用於監控系統。
  • Jaeger 負責服務鏈路追蹤,組件包括 collector、Jaeger UI。
  • Cassandra 分佈式 NoSQL 數據庫,用於 Jaeger 指標數據存儲。

用戶請求分析

  1. 咱們先從用戶請求端開始,用戶的請求經過 Tencent 4 層 LB 轉發到基於 Envoy 的 Istio Ingress,Ingress 根據配置將請求路由到 Service A 所在的 Pod
  2. Service A 所在 Pod 接收 Ingress 請求
    • 訪問 Service A 的請求會先到達 Proxy 再由它轉發到 Service A 進程
    • Service A 向 Service B 發出的請求被 iptables 路由到 Proxy(下文會提到 iptables 的初始化)
    • Proxy 進程發起對 Service B 所在 Pod 的請求
      • Proxy 進程同步請求 Mixer Policy 服務,檢查是否容許訪問 Service B,檢查經過,開始請求
      • Proxy 進程記錄請求的指標(QPS,Latency,Status Code 分佈等),異步並批量上報到 Mixer Telemetry 服務,這裏是客戶端指標
  3. Service B 所在 Pod 接收請求
    • Service B Proxy 接收請求並路由到 Service B 所在進程
      • Proxy 進程記錄請求的指標(QPS,Latency,Status Code 分佈等),異步並批量上報到 Mixer Telemetry 服務,這裏是服務端指標
    • Service B 進程處理完請求並返回
  4. 數據原路返回到用戶端

以上的流程能夠觀察到,服務之間通訊徹底依靠 Proxy 進程完成,Proxy 進程接管同一個 Pod 中服務的出入流量,完成請求的路由。apache

架構可行性

經過架構圖以及以上流程,咱們拆分出如下關鍵組件,觀察其性能、可用性、拓展性。後端

  1. Istio Ingress 高性能,可拓展 Istio Ingress 用來處理用戶入流量,使用 Envoy 實現,轉發性能高。掛載在負載均衡後,經過增長實例實現可拓展。api

  2. Istio Proxy 隨應用部署,輕微性能損耗,可隨應用數量拓展 Istio Proxy 以Sidecar形式隨應用一塊兒部署,增長 2 次流量轉發,存在性能損耗。 性能: 4 核 8G 服務器,上面運行 Proxy 服務和 API 服務,API 服務只返回 ok 字樣。(此測試只測試極限 QPS) 單獨測試 API 服務的 QPS 在 59k+,平均延時在 1.68ms,CPU 佔用 4 核。 經過代理訪問的 QPS7k+,平均延時 14.97ms,代理 CPU 佔用 2 核,API 服務 CPU 佔用 2 核。 CPU 消耗以及轉發消耗下降了 QPS,增長了延時,經過增長機器核數並增長服務部署數量緩解該問題,通過測試環境測試,延時能夠接受。 可用性:基於 Envoy,咱們認爲 Envoy 的可用性高於應用。依賴 Pilot Discovery 進行服務路由,可用性受 Pilot Discovery 影響。 拓展性:Sidecar 形式,隨應用數拓展緩存

  3. Istio Policy 服務可拓展,但同步調用存在風險 Istio Policy 須要在服務調用前訪問,是同步請求,會增長服務調用延時,經過拓展服務數量增長處理能力。屬於可選服務,見聞生產未使用該組件。 性能: 未測試 可用性:若開啓 Policy,必須保證 Policy 高可用,不然正常服務將不可用 拓展性:增長實例數量進行拓展

  4. Istio Telemetry 監控收集服務 性能: 從監控上觀察 Report 5000qps,使用 25 核,響應時間 p99 在 72ms。異步調用不影響應用的響應時間。 可用性:Telemetry 不影響服務可用性 拓展性:增長實例數量進行拓展

  5. Pilot Discovery 性能: 服務發現組件 1.0.5 版本通過監控觀察,300 個 Service,1000 個 Pod,服務變動次數 1 天 100 次,平均 CPU 消耗在 0.01 核,內存佔用在 1G 之內。 可用性: 在服務更新時須要保證可用,不然新建立的 Pod 沒法獲取最新路由規則,對於已運行 Pod 因爲 Proxy 存在路由緩存不受 Pilot Discovery 關閉的影響。 拓展性:增長實例數量能夠增長處理量。

能夠看到各個組件的可用性、拓展性都有相應的策略達到保障,咱們認爲 Istio 是具備可實施性的。

Istio 流量控制背後

Pilot Discovery: Istio 的交通大腦

Pilot Discovery 負責 Istio 服務發現,支持在 Kubernetes 裏部署,它讀取 K8S 資源配置,並生成 Proxy 可用的路由表。如下面的 Service A 服務爲例,介紹 Istio 如何進行精細路由。

Pilot Discovery生成配置

  1. Discovery 與對應 K8S 集羣的 API server 相連,拉取全量資源信息,並使用 Watch 方法對增量變動進行同步。
  2. 根據 Service A 的配置,生成對應 Service A 的路由配置,經過 gRPC 形式的 ADS 接口提供給 Proxy。
  3. Proxy 同步到最新配置,熱更新後配置生效。

要知道若是在 Istio 訪問一個服務,必須得聲明 K8S Service

Istio 經過 K8S CRD拓展 K8S 已有的服務訪問能力,咱們列舉網絡相關經常使用的配置:

  • Gateway 控制 Istio Ingress 的路由轉發及 TLS 證書綁定。
  • VirtualService 服務流量控制,實現如 A/B 測試、錯誤注入、服務保護等。
  • DestinationRule 用於目標服務的版本管理,根據 Pod 的 Label 區分目標服務的版本,聯合 VirtualService 進行流量控制。

如下舉個例子介紹如何利用它們配置一樣大小流量到服務的不一樣版本,

# serviceA.yaml
kind: Service
apiVersion: v1
metadata:
 name: serviceA
 labels:
 app: serviceA
spec:
 ports:
 - name: http-8080
 protocol: TCP
 port: 8080
 targetPort: 8080
 selector:
 app: serviceA
 type: ClusterIP

# virtualServiceA.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: serviceA
spec:
 hosts:
 - serviceA
 http:
 - route:
 - destination:
 host: serviceA
 subset: v1
 - route:
 - destination:
 host: serviceA
 subset: v2
---
# destinationRule
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
 name: serviceA
spec:
 host: serviceA
 subsets:
 - labels:
 version: v1
 name: v1
 - labels:
 version: v2
 name: v2
複製代碼

以上實現了 Istio 服務調用 serviceA 時,會隨機地 50%機率到 serviceA 的 v1 版本,50%機率到 serviceA 的 v2 版本。

能夠看到,VirtualService 經過 hosts 關聯 serviceA,在 http 區域有兩個 route,分別是 subset v1, subset v2,v1,v2 依賴 DestinationRule 來定義,一樣用 host 來標註該 DestinationRule 控制哪一個 host 的訪問,以及經過 pod label 中 version 來劃分不一樣版本。

流量控制方面,Istio 有至關豐富的功能支持,同時也帶來了至關的複雜度,建議用戶根據平常的使用頻率在後臺實現相應的前端控制檯,利用自動化來完成流量控制。

Proxy 工做機制

  1. 自動注入 在 K8S 1.9 以後的版本,Istio 利用 K8S 提供的MutatingAdmissionWebhook在 K8S 建立 Pod 前回調 Istio 提供的 istio-sidecar-injector 動態修改 Pod 配置,添加以 Sidecar 形式運行的 Proxy。這裏開啓自動注入有兩個維度,一是 namespace,namespace 須要添加istio-injection : enabled標籤,這樣實現該 namespace 下的全部 Pod 自動注入 Proxy;二是 deployment 能夠設置 annotation 關閉自動注入。 若是 K8S 版本不夠,能夠利用命令行工具修改 Deployment 的配置。
  2. 接管 Pod 流量 Service A 所在 Pod 至少運行 Service A 應用容器以及用於代理的 Envoy 容器,建立 Pod 時 proxy-init 命令負責獲取 Pod 監聽的端口和具體協議,以此初始化網絡,利用 iptables 將容器網絡出入流量都轉發到 Proxy 監聽的 localhost 端口。 若 Service A 的 Pod 聲明 servicePort 爲 8080:HTTP,最終 Proxy 將會接收 8080 端口的 Pod 入流量和所有的 Pod 出流量。
  3. 服務發現 Proxy 基於 Envoy,與 Pilot Discovery 鏈接,動態同步 Kubernetes 集羣中全部的服務信息:服務與 Pod IP、端口之間的映射表,經過路由信息實現智能路由,從而使服務發現從業務代碼中剝離。
  4. 鏈路追蹤 Proxy 支持設置 Zipkin URL,異步上報鏈路追蹤數據。
  5. 服務質量監控 Proxy 將屬性包上報給 Telemetry 服務,Telemetry 根據用戶的配置生成指標數據並由 Prometheus 收集。

適配 Istio

咱們目前的服務部署在騰訊雲託管 Kubernetes,節點使用 16 核 32G 的網絡加強型機器,全部的後端服務都以 Docker 部署,K8S 集羣外部署高可用 ETCD 支持集羣內服務發現,數據庫以 MySQL、Cassandra、MongoDB 爲主,消息隊列採用 Kafka、NSQ。在應用 Istio 的過程當中,咱們對基礎庫進行了修改,刪減了 Istio 已提供的功能並完成了對 Istio 的適配。

前情提要

見聞舊後端服務架構,全部 Golang 服務以打包成 Docker 鏡像,以"gRPC"協議通訊。

old-infrastructure

去"框架"

見聞 Golang 後端使用go-micro 框架,一個支持多插件的 Golang 微服務框架,做者將組件分紅 transport,server,client,registry,codec 等,經過組合不一樣類型的組件很是靈活地配置微服務技術棧。對於有定製需求的微服務架構,是值得推薦的選擇。

通訊協議做爲服務互通的基石,Istio 對 gRPC 和 HTTP 很是友好,根據協議 Istio 能解析 HTTP 頭中的信息,支持提取指標以供分析。go-micro 只是利用 HTTP 和 gRPC 做爲通訊協議,可是協議的解析邏輯是協議無關的,因此能夠說它只是用了這些通訊協議的外殼,傳輸的報文內容是"micro 方言",這就致使了 Golang 暴露的服務沒法被其它語言其它框架調用。爲了將協議能在多語言中徹底統一,也爲了更好地使用 Istio 的監控統計功能,這個時候咱們開始對 go-micro 的存留有一些新的思考,咱們是否還須要 go-micro?通過近 2 年的生產實踐,咱們是否是能夠更精簡咱們的框架?

通過這些思考事後,咱們的決定是去 go-micro 框架,擁抱更輕量級的基礎框架,這個框架只要支持:

  • gRPC 純原生便可
  • Istio 支持 Istio 的基礎功能,譬如一些 HTTP header 轉發等
  • 改動儘可能小 咱們已經存在上百個 Golang 項目,避免改動 Golang 項目代碼,將改動放到基礎庫爲佳

go-micro 經過定義自制 protobuf 插件的方式在 stub 代碼中集成框架功能,通過對邏輯的梳理,咱們決定複寫 protobuf 插件,生成兼容 micro 的 stub 代碼,經過對 micro 接口的向後兼容,開發人員不須要修改代碼,只須要在 CI 階段運行 protoc 即時生成新版代碼。

詳情可見再見,micro

運維流程

右半圖描述運維人員如何利用運維後臺運維 Kubernetes 集羣,Istio 的運維必須有自動化的工具來減小人工配置帶來的錯誤,見聞的舊運維後臺基於騰訊雲容器平臺暴露的開放 API,在引入 Istio 後,功能依賴於更細節的 label 以及 CRD(Custom Resource Definition),因而得依託更細粒度的 Kubernetes API,新的後臺須要能完成基本的 Kubernetes 運維,並且結合 Istio 的實際進行平常更新,通過選型,見聞基於 Kubernetes Dashboard 二次開發了 Istio 部分的一些功能(APP 部署、更新,Istio 配置更新等),利用 Istio Dashboard 實現 APP 建立、部署接口,並由此重構原有的運維後臺。

最終,SRE 提供兩個後臺,精細控制的 Istio Dashboard;提供給開發人員平常更新使用的簡化版後臺。

服務發佈

平常最重要、最高頻的功能,服務版本變動。

服務建立

服務建立包括對老服務的改造,一個 K8S 服務要通過一些配置上的更新才能成爲 Istio APP。一個 Kubernetes 服務須要知足如下要求來得到 Istio 的功能支持:

  • Service資源聲明服務監聽的端口號以及協議 這裏的服務端口聲明中 name 字段值須要以協議名爲起始值,譬如 grpc、http、tcp、udp 等,istio 識別前綴,用於初始化 Proxy,譬如grpc-svchttp-svc,不正確的端口命名會引發 Proxy 的異常行爲,以及監控服務沒法捕獲該協議下的指標。

  • 服務探活接口 每一個後端服務提供一個 HTTP 探活接口,這樣服務啓動時,不至於讓其它服務訪問到未就緒的狀態。 對於 HTTP 探活接口的定義包括 Proxy 以及 APP 是否初始化完成,見聞的實踐是在基礎鏡像中打入一個探活程序:

    1. 檢測 Proxy 是否初始化 經過 Proxy 的配置同步時間與 Pilot Discovery 的配置更新時間對比,相同時認爲其就緒。
    2. APP 自定義接口 APP 能夠在指定端口提供就緒 API。
    # serviceA.yaml
    kind: Service
    apiVersion: v1
    metadata:
     name: serviceA
     namespace: default
     labels:
     app: serviceA
    spec:
     ports:
     - name: grpc
     protocol: TCP
     port: 10088
     targetPort: 10088
     selector:
     app: serviceA
     type: ClusterIP
    複製代碼
  • Deployment 資源要求

    1. 有必要的兩個 label:app 和 version,明肯定義流量控制中的目標服務。 能夠看例子中 deployment 的 app 爲 serviceA,version 爲 v1。
    2. 聲明對外服務的端口,要求 Proxy 對指定端口入流量的接管。 例子中 ports 聲明瞭 10088 端口。
    # deploymentA.yaml
    kind: Deployment
    apiVersion: extensions/v1beta1
    metadata:
     name: serviceA-v1
     labels:
     app: serviceA
     version: v1
    spec:
     replicas: 1
     selector:
     matchLabels:
     app: serviceA
     version: v1
     template:
     metadata:
     labels:
     app: serviceA
     version: v1
     spec:
     containers:
     - name: serviceA
     image: "some-image"
     ports:
     - containerPort: 10088
     protocol: TCP
     resources:
     requests:
     cpu: 1000m
     livenessProbe:
     httpGet:
     path: /health
     port: 54321
     scheme: HTTP
     initialDelaySeconds: 1
     timeoutSeconds: 2
     periodSeconds: 5
     successThreshold: 1
     failureThreshold: 3
     terminationMessagePath: /dev/termination-log
     terminationMessagePolicy: File
     imagePullPolicy: Always
     securityContext:
     privileged: false
     restartPolicy: Always
     terminationGracePeriodSeconds: 30
     dnsPolicy: ClusterFirst
    複製代碼

符合以上要求,服務能正確接入 Istio 系統並得到服務發現和監控的能力。

服務更新

Istio 提供流量控制,給運維帶來方便的 A/B 測試,用於根據指定規則遷移流量。 見聞的服務更新依靠 Istio 流量遷移功能,發佈服務的新版本,並將流量經過 Istio 規則遷移到新版本,實際細節以下:

  1. 更新流量控制將流量指向已有版本 如下實例利用 VirtualService 將 ServiceA 的服務流量所有指向已存在的 v1 版本
    # virtualService
    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
     name: serviceA
    spec:
     hosts:
     - serviceA
     http:
     - route:
     - destination:
     host: serviceA
     subset: v1
    ---
    # destinationRule
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
     name: serviceA
    spec:
     host: serviceA
     subsets:
     - labels:
     version: v1
     name: v1
    複製代碼
  2. 部署新版本的 Deployment 查找符合 app label 的 deployment,運維人員基於該 deployment 建立 v2 版本的 deployment,並向 destinationRule 中增長 v2 版本。 yaml # destinationRule apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: serviceA spec: host: serviceA subsets: - labels: version: v1 name: v1 - labels: version: v2 name: v2
  3. 更新流量控制將流量指向新版本 如下實例利用 VirtualService 將 ServiceA 的服務流量所有指向 v2 版本 yaml # virtualService apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: serviceA spec: hosts: - serviceA http: - route: - destination: host: serviceA subset: v2
  4. 下線 v1 版本的 deployment,刪除 DestinationRule 中的 v1

使用Istio Dashboard來實現上述流程

canary-deployment

Ingress 配置

爲何使用 Istio Ingress 做爲新的 Ingress 方案?

過去咱們使用騰訊雲託管的 Kubernetes Ingress,爲了對 Ingress 流量控制而引入 Istio Ingress。咱們以前提到 Istio Ingress 是基於 Envoy,它讀取 Istio 控制的配置進行路由,與其它內部服務同樣方便地接入 Istio 全部功能。

除了 VirtualService 和 DestinationRule,Istio 定義了 Gateway 來控制實例支持的 Host 和證書。具體的流程是:

  1. 建立 Istio Ingress 提供的 Deployment 和 Service 建立 Deployment ingressgateway 時,以 ConfigMap 的形式掛載 Ingress 須要的證書。
  2. 配置 Gateway 配置 Ingress 接收具體域名(如 wallstreetcn.com)的流量,以及對應的 TLS 證書位置,這裏的證書路徑已經掛在到 Ingress 的 Deployment 上。如下是一個典型的 Gateway 配置。
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
 name: wallstreetcn-com
 namespace: istio-system
spec:
 selector:
 istio: ingressgateway
 servers:
 - hosts:
 - wallstreetcn.com
 port:
 name: http
 number: 80
 protocol: HTTP
 - hosts:
 - wallstreetcn.com
 port:
 name: https
 number: 443
 protocol: HTTPS
 tls:
 mode: SIMPLE
 privateKey: /etc/istio/ingressgateway-certs/tls.key
 serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
複製代碼

配置完成後,再配合 VirtualService 的路由控制,控制 Ingress 的反向代理到 default 命名空間下的 gateway 服務 80 端口,以下所示:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: wallstreetcn-com
 namespace: istio-system
spec:
 gateways:
 - wallstreetcn-com
 hosts:
 - wallstreetcn.com
 http:
 - route:
 - destination:
 host: gateway.default.svc.cluster.local
 port:
 number: 80
複製代碼

監控指標

Istio 支持 Prometheus 拉取集羣指標,並提供 Grafana 看板展現。這裏建議初期使用 Istio 自帶的 Grafana 看板配置,而且注意 Kubernetes 主機的類型劃分,Prometheus 服務適合放在內存型機器。能夠與 Dashboard 集成,在發佈服務過程當中即時查看指標。

服務質量

Istio 自帶一些默認的 Grafana 面板,統計全部能夠被訪問的 HTTP/gRPC 服務的返回碼以及延時狀況。

對於返回碼,認爲 5xx 爲錯誤,並在面板上使用label_join((sum(rate(istio_requests_total{reporter="destination", response_code!~"5.*"}[1m])) by (destination_workload, destination_workload_namespace) / sum(rate(istio_requests_total{reporter="destination"}[1m])) by (destination_workload, destination_workload_namespace)), "destination_workload_var", ".", "destination_workload", "destination_workload_namespace")計算服務錯誤率。

對於延時狀況採用histogram_quantile獲取多維度 p50、p90、p9五、p99 的延時分佈。

istio-mesh

鏈路追蹤

以前提到 Proxy 由 Envoy 實現,Envoy 支持設置 Zipkin 上報 API,Proxy 在收發請求時將鏈路指標上報到 Zipkin,爲了實現鏈路追蹤,Proxy 在流量轉發中解析協議中的 HTTP 或 gRPC 請求頭,找出其中的追蹤頭,組裝成指標。 因此應用端須要在收到調用方請求時解析出請求頭,並持續攜帶該請求頭向後傳遞。 因爲見聞在 Ingress 以後映射一個 HTTP gateway,請求從 Ingress 轉發到 HTTP gateway,再發送到後續的 gRPC 服務,因此 HTTP gateway 有段代碼生成 gRPC 請求頭。

import (
  "github.com/labstack/echo"
  gmeta "google.golang.org/grpc/metadata"
)

// Create a gRPC context from Echo.
func NewContextFromEcho(ec echo.Context) context.Context {
  md := gmeta.MD{}
  for _, header := range []string{
    "x-request-id",
    "x-b3-traceid",
    "x-b3-spanid",
    "x-b3-parentspanid",
    "x-b3-sampled",
    "x-b3-flags",
    "x-ot-span-context",
  } {
    md.Set(header, ec.Request().Header.Get(header))
  }

  md.Set("x-b3-parentspanid", ec.Request().Header.Get("x-b3-spanid"))
  return gmeta.NewOutgoingContext(context.Background(), md)
}
複製代碼

在後續的 gRPC 服務調用中使用該 Context,至於 gRPC 服務之間的調用,咱們發現會自動將 context 傳遞到下一個服務,因此沒有作相似處理。

這裏追蹤的數據若是全量捕獲將會是很是大的,而且對於監控來講也沒必要要,因此能夠設置抽樣率,Istio 提供 ConfigMap 中設置抽樣率,通常來講設置成 1%便可。

實踐中的寶貴經驗

在 Istio 實踐過程當中,有哪些須要注意的問題。

  1. API server 的強依賴,單點故障 Istio 對 Kubernetes 的 API 有很強的依賴,諸如流量控制(Kubernetes 資源)、集羣監控(Prometheues 經過 Kubernetes 服務發現查找 Pod)、服務權限控制(Mixer Policy)。因此須要保障 API server 的高可用,咱們曾遇到 Policy 組件瘋狂請求 Kubernetes API server 使 API server 沒法服務,從而致使服務發現等服務沒法更新配置。 _ 爲避免這種請求,建議使用者瞭解與 API server 直接通訊組件的原理,並儘可能減小直接通訊的組件數量,增長必要的 Rate limit。 _ 儘可能將與 API server 通訊的服務置於能夠隨時關閉的環境,這是考慮若是部署在同一 Kubernetes 集羣,若是 API server 掛掉,沒法關閉這些有問題的服務,致使死鎖(又想恢復 API server,又要依靠 API server 關閉服務)

  2. 服務配置的自動化 服務配置是 Istio 部署後的重頭戲,避免使用手動方式更改配置,使用代碼更新配置,將經常使用的幾個配置更新操做作到運維後臺,相信手動必定會犯錯的事實。

  3. 關於 Pilot Discovery Pilot Discovery 1.0.0 版本有很大的性能問題,1.0.4 有很大的性能提高,但引入了一個新 bug,因此請使用 1.0.5 及以上的版本,該版本在見聞的平均 CPU 負載從 10 核降到了 0.5 核,大大下降了 Proxy 同步配置的延時。

  4. 關於 Mixer Policy 1.0.0 這個組件曾致使 API server 負載太高(很高的 list pods 請求),因此咱們暫時束之高閣,慎用。

  5. 性能調優 在使用 Proxy、Telemetry 時,默認它們會打印訪問日誌,咱們選擇在生產上關閉該日誌。 時刻觀察 Istio 社區的最新版本,查看新版本各個組件的性能優化以及 bug 修復狀況,將 Istio 當作高度模塊化的系統,單獨升級某些組件。上面就提到咱們在 Istio1.0 的基礎上使用了 1.0.5 版本的 Policy、Telemetry、Pilot Discovery 等組件。

  6. 服務平滑更新和關閉 Istio 依靠 Proxy 來幫助 APP 進行路由,考慮幾種狀況會出現意外的狀態: _ APP 啓動先於 Proxy,並開始調用其它服務,這時 Proxy 還沒有初始化完畢,APP 調用失敗。 _ Service B 關閉時,調用者 Service A 的 Proxy 還沒有同步更新 Service A 關閉的狀態,向 Service B 發送請求,調用失敗。

第一種狀況要求 APP 有重試機制,能適當重試請求,避免啓動時的 Proxy 初始化與 APP 初始化的時差。 第二種狀況,一種是服務更新時,咱們使用新建新服務,再切流量;一種是服務異常退出,這種狀況是在客戶端重試機制。但願使用 Istio 的開發人員有更好的解決方案。

下一步計劃

見聞 Istio 化已於去年 10 月份完成並上線,咱們的線上集羣中 Istio 和非 Istio 的 APP 混合部署,上千的 Pod 數量曾對不夠健壯的服務發現組件形成巨大的壓力,在這期間曾遇到 Istio 的一些驚喜,並不斷總結經驗,但願給以後使用 Istio 的同窗一些借鑑。以後的過程當中,SRE 的目標依然是保障線上服務的健壯性。

  1. Istio Dashboard 優化 APP 部署流程,考慮自動部署的功能,經過服務指標自動完成灰度發佈和流量遷移。
  2. Prometheus Prometheus 的高可用、可拓展方案的探索。
相關文章
相關標籤/搜索