日志体系:Loki+Promtail 轻量方案落地

一句话定位:ELK 太重?Loki + Promtail 给你一条"像 grep 一样查日志,像 Prometheus 一样管日志"的轻量之路。

写在前面

2024年我在一家电商公司做 K8s 集群迁移,原来的日志方案是 ELK—— 3 台 16C64G 的 Elasticsearch 节点,每月存储成本 8000+。日志量大时 ES 频繁 OOM,Kibana 查询慢得让人想砸键盘。业务方天天投诉"日志查不出来"。

后来我们切到 Loki + Promtail,同样的日志量,存储成本降到原来的 1/5,查询速度反而更快。这篇文章就是把那次迁移的完整经验写出来,从原理到部署到踩坑,一条龙。

读完你能带走什么:

  • Loki 架构原理和标签设计方法论
  • DaemonSet vs Sidecar 两种采集模式的选型决策
  • 一套生产可用的 Loki+Promtail Helm 部署配置
  • LogQL 常用查询速查手册
  • 日志告警和成本控制策略

核心问题

ELK 太重,有没有轻量替代?回答这个问题之前,我们先搞清楚 ELK 到底"重"在哪:

  1. 全文索引开销大:ES 对每行日志建倒排索引,磁盘和内存消耗是原始日志的 2-3 倍
  2. 运维复杂:ES 集群分片、副本、JVM 调优,没个专职运维搞不定
  3. 与 K8s 生态割裂:ELK 不是云原生出身,和 Prometheus、Grafana 配合起来别扭

Loki 的思路很聪明:不索引日志内容,只索引标签(Labels)。这就像图书馆里不把每本书的全文做成索引卡片,只按分类号、作者、出版日期建卡片——找书时先按卡片定位,再翻内容。


一、原理剖析

1.1 Loki 整体架构

Loki 是一个"写多读少"的日志聚合系统,设计上大量借鉴了 Prometheus 的理念。

┌────────────────────────────────────────────────────────────────┐
│                         Loki 架构                                │
├────────────────────────────────────────────────────────────────┤
│                                                                  │
│   ┌──────────┐     ┌──────────┐     ┌──────────┐               │
│   │ Promtail │     │ Promtail │     │ Promtail │  (采集层)      │
│   │ (Node-1) │     │ (Node-2) │     │ (Node-3) │               │
│   └────┬─────┘     └────┬─────┘     └────┬─────┘               │
│        │                │                │                       │
│        └────────────────┼────────────────┘                       │
│                         │ (gRPC push)                            │
│                         ▼                                        │
│              ┌─────────────────────┐                             │
│              │    Distributor      │  (分发层)                    │
│              │  - 验证租户/标签    │                             │
│              │  - 哈希路由         │                             │
│              │  - 一致性哈希环     │                             │
│              └─────────┬───────────┘                             │
│                        │                                         │
│           ┌────────────┼────────────┐                            │
│           ▼            ▼            ▼                            │
│   ┌───────────┐ ┌───────────┐ ┌───────────┐                     │
│   │ Ingester  │ │ Ingester  │ │ Ingester  │  (写入层)            │
│   │ - 构建Chunk│ │ - 内存缓存│ │ - 刷写存储│                     │
│   └─────┬─────┘ └─────┬─────┘ └─────┬─────┘                     │
│         │             │             │                             │
│         └─────────────┼─────────────┘                             │
│                       ▼                                          │
│           ┌───────────────────────┐                               │
│           │   对象存储 (S3/GCS等) │  (持久化层)                    │
│           │   Chunks + Index      │                               │
│           └───────────┬───────────┘                               │
│                       │                                          │
│                       ▼                                          │
│           ┌───────────────────────┐                               │
│           │      Querier          │  (查询层)                     │
│           │  - 接收查询请求        │                              │
│           │  - 并行读取Chunks      │                              │
│           │  - 合并返回结果        │                              │
│           └───────────────────────┘                               │
│                                                                  │
└────────────────────────────────────────────────────────────────┘

各组件职责:

组件 职责 关键设计
Distributor 接收日志流,验证标签格式,按一致性哈希路由到 Ingester 无状态,可水平扩展
Ingester 接收日志、构建 Chunk、定期刷写到对象存储 有状态,通过 WAL 保证不丢数据
Querier 执行 LogQL 查询,从 Ingester + 对象存储读取数据并合并 无状态,读路径
Compactor 合并小 Index 文件,执行保留策略清理过期数据 减少查询时需要扫描的文件数
Query Frontend 查询缓存、查询拆分、重试、限流 可选但生产强烈建议部署
Ruler 周期性执行 LogQL 规则,生成告警或录制指标 日志告警的核心组件

1.2 核心设计:标签为王

Loki 最核心的设计哲学来自 Prometheus:Labels are the index

Loki 只对标签({app="nginx", env="prod"})建索引,日志内容本体(log line)不做索引,直接按时间排序存储在 Chunk 中。

这带来一个直接推论:标签的设计决定了查询性能和存储成本

标签索引原理(ASCII 示意):

日志流:
  {app="nginx", env="prod", pod="nginx-7d4f8"}
    2024-01-01 10:00:01 GET /api/users 200
    2024-01-01 10:00:02 POST /api/orders 201
    2024-01-01 10:00:03 GET /api/products 200

查询: {app="nginx", env="prod"} |= "orders"
                  │
                  ▼
        ┌──────────────────┐
        │ 1. 标签索引查找    │  ← 直接命中,O(1)
        │    app=nginx      │
        │    env=prod       │
        └──────┬───────────┘
               │
               ▼
        ┌──────────────────┐
        │ 2. 定位 Chunk 文件 │  ← 按时间范围过滤
        │    2024-01-01     │
        └──────┬───────────┘
               │
               ▼
        ┌──────────────────┐
        │ 3. 顺序扫描内容    │  ← 类似 grep,但不建索引
        │    匹配 "orders"  │
        └──────────────────┘

标签设计的黄金法则:

高基数标签 ──▶ 禁止!    例如 pod_name, container_id, trace_id
中等基数    ──▶ 谨慎     例如 user_id, request_id(考虑用结构化日志字段代替)
低基数标签 ──▶ 推荐!    例如 app, env, namespace, cluster, team

高基数标签为什么是大忌?Loki 为每个标签组合创建一个独立的流(Stream),如果你把 pod_name 当作标签,每次 Pod 重启都会创建新流,标签索引会爆炸式增长,DynamoDB/BigTable 存储成本直线上升。

1.3 采集模式对比:DaemonSet vs Sidecar

这是面试和方案评审中必问的问题。两种模式各有优劣,没有银弹。

DaemonSet 模式                          Sidecar 模式

┌──────────────────────┐              ┌──────────────────────┐
│        Node           │              │        Pod            │
│  ┌────────────────┐   │              │  ┌────────────────┐   │
│  │   Pod A        │   │              │  │  App Container  │   │
│  │ (stdout/stderr) │   │              │  │  → 写文件到     │   │
│  └────────┬───────┘   │              │  │    /var/log/    │   │
│           │ stdout    │              │  └───────┬────────┘   │
│  ┌────────▼───────┐   │              │          │ tail       │
│  │   Promtail     │◄──┤─ 所有Pod     │  ┌───────▼────────┐   │
│  │ (DaemonSet)    │   │  共享一个    │  │  Log Sidecar   │   │
│  │ /var/log/pods  │   │  Promtail    │  │  → push Loki   │   │
│  └────────┬───────┘   │              │  └────────────────┘   │
│           │ push      │              └──────────────────────┘
│     ┌─────▼─────┐     │
│     │   Loki    │     │              一个Pod一个Sidecar
│     └───────────┘     │              资源消耗随Pod线性增长
└──────────────────────┘
维度 DaemonSet Sidecar
资源占用 O(Node数量) O(Pod数量)
侵入性 无侵入,应用写 stdout 即可 需改造 Pod Spec
日志格式处理 统一处理 每个 Sidecar 独立处理
适用场景 标准应用日志采集 日志需要特殊解析/脱敏
网络开销 每节点一个 gRPC 连接 每 Pod 一个连接

生产建议:除非有特殊需求(如必须采集非 stdout 的文件日志、需要日志脱敏),一律用 DaemonSet 模式。简单就是最大的美德。


二、实战操作

2.1 环境准备

# 确认 K8s 版本
kubectl version --short

# 确认 Helm 版本
helm version --short

# 添加 Loki 官方 Helm 仓库
helm repo add grafana https://grafana.github.io/helm-charts
helm repo update

2.2 Loki 生产部署配置

# 创建命名空间
kubectl create namespace loki

# 创建 S3 凭证 Secret(以 MinIO 为例,生产用 AWS S3/GCS/Azure Blob)
kubectl create secret generic loki-s3-credentials \
  --from-literal=access_key_id="loki-admin" \
  --from-literal=access_key_secret="your-secret-key" \
  -n loki

loki-values.yaml —— 生产级部署配置:

# ============================================
# Loki 生产部署配置 (v2.9.x, Helm Chart 5.x)
# 适用规模:日均日志量 100GB-1TB
# ============================================

# ── Loki 核心配置 ──
loki:
  # 部署模式:SingleBinary 适合入门/小规模
  # 大规模场景用 microservices 模式分开部署各个组件
  deploymentMode: SingleBinary

  # 镜像版本
  image:
    repository: grafana/loki
    tag: 2.9.6

  # 认证:多租户模式下强制开启
  auth_enabled: false  # 单租户场景关闭,多租户必须开启

  # ── 存储配置 ──
  storage:
    type: s3
    bucketNames:
      chunks: loki-chunks
      ruler: loki-ruler
      admin: loki-admin
    s3:
      endpoint: minio.loki.svc.cluster.local:9000
      region: us-east-1
      secretAccessKey: ${S3_SECRET_KEY}
      accessKeyId: ${S3_ACCESS_KEY}
      insecure: true       # MinIO 非 TLS 场景
      s3ForcePathStyle: true

  # ── Ingester 配置 ──
  ingester:
    chunk_encoding: snappy    # snappy 平衡压缩率和 CPU 消耗
    chunk_target_size: 1572864       # 1.5MB,Chunk 目标大小
    chunk_idle_period: 30m           # 30分钟无新日志则关闭 Chunk
    chunk_retain_period: 1m          # Ingester 关闭后 Chunk 保留时间
    max_chunk_age: 2h                # Chunk 最大存活时间,到达后强制刷写
    chunk_block_size: 262144         # 256KB 块大小
    max_returned_stream_errors: 10
    wal:
      enabled: true                  # 生产必须开 WAL
      dir: /var/loki/wal
      replay_memory_ceiling: 2GB     # WAL 回放内存上限

  # ── 查询配置 ──
  querier:
    max_concurrent: 20               # 最大并发查询数
    query_ingesters_within: 2h       # 2小时内的数据从 Ingester 查
    query_timeout: 5m                # 查询超时
    engine:
      timeout: 3m
      max_look_back_period: 720h     # 30天

  # ── 查询前端(生产强烈推荐) ──
  queryFrontend:
    max_outstanding_per_tenant: 1024
    compress_responses: true
    log_queries_longer_than: 10s
    max_retries: 3

  # ── Query Scheduler ──
  queryScheduler:
    max_outstanding_requests_per_tenant: 100

  # ── 索引与 Chunk Schema ──
  schemaConfig:
    configs:
      - from: "2024-01-01"
        store: tsdb                    # TSDB 索引格式(Loki 2.8+ 推荐)
        object_store: s3
        schema: v13
        index:
          prefix: loki_index_
          period: 24h

  # ── 压缩器 ──
  compactor:
    working_directory: /var/loki/compactor
    compaction_interval: 10m
    retention_enabled: true
    retention_delete_delay: 2h
    delete_request_store: s3

  # ── 保留策略(关键!控制成本) ──
  limits_config:
    retention_period: 744h            # 保留31天日志
    max_entries_limit_per_query: 5000
    max_streams_per_user: 10000       # 每个租户最大流数
    max_global_streams_per_user: 50000
    ingestion_rate_mb: 16             # 每秒摄入速率限制(MB)
    ingestion_burst_size_mb: 32       # 突发摄入大小(MB)
    max_label_name_length: 1024
    max_label_value_length: 2048
    max_label_names_per_series: 30    # 每个流最多30个标签(鼓励标签收敛)

  # ── Ruler 日志告警 ──
  rulerConfig:
    storage:
      type: s3
      s3:
        bucketNames: loki-ruler
    alertmanager_url: http://alertmanager.monitoring.svc:9093
    enable_alertmanager_v2: true
    enable_api: true
    ring:
      kvstore:
        store: inmemory
    rule_path: /var/loki/rules-temp
    poll_interval: 1m

  # ── 资源配额 ──
  resources:
    requests:
      cpu: 500m
      memory: 1Gi
    limits:
      cpu: 2000m
      memory: 4Gi

  # 持久化
  persistence:
    enabled: true
    size: 50Gi
    storageClass: ssd-sc     # WAL 和临时数据建议用 SSD

  # 服务暴露
  service:
    type: ClusterIP
    port: 3100

# ── Promtail 配置 ──
promtail:
  enabled: true

  image:
    registry: docker.io
    repository: grafana/promtail
    tag: 2.9.6

  config:
    clients:
      - url: http://loki.loki.svc.cluster.local:3100/loki/api/v1/push
        batchsize: 1048576       # 1MB 批次
        batchwait: 1s
        backoff_config:
          min_period: 500ms
          max_period: 5m
          max_retries: 10

    # ── 管道配置(核心!日志处理在这里做) ──
    snippets:
      extraScrapeConfigs: |
        # 额外抓取配置示例

      pipelineStages:
        # Stage 1: 解析 CRI 格式的容器日志
        - cri: {}

        # Stage 2: 提取关键字段为标签
        - static_labels:
            cluster: "prod-k8s-1"
            datacenter: "cn-east-2"

        # Stage 3: 根据 Pod 标签动态添加 Loki 标签
        - labels:
            app:
            namespace:
            pod_template_hash:
            container:

        # Stage 4: 水位线(避免重复采集)
        - match:
            selector: '{app=~".*"}'
            stages:
              - json:
                  expressions:
                    level: level
                    message: message
                    trace_id: trace_id
              - labels:
                  level:
                  trace_id:

        # Stage 5: 删除不需要的标签(控制标签基数)
        - labeldrop:
            - pod_template_hash
            - controller_revision_hash
            - pod_uid

    # 资源限制
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 512Mi

    # 容忍所有污点
    tolerations:
      - operator: Exists

# ── 测试用 Grafana ──
grafana:
  enabled: true
  adminPassword: admin123
  datasources:
    datasources.yaml:
      apiVersion: 1
      datasources:
        - name: Loki
          type: loki
          url: http://loki.loki.svc.cluster.local:3100
          access: proxy
          isDefault: true

# ── MinIO(仅测试用,生产请用外部 S3) ──
minio:
  enabled: true
  mode: standalone
  rootUser: loki-admin
  rootPassword: changeme-dev-only
  buckets:
    - name: loki-chunks
      policy: none
      purge: false
    - name: loki-ruler
      policy: none
      purge: false
    - name: loki-admin
      policy: none
      purge: false
  persistence:
    enabled: true
    size: 20Gi

部署命令:

# 部署 Loki Stack (Loki + Promtail + Grafana + MinIO)
helm upgrade --install loki grafana/loki \
  --namespace loki \
  --values loki-values.yaml \
  --timeout 10m \
  --wait

# 验证所有 Pod 正常运行
kubectl get pods -n loki -w

# 预期输出:
# NAME                           READY   STATUS    RESTARTS   AGE
# loki-0                         1/1     Running   0          2m
# loki-grafana-xxxxx             1/1     Running   0          2m
# loki-minio-xxxxx               1/1     Running   0          2m
# loki-promtail-xxxxx            1/1     Running   0          2m  (每个节点一个)
# loki-promtail-yyyyy            1/1     Running   0          2m

2.3 验证部署

# 端口转发 Loki API
kubectl port-forward -n loki svc/loki 3100:3100 &

# 验证 Loki Ready
curl http://localhost:3100/ready
# 预期输出: Ready

# 查看所有标签(确认标签采集正常)
curl http://localhost:3100/loki/api/v1/labels | jq

# 查看某个标签的值
curl 'http://localhost:3100/loki/api/v1/label/app/values' | jq

# 发送一条测试日志查询
curl -G -s "http://localhost:3100/loki/api/v1/query_range" \
  --data-urlencode 'query={app=~".+"}' \
  --data-urlencode 'limit=5' \
  --data-urlencode 'start='$(date -d '1 hour ago' +%s)'000000000' \
  --data-urlencode 'end='$(date +%s)'000000000' | jq

三、踩坑与排查

3.1 坑一:标签基数爆炸

现象:部署一周后,Loki 查询越来越慢,S3 上的 Index 文件快速增长。Promtail 日志中出现 stream limit exceeded 错误。

原因:运维同学在 Promtail 管道中把 pod_name 加入了 labels:

# 这是错误的配置!
- labels:
    pod:          # pod name 每次滚动更新都会变!
    container:

每次 Deployment 滚动更新,Pod 名称变化就会创建全新的 stream。一个 100 副本的服务,一天滚动 3 次,就产生了 400 个 stream(100×3 + 原始100)。这还没算上 container_idpod_uid 等更多高基数标签。

排查过程

# 1. 查看每个租户的 stream 数量
curl http://localhost:3100/loki/api/v1/series | jq '.data | length'

# 2. 找出基数最高的标签(需要安装 logcli)
logcli series '{app=~".+"}' --since=24h | \
  awk '{print $1}' | sort | uniq -c | sort -rn | head -20

# 3. 检查标签基数
logcli labels --since=1h

解决方案

# 正确的标签策略
pipelineStages:
  - cri: {}
  - labels:
      app:              # 低基数 ✓
      namespace:        # 低基数 ✓
      env:              # 低基数 ✓ (dev/staging/prod)
  - labeldrop:
      - pod             # 高基数 ✗ 删除
      - container_id    # 高基数 ✗ 删除
      - pod_uid         # 高基数 ✗ 删除

如果确实需要在查询中按 Pod 名称过滤,用 LogQL 的内容匹配替代标签过滤:

# 不要这样(标签基数高)
{app="nginx", pod="nginx-7d4f8-abcde"}

# 改成这样(内容匹配)
{app="nginx"} |= "nginx-7d4f8-abcde"

3.2 坑二:Ingester OOM 频发

现象:高负载时段 Loki 频繁 OOMKilled。Ingester 内存持续上升不释放。

原因:Ingester 在内存中缓存 Chunk,直到 max_chunk_age 或 Chunk 满才刷写。如果配置不合理,Ingester 会囤积大量未刷写数据。

定位

# 查看 Ingester 内存
kubectl top pod loki-0 -n loki

# 查看 Loki 内部指标
curl http://localhost:3100/metrics | grep loki_ingester_memory_streams

# 关键指标
# loki_ingester_memory_streams          ← 活跃 stream 数
# loki_ingester_chunk_age_seconds       ← Chunk 平均年龄
# loki_ingester_memory_chunks           ← 内存中 Chunk 数

解决方案

loki:
  ingester:
    max_chunk_age: 1h                # 缩短为 1 小时(原 2h)
    chunk_idle_period: 15m           # 15分钟无新日志就关闭
    chunk_target_size: 1048576       # 降为 1MB(原 1.5MB),更频繁刷写
    max_returned_stream_errors: 10
  resources:
    limits:
      memory: 6Gi                    # 适当提高限制(前提是节点有资源)

3.3 坑三:查询超时

现象:查询最近 7 天的日志总是超时,返回 500。

原因:查询时间范围太大,Querier 需要扫描大量 Chunk 文件。没有部署 Query Frontend 或未配置查询拆分。

排查

# 先用 logcli 精确排查
logcli query '{app="nginx"}' --from="2024-07-01T00:00:00Z" --to="2024-07-01T01:00:00Z" --limit=100
# 如果 1 小时可以,7 天不行 → 确认是范围问题

# 查看 Query Frontend 日志
kubectl logs -n loki deployment/loki -c loki | grep "query"

解决方案

loki:
  queryFrontend:
    split_queries_by_interval: 30m   # 按 30 分钟拆分大型查询
    max_retries: 2
    parallelise_shardable_queries: true  # 并行分片查询
  
  querier:
    max_concurrent: 30               # 提高并发
    query_timeout: 3m                # 适当放宽

3.4 坑四:Promtail 重复采集

现象:同一行日志在 Loki 中出现多次,查询结果翻倍。

原因:Promtail 的 position 文件损坏或丢失,重启后从头读取日志文件。

定位

# 检查 Promtail position 文件
kubectl exec -n loki daemonset/loki-promtail -- cat /var/lib/promtail/positions.yaml

# 查看是否有文件被重复打开(inode 变化)
kubectl logs -n loki daemonset/loki-promtail | grep "new file"

解决方案

promtail:
  config:
    positions:
      filename: /var/lib/promtail/positions.yaml
      sync_period: 10s              # 更频繁地同步 position

  # 持久化 position 文件,Pod 重启不丢失
  extraVolumes:
    - name: positions
      hostPath:
        path: /var/lib/promtail-positions
        type: DirectoryOrCreate
  extraVolumeMounts:
    - name: positions
      mountPath: /var/lib/promtail

四、最佳实践

标签设计清单

  • 标签总数控制在 10 个以内
  • 使用 app(应用名)、env(环境)、namespace(K8s 空间)、cluster(集群名)、team(团队)等低基数标签
  • 禁止 podcontainer_idpod_uid 等会频繁变化的高基数标签
  • Pod 名称信息通过日志内容匹配过滤,不通过标签

性能优化清单

  • 部署 Query Frontend + Query Scheduler,开启查询拆分和结果缓存
  • Ingester 开启 WAL(wal.enabled: true),防止 OOM 丢数据
  • 使用 TSDB 索引格式(schema: v13store: tsdb),Loki 2.8+ 默认推荐
  • Chunk 编码选 snappy,压缩率 4-6x,CPU 开销小
  • 合理设置 max_entries_limit_per_query(默认 5000),防止一条查询拖垮集群

成本控制清单

  • 必做:设置 retention_period,删除过期日志(建议 30 天或 90 天)
  • 推荐:S3 配置生命周期策略,自动转换到标准-IA 或 Glacier
  • 推荐:按 env 标签配置不同保留期(生产 30 天、测试 7 天)
  • 可选:日志降采样 —— 7 天前的日志只保留 ERROR 级别
  • 禁止:使用 lz4 编码(虽然快但压缩率差,S3 存储成本高)

日志告警清单

# loki-alerts.yaml - 放入 Ruler 配置
groups:
  - name: loki-alerts
    rules:
      # 规则1: 错误率突增
      - alert: HighErrorRate
        expr: |
          sum(rate({app=~".+"} |~ "(?i)error|exception|fatal" [5m])) by (app)
          / sum(rate({app=~".+"} [5m])) by (app) > 0.05
        for: 5m
        labels:
          severity: P1
        annotations:
          summary: "应用 {{ $labels.app }} 错误率超过 5%"
          description: "当前错误率 {{ $value | humanizePercentage }}"

      # 规则2: 特定错误关键词
      - alert: OutOfMemoryDetected
        expr: |
          count_over_time({app=~".+"} |= "OutOfMemoryError" [5m]) > 0
        for: 1m
        labels:
          severity: P0
        annotations:
          summary: "检测到 OOM 错误"

      # 规则3: 应用日志量突降(可能采集挂了)
      - alert: LogVolumeDropped
        expr: |
          sum(rate({app=~".+"} [5m])) by (app) < 1
        for: 10m
        labels:
          severity: P2
        annotations:
          summary: "应用 {{ $labels.app }} 日志量异常下降"

LogQL 速查

场景 LogQL 查询 说明
应用全部日志 {app="myapp"} 最基础查询
时间范围+关键词 {app="myapp"} |= "error" 行包含 filter
正则匹配 {app="myapp"} |~ "(?i)error|exception" 大小写不敏感
排除关键词 {app="myapp"} != "debug" 不包含 debug 的行
JSON 字段过滤 {app="myapp"} | json | level="error" 解析 JSON 后过滤
计数统计 count_over_time({app="myapp"} [5m]) 5 分钟内日志行数
速率统计 rate({app="myapp"} [5m]) 每秒日志速率
按标签聚合 sum(rate({app=~".+"} [5m])) by (app) 每个应用的日志速率
TOP N 应用 topk(5, sum(rate({app=~".+"} [5m])) by (app)) 日志量 Top 5
无日志检测 absent_over_time({app="myapp"} [10m]) 10 分钟没有日志则触发
IP 解析过滤 {app="nginx"} | pattern "<ip>" 提取 IP 模式
字节日志 bytes_over_time({app="myapp"} [1h]) 1 小时内日志字节数

五、小结

Loki 不是要取代 ELK,而是提供了一种更适合云原生环境的日志方案。记住三句话:

  1. 标签是索引,内容是 grep —— 标签设计好了,Loki 就跑顺了
  2. DaemonSet 搞定 90% 的采集需求 —— Sidecar 只在有特殊需求时用
  3. Query Frontend + 合理保留策略 = 低成本高性能 —— 生产部署的基本姿势

如果你正在被 ELK 的运维成本折磨,给 Loki 两周时间试试。小规模(日均 < 100GB 日志)用 SingleBinary 模式跑单体就够了,大规模(> 1TB/天)上微服务模式 + 独立的 S3/GCS。


思考题

  1. 如果你的应用同时输出 JSON 格式的结构化日志和纯文本的非结构化日志,Promtail 管道应该怎么配?
  2. 多租户场景下,如何通过 X-Scope-OrgID header 实现租户隔离?如果一个租户的日志量是其他租户的 100 倍,如何限流?
  3. Loki 的 Ingester 如果宕机,多久会丢数据?(提示:WAL + Replication Factor)

延伸阅读

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐