97)loki日志監控系統介紹


1- 簡介

Loki 是 Grafana Labs 團隊最新的開源項目,是一個水平可擴展,高可用性,多租戶的日志聚合系統。它的設計非常經濟高效且易於操作,因為它不會為日志內容編制索引,而是為每個日志流配置一組標簽。項目受 Prometheus 啟發,官方的介紹就是:Like Prometheus, but for logs,類似於 Prometheus 的日志系統。

由Grafana Labs團隊開源的水平可擴展,高度可用的多租戶日志聚合系統。 開發語言: Google Go。它的設計具有很高的成本效益,並且易於操作。使用標簽來作為索引,而不是對全文進行檢索,也就是說,你通過這些標簽既可以查詢日志的內容也可以查詢到監控的數據簽,極大地降低了日志索引的存儲

1.1- 概述

Loki 只會對你的日志元數據標簽(就像 Prometheus 的標簽一樣)進行索引,而不會對原始的日志數據進行全文索引。然后日志數據本身會被壓縮,並以 chunks(塊)的形式存儲在對象存儲(比如 S3 或者 GCS)甚至本地文件系統。一個小的索引和高度壓縮的 chunks 可以大大簡化操作和降低 Loki 的使用成本

1.2- 特點

多租戶

支持多租戶模式,租戶之間的數據是完全分開的。多租戶是通過一個租戶 ID(用數字字母生成的字符串)實現的。當多租戶模式被禁用后,所有請求都會在內部生成一個假的租戶 ID

操作模式

可以在本地小規模運行也可以橫向擴展。Loki 自帶單進程模式,可以在一個進程中運行所有需要的微服務。單進程模式非常適合於測試 Loki 或者小規模運行。對於橫向擴展來說,Loki 的微服務是可以被分解成單獨的進程的,使其能夠獨立擴展。

組件

  • Distributor(分配器)

負責處理客戶端寫入的日志。本質上它是日志數據寫入路徑中的第一站。一旦分配器接收到日志數據,它就會把它們分成若干批次,並將它們並行地發送到多個采集器去。

分配器通過 gPRC 和采集器進行通信。它們是無狀態的,所以我們可以根據實際需要對他們進行擴縮容。

  • Hashing

分配器采用一致性哈希和可配置的復制因子結合使用,來確定哪些采集器服務應該接收日志數據。該哈希是基於日志標簽和租戶 ID 生成的。

存儲在 Consul 中的哈希環被用來實現一致性哈希;所有的采集器將他們自己的一組 Token 注冊到哈希環中去。然后分配器找到和日志的哈希值最匹配的 Token,並將數據發送給該 Token 的持有者。

  • 一致性

由於所有的分配器都共享同一個哈希環,所以可以向任何分配器發送寫請求。

為了確保查詢結果的一致性,Loki 在讀和寫上使用了 Dynamo 方式的法定人數一致性。這意味着分配器將等待至少有一半以上的采集器響應,再向用戶發送樣本,然后再響應給用戶。

  • Ingester(采集器)

采集器服務負責將日志數據寫入長期存儲的后端(DynamoDB、S3、Cassandra 等等)。

采集器會校驗采集的日志是否亂序。當采集器接收到的日志行與預期的順序不一致時,該行日志將被拒絕,並向用戶返回一個錯誤。有關更多相關信息,可以查看時間戳排序部分內容。

采集器驗證接收到的日志行是按照時間戳遞增的順序接收的(即每條日志的時間戳都比之前的日志晚)。當采集器接收到的日志不按照這個順序,日志行將被拒絕並返回錯誤。

每一個唯一的標簽集數據都會在內存中構建成chunks,然后將它們存儲到后端存儲中去。

如果一個采集器進程崩潰或者突然掛掉了,所有還沒有被刷新到存儲的數據就會丟失。Loki 通常配置成多個副本(通常為3個)來降低這種風險

  • 時間戳排序

一般來說推送到 Loki 的所有日志行必須比之前收到的行有一個更新的時間戳。然而有些情況可能是多行日志具有相同的納秒級別的時間戳,可以按照下面兩種情況進行處理:

  1. 如果傳入的行和之前接收到的行完全匹配(時間戳和日志文本都匹配),則傳入的行會被視為完全重復並會被忽略。

  2. 如果傳入行的時間戳和前面一行的時間戳相同,但是日志內容不相同,則會接收該行日志。這就意味着,對於相同的時間戳,有可能有兩個不同的日志行。

  • Handoff(交接)

默認情況下,當一個采集器關閉並視圖離開哈希環時,它將等待查看是否有新的采集器視圖進入,然后再進行 flush,並嘗試啟動交接。交接將把離開的采集器擁有的所有 Token 和內存中的 chunks 都轉移到新的采集器中來。

這個過程是為了避免在關閉時 flush 所有的 chunks,因為這是一個比較緩慢的過程,比較耗時

  • 文件系統支持

采集器支持通過 BoltDB 寫入到文件系統,但這只在單進程模式下工作,因為查詢器需要訪問相同的后端存儲,而且 BoltDB 只允許一個進程在給定時間內對 DB 進行鎖定

  • Querier(查詢器)

查詢器服務負責處理 LogQL 查詢語句來評估存儲在長期存儲中的日志數據。

它首先會嘗試查詢所有采集器的內存數據,然后再返回到后端存儲中加載數據。

  • 前端查詢

該服務是一個可選組件,在一組查詢器前面,來負責在它們之間公平地調度請求,盡可能地並行化它們並緩存請求。

  • Chunk(塊)存儲

塊存儲是 Loki 的長期數據存儲,旨在支持交互式查詢和持續寫入,無需后台維護任務。它由以下幾部分組成:

  1. 塊索引,該索引可以由 DynamoDB、Bigtable 或者 Cassandra 來支持。
  2. 塊數據本身的 KV 存儲,可以是 DynamoDB、Bigtable、Cassandra,也可以上是對象存儲

與 Loki 的其他核心組件不同,塊存儲不是一個獨立的服務、任務或者進程,而是嵌入到需要訪問 Loki 數據的采集器和查詢器中的庫。

塊存儲依賴統一的 ”NoSQL“ 存儲(DynamoDB、Bigtable 和 Cassandra)接口,該接口可以用來支持塊存儲索引。該接口假設索引是由以下幾個 key 構成的集合:

  1. 哈希 KEY - 這是所有的讀和寫都需要的。
  2. 范圍 KEY - 這是寫的時候需要的,讀的時候可以省略,可以通過前綴或者范圍來查詢。

上面支持的這些數據庫中接口的工作原理有些不同:

  1. DynamoDB 支持范圍和哈希 KEY。所以索引條目直接建模為 DynamoDB 的數據,哈希 KEY 為分布式 KEY,范圍為范圍 KEY。
  2. 對於 Bigtable 和 Cassandra,索引項被建模為單個的列值。哈希 KEY 成為行 KEY,范圍 KEY 成為列 KEY。

一些模式被用於對塊存儲的讀取和寫入時使用的匹配器和標簽集合映射到索引的適當操作中來。隨着 Loki 的發展也會增加一些新的模式,主要是為了更好地平衡些和提高查詢性能。

1.3- 優勢

  • 單二進制模式下的 Loki 可以將數據存儲在磁盤上,但在水平可擴展模式下,數據存儲需要在雲存儲系統中,如 S3、GCS 或 Cassandra。日志以純文本的形式存儲,並標記了一組標簽的名稱和值,其中只有標簽會被索引。這種權衡使其操作起來比完全索引更便宜。Loki 中的日志使用 LogQL 進行查詢。由於這種設計上的權衡,根據內容(即日志行內的文本)進行過濾的 LogQL 查詢需要加載搜索窗口內所有與查詢中定義的標簽相匹配的塊。

  • Promtail 是為 Loki 量身定做的。它的主要工作模式是發現存儲在磁盤上的日志文件,並將其與一組標簽關聯的日志文件轉發到 Loki。Promtail 可以為在同一節點上運行的 Kubernetes Pods 做服務發現,作為 Docker 日志驅動,從指定的文件夾中讀取日志,並對 systemd 日志不斷獲取。

  • Loki 通過一組標簽表示日志的方式與 Prometheus 表示指標的方式類似。當與Prometheus 一起部署在環境中時,由於使用了相同的服務發現機制,來自Promtail 的日志通常與你的應用指標具有相同的標簽。擁有相同級別的日志和指標,用戶可以在指標和日志之間無縫切換,幫助進行根本性原因分析。

2- 組成

2.1- 組成

  • Loki 是主服務器,負責存儲日志和處理查詢 。
  • promtail 是代理,負責收集日志並將其發送給 loki 。
  • Grafana 用於 UI 展示。

只要在應用程序服務器上安裝promtail來收集日志然后發送給Loki存儲,就可以在Grafana UI界面通過添加Loki為數據源進行日志查詢(如果Loki服務器性能不夠,可以部署多個Loki進行存儲及查詢)。作為一個日志系統不關只有查詢分析日志的能力,還能對日志進行監控和報警

2.2- 架構

  1. promtail收集並將日志發送給loki的 Distributor 組件

  2. Distributor會對接收到的日志流進行正確性校驗,並將驗證后的日志分批並行發送到Ingester

  3. Ingester 接受日志流並構建數據塊,壓縮后存放到所連接的存儲后端

  4. Querier 收到HTTP查詢請求,並將請求發送至Ingester 用以獲取內存數據 ,Ingester 收到請求后返回符合條件的數據 ;

    如果 Ingester 沒有返回數據,Querier 會從后端存儲加載數據並遍歷去重執行查詢 ,通過HTTP返回查詢結果

3- 安裝

3.1- 使用 Helm 安裝 Loki

  • 添加 Loki 的 chart 倉庫
helm repo add loki https://grafana.github.io/loki/charts
  • 更新 chart 倉庫
helm repo update
  • 部署 Loki
helm upgrade --install loki loki/loki-stack

##指定命名空間
helm upgrade --install loki --namespace=loki loki/loki
##指定配置
helm upgrade --install loki loki/loki --set "key1=val1,key2=val2,..."
##部署 Loki 工具棧(Loki, Promtail, Grafana, Prometheus
helm upgrade --install loki loki/loki-stack --set grafana.enabled=true,prometheus.enabled=true,prometheus.alertmanager.persistentVolume.enabled=false,prometheus.server.persistentVolume.enabled=false

3.2- helm安裝grafana

  • 使用 Helm 安裝 Grafana 到 Kubernetes 集群
helm install stable/grafana -n loki-grafana
  • 獲取 Grafana 管理員密碼
kubectl get secret --namespace <YOUR-NAMESPACE> loki-grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo
  • 訪問 Grafana UI 頁面
kubectl port-forward --namespace <YOUR-NAMESPACE> service/loki-grafana 3000:80

3.3- 本地安裝 Loki

二進制包下載地址:

https://github.com/grafana/loki/releases

  • 下載安裝包
curl -O -L "https://github.com/grafana/loki/releases/download/v1.5.0/loki-linux-amd64.zip" 
curl -O -L "https://github.com/grafana/loki/releases/download/v1.5.0/promtail-linux-amd64.zip"
wget https://dl.grafana.com/oss/release/grafana-6.7.4-1.x86_64.rpm

  • 自定義配置文件(loki.yaml和promtail.yaml)
#loki.yaml

auth_enabled: false

server:
  http_listen_port: 3100

ingester:
  lifecycler:
    address: 127.0.0.1
    ring:
      kvstore:
        store: inmemory
      replication_factor: 1
    final_sleep: 0s
  chunk_idle_period: 5m
  chunk_retain_period: 30s

schema_config:
  configs:
    - from: 2020-07-09
      store: boltdb
      object_store: filesystem
      schema: v9
      index:
        prefix: index_
        period: 168h

storage_config:
#標簽索引存儲地址
  boltdb:
    directory: /home/iocshare/loki/index
#塊文件存儲地址
  filesystem:
    directory: /home/iocshare/loki/chunks

limits_config:
  enforce_metric_name: false
  reject_old_samples: true
  reject_old_samples_max_age: 168h
  
  
#promtail.yaml
# Promtail服務配置
server:
  http_listen_port: 9080
  grpc_listen_port: 0

# 記錄讀取日志的位置信息文件,Promtail重新啟動時需要它
positions:
  filename: /tmp/positions.ymal

# Loki的api服務的地址
clients:
  - url: http://127.0.0.1:3100/loki/api/v1/push

scrape_configs:
# CMS日志收集並打標簽
  - job_name: CMS
    static_configs:
      - targets:
          - localhost
        labels:
          job: cms-45
          host: localhost
          __path__: /home/ccodrunner/Platform/log/cms2/cms2.log
# UMG日志收集並打標簽
  - job_name: UMG
    static_configs:
      - targets:
          - localhost
        labels:
          job: UMG-log
          host: localhost
          __path__: /home/umg/ATS4_setup/ChannelSoft/ATS4/runlog/UMG*.log
  • 啟動服務(先啟loki)
nohup ./loki-linux-amd64 -config.file=/etc/loki/loki.yaml &
nohup ./promtail-linux-amd64 -config.file=/etc/loki/promtail.yaml &

3.4- grafana添加數據源

然后進入Explore就可以搜索查詢日志了,日志查詢由兩部分組成:日志流選擇器搜索表達式。出於性能原因,需要先通過選擇日志標簽來選擇日志流。查詢字段Log labels旁邊的按鈕顯示了可用日志流的標簽列表

4- logcli

4.1- 安裝

wget https://github.com/grafana/loki/releases/download/v1.6.1/logcli-linux-amd64.zip
unzip logcli-linux-amd64.zip 
chmod +x logcli-linux-amd64/logcli-linux-amd64
mv logcli-linux-amd64/logcli-linux-amd64  /usr/sbin/logcli

4.2- 使用

  • 配置環境變量
export LOKI_ADDR=http://localhost:3100
  • 使用
logcli labels job
logcli query '{job="varlogs"}'
  • 批量查詢

從 Loki 1.6.0 開始,logcli 會分批向 Loki 發送日志查詢。

如果你將查詢的--limit 參數(默認為30)設置為一個較大的數,比如 10000,那么 logcli 會自動將此請求分批發送到 Loki,默認的批次大小是 1000。

Loki 對查詢中返回的最大行數有一個服務端的限制(默認為5000)。批量發送允許你發出比服務端限制更大的請求,只要 --batch 大小小於服務器限制。

請注意,每個批次的查詢元數據都會被打印在 stderr 上,可以通過設置--quiet 參數來停止這個動作。

對於配置的值會根據環境變量和命令行標志從低到高生效。

4.3- 命令

logcli help
usage: logcli [<flags>] <command> [<args> ...]

A command-line for loki.

Flags:
      --help             Show context-sensitive help (also try --help-long and --help-man).
      --version          Show application version.
  -q, --quiet            Suppress query metadata.
      --stats            Show query statistics.
  -o, --output=default   Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
  -z, --timezone=Local   Specify the timezone to use when formatting output timestamps [Local, UTC].
      --cpuprofile=""    Specify the location for writing a CPU profile.
      --memprofile=""    Specify the location for writing a memory profile.
      --addr="http://localhost:3100"
                         Server address. Can also be set using LOKI_ADDR env var.
      --username=""      Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.
      --password=""      Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.
      --ca-cert=""       Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.
      --tls-skip-verify  Server certificate TLS skip verify.
      --cert=""          Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.
      --key=""           Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.
      --org-id=""        adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
                         bypassing an auth gateway.

Commands:
  help [<command>...]
    Show help.

  query [<flags>] <query>
    Run a LogQL query.

    The "query" command is useful for querying for logs. Logs can be returned in a few output modes:

      raw: log line
      default: log timestamp + log labels + log line
      jsonl: JSON response from Loki API of log line

    The output of the log can be specified with the "-o" flag, for example, "-o raw" for the raw output format.

    The "query" command will output extra information about the query and its results, such as the API URL, set of common labels,
    and set of excluded labels. This extra information can be suppressed with the --quiet flag.

    While "query" does support metrics queries, its output contains multiple data points between the start and end query time.
    This output is used to build graphs, like what is seen in the Grafana Explore graph view. If you are querying metrics and just
    want the most recent data point (like what is seen in the Grafana Explore table view), then you should use the "instant-query"
    command instead.

  instant-query [<flags>] <query>
    Run an instant LogQL query.

    The "instant-query" command is useful for evaluating a metric query for a single point in time. This is equivalent to the
    Grafana Explore table view; if you want a metrics query that is used to build a Grafana graph, you should use the "query"
    command instead.

    This command does not produce useful output when querying for log lines; you should always use the "query" command when you
    are running log queries.

    For more information about log queries and metric queries, refer to the LogQL documentation:

    https://grafana.com/docs/loki/latest/logql/

  labels [<flags>] [<label>]
    Find values for a given label.

  series [<flags>] <matcher>
    Run series query.

$ logcli help query
usage: logcli query [<flags>] <query>

Run a LogQL query.

The "query" command is useful for querying for logs. Logs can be returned in a few output modes:

  raw: log line
  default: log timestamp + log labels + log line
  jsonl: JSON response from Loki API of log line

The output of the log can be specified with the "-o" flag, for example, "-o raw" for the raw output format.

The "query" command will output extra information about the query and its results, such as the API URL, set of common labels, and
set of excluded labels. This extra information can be suppressed with the --quiet flag.

While "query" does support metrics queries, its output contains multiple data points between the start and end query time. This
output is used to build graphs, like what is seen in the Grafana Explore graph view. If you are querying metrics and just want the
most recent data point (like what is seen in the Grafana Explore table view), then you should use the "instant-query" command
instead.

Flags:
      --help               Show context-sensitive help (also try --help-long and --help-man).
      --version            Show application version.
  -q, --quiet              Suppress query metadata.
      --stats              Show query statistics.
  -o, --output=default     Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
  -z, --timezone=Local     Specify the timezone to use when formatting output timestamps [Local, UTC].
      --cpuprofile=""      Specify the location for writing a CPU profile.
      --memprofile=""      Specify the location for writing a memory profile.
      --addr="http://localhost:3100"
                           Server address. Can also be set using LOKI_ADDR env var.
      --username=""        Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.
      --password=""        Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.
      --ca-cert=""         Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.
      --tls-skip-verify    Server certificate TLS skip verify.
      --cert=""            Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.
      --key=""             Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.
      --org-id=""          adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
                           bypassing an auth gateway.
      --limit=30           Limit on number of entries to print.
      --since=1h           Lookback window.
      --from=FROM          Start looking for logs at this absolute time (inclusive).
      --to=TO              Stop looking for logs at this absolute time (exclusive).
      --step=STEP          Query resolution step width, for metric queries. Evaluate the query at the specified step over the time
                           range.
      --interval=INTERVAL  Query interval, for log queries. Return entries at the specified interval, ignoring those between.
                           **This parameter is experimental, please see Issue 1779**.
      --batch=1000         Query batch size to use until 'limit' is reached.
      --forward            Scan forwards through logs.
      --no-labels          Do not print any labels.
      --exclude-label=EXCLUDE-LABEL ...
                           Exclude labels given the provided key during output.
      --include-label=INCLUDE-LABEL ...
                           Include labels given the provided key during output.
      --labels-length=0    Set a fixed padding to labels.
      --store-config=""    Execute the current query using a configured storage from a given Loki configuration file.
  -t, --tail               Tail the logs.
      --delay-for=0        Delay in tailing by number of seconds to accumulate logs for re-ordering.
      --colored-output     Show ouput with colored labels.

Args:
  <query>  eg '{foo="bar",baz=~".*blip"} |~ ".*error.*"'

$ logcli help labels
usage: logcli labels [<flags>] [<label>]

Find values for a given label.

Flags:
      --help             Show context-sensitive help (also try --help-long and --help-man).
      --version          Show application version.
  -q, --quiet            Suppress query metadata.
      --stats            Show query statistics.
  -o, --output=default   Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
  -z, --timezone=Local   Specify the timezone to use when formatting output timestamps [Local, UTC].
      --cpuprofile=""    Specify the location for writing a CPU profile.
      --memprofile=""    Specify the location for writing a memory profile.
      --addr="http://localhost:3100"
                         Server address. Can also be set using LOKI_ADDR env var.
      --username=""      Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.
      --password=""      Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.
      --ca-cert=""       Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.
      --tls-skip-verify  Server certificate TLS skip verify.
      --cert=""          Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.
      --key=""           Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.
      --org-id=""        adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
                         bypassing an auth gateway.
      --since=1h         Lookback window.
      --from=FROM        Start looking for labels at this absolute time (inclusive).
      --to=TO            Stop looking for labels at this absolute time (exclusive).

Args:
  [<label>]  The name of the label.

$ logcli help series
usage: logcli series --match=MATCH [<flags>]

Run series query.

Flags:
      --help             Show context-sensitive help (also try --help-long and --help-man).
      --version          Show application version.
  -q, --quiet            Suppress query metadata.
      --stats            Show query statistics.
  -o, --output=default   Specify output mode [default, raw, jsonl]. raw suppresses log labels and timestamp.
  -z, --timezone=Local   Specify the timezone to use when formatting output timestamps [Local, UTC].
      --cpuprofile=""    Specify the location for writing a CPU profile.
      --memprofile=""    Specify the location for writing a memory profile.
      --addr="http://localhost:3100"
                         Server address. Can also be set using LOKI_ADDR env var.
      --username=""      Username for HTTP basic auth. Can also be set using LOKI_USERNAME env var.
      --password=""      Password for HTTP basic auth. Can also be set using LOKI_PASSWORD env var.
      --ca-cert=""       Path to the server Certificate Authority. Can also be set using LOKI_CA_CERT_PATH env var.
      --tls-skip-verify  Server certificate TLS skip verify.
      --cert=""          Path to the client certificate. Can also be set using LOKI_CLIENT_CERT_PATH env var.
      --key=""           Path to the client certificate key. Can also be set using LOKI_CLIENT_KEY_PATH env var.
      --org-id=""        adds X-Scope-OrgID to API requests for representing tenant ID. Useful for requesting tenant data when
                         bypassing an auth gateway.
      --since=1h         Lookback window.
      --from=FROM        Start looking for logs at this absolute time (inclusive).
      --to=TO            Stop looking for logs at this absolute time (exclusive).
      --match=MATCH ...  eg '{foo="bar",baz=~".*blip"}'

4.4- Label 標簽

Label 標簽是一個鍵值對,可以定義任何東西,我們喜歡稱它們為描述日志流的元數據。如果你熟悉 Prometheus,那么一定對 Label 標簽有一定的了解,在 Loki 的 scrape 配置中也定義了這些標簽,和 Prometheus 擁有一致的功能,這些標簽非常容易將應用程序指標和日志數據關聯起來。

Loki 中的標簽執行一個非常重要的任務:它們定義了一個流。更具體地說,每個標簽鍵和值的組合定義了流。如果只是一個標簽值變化,這將創建一個新的流。

類似 Prometheus的序列,而且 Prometheus 中還有一個額外的維度:指標名稱。Loki 中簡化了這一點,因為沒有指標名,只有標簽,所以最后決定使用流而不是序列。

標簽示例

loki配置文件中labels:

scrape_configs:
 - job_name: system
   pipeline_stages:
   static_configs:
   - targets:
      - localhost
     labels:
      job: syslog
      env: dev
      __path__: /var/log/syslog
 - job_name: system
   pipeline_stages:
   static_configs:
   - targets:
      - localhost
     labels:
      job: apache
      env: dev
      __path__: /var/log/apache.log

查詢labels的日志:

{job="apache"} <- 顯示 job 標簽為 apache 的日志
{job="syslog"} <- 顯示 job 標簽為 syslog 的日志
{job=~"apache|syslog"} <- 顯示 job 標簽為 apache 或者 syslog 的日志

兩個任務的日志可以用下面的方式來代替 regex 的方式:

{env="dev"} <- 將返回所有帶有 env=dev 標簽的日志

Label 標簽是 Loki 日志數據的索引,它們用於查找壓縮后的日志內容,這些內容被單獨存儲為。標簽和值的每一個唯一組合都定義了一個 ,一個流的日志被分批,壓縮,並作為塊進行存儲。

4.5- Cardinality(勢)

定義動態標簽:

比如我們有下面這樣的日志數據:

11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

使用下面的方式來解析這條日志數據:

- job_name: system
   pipeline_stages:
      - regex:
        expression: "^(?P<ip>\\S+) (?P<identd>\\S+) (?P<user>\\S+) \\[(?P<timestamp>[\\w:/]+\\s[+\\-]\\d{4})\\] \"(?P<action>\\S+)\\s?(?P<path>\\S+)?\\s?(?P<protocol>\\S+)?\" (?P<status_code>\\d{3}|-) (?P<size>\\d+|-)\\s?\"?(?P<referer>[^\"]*)\"?\\s?\"?(?P<useragent>[^\"]*)?\"?$"
    - labels:
        action:
        status_code:
   static_configs:
   - targets:
      - localhost
     labels:
      job: apache
      env: dev
      __path__: /var/log/apache.log

這個 regex 匹配日志行的每個組件,並將每個組件的值提取到一個 capture 組里面。在 pipeline 代碼內部,這些數據被放置到一個臨時的數據結構中,允許在處理該日志行時將其用於其他處理(此時,臨時數據將被丟棄)。

從該 regex 中,我們就使用其中的兩個 capture 組,根據日志行本身的內容動態地設置兩個標簽:

action (例如 action="GET", action="POST") status_code (例如 status_code="200", status_code="400")

假設我們有下面幾行日志數據:

11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

則在 Loki 中收集日志后,會創建為如下所示的流:

{job="apache",env="dev",action="GET",status_code="200"} 11.11.11.11 - frank [25/Jan/2000:14:00:01 -0500] "GET /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="POST",status_code="200"} 11.11.11.12 - frank [25/Jan/2000:14:00:02 -0500] "POST /1986.js HTTP/1.1" 200 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="GET",status_code="400"} 11.11.11.13 - frank [25/Jan/2000:14:00:03 -0500] "GET /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"
{job="apache",env="dev",action="POST",status_code="400"} 11.11.11.14 - frank [25/Jan/2000:14:00:04 -0500] "POST /1986.js HTTP/1.1" 400 932 "-" "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 GTB6"

這4行日志將成為4個獨立的流,並開始填充4個獨立的塊。任何與這些 標簽/值 組合相匹配的額外日志行將被添加到現有的流中。如果有另一個獨特的標簽組合進來(比如 status_code="500")就會創建另一個新的流。

比如我們為 IP 設置一個 Label 標簽,不僅用戶的每一個請求都會變成一個唯一的流,每一個來自同一用戶的不同 action 或 status_code 的請求都會得到自己的流。

如果有4個共同的操作(GET、PUT、POST、DELETE)和4個共同的狀態碼(可能不止4個!),這將會是16個流和16個獨立的塊。然后現在乘以每個用戶,如果我們使用 IP 的標簽,你將很快就會有數千或數萬個流了。

這個 Cardinality 太高了,這足以讓 Loki 掛掉。

當我們談論 Cardinality 的時候,我們指的是標簽和值的組合,以及他們創建的流的數量,高 Cardinality 是指使用具有較大范圍的可能值的標簽,如 IP,或結合需要其他標簽,即使它們有一個小而有限的集合,比如 status_code 和 action。

高 Cardinality 會導致 Loki 建立一個巨大的索引(????),並將成千上萬的微小塊存入對象存儲中(慢),Loki 目前在這種配置下的性能非常差,運行和使用起來非常不划算的。

5- 查詢語法

標簽匹配符:

  • = 完全相等。
  • != 不相等。
  • =~ 正則表達式匹配。
  • !~ 不進行正則表達式匹配。

例: {job=“varlogs”,filename="/var/log/auth.log"}

搜索表達式:

  • |= 行包含字符串。
  • != 行不包含字符串。
  • |~ 行匹配正則表達式。
  • !~ 行與正則表達式不匹配。

例: {job=“/var/log/auth.log”} |= “07.18” |= “[-973]” != “0xffffffff”

6- Loki 性能優化

如果使用大量的標簽或有大量值的標簽是不好的,那我應該如何查詢我的日志呢?如果沒有一個數據是有索引的,那么查詢不會真的很慢嗎?

我們看到使用 Loki 的人習慣了其他重索引的解決方案,他們就覺得需要定義很多標簽,才可以有效地查詢日志,畢竟很多其他的日志解決方案都是為了索引,這是之前的慣性思維方式。

在使用 Loki 的時候,你可能需要忘記你所知道的東西,看看如何用並行化的方式來解決這個問題。Loki 的超強之處在於將查詢拆成小塊,並行調度,這樣你就可以在少量時間內查詢大量的日志數據了。

大型索引是非常復雜而昂貴的,通常情況下,你的日志數據的全文索引與日志數據本身的大小相當或更大。要查詢你的日志數據,需要加載這個索引,為了性能,可能在內存中,這就非常難擴展了,當你采集了大量的日志時,你的索引就會變得很大。

現在我們來談談 Loki,索引通常比你采集的日志量小一個數量級。所以,如果你很好地將你的流保持在最低限度,那么指數的增長和采集的日志相比就非常緩慢了。

Loki 將有效地使你的靜態成本盡可能低(索引大小和內存需求以及靜態日志存儲),並使查詢性能可以在運行時通過水平伸縮進行控制。

為了了解是如何工作的,讓我們回過頭來看看上面我們查詢訪問日志數據的特定 IP 地址的例子,我們不使用標簽來存儲 IP,相反,我們使用一個過濾器表達式來查詢它。

{job="apache"} |= "11.11.11.11"

在背后 Loki 會將該查詢分解成更小的碎片(shards),並為標簽匹配的流打開每個塊(chunk),並開始查找這個 IP 地址。

這些碎片的大小和並行化的數量是可配置的,並基於你提供的資源。如果你願意,可以將 shard 間隔配置到 5m,部署20個查詢器,並在幾秒內處理千兆字節的日志。或者你可以更加瘋狂地配置200個查詢器,處理 TB 級別的日志!

這種較小的索引和並行查詢與較大/較快的全文索引之間的權衡,是讓 Loki 相對於其他系統節省成本的原因。操作大型索引的成本和復雜度很高,而且通常是固定的,無論是是否在查詢它,你都要一天24小時為它付費。

這種設計的好處是,你可以決定你想擁有多大的查詢能力,而且你可以按需變更。查詢性能成為你想花多少錢的函數。同時數據被大量壓縮並存儲在低成本的對象存儲中,比如 S3 和 GCS。這就將固定的運營成本降到了最低,同時還能提供難以置信的快速查詢能力。


免責聲明!

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



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