日志平台搭建:Loki + Promtail + Grafana——替代 ELK 的轻量方案
引言
凌晨两点告警炸了,打开 ELK 想查日志:
Loading...
Loading...
Loading...
Timeout.
Kibana 加载 30 秒才出结果,ES 节点 CPU 100%,磁盘又满了。
每次扩容都是加节点、加磁盘、加内存,运维成本高到离谱。
ELK 是好东西,但对中小团队来说太重——Elasticsearch 索引全部日志内容,光存储就是一笔大开销,再加上 JVM 调优、集群维护,运维同学直呼"养不起"。
有没有更轻量的方案?有。Loki + Promtail + Grafana——Grafana Labs 出品的"日志版 Prometheus",只索引标签不索引全文,存储成本直接砍 80%,还能和 Grafana 无缝集成,在同一面板看 Metric + Trace + Log。
本文从零搭建一套完整的日志平台,附 docker-compose 一键部署 + Spring Boot 接入 + LogQL 查询实战。
一、为什么选 Loki 不选 ELK
1.1 ELK 的痛点
ELK = Elasticsearch + Logstash + Kibana,传统日志方案三件套。
痛点 1:存储贵
Elasticsearch 倒排索引:
"2026-08-08 14:30:15 ERROR order-service 订单创建失败"
→ 对每个词建索引:2026-08-08, 14:30:15, ERROR, order-service, 订单, 创建, 失败
1GB 日志 → 倒排索引膨胀到 2-3GB
500GB/天日志 → 集群存储 1-1.5TB/天,一个月 30TB+
痛点 2:资源吃得多
ES 节点 JVM 堆建议 32GB(不超过物理内存 50%)
3 节点 → 96GB 内存
+ Logstash JVM → 每个 1-2GB
+ Kibana → 1GB
整套栈起步 100GB+ 内存
痛点 3:运维复杂
- 分片分配不均
- 节点掉线导致分片重新平衡
- 集群状态变红(red/yellow)
- ILM(生命周期管理)配置复杂
- 慢查询拖垮整个集群
痛点 4:和 Prometheus/Grafana 生态割裂
监控用 Prometheus,日志用 ELK,链路用 Jaeger——三套系统三个 UI,排查问题要在三个页面来回切。
1.2 Loki 的核心思想
"像 Prometheus 一样存日志。"
Prometheus 存指标只索引标签(label),不索引指标值本身。Loki 学这个思路:
日志内容 → 原文压缩存储(不索引)
标签 → 建索引
一段日志:
2026-08-08 14:30:15 ERROR order-service 订单创建失败 userId=12345
Loki 只索引:
app=order-service
level=ERROR
host=pod-abc123
日志正文原文压缩存起来,查询时再解。
1.3 ELK vs Loki 全面对比
| 维度 | ELK (Elasticsearch) | Loki |
|---|---|---|
| 索引方式 | 全文倒排索引 | 只索引标签 |
| 存储成本 | 1-3 倍日志量 | 0.1-0.2 倍日志量(压缩) |
| 内存占用 | 高(JVM 32GB/节点) | 低(10-20% ES) |
| 全文搜索 | 强(lucene 语法) | 弱(正则 + 管道过滤) |
| 结构化查询 | 强 | 强(LogQL) |
| 水平扩展 | 复杂(分片/副本) | 简单(无状态) |
| 部署复杂度 | 高 | 低(单二进制) |
| 运维成本 | 高 | 低 |
| UI 集成 | Kibana | Grafana(和监控统一) |
| 保留周期 | ILM 复杂 | 简单配置 |
| 学习曲线 | 陡(Query DSL) | 缓(LogQL 类似 PromQL) |
1.4 存储成本对比
以 500GB/天日志量为例:
| 方案 | 单日存储 | 月存储 | 一年存储 |
|---|---|---|---|
| ELK(含索引) | 1.5TB | 45TB | 540TB |
| Loki(压缩) | 100GB | 3TB | 36TB |
| 节省 | 93% | 93% | 93% |
按云盘 0.5 元/GB/月算:
ELK 一年存储费用:540TB × 0.5 × 12 = 324 万
Loki 一年存储费用:36TB × 0.5 × 12 = 21.6 万
差了一个数量级。
1.5 什么时候不选 Loki
Loki 不擅长复杂全文搜索:
| 场景 | 是否适合 Loki |
|---|---|
| 按服务/级别查日志 | ✅ 完美 |
| 按 traceId 串联日志 | ✅ 完美 |
| 业务埋点统计(如订单量) | ✅ LogQL 支持 |
| 模糊搜索某个关键词 | ⚠️ 可用正则,但慢 |
| 全文搜索引擎(如日志内"订单号"检索) | ❌ ELK 更合适 |
| 自然语言处理/日志分析 | ❌ ELK 更合适 |
简单说:结构化查询用 Loki,全文搜索用 ELK。
1.6 三种选型建议
| 团队规模 | 日志量 | 推荐方案 |
|---|---|---|
| 小团队(<50GB/天) | <50GB | Loki(轻量、便宜) |
| 中型团队(50-500GB/天) | 100-500GB | Loki(性价比高) |
| 大团队 + 复杂查询 | >500GB | ELK(功能全) |
| 不想运维 | 任意 | 阿里云 SLS / 腾讯云 CLS |
二、Loki 架构
2.1 三件套职责
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 应用服务 │ │ │ │ │
│ (Spring Boot)│ ───→ │ Promtail │ ───→ │ Loki │
│ 日志输出 │ 采集 │ (Agent) │ 推送 │ (存储+查询) │
└──────────────┘ └──────────────┘ └──────────────┘
│
│ 查询
▼
┌──────────────┐
│ Grafana │
│ (可视化) │
└──────────────┘
| 组件 | 职责 | 类比 ELK |
|---|---|---|
| Promtail | 采集、处理、推送日志 | Logstash / Filebeat |
| Loki | 存储 + 查询 | Elasticsearch |
| Grafana | 可视化查询 | Kibana |
2.2 Loki 内部组件
单机模式下 Loki 是一个进程,但内部有多个微服务组件:
Loki
├── Distributor → 接收日志,按标签哈希分片
├── Ingester → 写入内存 + 刷盘
├── Query Frontend → 查询拆分、缓存
├── Querier → 从内存/磁盘查询
├── Compactor → 合并压缩历史数据
└── Ruler → 告警规则评估
生产环境可以用 微服务模式 独立部署每个组件,按需扩展。
2.3 数据模型
Loki 的数据模型和 Prometheus 一致:
Stream(日志流)= 一组标签的唯一组合
{app="order-service", level="ERROR", host="pod-1"} → 一个 stream
Stream 内是一系列日志条目:
timestamp: 2026-08-08 14:30:15.123
line: "订单创建失败 userId=12345"
标签设计很关键——见下文第 5 节。
三、Docker Compose 一键部署
3.1 完整 docker-compose.yml
version: '3.8'
services:
# Loki(存储 + 查询)
loki:
image: grafana/loki:3.1.0
container_name: loki
ports:
- "3100:3100"
volumes:
- ./loki/loki-config.yml:/etc/loki/loki-config.yml
- loki_data:/loki
command: -config.file=/etc/loki/loki-config.yml
# Promtail(采集 Agent)
promtail:
image: grafana/promtail:3.1.0
container_name: promtail
volumes:
- /var/log:/var/log # 系统日志
- /var/lib/docker/containers:/var/lib/docker/containers:ro # Docker 日志
- ./promtail/promtail-config.yml:/etc/promtail/promtail-config.yml
command: -config.file=/etc/promtail/promtail-config.yml
depends_on:
- loki
# Grafana
grafana:
image: grafana/grafana:11.2.0
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
- ./grafana/dashboards:/var/lib/grafana/dashboards
depends_on:
- loki
volumes:
loki_data:
grafana_data:
3.2 Loki 配置文件
loki/loki-config.yml:
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 # 副本数(生产建议 3)
ring:
kvstore:
store: inmemory
schema_config:
configs:
- from: 2024-01-01
store: tsdb # 新版存储引擎(替代 boltdb-shipper)
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h # 索引周期
storage_config:
filesystem:
directory: /loki/chunks
tsdb_shipper:
active_index_directory: /loki/tsdb-index
cache_location: /loki/tsdb-cache
limits_config:
retention_period: 720h # 保留 30 天
max_streams_per_user: 10000 # 单用户最大 stream 数
max_line_size: 256KB # 单行最大长度
reject_old_samples: true
reject_old_samples_max_age: 168h # 拒绝 7 天前的日志
compactor:
working_directory: /loki/compactor
shared_store: filesystem
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
ruler:
storage:
type: local
local:
directory: /loki/rules
rule_path: /loki/rules-temp
alertmanager_url: http://alertmanager:9093
关键参数说明:
| 参数 | 作用 | 建议值 |
|---|---|---|
retention_period | 日志保留周期 | 30 天(按需调) |
max_streams_per_user | 最大 stream 数 | 10000(防标签爆炸) |
max_line_size | 单行最大长度 | 256KB(超大行截断) |
reject_old_samples_max_age | 拒绝过旧日志 | 7 天(防补录) |
3.3 Promtail 配置文件
promtail/promtail-config.yml:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml # 记录读取位置(断点续传)
clients:
- url: http://loki:3100/loki/api/v1/push # Loki 推送地址
scrape_configs:
# 采集系统日志
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
host: docker-host
__path__: /var/log/*.log
# 采集 Docker 容器日志
- job_name: docker
docker_sd_configs:
- name: docker
host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: label
values: ["logging=promtail"] # 只采集有此 label 的容器
relabel_configs:
- source_labels: ['__meta_docker_container_name']
target_label: container
- source_labels: ['__meta_docker_container_log_streaming']
target_label: stream
# 采集 Spring Boot 应用日志
- job_name: spring-boot
static_configs:
- targets:
- localhost
labels:
job: app
app: order-service # 关键标签
env: production
__path__: /var/log/app/*.log # 应用日志路径
pipeline_stages:
# 解析 JSON 日志
- json:
expressions:
level: level
timestamp: timestamp
logger: logger
traceId: traceId
message: msg
# 提取 level 作为标签
- labels:
level:
# 提取 traceId 作为标签(关键!用于链路追踪)
- labels:
traceId:
# 设置时间戳
- timestamp:
source: timestamp
format: RFC3339Nano
3.4 Grafana 数据源自动配置
grafana/provisioning/datasources/datasource.yml:
apiVersion: 1
datasources:
- name: Loki
type: loki
access: proxy
url: http://loki:3100
isDefault: true
editable: true
jsonData:
maxLines: 1000 # 查询返回最大行数
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
3.5 启动验证
docker-compose up -d
# 检查 Loki 健康
curl http://localhost:3100/ready
# → ready
# 检查 Promtail 指标
curl http://localhost:9080/metrics | grep loki
访问 Grafana http://localhost:3000(admin/admin)→ Explore → 选 Loki → 开始查询。
四、Spring Boot 接入
4.1 Logback JSON 格式输出
Loki 强烈建议日志用 JSON 格式——便于 Promtail 解析提取标签。
logback-spring.xml:
<configuration>
<appender name="LOKI" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"order-service","env":"production"}</customFields>
<fieldNames>
<timestamp>timestamp</timestamp>
<message>msg</message>
<logger>logger</logger>
<levelValue>[ignore]</levelValue>
</fieldNames>
<throwableConverter class="net.logstash.logback.stacktrace.ShortenedThrowableConverter">
<maxDepthPerThrowable>10</maxDepthPerThrowable>
<shortenedClassNameLength>30</shortenedClassNameLength>
</throwableConverter>
</encoder>
</appender>
<!-- MDC 自动输出到 JSON(traceId/userId 自动带上) -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/var/log/app/order-service.log</file>
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<customFields>{"app":"order-service","env":"production"}</customFields>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>/var/log/app/order-service.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>7</maxHistory>
<totalSizeCap>5GB</totalSizeCap>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="LOKI"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
4.2 Maven 依赖
<!-- JSON 格式日志 -->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.4</version>
</dependency>
4.3 自动注入 traceId
接入 OpenTelemetry / Sleuth 后,traceId 会自动写入 MDC,logstash encoder 自动输出:
{
"timestamp": "2026-08-08T14:30:15.123+08:00",
"level": "ERROR",
"logger": "com.example.OrderService",
"traceId": "a1b2c3d4e5f67890",
"spanId": "1234567890abcdef",
"app": "order-service",
"env": "production",
"msg": "订单创建失败",
"userId": "12345"
}
4.4 业务字段打印
@Service
@Slf4j
public class OrderService {
public Order createOrder(Long userId, BigDecimal amount) {
// 用结构化日志代替字符串拼接
log.info("订单创建成功 userId={} orderId={} amount={}",
userId, order.getOrderId(), amount);
// 或者用 MDC 加业务字段
MDC.put("orderId", order.getOrderId().toString());
MDC.put("userId", userId.toString());
log.info("订单创建成功");
MDC.clear();
return order;
}
}
输出:
{
"timestamp": "2026-08-08T14:30:15.123+08:00",
"level": "INFO",
"logger": "com.example.OrderService",
"traceId": "a1b2c3d4e5f67890",
"orderId": "ORD12345",
"userId": "67890",
"msg": "订单创建成功"
}
五、LogQL 查询实战
LogQL = Log Query Language,Loki 的查询语言。语法类似 PromQL,但增加了日志过滤能力。
5.1 基础语法
LogQL 两个部分:
{标签选择器} |= "关键词" | json | 过滤表达式
↓ ↓ ↓ ↓
流选择 日志过滤 解析 行过滤
5.2 常用查询
1. 按应用查日志
{app="order-service"}
2. 按应用 + 级别
{app="order-service", level="ERROR"}
3. 关键词过滤
{app="order-service"} |= "订单创建失败"
4. 多关键词
{app="order-service"} |= "订单" |= "失败"
# 或关系
{app="order-service"} |= "订单" or "失败"
5. 排除关键词
{app="order-service"} != "DEBUG"
6. 正则匹配
{app="order-service"} |~ "订单号 ORD\\d+"
5.3 JSON 解析查询
如果日志是 JSON 格式,可以用 | json 提取字段:
1. 解析 JSON 后过滤
{app="order-service"} | json | level="ERROR"
2. 按字段过滤
{app="order-service"}
| json
| userId="12345"
3. 按 traceId 串联(关键!链路追踪)
{app="order-service"}
| json
| traceId="a1b2c3d4e5f67890"
跨服务查:
{app=~"order-service|user-service|payment-service"}
| json
| traceId="a1b2c3d4e5f67890"
5.4 聚合查询(统计)
像 PromQL 一样统计:
1. 每秒日志条数(rate)
sum by (app) (rate({app=~"order-service|user-service"}[1m]))
2. 错误日志数量
sum by (app) (
count_over_time({app="order-service", level="ERROR"}[5m])
)
3. Top K 慢日志
topk(10,
sum by (uri) (
rate({app="order-service"} | json | duration > 1 [5m])
)
)
4. 错误率
sum(rate({app="order-service", level="ERROR"}[5m]))
/
sum(rate({app="order-service"}[5m]))
5.5 常用 LogQL 模板
# 查某用户的所有日志
{app="order-service"} | json | userId="12345"
# 查某 traceId 的跨服务链路
{app=~".+"} | json | traceId="a1b2c3d4"
# 5 分钟内 ERROR 日志
{app="order-service", level="ERROR"}[5m]
# 排除健康检查日志
{app="order-service"} != "health check"
# 解析 JSON 后按 status 分组计数
sum by (status) (
count_over_time(
{app="order-service"} | json [5m]
)
)
# Top 10 出现最频繁的 ERROR 日志
topk(10, sum by (msg) (
count_over_time({app="order-service", level="ERROR"}[1h])
))
六、Grafana 日志面板
6.1 配置日志面板
Grafana → Dashboards → New → Add visualization → 选 Loki 数据源:
| 配置 | 值 |
|---|---|
| Query | {app="order-service"} |
| Visualization | Logs |
| Line limit | 1000 |
| Order | Descending |
6.2 日志字段提取
在 Grafana 日志面板,点 Extract fields:
原始日志:
{"level":"ERROR","msg":"订单失败","userId":"123"}
提取后:
level = ERROR
msg = 订单失败
userId = 123
6.3 统一可观测性面板
Grafana 同一面板可以同时显示:
| Panel | 数据源 | 用途 |
|---|---|---|
| QPS 曲线 | Prometheus | 接口 QPS |
| P99 响应时间 | Prometheus | 接口耗时 |
| 日志列表 | Loki | 实时日志 |
| 错误日志计数 | Loki | 错误率 |
| 调用链 | Tempo/Jaeger | 链路追踪 |
点击 Metric 面板跳转日志:
Grafana 支持仪表板联动——在 QPS 面板点击某个时间点,自动跳转到对应时间段的日志查询:
Data links 配置:
URL: /explore?left={"datasource":"Loki","queries":["${__field.labels.app}"]}
6.4 完整仪表盘 JSON
仪表盘 JSON 见配套配置文件 grafana/dashboards/loki-dashboard.json,启动时自动加载。
七、告警
7.1 Loki Ruler 触发告警
Loki 支持基于日志的告警规则:
/loki/rules/alerts.yml:
groups:
- name: app-alerts
rules:
# 错误日志激增
- alert: HighErrorRate
expr: |
sum by (app) (
rate({app="order-service", level="ERROR"}[5m])
) > 10
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.app }} 错误日志激增"
description: "近 5 分钟错误日志速率 {{ $value }} 条/秒"
# 异常关键字告警
- alert: OOMDetected
expr: |
sum by (app) (
count_overtime(
{app="order-service"} |= "OutOfMemoryError" [5m]
)
) > 0
for: 0m
labels:
severity: critical
annotations:
summary: "{{ $labels.app }} 检测到 OOM"
7.2 AlertManager 联动
Loki 配置里指定 AlertManager:
ruler:
alertmanager_url: http://alertmanager:9093
告警会通过 AlertManager 路由到钉钉/飞书/邮件。
八、标签设计原则
标签是 Loki 的灵魂,设计好坏直接影响查询性能和存储成本。
8.1 好的标签
| 标签 | 例子 | 说明 |
|---|---|---|
app | order-service | 应用名 |
env | production/staging | 环境 |
level | INFO/ERROR | 日志级别 |
host | pod-abc123 | 主机 |
traceId | a1b2c3d4 | 链路 ID |
container | docker-container-name | 容器名 |
8.2 坏的标签
❌ userId="12345" ← 基数高(百万级)
❌ requestId="req-abc" ← 唯一值
❌ timestamp="..." ← 每行都不同
❌ ip="10.0.0.1" ← 可能很多
为什么? Loki 为每个标签组合创建一个 stream。高基数标签 = 几百万个 stream = 内存爆炸。
8.3 标签基数控制
低基数(推荐做标签):
app → 10-100 个值
env → 3-5 个值
level → 5-10 个值
host → 100-1000 个值
高基数(不要做标签,放日志正文里):
userId → 百万级
requestId → 唯一值
sessionId → 唯一值
stream 数量公式:
stream 数 = 各标签基数相乘
app(10) × env(3) × level(5) × host(100) = 15000 streams ✅ 合理
app(10) × env(3) × level(5) × host(100) × userId(1000000) = 15 亿 streams ❌ 爆炸
8.4 高基数字段处理
把高基数字段放日志正文(JSON 字段),用 | json 解析后查询:
{
"app": "order-service", // 做标签
"level": "ERROR", // 做标签
"traceId": "a1b2c3d4", // 做标签(链路追踪需要)
"userId": "12345", // 不做标签,放正文
"orderId": "ORD12345", // 不做标签,放正文
"msg": "订单创建失败"
}
查询时:
{app="order-service"} | json | userId="12345"
九、生产部署建议
9.1 单机 vs 集群
| 部署模式 | 适用 | 说明 |
|---|---|---|
| 单机模式 | <100GB/天 | 单二进制,最简单 |
| 微服务模式 | >100GB/天 | 组件独立部署,按需扩展 |
| 云服务 | 不想运维 | Grafana Cloud / 阿里云 SLS |
9.2 存储选择
storage_config:
# 单机用文件系统
filesystem:
directory: /loki/chunks
# 生产用对象存储(推荐)
# aws/s3/gcs/azure/aliyun-oss 均可
aws:
endpoint: oss-cn-hangzhou.aliyuncs.com
bucketname: my-loki-logs
access_key_id: ${OSS_KEY}
secret_access_key: ${OSS_SECRET}
对象存储比文件系统:
- 成本低(OSS 0.12 元/GB/月)
- 容量无限
- 自动多副本
9.3 Promtail 部署位置
方案 A:每个节点一个 Promtail(DaemonSet)
→ 采集节点上所有 Pod 日志
→ K8s 场景推荐
方案 B:每个 Pod Sidecar 一个 Promtail
→ 灵活,但资源开销大
方案 C:应用直接推 Loki
→ 不用 Promtail,但耦合
9.4 性能优化
limits_config:
# 限制单查询返回行数
max_entries_limit_per_query: 5000
# 限制查询时间范围
max_query_length: 721h # 最大 30 天
# 限制 stream 数
max_streams_per_user: 10000
# chunk 缓存
chunk_idle_period: 30m
chunk_retain_period: 0s
十、ELK 迁移 Loki
10.1 迁移路径
阶段 1:双写
应用日志同时输出到 ELK 和 Loki
Promtail 采集 + Filebeat 同时跑
阶段 2:Grafana 优先用 Loki 查询
开发先习惯 Grafana 查询
阶段 3:ELK 停采集
历史数据保留在 ELK
新数据只进 Loki
阶段 4:下线 ELK
历史数据导出或过期删除
10.2 ELK → Loki 概念对照
| ELK | Loki | 说明 |
|---|---|---|
| Index | Stream | 数据流 |
| Logstash | Promtail | 采集 |
| Kibana | Grafana | 可视化 |
| Lucene Query DSL | LogQL | 查询语言 |
| Index Pattern | Label Selector | 数据范围选择 |
| ILM | Retention | 生命周期 |
| Shard | Chunk | 数据分片 |
十一、总结
方案对比一句话
| 方案 | 一句话 |
|---|---|
| ELK | 功能最全,全文搜索强,但运维最重 |
| Loki | 轻量、便宜、和 Grafana 无缝集成,90% 场景够用 |
| 阿里云 SLS | 免运维,但费用随量增长快 |
选择决策树
是否需要复杂全文搜索?
├── 是 → ELK
└── 否 → 日志量多大?
├── <500GB/天 → Loki(自建)
├── >500GB/天 + 团队有运维 → Loki 集群 / ELK
└── 不想运维 → Grafana Cloud / 阿里云 SLS
Loki 三大优势
- 存储成本降低 80%+:只索引标签,日志正文压缩存储
- 和 Grafana 无缝集成:同一面板看 Metric + Trace + Log
- 水平扩展简单:无状态组件,加节点即可
最佳实践
日志格式:JSON
标签设计:低基数(app/env/level/host/traceId)
存储:对象存储(OSS/S3)+ 本地缓存
采集:Promtail DaemonSet
保留:30 天(按需)
告警:Loki Ruler + AlertManager
互动话题:你们用 ELK 还是 Loki?有没有踩过日志平台的高基数坑?欢迎留言讨论!
参考资料
标题:日志平台搭建:Loki + Promtail + Grafana——替代 ELK 的轻量方案
作者:jiangyi
地址:http://jiangyi.space/articles/2026/08/09/1786161135069.html
公众号:服务端技术精选
- 引言
- 一、为什么选 Loki 不选 ELK
- 1.1 ELK 的痛点
- 1.2 Loki 的核心思想
- 1.3 ELK vs Loki 全面对比
- 1.4 存储成本对比
- 1.5 什么时候不选 Loki
- 1.6 三种选型建议
- 二、Loki 架构
- 2.1 三件套职责
- 2.2 Loki 内部组件
- 2.3 数据模型
- 三、Docker Compose 一键部署
- 3.1 完整 docker-compose.yml
- 3.2 Loki 配置文件
- 3.3 Promtail 配置文件
- 3.4 Grafana 数据源自动配置
- 3.5 启动验证
- 四、Spring Boot 接入
- 4.1 Logback JSON 格式输出
- 4.2 Maven 依赖
- 4.3 自动注入 traceId
- 4.4 业务字段打印
- 五、LogQL 查询实战
- 5.1 基础语法
- 5.2 常用查询
- 5.3 JSON 解析查询
- 5.4 聚合查询(统计)
- 5.5 常用 LogQL 模板
- 六、Grafana 日志面板
- 6.1 配置日志面板
- 6.2 日志字段提取
- 6.3 统一可观测性面板
- 6.4 完整仪表盘 JSON
- 七、告警
- 7.1 Loki Ruler 触发告警
- 7.2 AlertManager 联动
- 八、标签设计原则
- 8.1 好的标签
- 8.2 坏的标签
- 8.3 标签基数控制
- 8.4 高基数字段处理
- 九、生产部署建议
- 9.1 单机 vs 集群
- 9.2 存储选择
- 9.3 Promtail 部署位置
- 9.4 性能优化
- 十、ELK 迁移 Loki
- 10.1 迁移路径
- 10.2 ELK → Loki 概念对照
- 十一、总结
- 方案对比一句话
- 选择决策树
- Loki 三大优势
- 最佳实践
- 参考资料
评论