ELK的心臟,ElasticSearch學習方法論


寫在前面css

從初次瞭解elastic產品到正式投入使用,拖拖拉拉的也有小半年了,剛接觸的時候看到一些帖子都是安裝教程,後來看到一些都是深刻教程,此篇文章較居中一點,總結了我在踩的一些坑和記錄一些周邊插件的使用方式、方法,便於本身後續回顧,也但願能給新用戶一些引導,少走一些彎路;核心實際上是想表達一下對rockybean和KennyW的愛,這期間很是感謝兩位的協助,在非工做日深夜排查問題屢次,正文多處採用二位給予的講解,萬分感謝。

ElasticSearch簡介

  • 基於Lucene構建的分佈式,RESTful搜索和分析引擎;
  • 實時搜索、分析,穩定,可靠,快速;
  • JAVA編寫,開源,使用JSON開源經過HTTP來索引數據;

項目介紹

  • 歷史:
    由前同事工做交接,原有一套ES1.7集羣,可是常常jvm跑滿致使集羣不可用,沒有ES調優經驗,甚至沒有使用經驗,從零瞭解ES,過分版本ES5.3~5.6;
  • 背景:
    數據源主要是Nginx訪問日誌,因爲Nginx是集羣,相應的日誌分佈落在每臺機器上,當對總體日誌作一些數據分析、故障排查等,因數據分散且量很大,經過腳本已經不能作分析處理了,爲了對Nginx日誌作全文搜索、分析,實時監控等,因此踏上ELK之路;
  • 數據量:
    天天6-7T,Docs在100億左右

架構圖

圖片描述

第一部分:日誌收集(Nginx + Rsyslog)

  • 採用Nginx內置的syslog模塊,每臺機器啓用本地的rsyslog,經過UDP方式傳輸本地的514端口(Rsyslog),而後Rsyslog在將數據轉發至Kafka;
  • 選型比較:日誌收集有不少種方式,如flume、filebeat、lua腳本等,可是這些組件都須要額外安裝客戶端,而rsyslog在linux都集成了。簡單對比過Rsyslog和其餘區別,首先在Nginx中的syslog對於一個更改相對靈活,JSON日誌與落地日誌毫無干系(目前是兩份格式:人肉讀取的本地日誌格式,機器讀取JSON網絡傳輸格式),日誌輸出直接經過網絡傳輸走(網絡消耗很低)不受本地磁盤影響,對不一樣的server_name或location等能夠靈活的修改,總之控制權在Nginx手裏,Nginx的維護同窗就能夠自定義源數據格式,管理成本相對較低;
  • Rsyslog配置(雙打Kafka)
    現有的版本是0.8,而剛開始測試的用logstash5.x須要kafka0.10(最終hangout替換logstash),因此新搭建了一組新的集羣,Rsyslog向兩個Kafka集羣分別寫數據,配置以下html

    Module (load="imudp")
    Module (load="omkafka")
    Input (type="imudp" port="514")
    Module (load="mmsequence")
    $MaxMessageSize 4k
    
    local5.none /var/log/messages
    local5.none @log.domain.com:514
    set $!newmsg = replace($msg,'\\x','\\u00')
    
    template(name="kafka_topic" type="string" string="%programname%")
    template(name="kafka_msg" type="string" string="%!newmsg%")
    if ($syslogfacility-text == 'local5' and $syslogseverity-text == 'info') then{
    
    action(type="omkafka" topic="kafka_topic" partitions.auto="on"
    dynatopic="on" dynatopic.cachesize="1000"
    confParam=["compression.codec=snappy"]
    #kafka broker addr
    broker=["10.10.10.1:9092","10.10.10.2:9092",]
    template="kafka_msg"
    errorfile="/var/log/omkafka/log_kafka_failures.log")
    
    action(type="omkafka" topic="kafka_topic" partitions.auto="on"
    dynatopic="on" dynatopic.cachesize="1000"
    confParam=["compression.codec=snappy"]
    #kafka broker addr
    broker=["20.20.20.1:9092","20.20.20.2:9092",]
    template="kafka_msg"
    errorfile="/var/log/omkafka/log_kafka_failures.log")
    
    stop
    }
    複製代碼
  • 配置Nginx JSON格式日誌java

    log_format json_format  '{"@timestamp":"$time_iso8601",'
            '"cookie_id":"$cookie_id",' #內部cookie_id
            '"client_ip":"$remote_addr",'
            '"remote_user":"$remote_user",'
            '"request_method":"$request_method",'
            '"domain":"$host",'
            '"user_agent":"$http_user_agent",'
            '"xff":"$http_x_forwarded_for",'
            '"upstream_addr":"$upstream_addr",'
            '"upstream_response_time":"$upstream_response_time",'
            '"request_time":"$request_time",'
            '"size":"$body_bytes_sent",'
            '"idc_tag":"tjtx",'
            '"cluster":"$host_pass",'
            '"status":"$status",'
            '"upstream_status":"$upstream_status",'
            '"host":"$hostname",'
            '"via":"$http_via",'
            '"protocol":"$scheme",'
            '"request_uri":"$request_uri",'
            '"http_referer":"$http_referer"}';複製代碼
  • Nginx內置syslog模塊配置,而且引用剛剛定義的json日誌格式node

    access_log syslog:local5:info:127.0.0.1:514:nginx_aggregation_log json_format;
    #nginx_aggregation_log   這是自定義的Topic複製代碼

    NginxSyslog模塊介紹
    圖片描述linux

    注:

    1) UDP傳輸雖快,可是以太網(Ethernet)數據幀的長度必須在46-1500字節之間,UDP不能像TCP重組數據包,去除IP和UDP的數據包,最終可以使用只剩1472字節。若是傳輸大於這個長度的消息,並不會想UDP自己同樣直接丟棄,只是會損壞源數據格式,截斷超過限制字節之外的數據;
    2) 對於Nginx日誌來講,只要不保留POST數據,基本一條消息不會超過限制字節,我在NginxSyslog介紹中沒看到支持TCP,用lua腳本實現的TCP方式傳輸,可是看了不少帖子都不建議在Nginx中用TCP日誌傳輸。就是由於TCP傳輸可靠,但像網絡抖動、傳輸異常,可能會不停的重試屢次或等待,直接影響這條請求,也直接影響到了用戶;
    3) 消息超過了UDP傳輸限制怎麼辦,我這目前是保留一條消息的重要字段,如上述的json_format的格式,將 request_uri、http_referer等可能會較大的字段放到最後,若是真的發現消息不完整,直接丟棄http_referer,取request_uri問號前的內容;(在logstash或hangout中filters實現,具體配置詳見下文Hangout-filters)ios

第二部分-存儲中間件(Kafka)

  • Kafka性能很強,順序寫入磁盤,高吞吐量的分佈式發佈訂閱消息系統
  • Kafka一直不是瓶頸,也沒太多深刻優化,Topic數據保留了12小時,副本爲1
  • 針對不一樣的Topic,對Partition的數量有稍微改變,目前是5臺服務器,以前簡單測過增長Partition的性能,從八、1六、3二、64增長來看,明顯狀況就是Partition增長,CPU使用也會隨之增長,由於kafka自己不是瓶頸,其餘明顯問題也未遇到;
  • 目前這邊最大的Topic是一天近5T數據,64Partition沒有任何問題,部分小的Topic都是16Partitio,Kafka整個集羣的CPU空閒都在80%以上,內存、IO均無壓力,後續也考慮縮減機器。這邊的kafka團隊有個建議值,供你們參考:【天天數據規模小於50G選擇4分區、50G且小於100G選擇8分區、大於100G且小於500G選擇16分區、大於500G,選擇24分區】
  • Kafka監控插件:kafka-monitorkafka-managernginx

    注:
    目前咱們這kakfa集羣是kafka_2.10-0.8.1.1版本,可是logstash5.x對kafka有版本要求>0.10版本。後來採用hangout,更換了幾個jar包解決了此問題git

第三部分-數據搬運工(Hangout)

  • 模仿logstash作的一個應用,功能沒有logstash多,可是基本使用都有了,java編寫,性能能夠翻好幾倍,用到的功能就是從kafka訂閱消息,作一些簡單的過濾,而後寫入ES;目前hangout部署到2臺服務器上,每一個進程開8G內存,CPU在60-70左右;github

    inputs:
       - Kafka:
        topic: 
            nginx_aggregation_log: 32
        codec: 
            json
        consumer_settings:
            group.id: es-nginx_aggregation_log
            zookeeper.connect: "10.10.10.1:2181,10.10.10.2:2181"
            auto.commit.interval.ms: "20000"
            socket.receive.buffer.bytes: "1048576"
            fetch.message.max.bytes: "1048576"
            num.consumer.fetchers: "1"
    filters:
       - Filters:
       if:
            - '<#if message??>true</#if>' 
            #若是不是完整的JSON,會出現message,則走此邏輯
       filters:
           - Grok:
               match:
                 - '(?<msg>{"@timestamp":.*"request_uri":([^\?]+)\?)'
                 #正則匹配@timestamp開始到request_uri後邊的第一個?截止
           - Gsub:
               fields:
                   msg: ['$','"}']
                   #補全符號,完整新的JSON格式
           - Json:
               field: msg
               remove_fields: ['message'] 
               #幹掉錯誤的數據
    - Convert:
        fields:
            request_time:
                to: float
                remove_if_fail: true
            upstream_response_time:
                to: float
                remove_if_fail: true
            size:
                to: integer
                remove_if_fail: true
    - GeoIP2:
        source: client_ip
        database: '/opt/soft/hangout/etc/other/GeoLite2-City.mmdb'
        - Json:
             field: geoip
    - Remove:
            fields:
                - msg
    - Add:
           fields:
              request_url: '<#assign a=request_uri?split("?")>${a[0]}'
              #request_uri這個term的cardinality很高,因此?前用於聚合,原有的用於搜索
           if:
             - '<#if request_uri??>true</#if>'
    outputs:
    - Elasticsearch:
    cluster: es-nginx
    timezone: "Asia/Shanghai"
    hosts: "10.10.10.1:9300,10.10.10.2:9300"
    index: 'hangout-nginx_aggregation_log-%{+YYYY.MM.dd}'
    複製代碼
  • Hangout進程管理工具(supervisord
    主要是守護hangout進程,在web界面對hangout進行啓、停、重啓等操做
  • topic: nginx_aggregation_log: 32,不管是logstash仍是hangout都有這個概念,這個32表明須要創建多少子線程去kafka讀取數據,數量最好與Partition相等,若是少於Partition,會一個線程同時去2個Partition讀取消息,若大於Partition則會有不工做的進程web

第四部分-Elasticsearch(後面簡稱ES)

  • 硬件環境

    CPU:32C,內存:128G ,硬盤:STAT 6T * 12,網卡:萬兆
    複製代碼
  • 軟件環境:

    【系統】: Centos7 內核3.10
    【JDK】: 1.8.0_66/31G (聽說此版本JDK有BUG,請安裝最新JDK)
    【系統參數修改1】: vm.swappiness=1 [下降對硬盤的緩存]
    【系統參數修改2】: vm.max_map_count=262144 [Elasticsearch針對各類文件使用NioFS和MMapFS的混合。以便有足夠的虛擬內存可用於mmapped文件] 複製代碼
  • ES配置文件

    cluster.name: es-nginx
    node.name: 10.10.10.1 
    
    #爲後期冷熱數據使用
    node.attr.rack_id: hdd 
    path.data: /data 
    path.logs: /opt/logs/elasticsearch/
    network.host: 0.0.0.0 
    http.port: 9200
    
    #設置新節點被啓動時可以發現的主節點列表
    discovery.zen.ping.unicast.hosts: ["10.10.10.1","10.10.10.2","10.10.10.3"]
    
    #防止腦裂(n/2+1)
    discovery.zen.minimum_master_nodes: 2
    node.master: true
    node.data: false複製代碼
  • ES跳入的第一坑:node.master與node.data同時服務

    剛剛開始測試ES的第一個版本是ES5.3,先搞了3臺機器,每一個機器一個節點,配置是master和data共同提供服務,高可用架構集羣搭建完成,可是寫入性能特別差,cpu使用在20-30%,少許io.wait,下圖是當時3w左右的性能圖圖片描述當時以爲既然ES硬件很空閒必定是logstash出問題了,查看logstash確實有很嚴重的Full GC,開始從2臺服務器擴至4臺服務器,後來發現無果,期間各類調整ES的shard的數量都沒效果,又懷疑kafka性能,從二、四、六、8...64分區依舊無果。當時這個坑可爬了一段時間,後來在Google的遊蕩中無心中看到帖子說,不要將master和data都啓用,而後我照着作了改變,master單點,data兩臺,問題搞定,效果圖找不到了,起碼翻倍是有的;

    [Master除了網卡,其餘沒什麼消耗]
    
    複製代碼
  • template

    因shard數量、字段類型、其餘設置等都是都是在建立時生成,因此要提早建立好相應的模板,便於規範管理和引用,下面針對shard和aliases作的一些設置,以下:

    {
          "template": "agg-nginx-*",
          "aliases": {  
            "agg-nginx": {}  
          },
          "settings": {
            "number_of_shards": 4,
            "number_of_replicas": 1,
            "index.routing.allocation.include.rack_id": "ssd"
          }複製代碼

經過上述配置PUT到 _template/ur_name下在分片上的定義已經成功,可是像agg-nginx-

和test-agg-test-
這樣的2個索引名字,即便你建立了另外一個"template": "agg-nginx-test-*"的模板依舊都匹配第一個,固然換名字最簡單有效,在template的order的是專門解決這個問題的。默認建立"order": "0",值越高優先級越高,因此在想要先匹配的將order值調高便可

  • mapping

    ES的mapping很是相似於靜態語言中的數據類型:聲明一個變量爲int類型的變量, 之後這個變量都只能存儲int類型的數據。一樣的, 一個number類型的mapping字段只能存儲number類型的數據。同語言的數據類型相比,mapping還有一些其餘的含義,mapping不只告訴ES一個field中是什麼類型的值, 它還告訴ES如何索引數據以及數據是否能被搜索到

    下列是一個刪減版的mapping複製代碼
    "mappings": {
        "ngx_log": {
           "_all": {
            "enabled": false
          },
          "properties": {
            "@timestamp": {
              "type": "date"
            },
            "client_ip": {
              "type": "ip"
            },
            "domain": {
              "type": "keyword"
            },
            "geoip": {
              "properties": {
                "city_name": {
                  "type": "keyword"
                },
                "country_name": {
                  "type": "keyword"
                },
                "latitude": {
                  "type": "float"
                },
                "location": {
                  "type": "geo_point"
                },
                "longitude": {
                  "type": "float"
                },
              }
            },
    
            "request_time": {
              "type": "float"
            },
            "request_url": {
              "type": "keyword"
            },
            "status": {
              "type": "keyword"
      ype": "keyword" }, } } }複製代碼
  1. _all字段
    該_all字段是一個特殊的catch-all字段,它將全部其餘字段的值鏈接成一個大字符串,使用空格做爲分隔符,而後對其進行分析和索引,但不存儲。也就是說它能被查詢,但不能被取回顯示。由於Nginx每一個Key對應的value都是提早定義好的,因此不用全文查詢,不須要開啓_all字段,另外也節省了一半的存儲空間

  2. 默認的text類型
    圖片描述上邊這英文有點多,其實簡單理解就是不分詞,你就最好別用text了,並且Text類型也會相應的多佔用空間,依照上述,數據主要是日誌分析,每條數據的格式已經很明確,主要用於日誌分析,因此不須要分詞。像一些全部引擎的業務更適合須要分詞;

  3. 好比說像這個字段,get_ip中location這個字段類型默認text,可是若是不指定geo_point類型,根本沒法使用地圖功能,類型的指定是很重要的
  4. 向request_time這樣的數據類型須要作計算,好比說平均值、和、大於、小於等等的,默認的text也能使用,可是效率遠遠小於float類型
  5. 字段類型有不少種,什麼IP啊、DATE啊等等,根據相應的須要去官網查看詳解吧,mapping-types介紹
  • shard & replicas

    [摘取部分蘇若年博客內容]
    1)分片算法:
    shard = hash(routing) % number_of_primary_shards
    routing值是一個任意字符串,它默認是_id但也能夠自定義,這個routing字符串經過哈希函數生成一個數字,而後除以主切片的數量獲得一個餘數(remainder),餘數的範圍永遠是0到number_of_primary_shards - 1,這個數字就是特定文檔所在的分片。

    這也解釋了爲何主切片的數量只能在建立索引時定義且不能修改:若是主切片的數量在將來改變了,全部先前的路由值就失效了,文檔也就永遠找不到了。

    全部的文檔API(get、index、delete、bulk、update、mget)都接收一個routing參數,它用來自定義文檔到分片的映射。自定義路由值能夠確保全部相關文檔.好比用戶的文章,按照用戶帳號路由,就能夠實現屬於同一用戶的文檔被保存在同一分片上。


    2)分片與副本交互:

    新建、索引和刪除請求都是寫(write)操做,它們必須在主分片上成功完成才能複製到相關的複製分片上,下面咱們羅列在主分片和複製分片上成功新建、索引或刪除一個文檔必要的順序步驟:

    一、客戶端給Node 1發送新建、索引或刪除請求。

    二、節點使用文檔的_id肯定文檔屬於分片0。它轉發請求到Node 3,分片0位於這個節點上。

    三、Node 3在主分片上執行請求,若是成功,它轉發請求到相應的位於Node 1和Node 2的複製節點上。當全部的複製節點報告成功,Node 3報告成功到請求的節點,請求的節點再報告給客戶端。

    客戶端接收到成功響應的時候,文檔的修改已經被應用於主分片和全部的複製分片。你的修改生效了。

    一個索引要分多少片?何時該擴容?
    取決於硬件和你對響應速度的要求,通常來講一個shard的數據量控制在一、2千萬的級別,速度都還好,過億會比較緩慢。 可是任何事物都有兩面,shard劃分比較小,必然數量就比較多。 在用戶作一、2天數據搜索的時候可能還好,若是搜更長時間的數據,一次搜索須要並行搜索的shard就比較多。若是節點數量有限,就會比較吃力,須要擴充更多的節點

  • routing

    聽說是優化之王道,常常拿城市舉的例子,好比說我想看下網站的北京pv是多少,若是按照默認hash邏輯,必定要全shard掃描,而後聚合結果,可是若是提早設置好routing,好比說指定城市字段作hash計算,routing值同樣的放到特定幾個分片,這樣查起來也不須要全shard掃了;這樣弊端就是會形成shard大小不均,因此routing優化須要花一些功夫來觀察、測試;目前kibana還不支持routing查詢,因此目前在kibana上尚未使用routing,這是優化的重點因此先記錄下來。後續個人想法是,像nginx日誌的域名的字段都是英文字母,針對首字母作下routing,當想看某一個域名時不在全盤掃,查詢優化會有明顯效果,後續有結果在與你們分享;
    另外hangout開始對routing的支持,後來在GitHub提了一個小issue,很快就加上了,點個贊;

第五部分-Kibana圖形展現

Kibana是一個開源的分析與可視化平臺,設計出來用於和Elasticsearch一塊兒使用的。你能夠用kibana搜索、查看、交互存放在Elasticsearch索引裏的數據,使用各類不一樣的圖表、表格、地圖等kibana可以很輕易地展現高級數據分析與可視化。
先介紹下幾塊功能:

  • X-pack能夠無償使用部分功能,最強就是monitoring功能了,基本重要指標都收集了
  • Dev_tools的代碼補全神器,相似於IDE;還有強勁的可視化Search Profiler,便於直接定位問題點
  • 其餘就是經常使用的Discover、Visualize、Dashboard、Timelion搜索和繪圖功能了,沒有找到合適的帖子,直接吧迷妹兒的帖子放過來吧,主要介紹了如何優雅的使用kibana的搜索框
  • 還有就是Elastic官方提供了一個Demo,便於你們作圖形展現的時候參考和借鑑

(╯﹏╰)吐槽一下,用SF寫到如今,Chrome都快無法用了,打完字一會才顯示出來

  • 直接上幾張最終成果圖吧

  • [QPS展現]
    QPS展現
  • [QPS環比]
    圖片描述
  • [異常狀態碼趨勢]
    圖片描述
  • [慢請求QPS]
    圖片描述
  • [狀態碼比例]
    狀態碼比例
  • [Domin與URL TOP]
    圖片描述
  • 再來一張深夜[熱圖],北京和上海的孩子老是不碎覺
    圖片描述
  • 上圖中環比圖是Timelion完成的,其餘都是Visualize的功能
    Timelion語法:

    .es(index=index1,timefield=@timestamp).label('Today').title(QPS).color(#1E90FF), 
    .es(offset=-24h,index=index2,timefield=@timestamp).label('Yesterday').lines(fill=1,width=0.5).color(gray)複製代碼
  • kibana認證問題
    因爲x-pack試用版將認證功能被閹割掉了,直接暴露內容太風險,因此利用Nignx插件auth_basic的功能,作了一個簡單驗證模塊

最後調優

核心問題:查詢慢、查詢15Min數據都超時

  • 數據量:
    天天數據在6-7T,Docs在100億左右,其中一個大的索引在4-5T
  • ES升級
    版本升級會帶來一些新特性,以及一些bug修復,固然也會引起新問題,我就踩到了新版本的坑;
    ES5.x升級到5.5是滾動升級,相對升級步驟簡單,可是因爲數據太大,動輒幾十T,一臺臺完成升級,倒是一個漫長的過程。另外,1.x升級聽說很痛苦,有興趣的去看看,鏈接放在這裏reindex-upgrade
    簡述下5.x升級的過程
    1)關掉分片自動分配:"cluster.routing.allocation.enable": "none"
    2)強制刷新,儘量將緩存中的數據,寫入磁盤: _flush/synced
    3)中止一個節點,開始升級及升級插件,而後啓動
    4)打開分片自動分配:"cluster.routing.allocation.enable" :"all"
    5)等待集羣恢復至綠色,繼續下一臺
  • 擴容
    擴容很簡單,沒什麼可說的,除了配置文件中node.name不同,其餘都同樣;
    最初擴容只是將data節點從3臺擴至20臺,寫入沒問題,1-2k的數據,單機性能寫入在30-40k;

  • mapping字段優化:

    主要像上述的mapping介紹,作類型優化,不分詞的keyword,數學計算的改爲整型or浮點等

    status這個字段的類型,value通常都是200、30一、30二、40四、502,最多估計也就幾百個,像這樣的字段就不適合作long,long類型的索引是爲範圍查找優化的,用的是二叉樹這樣的索引,適合值範圍比較大的字段,好比body_size,可能最大值和最小值相差不少,而用keyword索引是倒排,只用存放一個全部status的詞典,因此keyword更適合

  • shard數量調整:

    開始主分片數量是每臺機器1個,副本1(20shard x 1replicas),每一個shard已經達到將近200G,看這個量級已經超過官方建議值30~50G之間(具體要根據實際狀況測試爲準)。因而開始將數量翻倍40shard * 1replicas,調整後查詢並無明顯改善,對寫入沒有什麼改變,繼續double,依舊沒效並且分片越多,寫入的時候消耗的CPU就越高

    若是過分分配shard,就增大了Lucene在合併分片查詢結果時的複雜度,從而增大了耗時,在新建索引時,更是一筆大的開銷。
    通常來講,剛開始的時候儘可能少分片爲佳, 只有到一個分片上數據太多,單次查詢太慢在考慮加分片。
    加分片也有負面做用,提升了併發量,隨之開銷就會越大,更多的shard通常也伴隨更多的segment文件。若是說節點數量沒變,每一個節點上會有更多的小文件,搜索的時候併發量是高了,前提是在磁盤io和cpu都還能應付的過來的時候,速度纔會快


  • 拆分索引
    更改shard已經得不到顯著效果,因而從拆索引下手。數據都是Nginx日誌,從源頭拆分沒什麼好的方法,因而從hangout這層開始作處理,很簡單就是將域名的第一個字母取出來,寫入相應的索引時候帶過去,例如:nginx-log-{首字母},這樣一拆,一下建立26個索引(shard20 * 1replicas),CPU立馬load 30+,負載直接上來,而後ES數據還跟不上,拒絕了不少內容,以下圖,最終仍是無果而了結此方案
    圖片描述

    上述的索引拆分是比較傻瓜式,首先已知的問題就是可能A開頭的域名很大,其餘很小就是很不均勻

  • Pcle-SSD測試
    通過上面的折騰,已經沒有什麼突破點,因而借用了8臺SSD的機器,修改ES配置node.attr.rack_id: ssd,將數據寫入SSD,全程io無壓力,寫入一個一天4-5T的索引,CPU在50%左右,可是查詢依舊不給力,通過無數shard調整依舊不給力,IO一直沒空閒,最終結論就是沒有將ssd的性能發揮出來,仍是未解決根本問題
  • kibana BUG
    以前沒有ES相關經驗,能想到的辦法、關注點都沒有什麼在突破的地方了,在一籌莫展的時候,又很是有幸認識了KennyW,再次感謝KennyW的支持;問題根本緣由是kibana5.4-5.5這兩個版本在查詢問題,爲了節省空間,我關掉了_all這個字段,若是搜索框不輸入內容的時候,則會補充*查詢全部字段,生成的bool條件就很是多,引起kibana的缺陷,引用:
    圖片描述
    當時的版本KennyW給的知道是臨時修復方法以下:圖片描述
    詳細問題請看這裏ES 5.4+ 引發的Kibana性能問題,Kibana5.5.2後已經修復此問題,因此最終版本仍是升級到了5.6,也是目前的最新版
  • 迴歸HDD
    通過SSD的折騰,查到了kibanaBug問題,其實SSD並未發現其餘的性能亮點,通過與KennyW的交流,他們本身有作過在SSD和多塊HDD的盤對比,寫入量並沒有明顯提高,因此在磁盤並非真正的瓶頸,查詢方面SSD明顯提升。可是SSD的高額付出換來那麼幾秒鐘的意義不大。相對,對一些公司的搜索業務,數據量級小,還有像一些監控業務,要求實時性很是高,對SSD是很好的選擇,速度快,容量不須要太多,也比較經濟實惠

    [KennyW經驗指導]
    當作複雜計算,bucket不少的時候主要消耗的是CPU和內存,磁盤並非瓶頸,hdd和ssd在咱們實際用下來,感受在大數據場景分別不大,ssd優點在大量的隨機磁盤io,ES自己作了不少優化,讓數據變成順序的磁盤訪問,並且搜索過的數據塊,ES都能利用文件系統緩存加速,因此即便使用hdd,可能第一次搜索磁盤訪問會帶來額外的幾秒耗時,但屢次執行同一個搜索時,後面幾回幾乎沒什麼磁盤io開銷,速度會有明顯提高

  • RAID0的重要性
    當全部的集羣所有更改回hdd的集羣時候,發現一個以前沒太關注的指標,每塊盤的利用率。剛開始解決的時候咱們的機器都是裸盤直接掛上,path.data:data1,data2,data...這樣掛載,可是在5.x版本發現這樣磁盤問題(CMD:iostat -x 1)圖片描述這樣看來很奇怪,爲何這塊盤這麼忙,多觀察一會發現,一會又發現其餘的盤又很忙,而後df查看磁盤使用率,扎心了
    圖片描述掛了這麼多盤,真實寫入連一半的盤都不到,既然這樣,沒得說的了,直接上raid0吧
  • 收尾
    作到目前這些調整,如今一天小於1T的索引任何查詢都沒有問題,查詢在10s左右返回全部數據(上圖kibana展現),可是那個一天4-5T的索引仍是有問題,一查詢IO就跑滿,到30s直接超時了,先說下IO跑滿的問題吧,問題是request_uri臺過於分散,聚合出現問題如圖:15分鐘就出現了2000多萬不一樣值,若是長時間計算,不可想象的恐怖
    圖片描述

    【KennyW指導】
    request_uri 會產生大量的磁盤IO。 ES作terms聚合的時候,爲了節省內存,不會將全部term的內容直接讀出來作bucket,由於有些term的內容可能很長,會比較耗費內存。 因此他會藉助一種叫作oridinals的數據結構, 這種數據結構相似這樣
    1 abc
    2 efg
    3 hfa
    .............

    一個該字段全部不一樣值的順序列表。 作分桶聚合的時候,只須要拿這個順序數字作key就能夠了,等聚合出結果,再經過這個key查ordinals表,獲得實際的key值填充結果。 可是這個ordinals是隨着segment 文件生成的,每一個segment文件的ordinals順序可能不同。 所以在聚合的時候,須要一個全局的global ordinals。 這個數據結構是在聚合的時候,實時生成後緩存在內存裏的。 若是某個字段的不一樣值很是多,計算價值很是的昂貴,那麼這個構造過程就很是的緩慢,除了大量的磁盤IO消耗,還會有很大的內存消耗。

    下圖是關掉這個有問題的visualize先後對比圖,雖然不快,可是latency降了不少圖片描述
    後來對uri的?後邊的參數所有丟棄,像這樣的問題只能減小而後作聚合使用,原有數據作搜索使用,可是因爲數據太大,作複雜計算仍是會超時30s,這種狀況只能是下降team的cardinality,或者加分片、加機器或者拆索引了,因此對kibana的超時時間作了一點調整,還有一些周邊小的修改以下
    1)kibana默認的30s超時改爲2min,kibana.yml中修改
    elasticsearch.requestTimeout: 120000
    2)kibana默認地圖使用高德,kibana.yml中新增
    tilemap.url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'
    3)結合cerebro插件,高效管理索引

後續

到這裏基本的一期項目算是結束,雖然部分查詢並無迅速返回,可是基本數據均可以展現,後續會關注幾個點繼續深刻優化和調整,有結果在與你們分享

  • routing優化查詢
  • curator管理過時索引
  • 比較大index索引作拆分
  • 增長client節點,減小集羣影響
  • 冷熱數據分離(node.attr.rack)、按期對冷數據force_merge,優化查詢速度

總結

首先在這裏仍是先要感謝rockybean和KennyW的大力支持。
對本身的總結就是,對ES經驗太少,踩了不少沒必要要的坑,另外就是沒有好好統一閱讀下官網文檔,這樣極其影響效率與進度,好多時候也會一籌莫展,不知從何下手。
第一次寫技術帖,並且時間稍緊,有哪些地方寫的很差或敏感煩請指出,我會及時更正。但願這篇文章,能給予像我這樣的小白用戶少踩一點坑,多一點愛。

文章有點長,你們以爲做者總結的還能夠,能夠關注一下做者的公衆號《Java技術zhai》,公衆號聊的不只僅是Java技術知識,還有面試等乾貨,後期還有大量架構乾貨。你們一塊兒關注吧!關注技術zhai,你會了解的更多..............

相關文章
相關標籤/搜索