一、问题背景:为啥分散的日志会坑哭运维

做过分布式任务调度的人都懂,DolphinScheduler(以下简称DS)这个工具,本来是帮大家把各种定时任务、批处理任务安排得明明白白的,可一旦任务跑崩了,找日志的过程能把人逼疯。

原因很简单:DS的任务是扔给各个Worker节点跑的,每个任务跑的日志,就存在对应Worker节点的本地磁盘里。比如你有10个Worker节点,某个每天跑的报表任务,今天报错了,你得先去DS的任务详情页看这个任务是哪个Worker跑的,然后再登录那个Worker的服务器,翻对应目录找日志。要是任务经常换Worker跑(比如集群有扩容缩容、节点调度策略变化),那找日志的时间可能比解决问题的时间还长。

更麻烦的是,要是Worker节点挂了、磁盘满了,之前的日志直接就没了,连补救的机会都没有。这就是分散日志的痛点:找着费劲、存着危险、查着麻烦。

二、集中日志采集的完整方案:从分散到统一的落地步骤

要解决这个问题,核心就是把所有Worker节点的日志,都搬到一个集中的地方存起来,同时让大家能直接在DS里快速找到对应的日志。这个方案不是凭空想的,我们拿真实的生产环境例子来说,整个流程分三步走。

2.1 第一步:确定日志的「搬运路线」

首先得搞清楚,DS的日志是怎么生成的,这样才能精准搬运。DS的任务日志,默认是存在Worker节点的/data/dolphinscheduler/logs/目录下,每个任务的日志文件名有固定格式:任务ID_任务执行ID.log,比如123_45678.log,代表任务ID是123,某次执行的ID是45678。

我们选的搬运工具是Filebeat,这个工具是专门干日志搬运的,轻量不占资源,每个Worker节点装一个就行,它会盯着日志目录,有新日志就自动搬。下面是Filebeat的配置,我们要做的核心是:只搬DS的任务日志,不搬别的,还要给每段日志打上「属于哪个任务、哪个执行」的标签,方便后面分类。

# Filebeat配置文件:filebeat.yml
# 全局配置:输出到Elasticsearch(集中存日志的地方)
output.elasticsearch:
  hosts: ["http://es-node1:9200", "http://es-node2:9200"] # 集中存储的ES地址
  index: "dolphinscheduler-task-logs-%{+yyyy.MM.dd}" # 每天建一个索引,方便管理

# 输入配置:只监听DS的任务日志目录
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /data/dolphinscheduler/logs/*.log # 只搬这个目录下的所有日志文件
  # 核心:从文件名里提取任务ID和执行ID,给日志打标签
  processors:
    - dissect:
        tokenizer: "%{task_id}_%{exec_id}.log" # 按文件名格式拆分,提取两个核心字段
        field: "log.file.path" # 从日志文件的路径里拆分
        target_prefix: "ds" # 把拆分后的字段放在ds标签下,避免冲突

这里要注意一个细节:为什么要给日志打标签?因为日志内容本身可能只写了任务跑了多久、报错了啥,但没说这个日志属于哪个任务。打了标签之后,集中存的时候,每一段日志都知道「我是任务123的第45678次执行的日志」,后面查的时候就能精准定位。

2.2 第二步:把集中日志和DS打通

光把日志搬去集中存储还不够,得让大家不用跳出DS就能看日志。DS本身有个日志展示的页面,我们要做的就是把这个页面的「从本地Worker读日志」改成「从集中存储读日志」。

具体怎么做?DS的任务详情页的日志逻辑,是在Worker服务里的,我们需要改Worker的配置,告诉它:别读本地的日志了,去集中的ES里查。下面是DS Worker的配置文件修改示例:

# DS Worker配置文件:worker.properties
# 原来的配置:读本地日志
# task.log.path=/data/dolphinscheduler/logs
# 新的配置:关闭本地日志读取,启用集中日志查询
task.log.path=
task.log.enable.remote=true # 开启远程日志查询
task.log.remote.type=elasticsearch # 远程存储的类型是ES
task.log.remote.elasticsearch.host=http://es-node1:9200 # ES地址
task.log.remote.elasticsearch.index.prefix=dolphinscheduler-task-logs # ES的索引前缀,和Filebeat的配置对应
task.log.remote.elasticsearch.task.id.field=ds.task_id # 日志里的任务ID字段,和Filebeat的标签对应
task.log.remote.elasticsearch.exec.id.field=ds.exec_id # 日志里的执行ID字段,和Filebeat的标签对应

改完之后重启Worker服务,再去DS的任务详情页看日志,就会发现:不管这个任务是哪个Worker跑的,都能直接加载到对应的日志了。

2.3 第三步:优化日志检索速度

集中存了日志之后,又会遇到新问题:要是一个任务跑了一年,每天都有日志,集中存储里的日志量特别大,查某一天的日志可能要等好几秒,甚至十几秒。这时候就得做检索优化,核心是让日志能被快速找到。

优化的核心是「给日志加索引」,ES本身是搜索引擎,自带索引功能,但我们要针对性调整。比如,我们可以把日志的任务ID执行ID这两个字段,设成「精确匹配」的索引类型,这样查的时候不用扫全量数据,直接定位到对应的数据块。

下面是给ES的索引加映射的示例,也就是告诉ES,哪些字段要重点索引:

# ES索引映射配置:给DS的日志索引加精确索引
PUT /dolphinscheduler-task-logs-*/_mapping
{
  "properties": {
    "ds.task_id": {
      "type": "keyword" # 设为keyword类型,精确匹配,速度快
    },
    "ds.exec_id": {
      "type": "keyword" # 同样设为精确匹配
    },
    "message": {
      "type": "text" # 日志内容设为文本类型,支持模糊搜索
    }
  }
}

加了这个映射之后,查某段日志的速度会提升好几倍。比如之前查任务ID123的第45678次执行的日志,可能要等3秒,加了之后可能只要几百毫秒。

三、方案的优缺点和注意事项

3.1 方案的优点

这个方案落地之后,解决了分散日志的所有痛点:首先,找日志不用再登录Worker节点,直接在DS里就能看;其次,集中存储可以做备份、容灾,就算Worker节点挂了,日志也不会丢;最后,还能做日志分析,比如统计某个任务最近一个月的报错次数,直接在ES里搜就行,不用一个个翻。

3.2 方案的缺点

当然,这个方案也有不足:第一,集中存储的成本会增加,原来日志存在Worker的本地磁盘,不用额外花钱,现在要单独搭ES集群,要是日志量特别大,比如每天产生100G的日志,ES集群的硬件成本会比较高;第二,要是集中存储挂了,整个DS的日志功能就废了,原来分散的时候,一个Worker挂了,只会影响那个Worker的日志,现在是一荣俱荣一损俱损;第三,配置稍微有点麻烦,要是Filebeat的配置写错了,比如日志路径设错了,就会漏搬日志,要是DS的配置和ES的映射不对应,就会查不到日志。

3.3 落地的注意事项

落地的时候有几个细节要特别注意:第一,日志的生命周期管理,集中存储的日志不能一直存,比如可以设成存3个月,超过3个月的自动删,不然ES的磁盘会爆;第二,权限控制,集中存储的日志可能包含敏感信息,比如数据库密码、用户手机号,要限制只有相关的人能查;第三,版本兼容,DS的版本和Filebeat、ES的版本要匹配,比如DS3.2版本可能不支持某些ES的新特性,要是版本不兼容,改完配置可能会报错。

四、应用场景和实际效果

这个方案适合所有用DS做分布式任务调度的场景,尤其是集群规模大(Worker节点超过5个)、任务数量多(每天跑的任务超过100个)、对问题排查速度要求高的场景。比如某电商公司,每天有几千个报表任务、数据同步任务,之前找一个报错的日志平均要10分钟,落地这个方案之后,找日志的时间降到了1分钟以内,问题排查效率提升了10倍。

再比如某互联网公司,原来Worker节点的磁盘经常满,导致旧日志丢失,落地这个方案之后,集中存储的磁盘容量大,还做了多副本,再也没出现过日志丢失的情况。

五、总结

分散日志的问题,本质是分布式架构下的「数据分散」问题,集中采集是解决这个问题的通用思路。DS的集中日志方案,核心是「搬运日志、打通入口、优化检索」三个步骤,每个步骤都有具体的配置和注意事项。落地的时候,要根据自己的集群规模、日志量、预算,选择合适的集中存储工具(比如除了ES,也可以用Loki、ClickHouse,成本更低),调整配置参数,避免踩坑。

最后要提醒的是,这个方案不是一劳永逸的,要定期检查日志的采集情况,比如有没有漏搬的日志、集中存储的磁盘容量够不够、检索速度有没有变慢,及时调整,才能保证日志系统一直稳定好用。