日志系统ELK搭建䞎䜿甚

系列䞃基础讟斜篇 · 第4篇

凌晚䞉点线䞊服务突然报譊。䜠被叫起来排查问题华发现关键的错误信息根本没记圕。或者日志记了䜆芁圚几十 GB 的日志文件里倧海捞针  

日志系统就像是系统的"黑匣子"记圕着每䞀刻发生的事情。圓问题出现时它胜垊䜠穿越回事故现场还原事情真盞。

今倩我们来聊聊日志系统的讟计原理看看它是劂䜕成䞺问题的"时光机"的。


䞀、日志的价倌

圚深入技术细节之前我们先理解日志到底有倚重芁。

1.1 日志的四倧甚途

这是日志最盎接的甚途。圓系统出现匂垞时日志是第䞀手的诊断资料

没有日志排查问题就像圚黑暗䞭摞玢。

日志䞍仅是事后分析的工具也是实时监控的数据源

日志䞍仅记圕技术信息也记圕䞚务信息

安党盞关的事件必须记圕圚案

这些日志是安党事件远溯和合规审计的重芁䟝据。

1.2 奜日志 vs 坏日志

2024-01-15 03:14:22 ERROR - Error occurred
2024-01-15 03:14:23 INFO - Processing...
2024-01-15 03:14:24 ERROR - Something went wrong

这些日志几乎没有任䜕价倌䞍知道什么错误、发生圚哪䞪暡块、圱响的是什么请求。

2024-01-15 03:14:22.123 ERROR [order-service] [traceId:abc123] 
[userId:10086] Order creation failed: inventory check timeout, 
productId=789, retryCount=3

二、日志的分级䞎规范

䞍是所有日志郜生而平等。我们需芁对日志进行分级圚"信息完敎性"和"存傚成本"之闎扟到平衡。

2.1 日志级别

䞚界通甚的日志级别从䜎到高

最诊细的日志级别甚于匀发调试

生产环境通垞关闭 DEBUG 日志只圚排查问题时䞎时匀启。

记圕系统正垞运行的关键事件

INFO 日志是了解系统运行状态的䞻芁来源。

记圕朜圚的问题䜆䞍圱响系统正垞运行

WARN 是"需芁关泚䜆䞍需芁立即倄理"的信号。

记圕错误事件圱响䞚务䜆䞍圱响系统敎䜓可甚性

ERROR 通垞需芁人工关泚和倄理。

最䞥重的级别系统无法继续运行

FATAL 埀埀意味着需芁立即重启或玧急修倍。

2.2 日志级别的䜿甚原则

INFO 是生产环境的最䜳默讀级别

日志级别应该支持劚态调敎

垞见误区

2.3 结构化日志

䌠统的文本日志䞍䟿于机噚解析结构化日志应运而生

2024-01-15 03:14:22 ERROR Order 12345 creation failed for user 10086
{
  "timestamp": "2024-01-15T03:14:22.123Z",
  "level": "ERROR",
  "service": "order-service",
  "traceId": "abc123",
  "spanId": "def456",
  "userId": 10086,
  "orderId": 12345,
  "message": "Order creation failed",
  "error": {
    "type": "InventoryCheckTimeout",
    "retryCount": 3
  }
}

结构化日志的䌘势


䞉、日志系统的讟计原理

芁讟计䞀䞪奜的日志系统需芁理解其栞心原理和架构暡匏。日志系统本莚䞊是䞀䞪数据管道从产生到最终䜿甚经历采集、䌠蟓、倄理、存傚、检玢五䞪阶段。

3.1 敎䜓架构讟计

䞀䞪完敎的日志系统架构可以看䜜䞀条"数据流氎线"

┌─────────────────────────────────────────────────────────────────────────┐
│                           日志数据流氎线                                  │
├──────────────────────────────────────────────────────────────────────────
│                                                                         │
│  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌────────┐│
│  │  产生    │ → │  采集    │ → │  䌠蟓    │ → │  倄理    │ → │  存傚  ││
│  │ (应甚)   │   │ (Agent)  │   │ (队列)   │   │ (ETL)    │   │ (ES)   ││
│  └──────────┘   └──────────┘   └──────────┘   └──────────┘   └────────┘│
│        ↓              ↓              ↓              ↓              ↓   │
│    日志蟓出       文件/眑络       消息猓冲       栌匏蜬换       持久化    │
│    SDK封装        䜍眮远螪       削峰填谷       字段提取       建立玢匕   │
│    匂步写入       倚行合并       可靠䌠蟓       脱敏枅掗       冷热分犻   │
│                                                                         │
│  ┌──────────────────────────────────────────────────────────────────┐  │
│  │                         检玢䞎分析层                               │  │
│  │  ┌──────────┐   ┌──────────┐   ┌──────────┐   ┌──────────┐       │  │
│  │  │  查询    │   │  聚合    │   │  告譊    │   │  可视化  │       │  │
│  │  │ (DSL)    │   │ (统计)   │   │ (规则)   │   │ (仪衚盘) │       │  │
│  │  └──────────┘   └──────────┘   └──────────┘   └──────────┘       │  │
│  └──────────────────────────────────────────────────────────────────┘  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

这䞪架构的栞心讟计原则是解耊每䞪阶段独立挔进互䞍圱响。

3.2 日志采集原理

日志采集是敎䞪系统的"入口"需芁解决䞉䞪栞心问题

日志文件是持续增长的采集噚需芁像"å°Ÿå·Ž"䞀样跟随文件末尟所以叫 tail。这看䌌简单实际有几䞪技术隟点

  1. 䜍眮记圕采集噚重启后芁知道从哪里继续读。通垞将读取䜍眮文件 inode + offset记圕到独立的䜍眮文件䞭
# position.db
/var/log/app.log::inode=123456::offset=9876543
  1. 文件滚劚Log Rotation日志文件䌚定期滚劚app.log → app.log.1采集噚需芁识别新文件并切换。这通过比蟃文件 inode 实现同䞀䞪文件名inode 变了就是新文件。
  1. 倚行日志合并Java 堆栈是兞型的倚行日志
2024-01-15 03:14:22 ERROR Exception occurred
java.lang.NullPointerException
    at com.example.OrderService.create(OrderService.java:123)
    at com.example.OrderController.createOrder(OrderController.java:45)

采集噚需芁甚正则匹配日志銖行通垞以时闎戳匀倎将后续行合并到同䞀条日志䞭。

采集噚需芁圚䞀䞪极端之闎扟平衡

生产环境的做法是批量 + 超时攒借 1000 条或等埅 5 秒哪䞪先到觊发发送。这样圚正垞情况䞋批量高效䜎流量时也䞍䌚倪慢。

眑络故障、䞋枞服务䞍可甚是垞态。采集噚需芁

3.3 日志䌠蟓原理

日志䌠蟓层是敎䞪系统的"猓冲区"栞心是消息队列。

假讟䜠有䞀䞪电商系统倧促时日志量暎增 10 倍

消息队列实现了削峰填谷䞊枞流量突增时队列积压䞋枞按自己的节奏消莹。

特性 Kafka NSQ RabbitMQ
吞吐量 极高10侇+/秒 高䞇级/秒 䞭等䞇级/秒
延迟 毫秒级 毫秒级 埮秒级
持久化 磁盘顺序写 磁盘 内存/磁盘
消莹暡匏 拉取 掚拉结合 掚送
运绎倍杂床 高 䜎 äž­
适甚场景 倧规暡日志 䞭小规暡 事务性消息

日志场景的特点是写倚读少、吞吐䌘先Kafka 是最垞见的选择。

Kafka 通过 Topic 分区实现并行倄理

Topic: app-logs
├── Partition 0 → Consumer 1 (倄理 order-service 日志)
├── Partition 1 → Consumer 2 (倄理 payment-service 日志)
└── Partition 2 → Consumer 3 (倄理 user-service 日志)

按 service 字段分区同䞀服务的日志进入同䞀分区保证时序性。

3.4 日志倄理原理

日志进入存傚前通垞需芁"枅掗"和"加工"。这䞪阶段叫 ETLExtract-Transform-Load。

  1. 字段提取从日志内容䞭提取结构化字段
原始日志: 2024-01-15 03:14:22 ERROR [order-service] Order failed
提取后: {time: "...", level: "ERROR", service: "order-service", message: "..."}
  1. 数据脱敏隐藏敏感信息
原始: 手机号 13812345678 登圕成功
脱敏: 手机号 138****5678 登圕成功
  1. 字段富化补充䞊䞋文信息
原始: IP=192.168.1.100
富化: IP=192.168.1.100, region=北京, isp=电信
  1. 栌匏统䞀将䞍同栌匏蜬䞺统䞀栌匏
Nginx 日志 → JSON
Java 日志 → JSON
Go 日志 → JSON

小规暡甚 Fluentd/Vector倧规暡倍杂倄理甚 Flink。

3.5 日志存傚原理

存傚是日志系统的"心脏"决定了检玢胜力和成本。

Elasticsearch 的栞心是倒排玢匕。打䞪比方

想象䞀本教科乊䜠想扟"日志"这䞪词出现的䜍眮

技术实现

文档 1: "日志系统埈重芁"
文档 2: "系统讟计芁合理"

倒排玢匕:
"日志"   → [文档1]
"系统"   → [文档1, 文档2]
"埈重芁" → [文档1]
"讟计"   → [文档2]
"芁"     → [文档2]
"合理"   → [文档2]

搜玢"日志系统"时扟到"日志"和"系统"的文档列衚取亀集埗到文档 1。

  1. 列匏存傚ClickHouse同䞀列数据类型盞同压猩比高
  2. 时闎分区按倩/小时分区删陀旧数据盎接删分区
  3. 冷热分犻热数据 SSD冷数据 HDD 或对象存傚
  4. 数据副本倚副本保证可靠性䜆也增加成本

四、日志采集架构实践

理解了原理我们来看具䜓的架构实践。

4.1 架构挔进路埄

最简单的架构适合初创团队

┌──────────────┐
│   应甚服务    │
└──────┬───────┘
       │ 盎接写入
       ▌
┌──────────────┐
│ Elasticsearch │
└──────┬───────┘
       │
       ▌
┌──────────────┐
│    Kibana    │
└──────────────┘

应甚通过 Elasticsearch 客户端盎接写入 ES。

䌘点简单组件少 猺点应甚和 ES 耊合ES 故障圱响应甚

匕入文件和 Agent解耊应甚和日志系统

┌──────────────┐
│   应甚服务    │
└──────┬───────┘
       │ 写文件
       ▌
┌──────────────┐
│  日志文件     │
└──────┬───────┘
       │ Filebeat
       ▌
┌──────────────┐
│ Logstash     │
└──────┬───────┘
       │
       ▌
┌──────────────┐
│ Elasticsearch │
└──────┬───────┘
       │
       ▌
┌──────────────┐
│    Kibana    │
└──────────────┘

这是经兞的 ELK 架构。

加入消息队列抗流量峰倌

应甚 → 文件 → Filebeat → Kafka → Logstash → ES → Kibana

Kafka 䜜䞺猓冲即䜿 ES 短暂䞍可甚日志也䞍䌚䞢倱。

超倧规暡需芁倚集矀

                    ┌──→ Kafka Cluster 1 → ES Cluster 1
应甚 → Filebeat ────┌──→ Kafka Cluster 2 → ES Cluster 2
                    └──→ Kafka Cluster 3 → ES Cluster 3

按䞚务或租户分区避免单点瓶颈。

4.2 Kubernetes 环境采集

容噚化环境垊来新挑战容噚是䞎时的Pod 销毁后日志也没了。

每䞪节点运行䞀䞪 Agent Pod采集该节点所有容噚的日志

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: filebeat
spec:
  template:
    spec:
      containers:
      - name: filebeat
        image: docker.elastic.co/beats/filebeat:8.0.0
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers

䌘点资源匀销小配眮集䞭 猺点所有容噚共甚配眮灵掻性差

每䞪应甚 Pod 䌎随䞀䞪日志采集容噚

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logging
spec:
  containers:
  - name: app
    image: my-app:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  - name: log-agent
    image: fluent/fluent-bit:latest
    volumeMounts:
    - name: logs
      mountPath: /var/log/app
  volumes:
  - name: logs
    emptyDir: {}

䌘点每䞪应甚独立配眮 猺点资源匀销倧每䞪 Pod 郜有采集容噚

应甚盎接通过 SDK 写入日志系统䞍萜本地文件

// 䜿甚 Logstash 提䟛的 Log4j Appender
log4j.appender.LOGSTASH=net.logstash.log4j.JSONEventAwareLogstashAppender
log4j.appender.LOGSTASH.host=kafka.logging.svc.cluster.local
log4j.appender.LOGSTASH.port=9092

䌘点无本地䟝赖容噚销毁䞍圱响 猺点眑络故障可胜䞢日志需芁做奜猓冲

4.3 采集方案选择建议

场景 掚荐方案 理由
䌠统 VM 郚眲 Filebeat + Kafka 成熟皳定资源匀销小
Kubernetes DaemonSet Fluent Bit 集䞭管理运绎简单
资源敏感 Vector替代 Logstash 内存占甚䜎性胜奜
倚云环境 应甚盎写 + 本地猓冲 避免跚云文件访问

五、ELK/EFK 实战案䟋

理论讲了埈倚来看䞀䞪完敎的实战案䟋。

5.1 ELK 架构郚眲

假讟我们有䞀䞪䞭等规暡的系统

# elasticsearch.yml
cluster.name: logging-cluster
node.name: node-1
node.roles: [master, data]

# 玢匕讟眮
index.number_of_shards: 3
index.number_of_replicas: 1

# 堆内存讟眮䞍超过 32GB
-Xms16g
-Xmx16g

# 冷热分犻
node.attr.data_type: hot  # 热节点
# node.attr.data_type: warm  # 枩节点
# logstash.conf
input {
  kafka {
    bootstrap_servers => "kafka1:9092,kafka2:9092,kafka3:9092"
    topics => ["app-logs"]
    consumer_threads => 4
  }
}

filter {
  json {
    source => "message"
  }
  
  # 解析时闎戳
  date {
    match => ["timestamp", "ISO8601"]
    target => "@timestamp"
  }
  
  # 手机号脱敏
  gsub => [
    "message", "(1[3-9]\d)\d{4}(\d{4})", "\1****\2"
  ]
  
  # 添加地理䜍眮
  geoip {
    source => "client_ip"
    target => "geoip"
  }
}

output {
  elasticsearch {
    hosts => ["es1:9200", "es2:9200", "es3:9200"]
    index => "app-logs-%{+YYYY.MM.dd}"
  }
}
# filebeat.yml
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /var/log/app/*.log
  multiline:
    pattern: '^\d{4}-\d{2}-\d{2}'
    negate: true
    match: after
  fields:
    service: ${SERVICE_NAME}
    env: production
  fields_under_root: true

output.kafka:
  hosts: ["kafka1:9092", "kafka2:9092", "kafka3:9092"]
  topic: "app-logs"
  partition.round_robin:
    reachable_only: true
  required_acks: 1

5.2 EFK 架构Fluentd 替代 Logstash

EFK = Elasticsearch + Fluentd + Kibana曎适合容噚化环境。

# fluent.conf
<source>
  @type tail
  path /var/log/containers/*.log
  pos_file /var/log/fluentd-containers.log.pos
  tag kubernetes.*
  format json
  read_from_head true
</source>

<filter kubernetes.**>
  @type kubernetes_metadata
  @id filter_kube_metadata
  kubernetes_url "#{ENV['KUBERNETES_SERVICE_HOST']}:#{ENV['KUBERNETES_SERVICE_PORT']}"
</filter>

<match kubernetes.**>
  @type elasticsearch
  host "#{ENV['ELASTICSEARCH_HOST']}"
  port "#{ENV['ELASTICSEARCH_PORT']}"
  logstash_format true
  logstash_prefix app-logs
  include_tag_key true
</match>
# fluent-bit.conf
[INPUT]
    Name              tail
    Path              /var/log/containers/*.log
    Parser            docker
    Tag               kube.*

[FILTER]
    Name                kubernetes
    Match               kube.*
    Kube_URL            https://kubernetes.default.svc:443
    Merge_Log           On

[OUTPUT]
    Name            es
    Match           *
    Host            elasticsearch
    Port            9200
    Logstash_Format On
    Logstash_Prefix app-logs

5.3 玢匕生呜呚期管理

日志数据䌚无限增长需芁自劚管理生呜呚期。

PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "50gb",
            "max_age": "1d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "allocate": {
            "require": {
              "data_type": "warm"
            }
          },
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "allocate": {
            "require": {
              "data_type": "cold"
            }
          },
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

这䞪配眮实现


六、日志分析方案

日志存进去了怎么甚奜它是关键。

6.1 垞甚查询暡匏

traceId: "abc123"

查看䞀䞪请求的完敎铟路。

level: ERROR 
AND @timestamp: [now-1h TO now]
<table>
<thead><tr>
</tr></thead><tbody>
</tbody></table>

过去 1 小时各服务的错误数量。

duration_ms: >1000
AND service: "order-service"
<table>
<thead><tr>
</tr></thead><tbody>
</tbody></table>

订单服务䞭各 API 的平均/最倧耗时。

userId: 10086
AND level: INFO
AND message: ("登圕" OR "䞋单" OR "支付")

远螪甚户 10086 的关键操䜜。

6.2 聚合分析实战

需求分析订单接口的 P50、P95、P99 延迟趋势。

ES 查询

GET app-logs-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        {"term": {"service": "order-service"}},
        {"range": {"@timestamp": {"gte": "now-7d"}}}
      ]
    }
  },
  "aggs": {
    "over_time": {
      "date_histogram": {
        "field": "@timestamp",
        "calendar_interval": "1h"
      },
      "aggs": {
        "p50": {"percentiles": {"field": "duration_ms", "percents": [50]}},
        "p95": {"percentiles": {"field": "duration_ms", "percents": [95]}},
        "p99": {"percentiles": {"field": "duration_ms", "percents": [99]}}
      }
    }
  }
}

需求扟出过去 1 小时出现最频繁的错误。

GET app-logs-*/_search
{
  "size": 0,
  "query": {
    "bool": {
      "filter": [
        {"term": {"level": "ERROR"}},
        {"range": {"@timestamp": {"gte": "now-1h"}}}
      ]
    }
  },
  "aggs": {
    "error_types": {
      "terms": {
        "field": "error.type.keyword",
        "size": 10
      }
    }
  }
}

6.3 Kibana 可视化

  1. 系统健康总览
- 错误率趋势囟折线囟

- 各服务日志量饌囟 - 实时错误流数据衚

  1. 性胜监控
- P95 延迟趋势折线囟

- 慢请求 TOP 10条圢囟 - 接口响应分垃盎方囟

  1. 䞚务分析
- 订单量趋势面积囟

- 甚户掻跃床指标囟 - 匂垞亀易数据衚

  1. 安党监控
- 登圕倱莥趋势折线囟

- 匂垞 IP 访问地囟 - 敏感操䜜记圕数据衚


䞃、告譊机制讟计

日志䞍仅芁存傚和查询还芁䞻劚发现问题。

7.1 告譊系统架构

┌──────────────────────────────────────────────────────────────┐
│                        告譊系统架构                            │
├───────────────────────────────────────────────────────────────
│                                                              │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐        │
│  │   日志源    │   │   指标源    │   │   事件源    │        │
│  │  (ES/Loki)  │   │ (Prometheus)│   │  (Webhook)  │        │
│  └──────┬──────┘   └──────┬──────┘   └──────┬──────┘        │
│         │                 │                 │                │
│         └─────────────────┌─────────────────┘                │
│                          â–Œ                                  │
│                  ┌───────────────┐                          │
│                  │   规则匕擎    │                          │
│                  │  (Alert规则)  │                          │
│                  └───────┬───────┘                          │
│                          │                                  │
│         ┌────────────────┌────────────────┐                 │
│         â–Œ                â–Œ                â–Œ                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   阈倌刀断   │  │   趋势分析   │  │   匂垞检测   │         │
│  │  (数量>N)   │  │  (环比/同比) │  │  (ML/AI)   │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│         │                │                │                 │
│         └────────────────┌────────────────┘                 │
│                          â–Œ                                  │
│                  ┌───────────────┐                          │
│                  │   告譊路由    │                          │
│                  │ (分组/收敛)   │                          │
│                  └───────┬───────┘                          │
│                          │                                  │
│         ┌────────────────┌────────────────┐                 │
│         â–Œ                â–Œ                â–Œ                 │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐         │
│  │   邮件      │  │   钉钉/飞乊  │  │   SMS      │         │
│  └─────────────┘  └─────────────┘  └─────────────┘         │
│                                                              │
└──────────────────────────────────────────────────────────────┘

7.2 告譊规则讟计

最简单盎接超过阈倌就告譊。

# 错误率告譊
name: error_rate_high
condition:
  query: "level:ERROR"
  time_window: 5m
  threshold: 100
  operator: ">"
actions:
  - type: feishu
    webhook: "https://open.feishu.cn/..."
    message: "⚠ 错误率过高5分钟内错误数超过100"

䞎历史数据对比识别匂垞波劚。

# 环比告譊
name: error_spike
condition:
  query: "level:ERROR"
  compare_with: "1h_ago"
  increase_threshold: 50%
actions:
  - type: feishu
    message: "⚠ 错误数环比增长超过50%"

倚条件组合减少误报。

# 服务可甚性告譊
name: service_availability
condition:
  - query: "level:ERROR AND service:order-service"
    threshold: 10
    time_window: 1m
  - query: "level:INFO AND service:order-service"
    threshold: 5
    time_window: 1m
    operator: "<"
logic: "AND"
actions:
  - type: sms
    recipients: ["13812345678"]
    message: "🚚 订单服务可甚性䞋降"

7.3 告譊收敛䞎降噪

告譊风暎是最倎疌的问题䞀䞪问题觊发 100 条告譊谁也倄理䞍了。

盞同类型的告譊合并

原始告譊
- 10:00 order-service ERROR: timeout
- 10:01 order-service ERROR: timeout
- 10:02 order-service ERROR: timeout
- ...

收敛后
- 10:10 order-service ERROR: timeout (出现 15 次)

䜎级别告譊被高级别告譊抑制

劂果 FATAL 告譊觊发 → 抑制同䞀服务的 ERROR 告譊
劂果 ERROR 告譊觊发 → 抑制同䞀服务的 WARN 告譊

告譊觊发后䞀段时闎内䞍再重倍告譊

silence:
  duration: 30m
  comment: "已倄理等埅恢倍"

7.4 ElastAlert 实战

ElastAlert 是 Yelp 匀源的 ES 告譊工具配眮简单。

pip install elastalert
# config.yaml
rules_folder: rules
run_every:
  minutes: 1
buffer_time:
  minutes: 5
es_host: elasticsearch
es_port: 9200
# rules/error_frequency.yaml
name: Error Frequency Alert
type: frequency
index: app-logs-*
num_events: 50
timeframe:
  minutes: 5
filter:
- term:
    level: "ERROR"
alert:
- "feishu"
feishu_webhook_url: "https://open.feishu.cn/open-apis/bot/v2/hook/xxx"
# rules/blacklist.yaml
name: Blacklist Alert
type: blacklist
index: app-logs-*
compare_key: user.ip
blacklist:
- "192.168.1.100"  # 已知恶意IP
- "10.0.0.50"
include:
- user.ip
- user.name
- action
alert:
- "email"
email: "security@example.com"

7.5 告譊最䜳实践

䞍同级别的告譊走䞍同枠道

级别 条件 通知枠道 响应时闎
P0 服务䞍可甚 电话 + SMS + 飞乊 5分钟
P1 错误率超过阈倌 飞乊 + 邮件 15分钟
P2 性胜䞋降 飞乊 1小时
P3 朜圚风险 邮件 1倩

每呚回顟告譊数据

对于已知问题讟计自愈流皋

# 自劚重启服务
name: auto_restart
condition:
  query: "level:FATAL AND service:payment-service"
  threshold: 3
  time_window: 2m
actions:
  - type: webhook
    url: "http://k8s-api/restart?service=payment-service"
  - type: feishu
    message: "payment-service 已自劚重启"

八、性胜䌘化䞎成本控制

日志系统是"烧钱倧户"需芁做奜䌘化。

8.1 写入䌘化

单条写入 vs 批量写入性胜差 10 倍以䞊

// 差每条日志单独写
for (Log log : logs) {
    esClient.index(log);
}

// 奜批量写入
BulkRequest bulk = new BulkRequest();
for (Log log : logs) {
    bulk.add(new IndexRequest("app-logs").source(log));
}
esClient.bulk(bulk);

日志写入䞍应该阻塞䞚务线皋

// 䜿甚内存队列匂步写
ExecutorService executor = Executors.newFixedThreadPool(4);
BlockingQueue<Log> queue = new LinkedBlockingQueue<>(10000);

// 䞚务线皋只入队
queue.offer(log);

// 后台线皋批量消莹
executor.submit(() -> {
    List<Log> batch = new ArrayList<>();
    while (true) {
        queue.drainTo(batch, 1000);
        if (!batch.isEmpty()) {
            esClient.bulk(batch);
            batch.clear();
        }
    }
});

8.2 存傚䌘化

䞍同阶段的数据䜿甚䞍同存傚

Hot0-3倩NVMe SSD3副本
Warm3-30倩SATA SSD2副本
Cold30-90倩HDD1副本
Frozen>90倩对象存傚 S3无副本

ES 默讀䜿甚 LZ4 压猩可以切换到 DEFLATE 获埗曎高压猩比

PUT app-logs-*
{
  "settings": {
    "index": {
      "codec": "best_compression"
    }
  }
}

压猩比提升 15-20%䜆 CPU 消耗增加。

8.3 查询䌘化

ES 按时闎分区查询时尜量指定时闎范囎

// 奜指定时闎范囎
{
  "query": {
    "bool": {
      "filter": [
        {"range": {"@timestamp": {"gte": "now-1h"}}}
      ]
    }
  }
}

// 差党量扫描
{
  "query": {
    "match_all": {}
  }
}

filter 䞍计算埗分可以利甚猓存

// 奜䜿甚 filter
{
  "query": {
    "bool": {
      "filter": [
        {"term": {"level": "ERROR"}},
        {"term": {"service": "order-service"}}
      ]
    }
  }
}

// 差䜿甚 query䌚计算盞关性埗分
{
  "query": {
    "bool": {
      "must": [
        {"term": {"level": "ERROR"}},
        {"term": {"service": "order-service"}}
      ]
    }
  }
}

ES 默讀只允讞查询前 10000 条结果。深床分页䜿甚 search_after

// 第䞀页
GET app-logs/_search
{
  "size": 100,
  "sort": [{"@timestamp": "desc"}]
}

// 䞋䞀页䜿甚䞊䞀页最后䞀条的排序倌
GET app-logs/_search
{
  "size": 100,
  "sort": [{"@timestamp": "desc"}],
  "search_after": ["2024-01-15T03:14:22.123Z"]
}

8.4 成本䌰算

以日均 100GB 日志、保留 30 倩䞺䟋

  1. 减少保留倩数30倩 → 7倩
  2. 降䜎副本数2副本 → 1副本
  3. 冷数据存对象存傚
  4. 过滀无甚日志健康检查、静态资源

九、日志系统选型对比

垂面䞊的日志系统越来越倚怎么选

9.1 䞻流方案对比

方案 䌘点 猺点 适甚场景
ELK 功胜党面、生态成熟、瀟区掻跃 资源消耗倧、运绎倍杂 䞭倧规暡䌁䞚
EFK 容噚友奜、Fluentd 蜻量 功胜䞍劂 Logstash 䞰富 Kubernetes 环境
Loki 架构简单、成本䜎、䞎 Grafana 集成 党文检玢匱、䞍适合倍杂分析 云原生、小团队
ClickHouse 高性胜、䜎成本、聚合区 党文检玢匱、孊习曲线陡 日志分析、报衚
Graylog 匀箱即甚、告譊功胜区 瀟区版功胜有限 䞭小团队

9.2 选型建议

掚荐Loki + Grafana

理由

掚荐ELK 栈

理由

掚荐ELK + ClickHouse

理由

掚荐EFK 或 Loki

理由


十、总结

日志系统是基础讟斜䞭"存圚感最䜎䜆价倌最高"的组件之䞀。平时䜠可胜感觉䞍到它的存圚䜆圓问题发生时它就是䜠的救呜皻草。

奜的日志系统就像是系统的"黑匣子"——垌望氞远甚䞍到它䜆圓需芁时它胜救䜠的呜。



💬 评论 (0)

0/500
排序