ellasticsearch使用

Elasticsearch 使用总结

背景:使用容器平台,看日志不方便.使用logstash 收集所有日志 elasticsearch作为搜索引擎.在云平台中可以归集所有应用的日志。研究不够深入随着日志量打不断增大,查询日志出现大量超时时间,另外不希望看日志的人员随意操作云平台的其他功能,需要做严格的权限控制.

  • 首先最紧要的问题,查询超时问题.在了解了整个日志系统的运行流程后,发现平台使用的是logstash默认打建索引规则,即按照日期,每天一个索引: logstash-2017.01.02 由于平台有几十个运行的应用,一天的日志量为30G,全部放在一个索引里,固然搜索速度会很慢.所以从创建索引入手解决 查询超时问题是一个好的切入点.
  • 第二,需要有严格的权限控制,或者是说查询日志的人员就不应该进入到云平台的管理界面.在elasticsearch官网了解到,kibana就是一个很好的解决方案。它只是用于日志查询 且有权限控制,用户体系,安全插件,滚动日志插件等.

整个系统的架构依然是最为流行的 shipper--> redis --> indexer --> elasticsearch 这种架构.即 由logstash(后期用filebeats替代)在各个宿主机收集日志缓存到redis里,由indexer读取redis数据并解析处理再存储到elasticsearch里。

系统结构

1.换行问题

logstash 默认数一行一行收集日志打,但是很多时候一条日志却是占用多行的.然后百度搜发现 基本就一个答案,类似这种.这仅仅是提供一个思路,而真实情况是几十个运行的项目起码有8种以上的日志格式 也就是说需要自己来写正则表达式,来包含所有这些项目.一直想学的正则,借这次契机正好学习一下.

官方的正则参考,另外logstash 使用--debug模式启动,它会打印它系统自带的所有正则表达式.都可以用来参考 https://github.com/elastic/logstash/blob/v1.4.2/patterns/grok-patterns

Tips 另外这里还有一个小问题,这种方式下,在没有收到下一条与正则表达式匹配的日之前一直都不会被打印, 可以加一个参数来解决 auto_flush_interval => 1 即1秒还没收到下一条那么就把剩下打当作一条记录

input {
        file {
                type => "type"
                path => ["info.log"]
                exclude => ["*.gz", "access.log"]
                codec => multiline {
                                     pattern => "^2015"
                                     negate => true
                                     what => "previous"
                                    }
        }
}

以下是我最终的配置

       start_position => "beginning"
        path => ["/opt/var/logs/*/*/*/*/*/*","/opt/var/logs/*/*/*/*","/opt/var/logs/*/*/*/*/*"]
        type => 'filelog'
          codec=> multiline {
                        pattern => "(^\s*\[*(\d{2,4}(\-|\/|.|:|\s|,)){6}\d{0,3})|(^\s*\[\S*]\s*(\d{2,4}(\-|\/|.|:|\s|,)){6}\d{0,3})|(((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)(\S|\s){5}\[\d{1,2}/\b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|ruar)?|[Mm](?:a|ä)?r(?:ch|z)?|[Aa]pr(?:il)?|[Mm]a(?:y|i)?|[Jj]un(?:e|i)?|[Jj]ul(?:y)?|[Aa]ug(?:ust)?|[Ss]ep(?:tember)?|[Oo](?:c|k)?t(?:ober)?|[Nn]ov(?:ember)?|[Dd]e(?:c|z)(?:ember)?)\b/(\d{2,4}[:|\s]){4})|((?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)\s?\b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|ruar)?|[Mm](?:a|ä)?r(?:ch|z)?|[Aa]pr(?:il)?|[Mm]a(?:y|i)?|[Jj]un(?:e|i)?|[Jj]ul(?:y)?|[Aa]ug(?:ust)?|[Ss]ep(?:tember)?|[Oo](?:c|k)?t(?:ober)?|[Nn]ov(?:ember)?|[Dd]e(?:c|z)(?:ember)?)\b\s?(\d{1,2}(\s|:|-)){4}\s?[A-Z]{2,5}\s?\d{2,4})|((一|二|三|四|五|六|七|八|九|十|十一|十二)月\s?\d{2,4},?\s?\d{2,4}\s?(\d{1,2}(:|\s?|-)){3}\s*(上午|下午))"
                        negate => true
                        what => "previous"
                        max_bytes => "100 MiB"
                        auto_flush_interval => 1
                }
    }

正则非常的长,但是它可以匹配大多数的java日志 如

正则1
^\s*\[*(\d{2,4}(\-|\/|.|:|\s|,)){6}\d{0,3}

#可匹配 以下多种以日期开头的日志
17-09-12 09:50:31  INFO SpringJobSche
2017-09-12 10:05:00,000  INFO Scheduler:27 
17-09-12 09:51:00 001  INFO Se

正则2
^\s*\[\S*]\s*(\d{2,4}(\-|\/|.|:|\s|,)){6}\d{0,3}
#可匹配下面的情况
[http-bio-8443-exec-81] 2017-09-12 10:17:09

正则3
((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)(\S|\s){5}\[\d{1,2}/\b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|ruar)?|[Mm](?:a|ä)?r(?:ch|z)?|[Aa]pr(?:il)?|[Mm]a(?:y|i)?|[Jj]un(?:e|i)?|[Jj]ul(?:y)?|[Aa]ug(?:ust)?|[Ss]ep(?:tember)?|[Oo](?:c|k)?t(?:ober)?|[Nn]ov(?:ember)?|[Dd]e(?:c|z)(?:ember)?)\b/(\d{2,4}[:|\s]){4}
#可匹配下面的情况
10.128.38.1 - - [12/Sep/2017:10:17:32 +0800] "GET /vat-web/wx/css/base.css HTTP/1.0" 200 5359

正则4 
(?:Mon(?:day)?|Tue(?:sday)?|Wed(?:nesday)?|Thu(?:rsday)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)\s?\b(?:[Jj]an(?:uary|uar)?|[Ff]eb(?:ruary|ruar)?|[Mm](?:a|ä)?r(?:ch|z)?|[Aa]pr(?:il)?|[Mm]a(?:y|i)?|[Jj]un(?:e|i)?|[Jj]ul(?:y)?|[Aa]ug(?:ust)?|[Ss]ep(?:tember)?|[Oo](?:c|k)?t(?:ober)?|[Nn]ov(?:ember)?|[Dd]e(?:c|z)(?:ember)?)\b\s?(\d{1,2}(\s|:|-)){4}\s?[A-Z]{2,5}\s?\d{2,4}
#可匹配下面的情况
Tue Aug 29 08:57:34 CST 2017 

正则4 
(一|二|三|四|五|六|七|八|九|十|十一|十二)月\s?\d{2,4},?\s?\d{2,4}\s?(\d{1,2}(:|\s?|-)){3}\s*(上午|下午)    
#可匹配下面的情况
八月 17, 2017 9:44:28 上午 org.apache.catalina.core.StandardWrapperValve invoke

2.时间索引问题

正常情况下,可以认为日志基本属于实时日志,即日志打印时间与日志收集时间一致。但是如果是首次安装,那么收集时间与打印时间会不一致 这样收集到的日志将无法根据时间索引来进行搜索.为了解决这个问题,在indexer种解析message 将日志打印时间作为日志的@timestamp 当然,依然要用到正则表达式来匹配各种各样的日期格式,然后转化

实际使用中发现有些项目打印的日志没有精确到秒的,使用以上这种方案会出现同一秒打印的日志会乱序。所以这里再次进行了一次优化。默认的@timestamp依然还是保留不覆盖,另外新加一个字段 用来做搜索关键字和动态索引的关键字。而@timestamp 则作为排序的字段以保证日志的顺序

 grok{
        patterns_dir=>["/home/leoyer/soft/logstash-5.5.0/config/pattern"]
        match=>{
               "message"=>[
                "^\s*\[+%{TIME_QUEUEID:logdate}",
                "^\s*\[\S*\]\s*%{TIME_QUEUEID:logdate}",
        "^\s*%{TIME_QUEUEID:logdate}",
                "^\s*%{IPORHOST} - - \[%{HTTPDATE:logdate}\]",
                "^\s*%{CATALINA_DATESTAMP:logdate}",
         "^\s*%{DATESTAMP_OTHER:logdate}",
        "^\s*%{TIMESTAMP_ISO8601:logdate}",
        "^\s*%{MONTH_CN:logdate}",
                "^\s*%{TOMCAT_DATESTAMP:logdate}"
            ]
        }
    }
    date{
         match=>[
            "logdate",
            "yy-MM-dd HH:mm:ss SSS",
            "yy-MM-dd HH:mm:ss,SSS",
            "yy-MM-dd HH:mm:ss.SSS",
            "yy-MM-dd HH:mm:ss ",
        "yy-MM-dd HH:mm:ss",
            "dd/MMM/yyyy:HH:mm:ss Z",
        "MMM dd, yyyy hh:mm:ss a",
            "EEE MMM dd HH:mm:ss z yyyy"

        ]
        target=>"@timestamp"
    }

3.索引规划

默认是logstash-2017.01.02 这种形式, 这个基础上再多加一个维度,如 logstash-app1-2017.01.02 另外在查询时指定具体的index而不是logstash-*

4.定制kibana

前端学习

logtrail 插件安装及二次开发

登录验证码添加

5.后续

数据备份

elasticsearch 集群

indexer 调优

数据备份恢复

6.收集断使用filebeat

filebeat作为收集端(shipper),可以说是用go改写的logstash,最大的优势是简单,配置基本与logstash一致, 占用资源少,作为轻量级的收集端自然没有logstash那样丰富的插件,所以在解析方面还无法替代logstash,因此 indexer依然还是使用logstash,当然github上已经有几个使用java重写的logstash 开源项目.目的是优化 indexer 性能问题和消息丢失问题