4. Databricks日志采集与结构化处理
Databricks 的可观测性数据并非集中在一个日志文件里,而是分散在五类来源中:集群日志、驱动日志、执行器日志、审计日志和作业日志。它们分别回答不同问题——集群日志说明“集群本身发生了什么”,驱动日志说明“作业调度与 Spark 上下文发生了什么”,执行器日志说明“任务在哪个 executor 上失败或变慢”,审计日志说明“谁在什么时间对什么对象做了什么操作”,作业日志说明“这次 run 的最终状态与耗时”。要建立可观测性,第一步就是把这五类日志的采集路径、格式和聚合方式梳理清楚。
五类日志的采集路径与格式
集群日志(Cluster Logs)通过集群配置中的 cluster_log_conf 指定投递位置,支持 DBFS 路径或 S3/ADLS 等云存储路径。其典型格式为每行一条 JSON 或纯文本,包含 timestamp、level、logger、message、thread 等字段。驱动日志(Driver Logs)默认写入 dbfs:/cluster-logs/<cluster-id>/driver/,执行器日志(Executor Logs)写入 .../executor/<executor-id>/,两者都是 Log4j 输出的文本或 JSON 行。审计日志(Audit Logs)由 Databricks 控制面自动生成,可投递到云存储或通过 Audit Log Delivery 配置,格式为 JSON,字段包括 timestamp、actionName、userIdentity、requestParams、response、sourceIPAddress 等。作业日志(Job Logs)则通过 Jobs API 或作业运行详情页获取,包含 run 的 state、result_state、start_time、end_time、task 列表等结构化信息。
Log4j:统一驱动与执行器日志格式
驱动日志和执行器日志默认由 Log4j 输出,格式不统一会导致后续解析困难。推荐在集群初始化脚本中写入 log4j.properties,将 layout 改为 JSON,并统一字段名。例如:
log4j.appender.file.layout=org.apache.log4j.JsonLayout
log4j.appender.file.layout.fields=timestamp,level,logger,thread,message,clusterId,executorId
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=/databricks/driver/logs/driver.log
log4j.appender.file.MaxFileSize=100MB
log4j.appender.file.MaxBackupIndex=5
这样驱动日志与执行器日志都会输出为 JSON 行,每行包含 timestamp、level、logger、thread、message 等字段。执行器日志中还会额外带上 executorId,便于按 executor 维度聚合。注意:Log4j 配置需在集群启动时生效,若集群已运行,需重启或通过 init script 重新加载。
Fluentd:聚合与字段标准化
Fluentd 适合做日志聚合层,它可以从 DBFS 挂载路径或云存储中读取日志文件,解析后写入 Delta 表。典型配置如下:
<source>
@type tail
path /dbfs/cluster-logs/*/driver/*.log
pos_file /var/log/td-agent/driver.pos
tag databricks.driver
<parse>
@type json
</parse>
</source>
<match databricks.**>
@type delta
path /mnt/observability/logs_delta
mode append
</match>
对于非 JSON 的旧格式日志,可用 grok 或正则解析。Fluentd 的核心价值在于:把不同来源的日志统一成同一套字段(ts、cluster_id、log_type、level、message),再写入 Delta 表。这样后续查询就不需要关心原始文件路径差异。
Delta 表:统一查询入口
将五类日志写入同一张 Delta 表或按 log_type 分区的 Delta 表,是建立可观测性的关键一步。建议表结构如下:
| 字段 | 类型 | 说明 |
|---|---|---|
| ts | timestamp | 日志时间戳 |
| cluster_id | string | 集群标识 |
| log_type | string | cluster / driver / executor / audit / job |
| level | string | INFO / WARN / ERROR |
| message | string | 原始日志内容 |
| user | string | 审计日志中的操作者 |
| action | string | 审计日志中的操作名 |
| run_id | string | 作业运行标识 |
写入后可用 SQL 直接查询,例如统计某集群最近一小时的 ERROR 数量:
SELECT log_type, count(*) AS error_cnt
FROM observability.logs_delta
WHERE cluster_id = '0421-120000-abc123'
AND level = 'ERROR'
AND ts >= current_timestamp() - INTERVAL 1 HOUR
GROUP BY log_type;
json 解析器入 Delta;驱动/执行器日志需先经 Log4j 统一格式,再由 Fluentd 聚合。若集群日志量较大,建议按 log_type 和日期分区,避免全表扫描。
pos_file 必须持久化,否则重启后会重复读取日志,导致 Delta 表出现重复记录。
完成上述采集与结构化后,五类日志就统一到了 Delta 表中。下一步即可基于该表建立告警规则、构建根因分析视图,或对接外部监控系统。采集路径的稳定性、字段命名的一致性和写入的幂等性,是后续所有可观测性工作的基础。