ELK體系大型日誌分析集羣方案設計.搭建.調優.管理

最新記錄:11臺ES(12核64G機械盤),天天日誌量在37.4億條,Primary Shard大小1.7T,最高索引速度每秒8萬左右。php

圖片.png

   此文爲原標題「玩兒透日誌分析集羣搭建.調優.管理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

QQ截圖20170906181720.png 

工做中對不一樣場景的各類架構進行了梳理,詳見博文:運維數據分析平臺建設的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:elk日誌收集之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遠遠是沒問題的

QQ截圖20170620165111.png

備註: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的狀態,執行結果以下:

wKiom1iAezLzwcflAAAlWrHKv18771.png

腳本內容以下:

#!/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

壓測結果以下:

wKiom1h_UVHyuE0MAAASrG8qSoo997.png

每一個點是一個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統一管理,截屏以下:

圖片.png

原文地址

相關文章
相關標籤/搜索