开源项目聚焦:Sawmill,数据处理项目

作者:Daniel Berman

介绍 Sawmill,一个用于丰富、转换和过滤 JSON 文档的开源 Java 库。

如果您对集中式日志记录感兴趣,您可能熟悉 ELK Stack:Elasticsearch、Logstash 和 Kibana。如果您不熟悉,ELK(或 Elastic Stack,正如最近更名那样)是由三个开源组件组成的软件包,每个组件负责数据管道中不同的任务或阶段。

Logstash 负责从您不同的数据源聚合数据,并在发送到 Elasticsearch 进行索引和存储之前对其进行处理。这是一个关键角色。您如何处理日志数据直接影响您的分析工作。如果您的日志结构不正确,并且您没有正确配置 Logstash,那么您的日志将不会以允许您在 Kibana 中查询和可视化的方式进行解析。

Logz.io 过去曾严重依赖 Logstash 从我们的客户那里摄取数据,并在任何给定时间运行多个 Logstash 实例。然而,我们开始遇到一些痛点,这些痛点最终引导我们走上了本文主题项目 Sawmill 的道路。

解释动机

随着时间的推移,并且随着我们的数据管道变得越来越复杂和繁重,我们开始遇到严重的性能问题。我们的 Logstash 配置文件变得极其复杂,这导致了极长的启动时间。处理也花费了太长时间,尤其是在长日志消息的情况下以及配置与实际日志消息不匹配的情况下。

以上几点导致了严重的稳定性问题,Logstash 可能会停止运行或有时崩溃。最糟糕的是,故障排除是一个巨大的挑战。我们缺乏可见性,并且越来越需要一种方法来监控关键性能指标。

我们还遇到了一些其他问题,例如动态配置重载和应用业务逻辑的能力,但总而言之,Logstash 对我们来说已经不够用了。

介绍 Sawmill

在深入了解 Sawmill 之前,重要的是指出 Logstash 自我们开始从事此项目以来已经发展,并具有有助于解决上述一些痛点的新功能。

那么,Sawmill 是什么?

Sawmill 是一个用于丰富、转换和过滤 JSON 文档的开源 Java 库。

对于 Logstash 用户来说,理解 Sawmill 的最佳方式是将其视为 Logstash 配置文件中过滤器部分的替代品。与 Logstash 不同,Sawmill 没有任何输入或输出来读取和写入数据。它仅负责数据转换。

使用 Sawmill 管道,您可以以描述性的方式,使用配置文件或构建器,以简单的 DSL,使用 groks、geoip、用户代理解析、添加或删除字段/标签等,从而允许您动态更改转换。

Sawmill 主要特性

以下是 Sawmill 支持的主要特性和处理能力列表

  • Sawmill 使用 Java 编写,是线程安全的、高效的,并在需要时使用缓存。
  • Sawmill 可以使用 HOCON 或 JSON 进行配置。
  • Sawmill 允许您使用可配置的阈值为长时间处理配置超时。
  • Sawmill 生成关于成功、失败、过期和丢弃执行的指标,以及关于处理超过定义阈值的指标。所有指标都可用于每个管道和处理器。
  • 25+ 个处理器,包括 grok、geoip、user-agent、date、drop、key-value、json、math 等。
  • 九个逻辑条件,包括基本条件以及 field-exists、has-value、match-regex 和 math-compare。
使用 Sawmill

这是一个演示如何使用 Sawmill 的基本示例


Doc doc = new Doc(myLog);
PipelineExecutor pipelineExecutor = new PipelineExecutor();
pipelineExecutor.execute(pipeline, doc);

 

如您在上面所见,Sawmill 中有几个实体

  • Doc — 本质上是一个代表 JSON 的 Map。
  • Processor — 单个文档逻辑转换。例如 grok-processor、key-value-processor、add-field 等。
  • Pipeline — 指定使用处理器有序列表的一系列处理步骤。每个处理器以某种特定方式转换文档。例如,一个管道可能有一个处理器从文档中删除一个字段,然后是另一个重命名字段的处理器
  • PipelineExecutor — 在文档上执行管道中定义的处理器PipelineExecutor 负责执行流程——处理 onFailure 和 onSuccess 流程、在失败时停止、公开执行指标等等。
  • PipelineExecutionTimeWatchdog — 负责在长时间处理时发出警告、中断并在超时时停止处理(在上面的示例中未显示)。
Sawmill 配置

Sawmill 管道可以从 HOCON 字符串(人类优化配置对象表示法)构建。

这是一个简单的配置代码片段,让您感受一下


{
"steps": [{
    "grok": {
        "config": {
            "field": "message",
            "overwrite": ["message"],
"patterns":["%{COMBINEDAPACHELOG}+%{GREEDYDATA:extra_fields}"]
           }
        }
    }]
}

 

这相当于 HOCON 中的以下内容


steps: [{
    grok.config: {
            field : "message"
            overwrite : ["message"]
            patterns :
["%{COMBINEDAPACHELOG}+%{GREEDYDATA:extra_fields}"]
           }
    }]

 

为了理解如何使用 Sawmill,这是一个展示 GeoIP 解析的简单示例


package io.logz.sawmill;

import io.logz.sawmill.Doc;
import io.logz.sawmill.ExecutionResult;
import io.logz.sawmill.Pipeline;
import io.logz.sawmill.PipelineExecutor;

import static io.logz.sawmill.utils.DocUtils.createDoc;

public class SawmillTesting {

    public static void main(String[] args) {

        Pipeline pipeline = new Pipeline.Factory().create(
                "{ steps :[{\n" +
                "    geoIp: {\n" +
                "      config: {\n" +
                "        sourceField: \"ip\"\n" +
                "        targetField: \"geoip\"\n" +
                "        tagsOnSuccess: [\"geo-ip\"]\n" +
                "      }\n" +
                "    }\n" +
                "  }]\n" +
                "}");

        Doc doc = createDoc("message", "testing geoip resolving",
         ↪"ip", "172.217.11.174");
        ExecutionResult executionResult = new
PipelineExecutor().execute(pipeline, doc);

        if (executionResult.isSucceeded()) {
            System.out.println("Success! result
             ↪is:"+doc.toString());
        }
    }
}

 

最终结果

一年多来,我们一直在我们的摄取管道中成功使用 Sawmill,处理用户发送给我们的海量日志数据。

我们知道 Sawmill 仍然缺少一些关键特性,并且我们期待收到来自社区的贡献。我们也意识到,归根结底,Sawmill 是为我们的特定需求而开发的,可能与您的用例无关。尽管如此,我们很乐意收到您的反馈。

关于作者

Daniel Berman 是 Logz.io 的产品布道师。他对日志分析、大数据、云计算和家庭充满热情,并且热爱跑步、利物浦足球俱乐部和撰写关于颠覆性科技的文章。关注他的 Twitter @proudboffin。

加载 Disqus 评论