最近接手维护了几个ELK集群,对接的是IaaS、PaaS服务日志,简单的ELK架构,通过filebeat采集日志,发送到logstash结构化日志然后发送到ElasticSearch,用户可以通过Kibana查看服务日志定位问题、做一些性能分析图表等,同时利用elastalert做日志报警。

在ElasticSearch须要对用户的索引建立合适的类型映射(尤其是int类型),才可以在kibana中对数据进行分析,关于ES的映射类型可以看这里,需指出的是一旦某个field字段类型确定就很难更改该字段的类型(需reindex)。

Logstash将非结构化数据转化为结构化数据,通过JSON将数据发送给ElasticSearch,所有字段都会被当作string来处理,而ElasticSearch在自动判断字段类型建立映射这方面做的不足,与我们需求不符,那么如何正确建立索引类型映射呢?

一、通过Logstash的grok、mutate确定字段类型

  • grok

    根据grok官方文档,在grok正则表达式后可以添加一个数据类型,默认是string类型,如果你想使字段类型为int,你可以在表达式后加int,例如%{NUMBER:num:int},那么num字段会从string类型变为int类型,目前只支持int和float。

  • mutate

    通过mutate可以将field转化为integer、float、string,例如:

    filter {
        mutate {
           convert => { "num" => "integer" }
        }
    }
    

二、ElasticSearch mapping template

映射(mappings)决定了一个字段(field)如何被ElasticSearch解释、存储,例如数据{“ip”:“223.5.5.5”}发送给ES,ES会将ip字段存储为string类型,而不是ip类型,不能做IP范围查询同时造成存储空间浪费、查询效率低等。**不管在Logstash如何转换类型,ElasticSearch不会知道你的用意除非你正确映射。**所有整型会存为long,小数会存为float或double,关于最小类型可以看这里,使用integer而不是long会有效的减少ELasticSearch负担。

  • 映射模版

    编写模版文件my_template.json

    {
          "index_patterns" : "index*",
          "version" : 1,
          "settings" : {
              "index.refresh_interval" : "5s"
          },
          "mappings" : {
              "_default_" : {
                  "properties":{
                      "host": { "type" : "string"},
                      "ip": {"type" : "ip"},
                      ....
                  }
              }
          }
      }
    
上传template.json
`curl -XPUT http://localhost:9200/_template/index_template?pretty -d @my_template.json`
   
删除旧的索引数据
`curl -XDELETE http://localhost:9200/index?pretty`