Loki 生產環境集羣方案

很多新入坑 Loki 的小夥伴當看到 distributor、ingester、querier 以及各種依賴的三方存儲時,往往都比較懵逼,不知道從哪兒入手。此外再加上官方的文檔裏面對於集羣部署的粗淺描述,更是讓新手們大呼部署太難。其實,除了官方的 helm 外,藏在 Loki 倉庫的 production 目錄裏面有一篇生產環境的集羣部署模式。

原文裏面,社區採用的是 docker-compose 的方式來快速拉起一套 Loki 集羣。雖然我們正式在生產環境中實施時,不會傻到用 docker-compose 部署在一個 node 上(顯然這裏我們強行不考慮 docker-swarm)。不過裏面關於 Loki 的架構和配置文件卻值得我們學習。

那麼,與純分佈式的 Loki 集羣相比,這套方案有什麼特別的呢?首先我們先來看看下面這張圖:

可以看到,最明顯的有三大不同點:

  1. loki 核心服務 distributor、ingester、querier 沒有分離,而是啓動在一個實例當中;

  2. 拋棄了 consul 和 etcd 外部的 kv 存儲,而是直接用 memberlist 在內存中維護集羣狀態;

  3. 使用 boltdb-shipper 替代其他日誌索引方案

這樣看起來,Loki 集羣的整體架構就比較清晰,且更少的依賴外部系統。簡單總結了下,除了用於存儲 chunks 和 index 而繞不開的 S3 存儲外,還需要一個緩存服務用於加速日誌查詢和寫入。

Loki2.0 版本之後,對於使用 boltdb 存儲索引部分做了較大的重構,採用新的 boltdb-shipper 模式,可以讓 Loki 的索引存儲在 S3 上,而徹底擺脫 Cassandra 或者谷歌的 BigTable。此後服務的橫向擴展將變得更加容易。關於 bolt-shipper 的更多細節,可以參考:https://grafana.com/docs/loki/latest/operations/storage/boltdb-shipper/

說得這麼玄乎,那我們來看看這套方案的配置有哪些不一樣呢?

原生部分

memberlist

memberlist:
  join_members: ["loki-1""loki-2""loki-3"]
  dead_node_reclaim_time: 30s
  gossip_to_dead_nodes_time: 15s
  left_ingesters_timeout: 30s
  bind_addr: ['0.0.0.0']
  bind_port: 7946

Loki 的 memberlist 使用的是 gossip 協議來讓集羣內的所有節點達到最終一致性的。此部分的配置幾乎都是協議頻率和超時的控制,保持默認的就好

ingester

ingester:
  lifecycler:
    join_after: 60s
    observe_period: 5s
    ring:
      replication_factor: 2
      kvstore:
        store: memberlist
    final_sleep: 0s

ingester 的狀態通過 gossip 協議同步到集羣的所有 member 當中,同時讓 ingester 的複製因子爲 2。即一個日誌流同時寫入到兩個 ingster 服務當中以保證數據的冗餘。

擴展部分

社區的集羣模式配置原生部分仍然顯得不太夠意思,除了 memberlist 的配置稍顯誠意外,其它部分仍然不夠我們對生產環境的要求。這裏小白簡單改造了一下,分享給大家。

storage

將 index 和 chunks 的存儲統一讓 S3 對象存儲納管,讓 Loki 徹底擺脫三方依賴。

schema_config:
  configs:
  - from: 2021-04-25
    store: boltdb-shipper
    object_store: aws
    schema: v11
    index:
      prefix: index_
      period: 24h
    
storage_config:
  boltdb_shipper:
    shared_store: aws
    active_index_directory: /loki/index
    cache_location: /loki/boltdb-cache
  aws:
    s3: s3://<S3_ACCESS_KEY>:<S3_SECRET_KEY>@<S3_URL>/<S3__BUCKET>  
    s3forcepathstyle: true
    insecure: true

這裏值得說明的就是用於存儲日誌流索引的是 bolt_shipper,它是可以通過共享存儲方式寫到 s3 當中的。那麼active_index_directory就是 S3 上的 Bucket 路徑,cache_location則爲 Loki 本地 bolt 索引的緩存數據。

事實上 ingester 上傳到 s3 的 index 路徑爲<S3__BUCKET>/index/

redis

原生的方案裏並不提供緩存,這裏我們引入 redis 來做查詢和寫入的緩存。對於很多小夥伴糾結的是一個 redis 共用還是多個 redis 單獨使用,這個看你集羣規模,不大的情況下,一個 redis 實例足以滿足需求。

query_range:
  results_cache:
    cache:
      redis:
        endpoint: redis:6379
        expiration: 1h
  cache_results: true

index_queries_cache_config:
  redis:
    endpoint: redis:6379
    expiration: 1h
    
chunk_store_config:
  chunk_cache_config:
    redis:
      endpoint: redis:6379
      expiration: 1h    
  write_dedupe_cache_config:
    redis:
      endpoint: redis:6379
      expiration: 1h

ruler

既然 Loki 以及做了集羣化部署,當然 ruler 這個服務也得跟在切分。難以接受的是,社區這部分的配置竟然是缺失的。所以我們得自己補充完整。我們知道日誌的 ruler 可以寫在 S3 對象存儲上,同時每個 ruler 實例也是通過一致性哈希環來分配自己的 rules。所以這部分配置,我們可以如下參考:

ruler:
  storage:
    type: s3
    s3:
      s3: s3://<S3_ACCESS_KEY>:<S3_SECRET_KEY>@<S3_URL>/<S3_RULES_BUCKET>
      s3forcepathstyle: true
      insecure: true
      http_config:
        insecure_skip_verify: true
    enable_api: true
    enable_alertmanager_v2: true
    alertmanager_url: "http://<alertmanager>"
    ring:
      kvstore:
      store: memberlist

支持 kubernetes

最後,最最最重要的是要讓官方的 Loki 集羣方案支持在 Kubernetes 中部署,否則一切都是瞎扯。由於篇幅的限制,我將 manifest 提交到 github 上,大家直接 clone 到本地部署。

GitHub 地址:https://github.com/CloudXiaobai/loki-cluster-deploy/tree/master/production/loki-system

這個 manifest 只依賴一個 S3 對象存儲,所以你在部署到生產環境時,請務必預先準備好對象存儲的 AccessKey 和 SecretKey。將他們配置到 installation.sh 當中後,直接執行腳本就可以開始安裝了。

文件中的 ServiceMonitor 是爲 Loki 做的 Prometheus Operator 的 Metrics 服務發現,你可以自己選擇是否部署

總結

本文介紹了官方提供的一種 Loki 生產環境下的集羣部署方案,並在此基礎上加入了一些諸如緩存、S3 對象存儲的擴展配置,並將官方的 docker-compose 部署方式適配到 Kubernetes 當中。官方提供的方案有效的精簡了 Loki 分佈式部署下複雜的結構,值得我們學習。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/qnt7JUzHLUU6Qs_tv5V0Hw