Logstash + ElasticSearch:初始类型映射导致缺少日志行

时间:2014-04-21 07:08:11

标签: elasticsearch logstash kibana

我们有一个经典的logstash + elasticsearch + kibana设置用于日志聚合。我们使用它来汇总所有服务器和应用程序中的日志,我们偶然发现了以下问题:ES第一次收到日志行(在我们的案例中是一个JSON文档),它为该文档创建了一个映射(参见{{ 3}})。大多数情况下,属性被映射为字符串,但在某些情况下,它们被映射为日期或数字。在后一种情况下,如果另一个日志行(来自不同的应用程序)具有相同的字段,但具有字符串值,则ES将无法对其进行索引(向其日志抛出异常并像往常一样继续)。作为一种解决方法,我们已将ES配置为忽略格式错误的文档(index.mapping.ignore_malformed:true),但感觉更像是黑客攻击。

如何以优雅的方式解决这个问题?

3 个答案:

答案 0 :(得分:2)

听起来你们并不关心日期类型或任何类型。 我认为最好的解决方案是定义一个动态模板,将所有类型定义为字符串:

{
    "_default_" : {
        "dynamic_templates" : [
            {
                "long_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "long",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            },
            {
                "double_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "double",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            },
            {
                "float_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "float",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            },
            {
                "integer_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "integer",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            },
            {
                "date_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "date",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            },
            {
                "boolean_to_string" : {
                    "match" : "*",
                    "match_mapping_type": "boolean",
                    "mapping" : {
                        "type" : "string",
                        "index" : "analyzed"
                    }
                }
            }
        ]
    }
}

来自here

答案 1 :(得分:1)

经过大量研究,我可以遗憾地宣称,目前尚无优雅的解决方案。虽然您可以声明不应该分析字段,但您不能告诉它动态更改其类型,也不能自动忽略类型。

这实际上意味着您首先发送的任何类型都是您可以索引到该字段的唯一类型。 如果您使用类型预先声明了该字段,那么您将无法为该类型以外的任何内容编制索引。 在任何一种情况下,所有不匹配类型都将下降。 另外,请注意,这通常会使elasticsearch的日志文件泛滥,您应该设置日志轮换或配置elasticsearch以不在其日志记录中记录这些错误。

您的解决方案确实是潜在的黑客攻击(除非您确定未编入索引的数据无关紧要)。这很像一个尝试:除了:传递python之外的东西。

作为一般规则(从经验来讲),我建议你不要将不同类型的数据(不是不同的弹性搜索类型)索引到具有相同名称的字段中,然后在Kibana中变得非常难以分析尝试使用基于数字/字符串的查询(您无法在该特定字段上排序或显示直方图或饼图。) 显然,仅仅更改代码(或其他应用程序的代码)并不容易索引到同一字段,在这种情况下,我会识别原始应用程序并使用logstash' s grok(除非您已经发送了json)并使用mutate过滤器来替换字段的名称。

答案 2 :(得分:1)

想知道为什么ignore_malformed被认为是黑客?我猜测,他们将这个功能放入了完全相同的原因 - 有时候某个字段可能无法评估为声明的数据类型。它真的破坏了吗?

修改/更新:
对于日志摄取/处理/索引,我的经验是,将日志直接摄取到像ES这样的商店是一个坏主意,原因很多(如果你好奇的话,可以随意问这些是什么)。

简而言之,在将数据推送到任何数据存储库(如ElasticSearch或HDFS)之前,我总是使用摄取/解析引擎。您可以使用logStash或flume等代理程序使用grok处理/解析数据。或者,编写一个自定义Spark应用程序来摄取,验证和构建数据,然后再将其提供给ES。

通常,我会像这样构建日志管道: 制片人(系统日志等) - > Kafka / Kinesis(主题-1) - > Spark Streaming App(应用解析/结构化规则) - > Kafka / Kinesis(主题-2) - >多个代理(每个数据存储库一个代理组)。因此,例如,我将部署一组订阅topic-2并写入HDFS的flume代理。同时,部署一堆logStash代理并写入ES。

可能看起来有点牵扯,但更清晰/一致的数据的好处是多方面的。从休闲数据探索者到数据科学家的每个人都会感谢你:)。