Grafana Loki 轻量级日志聚合实战
Raj Kumar | 2026-09-02T01:08:32 | DevOps, Cloud
介绍 Grafana Loki 的架构设计和部署方式,演示如何用 Promtail 采集日志、LogQL 查询语法以及告警规则配置。
# Grafana Loki 轻量级日志聚合实战 ## 为什么选 Loki ELK(Elasticsearch + Logstash + Kibana)是日志聚合的经典方案,但资源消耗大、运维复杂。Grafana Loki 采用了不同的设计理念:只索引标签(labels),不索引日志内容,大幅降低存储和计算成本。 ## 架构对比 | 维度 | ELK | Loki | |------|-----|------| | 索引方式 | 全文索引 | 仅索引标签 | | 存储成本 | 高 | 低(10-100 倍差距) | | 查询速度 | 任意关键词快速查询 | 标签过滤快,文本搜索较慢 | | 资源消耗 | 高(ES 吃内存) | 低 | | 适合场景 | 复杂日志分析 | 日常运维和排错 | ## Docker Compose 部署 ```yaml version: "3.8" services: loki: image: grafana/loki:3.0.0 ports: - "3100:3100" volumes: - ./loki-config.yaml:/etc/loki/config.yaml - loki-data:/loki command: -config.file=/etc/loki/config.yaml promtail: image: grafana/promtail:3.0.0 volumes: - ./promtail-config.yaml:/etc/promtail/config.yaml - /var/log:/var/log:ro command: -config.file=/etc/promtail/config.yaml grafana: image: grafana/grafana:11.0.0 ports: - "3000:3000" environment: GF_SECURITY_ADMIN_PASSWORD: admin volumes: - grafana-data:/var/lib/grafana volumes: loki-data: grafana-data: ``` ## Loki 配置 ```yaml # loki-config.yaml auth_enabled: false server: http_listen_port: 3100 common: path_prefix: /loki storage: filesystem: chunks_directory: /loki/chunks rules_directory: /loki/rules replication_factor: 1 ring: kvstore: store: inmemory schema_config: configs: - from: 2024-01-01 store: tsdb object_store: filesystem schema: v13 index: prefix: index_ period: 24h limits_config: retention_period: 30d max_query_lookback: 30d ``` ## Promtail 采集配置 ```yaml # promtail-config.yaml server: http_listen_port: 9080 positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: system static_configs: - targets: [localhost] labels: job: syslog host: server-01 __path__: /var/log/syslog - job_name: app static_configs: - targets: [localhost] labels: job: myapp env: production __path__: /var/log/myapp/*.log pipeline_stages: - regex: expression: "^(?P\\S+) (?P\\S+) (?P.*)quot; - labels: level: - timestamp: source: timestamp format: "2006-01-02T15:04:05.000Z" ``` ## LogQL 查询语法 ### 基础查询 ```logql # 按标签过滤 {job="myapp", env="production"} # 文本过滤 {job="myapp"} |= "error" {job="myapp"} != "debug" {job="myapp"} |~ "timeout|refused" {job="myapp"} !~ "health_check" ``` ### 日志解析 ```logql # JSON 日志解析 {job="myapp"} | json | level="error" | line_format "{{.message}}" # 正则提取字段 {job="nginx"} | regexp "status=(?P\\d+)" | status >= 500 # logfmt 解析 {job="myapp"} | logfmt | duration > 5s ``` ### 聚合查询(Metrics from Logs) ```logql # 每分钟错误日志数量 rate({job="myapp"} |= "error" [5m]) # 按 level 分组统计 sum by (level) (count_over_time({job="myapp"} | json [1h])) # P99 响应时间(从日志中提取) quantile_over_time(0.99, {job="myapp"} | json | unwrap duration [5m]) by (endpoint) ``` ## Spring Boot 集成 使用 Loki4j 直接从 Java 应用推送日志: ```xml com.github.loki4j loki-logback-appender 1.5.1 ``` ```xml http://loki:3100/loki/api/v1/push app=myapp,host=${HOSTNAME},level=%level %d{ISO8601} [%thread] %-5level %logger - %msg%n ``` ## 告警规则 ```yaml # loki-rules.yaml groups: - name: app-alerts rules: - alert: HighErrorRate expr: | sum(rate({job="myapp"} |= "error" [5m])) > 10 for: 5m labels: severity: critical annotations: summary: "Error rate exceeds 10/s for 5 minutes" ``` ## 最佳实践 1. **标签不要太多**:高基数标签(如 user_id)会严重影响性能 2. **合理设置保留期**:生产 30 天,开发 7 天 3. **日志格式统一**:推荐 JSON 格式,方便 LogQL 解析 4. **配合 Grafana 仪表盘**:将日志面板和指标面板放在同一个 Dashboard ## 总结 Loki 用"标签索引 + 日志压缩存储"的设计大幅降低了日志聚合的成本和复杂度。对于大多数运维场景,它在成本和功能之间找到了最佳平衡点。配合 Grafana 和 Promtail,几乎零配置就能搭建出完整的日志系统。