最新记录:11台ES(12核64G机械盘),天天日志量在37.4亿条,Primary Shard大小1.7T,最高索引速度每秒8万左右。php
此文为原标题“玩儿透日志分析集群搭建.调优.管理rsyslog->kafka->spark->elk”的更改版。html
实时日志分析做为掌握业务状况、故障分析排查的一个重要手段,目前使用最多最成熟的莫过于ELK方案,总体方案也有各类架构组合,像rsyslog->ES->kibana、rsyslog->Redis->Logstash->ES->kibana、rsyslog->kafka->Logstash->ES->kibana等等,复杂点的有spark的引用。每种方案适合不一样的应用场景,没有优劣之分,我目前用的是rsyslog->kafka->(Logstash/spark)->ES->kibana和rsyslog->rsyslog中继->kafka->(Logstash/spark)->ES->kibana方案,中间使用spark对日志进行再次聚合。前端
从总体架构进行抽象总结,其实就是采集->清洗汇聚->索引->展示四个环节,再去考虑各环节中缓存、队列的使用,每一个环节点用不一样的软件来实现。下面介绍一下我目前方案集群的搭建和配置,但愿对同行有所帮助,也算是积福德消业,在ELK探索过程当中多谢远川和冯超同窗的奉献交流。附上我目前使用的方案选型架构图以下:node
工做中对不一样场景的各类架构进行了梳理,详见博文:运维数据分析平台建设的4个段位——架构演进linux
1、采集(使用rsyslog)nginx
客户端使用rsyslog8.19.0作的收集,直接centos安装rpm包,安装详细见:redis
http://www.rsyslog.com/rhelcentos-rpms/shell
将yum源配置好后:apache
yum install rsyslog yum install rsyslog-kafka
安装好后对应rsyslog的配置文件以下:centos
module(load="imfile") module(load="omkafka") $PreserveFQDN on main_queue( queue.workerthreads="10" # threads to work on the queue queue.dequeueBatchSize="1000" # max number of messages to process at once queue.size="50000" # max queue size ) ##########################nginx log################################ $template nginxlog,"%$myhostname%`%msg%" if $syslogfacility-text == 'local6' then { action( broker=["10.13.88.190:9092","10.13.88.191:9092","10.13.88.192:9092","10.13.88.193:9092"] type="omkafka" topic="cms-nginx" template="nginxlog" partitions.auto="on" ) stop } ############################redis log######################### $template redislog,"%$myhostname%`%msg%" ruleset(name="redis7215-log") { action( broker=["10.13.88.190:9092","10.13.88.191:9092","10.13.88.192:9092","10.13.88.193:9092"] type="omkafka" topic="redis-log" template="redislog" partitions.auto="on" ) } input(type="imfile" File="/data1/ms/log/front/redis7215.log" Tag="" ruleset="redis7215-log" freshStartTail="on" #start tailf reopenOnTruncate="on" #Truncate reopen ) input(type="imfile" File="/data1/ms/log/front/redis7243.log" Tag="" ruleset="redis7215-log" freshStartTail="on" reopenOnTruncate="on" ) ############################php curl log############################# $template phpcurl-log,"%$myhostname%`%msg%" ruleset(name="phpcurl-log") { action( broker=["10.13.88.190:9092","10.13.88.191:9092","10.13.88.192:9092","10.13.88.193:9092"] type="omkafka" topic="phpcurl-log" template="phpcurl-log" partitions.auto="on" ) } input(type="imfile" File="/data1/ms/log/php_common/php_slow_log" Tag="" ruleset="phpcurl-log" freshStartTail="on" reopenOnTruncate="on" )
为了不在日志发送错误时,丢在message日志里,瞬间将磁盘占满,同时配置丢弃策略
*.info;mail.none;authpriv.none;cron.none;local6.none /var/log/messages
目前收集了nginx、redis、php curl三种日志,说一下收集方案。
一、对于nginx
方案1:采用nginx的rsyslog模块将日志打到local6,对应nginx的配置以下
##########elk############################# access_log syslog:local6 STAT;
而后经过如上rsyslog的配置,将日志直接入kafka队列,kafka集群是4个broker。
方案2:线上还有另外一个传输方案,rsyslog设置一个中继,经过udp的方式将日志传到中继的rsyslog,由中继rsyslog入kafka,这么作的目的是方便了管理,当时还有个考虑是udp不会堵,但通过多轮测试后,nginx的rsyslog模块也是很健壮,不会堵的。
二、对于redis、php curl的日志
经过rsyslog的imfile模块,直接对文件监听,配置见上面的rsyslog配置,在日志轮转时经过超连接的方式进行新文件的链接,对应的超链接计划任务以下,天天0点5分执行:
5 0 * * * root sh /usr/local/script/php_slow_log.sh &> /dev/null
对应的php_slow_log.sh的脚本以下:
#!/bin/bash DATE=`date +%F` ln -sf /data1/ms/log/php_common/curl-$DATE /data1/ms/log/php_common/php_slow_log
备注:
a、rsyslog向kafka推送消息时,轮询发送消息到broker上的leader partition;
b、rsyslog经过udp或tcp向外转发日志时,会默认加上时间、主机名、主机ip的属性。
c、rsyslog的其他知识博文详见:
博文1:巧用rsyslog收集多套日志并作单套日志的过滤分离
2、队列(kafka+zookeeper)
队列用的是kafka,kafka集群使用zookeeper管理,咱们用了4台服务器混装了4个kafka和3个zookeeper,kafka和zookeeper的安装地址以下:
http://kafka.apache.org/downloads 注意:下载Binary downloads版本,别下错了,解压后就能用
http://zookeeper.apache.org/ 注意:安装过程很简单,按照文档来便可,不在说明
kafka管理能够用kafka-manager详见博文:kafka与zookeeper管理之kafka-manager踩坑小记
kafka原理介绍推荐:Kafka设计与原理详解
一、关于kafaka
a、配置比较简单,基本默认便可,常调整的配置项以下:
配置文件:server.properties broker.id=190 #id num.partitions=20 #默认kafka的partion数量 log.dirs=/data1/kafka-logs #日志文件存放目录 log.retention.hours=3 #日志保留时间长短 zookeeper.connect=10.13.88.190:2181,10.13.88.191:2181,10.13.88.192:2181 #zookeeper指定 delete.topic.enable=true #topic是能够删除的
b、安装后测试(假设kafka和zookeeper都装了):
开两个终端,两个终端分别运行以下命令
启动:./bin/kafka-server-start.sh /usr/local/kafka/config/server.properties & 关闭:./bin/kafka-server-stop.sh 终端1:./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test 终端2:./bin/kafka-console-consumer.sh --zookeeper localhost:2181 --from-beginning --topic test
注意两个终端的topic要一个名字,这时你在终端1输入任何数据,在终端2是同步的,证实你安装成功。
c、kafka经常使用管理命令
建立topic:./bin/kafka-topics.sh --create --topic test --replication-factor 1 --partitions 32 --zookeeper localhost:2181 删除topic:./bin/kafka-topics.sh --delete --topic test --zookeeper localhost:2181 查看topic列表:./bin/kafka-topics.sh --list --zookeeper localhost:2181 查看某个topic详细:./bin/kafka-topics.sh --describe --topic test --zookeeper localhosts:2181 监控某个topic的消费:./bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test 指定消费组查看消费状况:./bin/kafka-consumer-offset-checker.sh --zookeeper localhost:2181 --group test
d、kafka集群消费吞吐量性能测试以下,每秒能够支持消费50万条信息,咱们目前的QPS远远是没问题的
备注:topic下partitions的数量决定了并发消费的数量,在设置上要根据消息的QPS和硬盘状况合理配置。
二、关于zookeeper
a、配置比较简单,大多数默认项,最好奇数个,半数以上zookeeper存活可用
配置文件:zoo.cfg dataDir=/data1/zookeeper server.1=10.13.88.190:3888:4888 server.2=10.13.88.191:3889:4888 server.3=10.13.88.192:3889:4888
注意:要在数据目录手动创建myid,myid的值是server后面的数字,数字是有范围限制的1~255
b、zookeeper的经常使用管理命令
zookeeper我主要是看下它的总体状态,写了个简单脚本获取zookeeper的状态,执行结果以下:
脚本内容以下:
#!/bin/sh #writer:gaolixu [ -z $1 ] && echo "Please specify zoo.cfg like /usr/local/zookeeper/conf/zoo.cfg " && exit cat $1 |grep "^server" |awk -F'[:|=]' '{print $2}' | while read line do echo -ne "$line\t" echo stat|nc -w 2 $line 2181 |egrep "^(Node|Zxid|Mode|Connections)" |tr "\n" "\t" echo stat|nc -w 2 $line 2181 |egrep "^(Node|Zxid|Mode|Connections)" &>/dev/null || echo -n "host is done." echo done 使用方式:zkstat.sh /配置文件zoo.cfg的位置
zookeeper是至关稳定的,基本不用管。
备注:zookeeper配置文件里不能有汉字,不然启动不起来。
3、清洗汇聚(logstash/spark)
logstash用作清洗,而且将处理好的日志推送到es里,安装过程很简单详见网址:
https://www.elastic.co/guide/en/logstash/current/installing-logstash.html#package-repositories
我线上的nginx的配置文件以下:
input { kafka { zk_connect => "10.13.88.190:2181,10.13.88.191:2181,10.13.88.192:2181" topic_id => "cms-nginx" group_id => "cms-nginx" consumer_threads => 1 reset_beginning => false decorate_events => false } } filter { ruby { init => "@kname = ['host-name','front','http_x_up_calling_line_id','request','http_user_agent','status','remote_addr_1','id','http_referer','request_time','body_bytes_sent','http_deviceid','http_x_forwarded_for','domain','cookie']" code => "event.append(Hash[@kname.zip(event['message'].split('`'))]) " remove_field => ["@version","_score","id","tags","key","message","http_deviceid","http_x_up_calling_line_id","","cookie"] } if [front] { grok { match => ["front","%{HTTPDATE:logdate}"] } date { match => ["logdate", "dd/MMM/yyyy:HH:mm:ss Z"] target => "@timestamp" remove_field => ["front","logdate"] } } if [request] { ruby { init => "@kname = ['method','uri','verb']" code => "event.append(Hash[@kname.zip(event['request'].split(' '))])" remove_field => [ "request","method","verb"] } } if [remote_addr_1] { grok { match => [ "remote_addr_1", "%{IPV4:remote_addr}" ] remove_field => ["remote_addr_1"] } } mutate { convert => [ "body_bytes_sent" , "integer", "status" , "integer", "request_time" , "float" ] } } output { elasticsearch { hosts => ["10.39.40.94:9200","10.39.40.95:9200","10.39.40.96:9200","10.39.40.97:9200"] workers => 1 index => "logstash-cms-nginx-%{+YYYY.MM.dd.hh}" } #stdout { codec => dots #workers => 5 #} #测试性能时使用 #stdout { codec => rubydebug } #调试时使用 } 启动命令:./bin/logstash -w 4 -b 1000 -f /etc/logstash/conf.d/kafka_logstash_cms_nginx.conf & -w 后面的worker数是根据cpu的核心数大概算一下,我这里一台服务器开三个logstash,每一个起4个worker
配置文件看着很长,其实阅读性很好,很易懂上手编写,无非就是定义切割点,若是大切割点下须要继续切割,就加if判断,继续切割,吐个槽里面threads和workers的数量好像无论用,我压测时去看线程数对不上,看的方法是top -H -p logstash的pid。
再就是看看哪些须要计算的变成数字型,还有个timestamp的处理,这个能够看看上面的代码,对于nginx打印的时间符合ISO8601标准,能够用他作es的时间索引,这样有个好处,若是某个环节慢索引赶不上的话,日志不会错序。时间标准详细可见:http://udn.yyuap.com/doc/logstash-best-practice-cn/filter/date.html
备注:
a、尽可能去掉没用的字段,精简索引,很是重要;
b、nginx打印出来的时间是标准化的,能够用它传到es做为timestamp建索引;
c、对于响应时间、响应内容大小、状态码要转换成数字类型,方便在kibana里作计算等操做;
d、切割双引号可使用以下配置
code => "event.append(Hash[@kname.zip(event['message'].split(34.chr))])"
e、抓包后发现,logstash向es推数据是轮训的,从zookeeper取broker的相关信息并不轮训,最终logstash从zookeeper只是拿到broker的信息,而后到kafka的broker上进行数据消费读取。
f、尽可能按照官方以下写法创建多个索引向es推送,防止单个索引巨大,search时计算不出来
index => "logstash-cms-nginx-%{+YYYY.MM.dd.hh}"
g、测试性能方法以下
因为没有现成工具,咱们用了打点计量的方式进行压测,摘掉es后将输出变为一个点,每处理一条信息打一个点,而后将打出的点用pv命令统计出字节流量,反推出logstash的吞吐量。
cp一个配置文件,修改output以下:
output { stdout { codec => dots workers => 1 } }
同时为了避免影响线上业务,修改group_id,这样的话测试消费和线上消费互不影响,配置文件修改以下:
kafka { zk_connect => "10.13.88.190:2181,10.13.88.191:2181,10.13.88.192:2181" topic_id => "nginx" group_id => "test001" consumer_threads => 12 reset_beginning => false decorate_events => flase }
测试时执行命令:/opt/logstash/bin/logstash -f /tmp/kafka_test.conf |pv -abt > /dev/null
压测结果以下:
每一个点是一个byte,等到数据稳定后,计算每s的吞吐量为2.93*1024=3000,也就是这一个logstash最大吞吐量为能处理3000条信息每s。
4、索引(es)
ES升级调优5.2.1详见博文:**ELK之ES2.4.1双实例平滑升级调优至5.2.1踩坑并supervisor管理记**
ES工做原理及集群调优见博文:**深刻浅出剖析Elasticsearch的工做原理**
线上业务最先使用的是es2.x版本,后来升级到了es5.x版本,变化是比较大的,不少配置点都不同了,但道法天然而术变万千,不论是哪一个版本,全部的调整中遵循着不变的法则,从中总结概括,其实分为下面几个层次:
一、系统层:
HEAP、GC、文件描述符、进程数调整、关闭交换分区、进程管理最大内存、系统内存回收机制调优。
二、结构层:
a、master、client节点分离;
b、冷、热数据分群,共用一个client管理。
三、业务层:
a、index调优(复制分片数、shard数、刷新时间)
b、flush调优(translog控制flush频率、同步异步)
c、merge调优(segment相关参数、触发条件)
d、空闲时间强制merge(减小segment的数量)
e、内存请求熔断调优(fielddata、request内存)
f 、数据保留7天,限制查询1天(开关索引实现)
g、跟进官方新版本,并及时升级。
四、硬调优:
a、磁盘换ssd。
es的安装也是比较简单详见:https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html
es的节点类型相关说明详见:https://my.oschina.net/secisland/blog/618911
经常使用es的集群管理命令,固然只是看信息的能够浏览器里直接输入查看
curl http://10.39.40.94:9200/_cat/nodes?v #节点概况 curl http://10.39.40.94:9200/_cat/shards?v #查看shards的信息 curl http://10.39.40.94:9200/_cat/indices?v #查看索引信息,若是新推的日志,能够看这个确认是否索引成功 curl -X DELETE "http://10.39.40.94:9200/索引名称" #删除指定历史索引,速度很快
对于咱们线上的日志,默认保存7天,天天晚上清除一次,并关索引,仅能查看一天的日志数据,清除的脚本以下:
#!/bin/bash DATE=`date +%Y.%m.%d.%I` DATA1=`date +%Y.%m.%d -d'-2 day'` DATA2=`date +%Y.%m.%d -d'-7 day'` curl -XPOST -u elastic:elastic "http://10.39.40.94:9220/logstash*${DATA1}*/_close?pretty" curl -XDELETE -u elastic:elastic "http://10.39.40.97:9220/logstash*${DATA2}*?pretty"
5、展示(kibana)
展示kibana没什么可说的,直接安装后,配置好es的地址就能够用,安装很简单有rpm包,前端能够用nginx作个代理,作限制,安装详见:https://www.elastic.co/downloads/kibana
安装后模型搭建也比较人性化,用几回就熟练了。
备注:像logstash、kafka这种加&号启动的服务(有些启动后本身fork新进程而后退出的其实不合适)能够用supervisor管理,比较方便。配置至关简单,能够在浏览器看状态,后使用supervisor monitor统一管理,截屏以下: