4. 日志采集与集中管理
在 Databricks 平台上,日志并不是集中存放在一个文件里,而是按“谁产生、在哪产生、生命周期多长”分散在多个位置。要做好可观测性,第一步不是急着搭 ELK 或 Loki,而是先厘清五类日志的采集路径:集群日志、驱动日志、执行器日志、审计日志、作业日志。它们分别对应基础设施层、应用层、计算层、控制面与调度层,采集方式、时效性和结构化难度差异很大。
五类日志的采集路径
集群日志指集群生命周期事件,例如创建、启动、扩容、终止、配置变更。它们由控制面产生,主要通过 cluster_events 或云厂商的集群事件接口获取,属于低频、结构化程度高的元数据,适合用 API 拉取后写入日志平台。
驱动日志是 Driver 节点上 Spark 应用的主日志,包含作业提交、DAG 调度、任务失败堆栈、stdout/stderr 输出。默认路径在 DBFS 或云存储上,例如 dbfs:/cluster-logs/<cluster-id>/driver/,也可通过集群日志投递(Log Delivery)配置到 S3、ADLS 或 GCS。
执行器日志分布在每个 Executor 节点,记录任务级执行细节、GC 情况、shuffle 读写、OOM 等。路径通常为 .../executor/<executor-id>/stderr。执行器数量多、日志量大,是采集成本最高的部分,建议按需采集或只采集 ERROR/WARN 级别。
审计日志由 Databricks 审计系统统一产生,记录谁在何时对什么对象做了什么操作,例如登录、运行作业、修改权限、访问表。它通过审计日志投递到云存储,格式为 JSON,字段规范,是安全与合规分析的核心数据源。
作业日志是作业运行产生的输出,包括 notebook 输出、任务日志、运行结果。可通过 Jobs API 的 /runs/get-output 或运行详情接口获取,也可在作业配置中开启日志投递。
与 ELK / Loki 的集成方式
ELK 与 Loki 的定位不同,选择取决于查询模式与成本约束。ELK 基于 Elasticsearch 建立倒排索引,适合全文检索、复杂聚合和字段级分析,例如“查找过去 24 小时内所有包含 OutOfMemoryError 的执行器日志,并按集群聚合”。Loki 只索引标签,日志正文压缩存储,成本低、写入吞吐高,适合“按 cluster_id、job_id、log_level 快速过滤后查看原始日志”的场景,配合 Grafana 做告警。
集成路径通常有三条:
- 云存储中转:Databricks 将日志投递到 S3/ADLS/GCS,再由 Filebeat 或 Fluent Bit 从对象存储读取并推送到 Elasticsearch 或 Loki。这是最通用的方式,适合驱动日志、执行器日志和审计日志。
- API 拉取:用定时任务调用 Databricks REST API 获取集群事件、作业输出和审计日志,经处理后写入日志平台。适合低频、结构化数据。
- 直接推送:在集群初始化脚本中安装日志代理,将 Driver 和 Executor 日志实时推送到远端。延迟最低,但需要管理代理生命周期和网络出口。
日志解析与结构化处理
原始日志大多是非结构化文本,直接入湖或入搜索引擎会导致查询效率低、字段无法聚合。结构化处理的目标是把每条日志转成带固定字段的 JSON 文档。以驱动日志中的一行典型输出为例:
25/06/12 14:32:07 INFO DAGScheduler: Job 3 finished: count at <unknown>:1, took 2.345 s
用 Grok 模式可以提取出时间、级别、组件、消息体:
%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:log_level} %{DATA:component}: %{GREEDYDATA:message}
解析后得到结构化文档:
{
"timestamp": "2025-06-12T14:32:07",
"log_level": "INFO",
"component": "DAGScheduler",
"message": "Job 3 finished: count at <unknown>:1, took 2.345 s",
"cluster_id": "0612-143207-abc123",
"job_id": 3,
"duration_ms": 2345,
"service_name": "spark-driver"
}
对于审计日志,本身已是 JSON,只需做字段映射和类型转换,例如把 timestamp 从毫秒转成 ISO8601,把 action_name 映射为统一枚举。对于执行器日志,建议先按 executor_id 和 log_level 做标签化,再决定是否保留完整正文。
采集策略与成本控制
执行器日志量可能是驱动日志的几十倍,全量采集成本很高。一个实用的策略是:驱动日志和审计日志全量采集;执行器日志只采集 WARN 和 ERROR 级别,或仅在作业失败时按 run_id 回溯拉取;集群日志和作业日志按 API 定时拉取,保留 30 到 90 天。在 Loki 中,可以通过 log_level 标签过滤,把 INFO 级别日志降采样或只保留最近 7 天。
databricks-driver-*、databricks-audit-*、databricks-executor-*,否则查询时会扫描大量无关数据,既慢又贵。
一个可落地的采集配置示例
下面是一个 Filebeat 从 S3 读取 Databricks 驱动日志并推送到 Elasticsearch 的配置片段,用于说明关键字段:
filebeat.inputs:
- type: s3
bucket: my-databricks-logs
prefix: cluster-logs/
queue_url: https://sqs.us-east-1.amazonaws.com/123456789/databricks-logs
processors:
- add_fields:
target: ''
fields:
service_name: spark-driver
source_type: driver_log
- dissect:
tokenizer: "%{timestamp} %{log_level} %{component}: %{message}"
field: "message"
target_prefix: ""
output.elasticsearch:
hosts: ["https://es.internal:9200"]
index: "databricks-driver-%{+yyyy.MM.dd}"
这段配置做了三件事:从 S3 读取日志、用 dissect 做轻量结构化、按日期写入索引。实际生产中还需要处理多行堆栈合并、字段类型映射和索引生命周期管理。判断采集是否成功,可以看三个信号:Elasticsearch 或 Loki 中是否出现对应 service_name 的文档;timestamp 字段是否可排序且时区正确;按 cluster_id 过滤时能否在秒级返回结果。如果文档数量远小于预期,优先检查 SQS 队列权限和 S3 前缀是否匹配。
把五类日志的采集路径、解析规则和存储策略固定下来之后,后续的告警、根因分析和审计追溯才有可靠的数据基础。日志集中管理不是一次性任务,而是需要随集群规模、作业数量和合规要求持续调整的工程实践。