ELK Stack
ELK Stack我们常常说这是日志分析平台,但是我认为这更应该是大数据分析平台,因为这不仅仅是可以分析日志,只是对于大部分公司来说这是分析日志绝佳的技术栈,所以这里我们也是根据公司业务做日志分析。
ELK Stack我们统称是Elasticsearch,LogStash,Kibana的集群构造,Elastcsearch我们大致介绍了下这是一个功能强大的搜索引擎和文档NoSQL数据库,LogStash我们可以理解是一个数据采集器和管道,Kibina将LogStash收集到的数据存在Elasticsearch的数据通过web展示出来。在这里Elasticsearch我们讲过了,LogStash是需要讲的重点,而Kibana只是数据展示可以自行摸索展示。
LogStash
为什么说是LogStash是数据采集器和管道呢?因为LogStash可以通过多种机制采集数据,如通过tcp/udp协议、文件、syslog、windows eventlog及stdin等,获取数据后可以通过内部filter插件对数据进行过滤修改操作,然后输出到stdout或者存储设备上。所以在这里我们也可以猜出LogStash的大致工作过程是stdin–>filter–>stdout的过程,这就像一个管道过一遍数据。
LogStash由JRuby编写,所以运行环境需要JVM虚拟机,而最新的LogStash需要JAVA 1.8的版本才可以运行,ELK的框架如下所示:
在数据的采集过程中我们加了了以broker,因为在生成环境中,生成日志是海量的,如果将日志持续不进行缓冲存入ES集群,ES集群的压力将会很大,也会影响ES集群的工作效率,所以我们加入broker来承上启下,而这个broker有很多选择,最常用的就是redis,redis可以很轻松的处理几十万的并发请求。
LogStash是一个高度插件化的程序,而我们常用的插件不外乎:
- input
- filter
- codec
- output
LogStash支持的数据类型:
- Array:[items1,items2,…]
- Boolean:true,false
- Bytes:
- Codec:编码器
- Hash: key => value
- Number
- Password
- Path: 问价路径
- String: 字符串
支持字段引用:[]
条件判断: - ==、!=、<=、<、>、>=
- =
、! - in,not in
- and,or
LogStash配置
input插件
- LogStash测试一:从标准输入读入,从标准输出输出
1 | ~]# vim /etc/logstash/conf.d/simple.conf |
2 | input { |
3 | stdin {} |
4 | } |
5 | |
6 | output { |
7 | stdout { |
8 | codec => rubydebug |
9 | } |
10 | } |
11 | ~]# /usr/share/logstash/bin/logstash -f /etc/logstash/conf.d/simple.conf |
- LogStash测试二:从文件中读入,从标准输出输出
1 | ~]# vim /etc/logstash/conf.d/fromfile.conf |
2 | input { |
3 | file { |
4 | path => "/var/log/messages" |
5 | type => "system" |
6 | start_position => "beginning" |
7 | } |
8 | } |
9 | |
10 | output { |
11 | stdout { |
12 | codec => rubydebug |
13 | } |
14 | } |
file插件从文件中读入事件流,使用ruby gem的filewatch监听文件变化,并把监听的inode,marjor number,minor number,pos记录在.sincedb中,所以不必担心每次从头开始读取文件。
- LogStash测试三:从udp中读入,从标准输出输出
为了测试udp读入数据,我们需要有程序往udp放松数据,而collectd是由c语言写的性能监听程序,我们可以是他的network模块来发送系统的健康数据。
1 | ~]# yum install -y collectd #注意在epel源中 |
2 | ~]# vim /etc/collectd.conf |
3 | Hostname "test" |
4 | LoadPlugin syslog |
5 | LoadPlugin cpu |
6 | LoadPlugin interface |
7 | LoadPlugin load |
8 | LoadPlugin memory |
9 | LoadPlugin network |
10 | <Plugin network> |
11 | <Server "127.0.0.1" "25826"> |
12 | </Server> |
13 | </Plugin> |
14 | ~]# systemctl start collectd |
15 | |
16 | ~]# vim /etc/logstash/conf.d/collectd.conf |
17 | input{ |
18 | udp { |
19 | port => 25826 |
20 | type => "collectd" |
21 | codec => collectd{} |
22 | } |
23 | } |
24 | output { |
25 | stdout { |
26 | codec => rubydebug |
27 | } |
28 | } |
redis插件:从redis读取数据,支持redis channel和listen两种方式
下面会演示
filter插件
用于在将event通过output发出之前对其实现某些处理功能
其中在ELK中最重要的插件grok,用于分析并结构化文本数据:目前 是logstash中将非结构化日志数据转化为结构的🉑️查询数据的不二之选
模式定义位置:/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.1/patterns/grok-patterns
语法格式:
%{SYNTAX:SEMANTIC}
- SYNTAX:预定于模式名称,即在/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.1/patterns/grok-patterns中预定义的正则匹配
- SEMANTIC:匹配到的文本的自定义标识符,即匹配到的再次重命名成自定义的名字
如:匹配将 message => 10.211.55.24 GET /index.html 28 0.23,我们来拆解这个message信息。
1 | input { |
2 | stdin{} |
3 | } |
4 | filter { |
5 | grok { |
6 | match => { "message" => "%{IP:client} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" } |
7 | } |
8 | } |
9 | output { |
10 | stdout { |
11 | codec => rubydebug |
12 | } |
13 | } |
匹配apache log:
1 | input { |
2 | file { |
3 | path => ["/var/log/httpd/access_log"] |
4 | type => "apachelog" |
5 | start_position => "beginning" |
6 | } |
7 | } |
8 | |
9 | filter { |
10 | grok { |
11 | match => {"message" => "%{COMBINEDAPACHELOG}"} #在/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.1/patterns/grok-patterns中预定义apache的日志格式 |
12 | } |
13 | } |
14 | |
15 | output { |
16 | stdout { |
17 | codec => rubydebug |
18 | } |
19 | } |
而nginx的日志格式在/usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.1/patterns/grok-patterns中却没有,所以我们需要自己写:
1 | ~]# vim /usr/share/logstash/vendor/bundle/jruby/1.9/gems/logstash-patterns-core-4.1.1/patterns/grok-patterns |
2 | #nginx log |
3 | NGUSERNAME [a-zA-Z\.\@\-\+_%]+ |
4 | NGUSER %{NGUSERNAME} |
5 | NGINXACCESS %{IPORHOST:clientip} - %{NOTSPACE:remote_user} \[%{HTTPDATE:timestamp}\] \"(?:%(WORD:verb) %{NOTSPACE:request}(?:HTTP/%{NUMBER:httpversion})?|%{DATA:rawrequest})\" %{NUMBER:response} (?:%{NUMBER:bytes}|-) %{QS:referrer} %{QS:agent} %{NOTSPACE:http_x_forwarded_for} |
ELK Stack配置过程
logstash采集服务器日志数据并存到reids中:
1 | ~]# vim /usr/logstash/conf.d/nginx-redis.conf |
2 | input { |
3 | file { |
4 | path => ["/var/log/nginx/access.log"] |
5 | type => "nginxlog" |
6 | start_position => "beginning" |
7 | } |
8 | } |
9 | |
10 | filter { |
11 | grok { |
12 | match => {"message" => "%{NGINXACCESS}"} |
13 | } |
14 | } |
15 | |
16 | output { |
17 | redis{ |
18 | port => 6379 |
19 | host => ["10.211.55.23"] |
20 | data_type => "list" |
21 | key => "logstash-%{type}" |
22 | } |
23 | } |
从redis中取得数据并将数据输出到es集群:
1 | ~]# /usr/logstash/conf.d/redis-es.conf |
2 | input { |
3 | redis { |
4 | port => 6379 |
5 | host => ['10.211.55.23'] |
6 | data_type => "list" |
7 | |
8 | key => "logstash-nginxlog" |
9 | } |
10 | |
11 | } |
12 | |
13 | output { |
14 | |
15 | elasticsearch { |
16 | hosts => "10.211.55.48:9200" |
17 | index => "logstash-%{+YYYY.MM.dd}" |
18 | |
19 | |
20 | } |
21 | } |
部署kibana
1 | ~]# vim /usr/local/kibana/config/kibana.yml |
2 | server.port: 5601 |
3 | server.host: "0.0.0.0" |
4 | elasticsearch.url: "http://localhost:9200" |
5 | server.name: "my-kibana" |
6 | ~]# sh /usr/local/kibana/bin/kibana |
当然ELK的功能并没有这么简单,但是在这里整个ELK的工作过程应该很清楚了,还有LogStash太过重量级,作为agent收集日志对系统的性能损耗还是蛮严重的,如果有能力可以自行开发来收集数据,应该不是很难。kibana的功能可以对数据很快的进行整合,并以图表展示,有利于数据分析,而且在这里测试600条数据的搜索也是秒级就完成,再一次证明了ES的集权强大。