iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Cloud Native

時光之鏡:透視過去、現在與未來的 Observability系列 第 28

In Production - 能力越強責任越大,別成為單點故障

  • 分享至 

  • xImage
  •  

當大家都依靠 Observability 確保服務品質時,我們能保證他們一定永遠健康強壯嗎?如果連確保系統運作正常的機制也壞掉了,那我們還能知道問題發生了嗎?這也是為什麼大部分負責收集與儲存資料工作的 Observability 工具都會強調他們具備 「可擴展性(Scalability)」與「高可用性(High Availability, HA)」。這兩個特性在微服務架構的設計中佔有關鍵地位,因為它們直接影響服務性能和使用者體驗。

  1. 可擴展性(Scalability):隨著使用者數量增加或資料處理需求升高,服務能夠無縫地水平擴展,以滿足各方面需求,同時不影響當前效能和使用者體驗。
  2. 高可用性(High Availability, HA):即使面對硬體故障、網路問題或其他不確定因素,服務仍需提供穩定和可靠的運行。這通常透過冗餘(redundancy)和故障轉移機制來達成。

Observability 工具不僅需要監控正在運行的服務,也需要隨著系統變化靈活地擴展,以確保在各種狀況下都能提供穩定的服務。

Scalability

在微服務架構中,可擴展性常常是透過水平擴展(Horizontal Scaling)來實現,也就是增加機器或實例(Instance)數量。與之相對的是垂直擴展(Vertical Scaling),也就是增加單一硬體的配置(如CPU、記憶體、硬碟等),很容易受限於物理條件。水平擴展的前提是,資料的讀取與寫入機制必須從一開始就設計為可擴展的,否則可能會遇到資料不一致的問題。

為了提高服務的可擴展性,操作資料的微服務架構通常分為寫入(Write)和讀取(Read)兩類型。依照不同應用場景,讀寫效能的需求也會有所不同。最常用的技巧是命令查詢責任區隔(Command Query Responsibility Segregation, CQRS)。通過 CQRS,寫入和讀取負責的服務可以分開,並根據各自的需求進行擴展,可以更精準的將資源應用在實際需求上。

Grafana Stack

Grafana 旗下的 Loki、Mimir、Tempo 都承襲了 Cortex 的架構設計,將資料流分為寫入(Write)與讀取(Read)兩大類,各由不同的 Component 負責。透過對這些 Component 進行擴展,即可有效提升系統效能。以下為 Cortex、Loki、Mimir 和 Tempo 的架構圖比對:

Architecures
圖片來源:CortextGrafana

觀察以上四種服務,可以看到主要讀寫路徑的 Components 名字都一樣:

  1. Write
    1. Distributor:負責接收資料並將資料分發給不同的 Ingester。
    2. Ingester:負責接收資料並寫入到 Object Storage。
  2. Read
    1. Querier:負責從 Object Storage 讀取資料並回傳給 Query Frontend。
    2. Query Frontend:負責接收使用者的查詢並將查詢分發給不同的 Querier。

透過讀寫 Components 的拆分,讓這個架構能夠適應不同使用者需求,Loki、Mimir 和 Tempo 各自提供三種不同的佈署模式:

  1. Monolithic Mode:單一服務負責所有功能,使用簡單,但不具擴展性。
  2. Scalable Monolithic:基於 Monolithic 的進階模式
    1. Loki 和 Mimir 分為 Read、Write、Backend 三個組合,透過擴展這三組即可達到擴展效果。
    2. Tempo 目前僅能擴展整個 Monolithic,但預計未來亦可分為 Read、Write、Backend 三組,以實現更細緻的擴展。
  3. Microservices Mode:每個 Component 都個別執行,可以達到最細緻的擴展。

詳細的 Component 介紹與部署方式差別,可以參考官方文件中各工具的 Components 與 Deployment modes 章節。

若選擇使用 Microservices Mode,基本上會搭配 Kubernetes 使用。官方為不同佈署模式也提供了對應的 Helm Chart,只需根據需求選擇和調整,即可快速建立服務。

Helm Chart 一覽:

  1. Loki:
    1. Monolithic、Scalable Monolithic:透過 singleBinary 參數選擇 Monolithic Mode 或 Scalable Monolithic Mode。
    2. loki-distributed:微服務架構下的 Loki Helm Chart。
  2. Mimir:
    1. mimir-distributed:微服務架構下的 Mimir Helm Chart。
  3. Tempo:
    1. tempo:單體架構下的 Tempo Helm Chart。
    2. tempo-distributed:微服務架構下的 Tempo Helm Chart。

Kafka

Kafka 能夠提供 Message Queue 服務。在微服務架構下,它可以作為資料的緩衝區。當資料量過大時,Kafka 先行接收資料,再由 Consumer 逐一消耗處理,如此可防止因資料過量而讓服務變得不可用。

以 Traces 或 Logs 收集為例,可以透過 OpenTelemetry Collector 或 Fluent Bit 先將資料寫入 Kafka,再用 OpenTelemetry Collector 和 Promtail 讀取並寫入 Tempo 和 Loki。這種方法可預防 Loki 或 Tempo 的組件因資料過量而導致服務不可用。儘管可能有延遲問題,但 Traces 與 Logs 對於即時性的要求並不高,輕微延遲的延遲相對可以接受,就無需因短暫的大流量進行 Scaling。

Kafka Pipeline

Jaeger 原生也有支援 Kafka 模式。在這種模式下,Jaeger Collector 不再直接寫入 Storage Backend,而是先將資料寫入 Kafka,再由 Jaeger Ingester 讀取 Kafka 的資料,最後寫入 Storage Backend。

Jaeger with Kafka
圖片來源:Jaeger

High Availability

微服務架構中的服務通常被預設為是可能會發生故障的,因此透過架構設計讓服務可以承受部分服務失效,但仍可以正常運行就是高可用性(High Availability, HA)要解決的問題。

達成 HA 的一個簡單方法是選擇本身支援 HA 的工具,或是依照工具文件中的 HA 部署方式。以 Prometheus 為例,可透過多個 Prometheus Server 收集資料,並搭配 Mimir 進行資料儲存,以防單一 Prometheus Server 故障導致資料遺失。

除了架構本身就支援 HA 外,還是要確保服務真的是可用的,所以也需要一視同仁,用照顧其他服務的方式一樣照顧我們的 Observability 工具,蒐集它們的 Metrics 和 Logs,再搭配告警通知,確保使用者都能夠正常使用 Observability 工具。大多數工具都有內建監控機制或提供指標,例如 Fluent Bit 的 Monitoring 和 OpenTelemetry Collector 的 Telemetry 資訊。除此之外,Loki、Tempo 和 Mimir 不僅提供指標,官方文件中也有各種 Dashboard 或是 Runbook 等,這些都有助於確保服務的可用性。

Lab

範例程式碼:28-scalability

Quick Start

Loki Scalable Monolithic

  1. 啟動所有服務

    docker-compose up -d
    
  2. 檢視服務

    1. FastAPI App: http://localhost:8000
    2. Nginx: http://localhost:8080
    3. Prometheus: http://localhost:9090
    4. Loki:
      1. loki-read: http://localhost:3101/metrics
      2. loki-write: http://localhost:3102/metrics
    5. MinIO: Web UI Console http://localhost:9001,登入帳號密碼為 loki/supersecret
    6. Grafana: http://localhost:3000,登入帳號密碼為 admin/admin
      1. Log
        1. 使用 k6 發送 Request

          k6 run --vus 1 --duration 300s k6-script.js
          
        2. 使用 Explore 檢視 Loki 資料

      2. Loki Metrics
        1. 點擊左上 Menu > Dashboards > Loki Metrics,即可看到透過 Provisioning 建立的 Dashboard
  3. 關閉所有服務

    docker-compose down
    

Jaeger with Kafka

  1. 啟動所有服務

    docker-compose -f docker-compose.jaeger.yaml up -d
    
  2. 檢視服務

    1. 因 Kafka 需要一些時間初始化,確認 Kafka 已啟動後,再繼續下一步

      docker-compose ps
      
    2. Jaeger UI: http://localhost:16686

      1. 選擇 Service 後點選 Find Traces,即可看到 xk6-client-tracing 自動發送的 Trace Data
  3. 關閉所有服務

    docker-compose -f docker-compose.jaeger.yaml down
    

Goals

Loki Scalable Monolithic

Loki Scalable Monolithic Pipeline
藍色線為 Write,綠色線為 Read

  1. 建立 FastAPI App 與 Nginx,模擬服務產生 Log
  2. 建立 Promtail,並 Mount Docker Socket 至 Promtail Container,讓 Promtail 可以讀取 Label 為 logging=promtail 的 Container 的 Log
  3. 建立 Loki
    1. loki-gateway: Nginx proxy,根據 URL 將 Request 轉發至 loki-read 或 loki-write
    2. loki-read: 負責查詢 Log,從 MinIO 讀取 Log
    3. loki-write: 負責接收 Promtail 傳送的 Log,並寫入到 MinIO
  4. 建立 Minio,作為 Loki 的 Object Storage
  5. 建立 Prometheus,爬取 loki-read 與 loki-write 的 Metrics
  6. 建立 Grafana,讀取 Loki 的資料

Jaeger with Kafka

Jaeger with Kafka Pipeline

  1. 建立 Jaeger Components
    1. Jaeger Collector: 接收 Application 發送的 Trace Data
    2. Jaeger Query: 對 Jaeger Remote Storage 發送查詢,提供 UI 查看 Trace Data
    3. Jaeger Remote Storage: 負責儲存 Trace Data
    4. Jaeger Ingester: 從 Kafka 讀取 Trace Data,並將 Trace Data 寫入到 Storage Backend
  2. 建立 Kafka Components
    1. Kafka: 接收 Jaeger Collector 發送的 Trace Data,供 Jaeger Ingester 讀取
    2. Zookeeper: Kafka 的依賴
  3. 建立 xk6-client-tracing,Container 啟動後會自動產生 Traces 資料並發送至 Jaeger,模擬真實環境的 Traces 資料

小結

如果導入一切順利 Observability 工具無疑是確保其他服務運作無虞的關鍵。然而,若這些 Observability 工具自身無法提供穩定的服務,它們將反而成為監控機制的單點故障(single point of failure)。這種情況顯然是我們不願見到的,因此,這些工具不僅需要高度的可用性,也必須具有良好的可擴充性。

就如同「吃自己的狗糧」(eating your own dog food),Observability 不僅要能確保其他服務的品質,更應用同的工具與機制對 Observability 工具自身給予更高的服品質標準。透過這樣的全方位守護,我們才能真正確保服務都被良好的監控與管理著。

參考資料

  1. [KCD Taiwan 2023 x COSCUP] Grafana 全家桶,如何打造高可用且具可擴充性的 o11y 平台 by HungWei Chiu

上一篇
In Production - 準備釋放你的 Observability 原力吧!
下一篇
In Production - 如果資料要加上一個期限,我希望是一萬年
系列文
時光之鏡:透視過去、現在與未來的 Observability30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言