标签归档:Kibana

CentOS6.5下部署ELK5.5收集Nginx Log

0x01 概述


前段时间监控到公司站点的手机号是否存在的接口被单IP高频率访问,站点解析到腾讯云上,LB后是20+腾讯云主机做Nginx代理,使用Filebeat+ELK收集监控此类异常行为,当前最新的是6.2,有些改动,我还是用5.5版本。

ELK可以当作一个MVC模型,logstash是controller层,Elasticsearch是一个model层,kibana是view层。

使用三台机器,配置和角色如下:

10.59.0.248(32核+64G内存) Logstash Elasticsearch(Master) Kibana

10.59.0.116(24核+32G内存) Logstash Elasticsearch(Data)

10.211.0.107(64核+64G内存) Logstash Elasticsearch(Data)

 

0x02 Filebeat


Filebeat的性能消耗要比logstash小的多,配置如下:

[root@VM_1_216_centos filebeat]# cat filebeat.yml | grep -v "^\s*#" | grep -v "^$"

filebeat.prospectors:

- type: log

  enabled: true

  paths:

    - /马赛克/*.log

  tail_files: true

output.logstash:

  hosts: ["10.59.0.116:5044","10.59.0.248:5044","10.211.0.71:5044"]

  loadbalance: true  #如无该配置默认仅向一台机器发送日志,该机器如果Down掉之后,才会切换其他的机器

data/registry记录了文件读取的offset,如果文件data/registry不存在,则会重新发送文件。

配置tail_files: true 仅发送新的数据

 

0x03 Logstash


在logstash-5.4.0/bin/logstash.lib.sh文件第一行添加

export JAVA_HOME=/usr/local/jdk1.8

所遇到的问题:

1)

ELK部署运行后,非常常见的一个现象是429错误,如下所示:

[2018-04-04T09:08:16,479][INFO ][logstash.outputs.elasticsearch] retrying failed action with response code: 429 ({"type"=>"es_rejected_execution_exception", "reason"=>"rejected execution of org.elasticsearch.transport.TransportService$7@4e1276c3 on EsThreadPoolExecutor[bulk, queue capacity = 200, org.elasticsearch.common.util.concurrent.EsThreadPoolExecutor@4892020c[Running, pool size = 24, active threads = 24, queued tasks = 200, completed tasks = 4786420]]"})

表示Elasticsearch处理不过来了。

在ES5.0以后,Elasticsearch将bulk、flush、get、index、search等线程池完全分离,自身的写入不会影响其他功能的性能。

来查询一下ES当前的线程情况:

Get http://elasticsearch.cdeledu.com/_nodes/stats/thread_pool

其中

"bulk": {

    "threads": 24,

    "queue": 74,

    "active": 24,

    "rejected": 666890,

    "largest": 24,

    "completed": 4817519

},

最需要关注的是rejected。当某个线程池active==threads时,表示所有线程都在忙,那么后续新的请求就会进入queue中,即queue>0,一旦queue大小超出限制,那么elasticsearch进程将拒绝请求(bulk HTTP状态码429),相应的拒绝次数就会累加到rejected中。

解决方案为优化logstash.yml的参数,修改batch.size参数为3000,增加每次发送的事件数,从而降低调用ES的频率。另外修改worker/output.workers为CPU数。

logstash.yml配置如下:

[root@localhost config]# cat logstash.yml | grep -v "^\s*#" | grep -v "^$"

pipeline.workers: 32

pipeline.output.workers: 32

pipeline.batch.size: 3000

pipeline.batch.delay: 5

2)

增加Logstash JVM内存,Logstash报错内存溢出

java.lang.OutOfMemoryError: Java heap space

需要修改logstash启动文件bin/logstash

export LS_JAVA_OPTS=" -Xmx8g -Xms8g"

Logstash配置文件如下:

input {

    beats {

        port => 5044

      }

}



filter{

    grok{

        match => {

            "message" => "%{IP:client-ip}(,\s)?(?<proxy-ip>[\d\.,\s]*) (%{USER:ident}|-) (%{USER:auth}|-) \[%{HTTPDATE:timestamp}\] \"(?:%{WORD:verb} %{URIPATH:uri}%{DATA:parameter}(?: HTTP/%{NUMBER:http_version})?|-)\" %{NUMBER:status-code} %{NUMBER:bytes} \"(%{GREEDYDATA:referer}|-)\" \"(%{GREEDYDATA:user-agent}|-)\" (%{BASE16FLOAT:response_time}|-) (%{BASE16FLOAT:request_time}|-) \"(%{GREEDYDATA:cookie}|-)\" \[%{GREEDYDATA:servername}\]"

        }

    }

    if ([uri] =~ "\.(js|css)$"){

        drop {}

    }

    date {

        match => ["timestamp", "dd/MMM/yyyy:HH:mm:ss Z"]

        target => "@timestamp"

    }

    ruby {

        code => "event.set('timestamp', event.get('@timestamp').time.localtime + 8*60*60); event.set('@timestamp', event.get('timestamp'))"

    }

    if ([verb] == "POST")

    {

        mutate {

            add_field => {"dynamic" => 1}

        }

    }

    else if ([verb] == "GET" and [parameter])

    {

        mutate {

            add_field => {"dynamic" => 1}

        }

    }

    else {

        mutate {

            add_field => {"dynamic" => 0}

        }

    }

    mutate {

        remove_field => [ "message" ]

    }

}



output {

    if "_grokparsefailure" not in [tags] {

        elasticsearch {

            hosts => "10.59.0.248:9200"

            index => "nginx_%{+YYYY.MM.dd}"

        }

    }

}

这里grok正则匹配非常耗费性能,可以使用dissect替换。

 

0x04 ELasticsearch


ElasticSearch是一个基于Lucene的搜索服务器,Lucene是一个开源的全文检索引擎工具包(类似于Java api),而Elasticsearch底层是基于这些包,对其进行了扩展,提供了比Lucene更为丰富的查询语言,可以非常方便的通过Elasticsearch的HTTP接口与底层Lucene交互。Elasticsearch是Lucene面向企业搜索应用的扩展,极大的缩短研发周期。

在if [ -x “$JAVA_HOME/bin/java” ]; then上添加两行

export JAVA_HOME=/usr/local/jdk1.8

export PATH=$JAVA_HOME/bin:$PATH

启动时遇到其他问题汇总:

1) 启动 elasticsearch 如出现异常  can not run elasticsearch as root

解决方法:创建ES 账户,修改文件夹 文件 所属用户 组

2) 启动异常:ERROR: bootstrap checks failed

system call filters failed to install; check the logs and fix your configuration or disable system call filters at your own risk

解决方法:在elasticsearch.yml中配置bootstrap.system_call_filter为false,注意要在Memory下面:

bootstrap.system_call_filter: false

3) 启动后,如果只有本地可以访问,尝试修改配置文件 elasticsearch.yml中network.host(注意配置文件格式不是以 # 开头的要空一格, : 后要空一格)

为 network.host: 0.0.0.0

默认端口是 9200

注意:关闭防火墙 或者开放9200端口

4) ERROR: bootstrap checks failed

max file descriptors [4096] for elasticsearch process likely too low, increase to at least [65536]

max number of threads [1024] for user [lishang] likely too low, increase to at least [2048]

解决方法:切换到root用户,编辑limits.conf 添加类似如下内容

vim /etc/security/limits.conf

添加如下内容:

* soft nofile 65536

* hard nofile 131072

* soft nproc 2048

* hard nproc 4096

5)

max number of threads [1024] for user [lish] likely too low, increase to at least [2048]

解决:切换到root用户,进入limits.d目录下修改配置文件。

vi /etc/security/limits.d/90-nproc.conf

修改如下内容:

* soft nproc 1024

#修改为

* soft nproc 2048

6)

max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]

解决:切换到root用户修改配置sysctl.conf,添加下面配置:

vm.max_map_count=655360

并执行命令:

sysctl -p

然后,重新启动elasticsearch,即可启动成功。

Elasticsearch Master配置文件如下:

cluster.name: logstash_sec

node.name: "node-1"

node.master: true

node.data: false

discovery.zen.ping.unicast.hosts: ["10.59.0.248", "10.211.0.71", "10.59.0.116"]

network.host: 0.0.0.0

path.data: /soft/elasticsearch55/data

path.logs: /soft/elasticsearch55/logs

http.enabled: true

http.cors.enabled: true

http.cors.allow-origin: "*"

bootstrap.mlockall: true

thread_pool.bulk.queue_size: 3000

 

0x05 ELasticsearch plugins


1) Head插件

yum install git -y

git clone git://github.com/mobz/elasticsearch-head.git

下载Node.js:

wget https://nodejs.org/dist/v4.6.1/node-v4.6.1-linux-x64.tar.gz

tar zxvf node-v4.6.1-linux-x64.tar.gz

配置node.js环境变量:

vim /etc/profile:

export PATH=/soft/elasticsearch-5.4.0/node-v4.6.1-linux-x64/bin:$PATH

执行source /etc/profile使环境变量生效

查看当前head插件目录下有无node_modules/grunt目录:

没有则执行命令创建:

npm install grunt --save

安装head插件:

npm install

安装grunt:

npm install -g grunt-cli

编辑Gruntfile.js

文件93行添加

hostname:'0.0.0.0'

检查head根目录下是否存在base文件夹,没有:将 _site下的base文件夹及其内容复制到head根目录下

修改elasticsearch.yml,添加:

http.cors.enabled: true

http.cors.allow-origin: "*"

启动grunt server:在head下运行

grunt server -d

访问head插件:http://localhost:9100

 

2) bigdesk插件

bigdesk是elasticsearch的一个集群监控工具,可以通过它来查看es集群的各种状态,如:cpu、内存使用情况,索引数据、搜索情况,http连接数等。

安装步骤:

git clone https://github.com/hlstudio/bigdesk

cd bigdesk/_site/

python -m SimpleHTTPServer

 

0x06 ELasticsearch 优化


1) shard与Replicas

shard不能修改,一个node不要超过2个shard。

replica只会参与读操作,它的主要作用就是提高集群错误恢复的能力,并且可以在集群建立之后变更。

2) 索引存储

最好是使用SSD,没有的话,最好将es数据节点配置多个数据存储路径,尽量避免使用远程文件系统存储,如NFS 或 SMB。

3) “refresh_interval”: “30s”

优化点: 减少刷新频率,降低潜在的写磁盘性能损耗

另外如果需要一次加载较大的数据量进 index 里面时,可以先禁用 refresh ,把 index.refresh_interval 设置成为 -1 ,把 index.number_of_replicas 设置成 0。暂时把多个shard副本关闭,这样做可以大大加快索引速度。当初始化索引完成,可以将 index.refresh_interval 和 index.number_of_replicas 设置回原来的值。

4) translog优化

Lucene只有在commit的时候才会把之前的变更持久化存储到磁盘(每次操作都写到磁盘的话,代价太大),在commit之前如果出现故障,上一次commit之后的变更都会丢失

为了防止数据丢失,Lucene会把变更操作都记录在translog里,在出现故障的时候,从上次commit起记录在translog里的变更都可以恢复,尽量保证数据不丢失

Lucene的flush操作就是执行一次commit,同时开始记录一个新的translog,所以translog是用来记录从上次commit到下一次commit之间的操作的

flush操作的频率是通过translog的大小控制的,当translog大小达到一定值的时候就执行一次flush,对应参数为index.translog.flush_threshold_size,默认值是512mb,这里调整为1gb,减少flush的次数

translog本身是文件,也需要存储到磁盘,它的存储方式通过index.translog.durability和index.translog.sync_interval设定。默认情况下,index.translog.durability=request,意为每次请求都会把translog写到磁盘。这种设定可以降低数据丢失的风险,但是磁盘IO开销会较大

这里采用异步方式持久化translog,每隔30秒写一次磁盘

{

  "index": {

      "translog": {

          "flush_threshold_size": "1gb",

          "sync_interval": "30s",

          "durability": "async"

      }

  }

}

5) 429错误

增加bulk的queue大小

thread_pool.bulk.queue_size: 3000

改配置会增加JVM内存,修改config/jvm.options

-Xms8g

-Xmx8g

建议配置为物理内存的一半,因为文件系统缓存是为了缓冲磁盘的IO操作。至少确保有一半机器的内存保留给操作系统,并且JVM内存不要超过32G。

6)

index.merge.scheduler.max_thread_count: 1

index由多个shard组成,每个shard又分成很多segment,segment是index数据存储的最小单位。segment比较多的时候会影响搜索性能,ES通过merge对小的segment进行合并,优化查询性能。但是合并过程中会消耗较多磁盘IO,会影响查询性能。Elasticsearch 5 采用了多线程去执行merge,可以通过修改index.merge.scheduler.max_thread_count 来动态调整这个线程数,默认的话是通过下面公式去计算:

Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))

要注意的是如果你是用HDD而非SSD的磁盘的话,最好是用单线程为妙。

 

另外也可以手工进行merge操作,这里有3个参数可以用

max_num_segments 期望merge到多少个segments,1的意思是强行merge到1个segment

only_expunge_deletes 只做清理有deleted的segments,即瘦身

flush 清理完执行一下flush,默认是true

你可以用下面的URL来执行强行的merge

[root@localhost elasticsearch55]# curl -XPOST "http://localhost:9200/nginx_2018.04.12/_forcemerge?max_num_segments=1"

{"_shards":{"total":5,"successful":5,"failed":0}}

7) 避免内存交换

设置为true来锁住内存不进行swapping,因为当jvm开始swapping时es的效率会降低。

bootstrap.mlockall: true

[待补充]

 

0x07 告警配置


告警方面可以选择Elastalert

这里我以单IP高频请求api监控为例,查询语句如下:

{

  "size": 0,

  "query": {

    "bool": {

      "must": [

        {

          "range": {

            "timestamp": {

              "from": "%d",

              "to": "%d"

            }

          }

        },

        {

          "term": {

            "status-code": {

              "value": "200"

            }

          }

        },

        {

          "term": {

            "dynamic": {

              "value": 1

            }

          }

        }                                  

      ]

    }

  },

  "aggs": {

    "group_by_clientip": {

      "terms": {

        "field": "client-ip",

        "order": {

          "_count": "desc"

        },

        "min_doc_count": %d

      },

      "aggs": {

        "group_by_servername": {

          "terms": {

            "field": "servername",

            "size": 2,

            "order": {

              "_count": "desc"

            }

          }

        }

      }

    }

  }

}

 

参考文章:

https://cloud.tencent.com/developer/article/1006124

https://www.jianshu.com/p/9b872a41d5bb