簡單ELK配置實現生產級別的日誌採集和查詢實踐

概述

生產問題

  • 集群規模如何規劃?
  • 集群中節點角色如何規劃?
  • 集群之腦裂問題如何避免?
  • 索引分片如何規劃?
  • 分片副本如何規劃?

集群規劃

  • 準備條件
    • 先估算當前系統的數據量和數據增長趨勢情況。
    • 現有伺服器的配置如CPU、記憶體、磁碟類型和容量的了解。
  • 建議設置
    • ElasticSearch推薦的最大JVM堆空間是30~32G,一般可以設置為30Gheap ,大概能處理的數據量 10 T。單個索引數據量建議不超過5T,如果有100T數據量可以部署20個節點。
    • 官方建議:節點分片最好按照JVM記憶體來進行計算,每Gb記憶體可以為20個分片,假設我們的JVM設置為30G,那麼分片數據量最大600個。如果分片數量就是非常多,那麼整個集群分片數量最好不要超過10萬。
    • 集群規劃滿足當前數據規模+一定估算適量增長規模,後續再按需擴展即可。
  • 業務場景
    • 用於構建垂直領域的搜索的業務搜索功能,一般的數據量級幾千萬到數十億量級,需要部署3-5台ES節點的規模。
    • 用於大規模數據的實時OLAP(聯機處理分析),經典的如ELK Stack,數據規模可能達到千億或更多,這是可能需要幾十到上百ES節點的規模。

集群角色

ES為了處理大型數據集,實現容錯和高可用性,ES可運行多伺服器組成分散式環境下也稱為集群;集群內的節點的cluster.name相同,形成集群的每個伺服器稱為節點。ES 為分配不同的任務,定義了以下幾個節點角色:Master,Data Node,Coordinating Node,Ingest Node:

  • 主節點(Master Node):主要職責是負責集群層面的相關操作,管理集群變更,如創建或刪除索引,跟蹤哪些節點是群集的一部分,並決定哪些分片分配給相關的節點。

    • 主節點也可作為數據節點,但穩定的主節點對集群的健康是非常重要的,默認情況下任何一個集群中的節點都有可能被選為主節點,索引數據和搜索查詢等操作會佔用大量的cpu、記憶體、io資源,為了確保集群穩定,特別是非小型規模的集群(如10台以內)分離主節點和數據節點是推薦做法。
    • 通過配置node.master:true(默認)使節點具有被選舉為Master的資格。主節點全局唯一併從有資格成為Master的節點中選舉。
    # 設置如下,後續所有節點設置可以通過這三個切換配置
    node.master: true
    node.data: false
    node.ingest: false
    
  • 數據節點(Data Node):主要是存儲索引數據的節點,執行數據相關操作:CRUD、搜索,聚合操作等。

    • 數據節點對cpu,記憶體,I/O要求較高, 在優化的時候需要監控數據節點的狀態,當資源不夠的時候,需要在集群中添加新的節點。
    • 通過配置node.data: true(默認來是一個節點成為數據節點)。
  • 預處理節點(Ingest Node):預處理操作運行在索引文檔之前,即寫入數據之前,通過事先定義好的一系列processors(處理器)和pipeline(管道),對數據進行某種轉換。

    • processors和pipeline攔截bulk和index請求,在應用相關操作後將文檔傳回給index或bulk API。
    • 如果想在某個節點上禁用ingest,則可以配置node.ingest: false。
  • 協調節點(Coordinating Node):作為處理客戶端請求的節點,只作為接收請求、轉發請求到其他節點、匯總各個節點返回數據等功能的節點;客戶端請求可以發送到集群的任何節點(每個節點都知道任意文檔的位置),節點轉發請求並收集數據返回給客戶端。

    • 協調節點將請求轉發給保存數據的數據節點,每個數據節點則先在本地執行請求,並將結果返回給協調節點。協調節點收集完每個節點的數據後將結果合併為單個全局結果,在這過程中的結果收集和排序可能需要很多CPU和記憶體資源。
    • 上述三個節點角色配置為false則為協調節點。

一個節點可以充當一個或多個角色,默認三個角色都有。

  • 集群角色建議設置
    • 小規模集群,基本不需嚴格區分。
    • 中大規模集群(十個以上節點),應考慮單獨的角色充當。特別並發查詢量大,查詢的合併量大,可以增加獨立的協調節點。角色分開的好處是分工明確,互不影響。

腦裂問題

所謂腦裂問題,就是同一個集群中的不同節點,對於集群的狀態有了不一樣的理解,比如集群中存在兩個master,正常情況下我們集群中只能有一個master節點。如果因為網路的故障,導致一個集群被劃分成了兩片,每片都有多個node,以及一個master,那麼集群中就出現了兩個master了。但是因為master是集群中非常重要的一個角色,主宰了集群狀態的維護,以及shard的分配,因此如果有兩個master,可能會導致數據異常

  • 建議設置
    • 至少配置3個節點為主節點。
    • Master 和 dataNode 角色分開,配置奇數個master,如3 、5、7。
    • 添加最小數量的主節點配置,在elasticsearch.yml中配置屬性:discovery.zen.minimum_master_nodes,這個參數作用是告訴es直到有足夠的master候選節點支援時,才可以選舉出一個master,否則就不要選舉出一個master。官方的推薦值公式為:master候選資格節點數量 / 2 + 1,並在所有有資格成為master的節點都需要加上這個配置。例如在3個節點,三台主節點通過在elasticsearch.yml中配置discovery.zen.minimum_master_nodes: 2,就可以避免腦裂問題的產生。

索引分片

分片數指定後不可變,除非重索引,分片對應的存儲實體是索引,分片並不是越多越好,分片多浪費存儲空間、佔用資源、影響性能。

  • 分片過多的影響:
    • 每個分片本質上就是一個Lucene索引, 因此會消耗相應的文件句柄, 記憶體和CPU資源。
    • 每個搜索請求會調度到索引的每個分片中. 如果分片分散在不同的節點倒是問題不太. 但當分片開始競爭相同的硬體資源時, 性能便會逐步下降。
    • ES使用詞頻統計來計算相關性. 當然這些統計也會分配到各個分片上. 如果在大量分片上只維護了很少的數據, 則將導致最終的文檔相關性較差。
  • 建議設置
    • 每個分片處理數據量建議在30G-50G,如果是商品類搜索場景推薦使用低值30G,然後再對分片數量做合理估算. 例如數據能達到200GB, 推薦分片最多分配5-7分片左右。
    • 開始階段也可先根據節點數量按照1.5~3倍的原則來創建分片. 例如,如果你有3個節點, 則推薦你創建的分片數最多不超過9(3×3)個。當性能下降時,增加節點,ES會平衡分片的放置。
    • 對於基於日期的索引需求, 並且對索引數據的搜索場景非常少. 也許這些索引量將達到成百上千, 但每個索引的數據量只有1GB甚至更小. 對於這種類似場景, 建議只需要為索引分配1個分片。如日誌管理就是一個日期的索引需求,日期索引會很多,但每個索引存放的日誌數據量就很少。

分片副本

副本數是可以隨時調整的,副本的作用是備份數據保證高可用數據不丟失,高並發的時候參與數據查詢。

  • 建議設置
    • 一般一個分片有1-2個副本即可保證高可用,副本過多浪費存儲空間、佔用資源和影響性能。
    • 要求集群至少要有3個節點,來分開存放主分片、副本。如發現並發量大時,查詢性能會下降,可增加副本數,來提升並發查詢能力;新增副本時主節點會自動協調,然後拷貝數據到新增的副本節點。

ElasticSearch部署

部署規劃

這裡我們部署一個3個節點組成的ES集群,因此也不單獨分節點類型部署,三台伺服器分別為192.168.5.52 es-node-01、192.168.5.53 es-node-02、192.168.12.27 es-node-03,作業系統版本為CentOS 7.8。

部署方式

官網支援二進位部署,也支援使用Docker和K8S部署方式,這裡我們使用二進位部署方式,使用最新版本8.2.3

# 官方下載
wget //artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.2.3-linux-x86_64.tar.gz
# 三台伺服器都準備好安裝包,進行解壓
tar -xvf elasticsearch-8.2.3-linux-x86_64.tar.gz
# 進入ES目錄,ES安裝包已自帶的JDK17,無需單獨下載安裝JDK

image-20220627172526243

前置配置

在每一台伺服器上先做下面環境設置

  • 創建用戶(基於安全考慮ES默認不能用root啟動)
# 創建es用戶
useradd es
# 授權es用戶
chown -R es:es elasticsearch-8.2.3
  • 調整進程最大打開文件數數量
vim /etc/security/limits.conf
# 直接末尾添加限制
es soft nofile 65536
es hard nofile 65536
  • 調整進程最大虛擬記憶體區域數量
echo vm.max_map_count=262144>> /etc/sysctl.conf
sysctl -p
  • 防火牆設置,我這裡就簡單停掉防火牆,線上環境則根據埠進行相應防火牆規則配置
systemctl stop firewalld
systemctl disable firewalld
  • 添加伺服器名解析
cat > /etc/hosts << EOF
192.168.5.52 es-node-01
192.168.5.53 es-node-02
192.168.12.27 es-node-03
EOF

配置文件

先創建logs和data目錄;ES的集群名稱配置一樣es-cluster,三台ES節點的node.name分別為 es-node-01、es-node-02、es-node-03,network.host配置為各自本機的IP地址。修改配置文件資訊為如下vi config/elasticsearch.yml

cluster.name: es-cluster
node.name: es-node-01
node.attr.rack: r1
path.data: /home/commons/elasticsearch-8.2.3/data
path.logs: /home/commons/elasticsearch-8.2.3/logs
network.host: 192.168.5.52
discovery.seed_hosts: ["192.168.5.52", "192.168.5.53", "192.168.12.27"]
cluster.initial_master_nodes: ["192.168.5.52", "192.168.5.53","192.168.12.27"]
xpack.security.enabled: false
xpack.security.transport.ssl.enabled: false
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization,X-Requested-With,Content-Type,Content-Length

啟動

# 依次啟動三台伺服器的ES服務
./bin/elasticsearch -d

訪問3台伺服器9200埠,//192.168.5.52:9200/ ,如果都看到如下資訊則代表ES啟動成功

image-20220627174638914

再次查看集群的健康狀態,//192.168.5.52:9200/_cat/health

image-20220627174832419

Kibana部署

下載

Kibana的版本與ES版本保持一致,也是使用最新的8.2.3。我們在192.168.5.52上部署

# Kibana下載
wget //artifacts.elastic.co/downloads/kibana/kibana-8.2.3-linux-x86_64.tar.gz
# 解壓文件
tar -xvf kibana-8.2.3-linux-x86_64.tar.gz 
# 授權
chown -R es:es kibana-8.2.3
# 進入Kibana的目錄
cd kibana-8.2.3

配置

vim config/kibana.yml

# 直接再末尾添加以下配置

# 伺服器地址
server.host: "0.0.0.0"
# ES服務IP
elasticsearch.hosts: ["//192.168.5.52:9200/"]
# 設置中文
i18n.locale: "zh-CN"

啟動

# 後台啟動kibana
nohup ./bin/kibana  > logs/kibana.log 2>&1 &

訪問Kibana控制台頁面,//192.168.5.52:5601/

image-20220627180837163

部署IK分詞器

默認分詞器是不支援中文分詞,我們可以安裝IK分詞器實現中文的分詞

# IK分詞器在GitHub上,下載最新版本8.2.0
wget //github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.2.0/elasticsearch-analysis-ik-8.2.0.zip
./bin/elasticsearch-plugin install //github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.2.0/elasticsearch-analysis-ik-8.2.0.zip
# 解壓到elasticsearch目錄下的plugins/ik目錄
unzip elasticsearch-analysis-ik-8.2.0.zip -d ./plugins/ik

由於ik的版本與ES版本不一致,修改解壓目錄到ik下的 plugin-descriptor.properties 文件中的

elasticsearch.version=8.2.3

image-20220627180516773

如果版本一致也可以直接在線安裝

./bin/elasticsearch-plugin install //github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.2.0/elasticsearch-analysis-ik-8.2.0.zip

ES索引管理

索引聲明周期策略

  • ES可用於索引日誌類數據,在此場景下,數據是源源不斷地被寫入到索引中。為了使索引的文檔不會過多,查詢的性能更好,我們希望索引可以根據大小、文檔數量或索引已創建時長等指標進行自動回滾,可以自定義將超過一定時間的數據進行自動刪除。ES為我們提供了索引的生命周期管理來幫助處理此場景下的問題。
  • 索引的生命周期分為四個階段:HOT->WARM->COLD->DELETE
    • Hot:索引可寫入,也可查詢。
    • Warm:索引不可寫入,但可查詢。
    • Cold:索引不可寫入,但很少被查詢,查詢的慢點也可接受。
    • Delete:索引可被安全的刪除。
  • 索引的每個生命周期階段都可以配置不同的個階段都可以配置不同的轉化行為(Action)。下面我們看下幾個常用的Action:
    • Rollover 當寫入索引達到了一定的大小,文檔數量或創建時間時,Rollover可創建一個新的寫入索引,將舊的寫入索引的別名去掉,並把別名賦給新的寫入索引。所以便可以通過切換別名控制寫入的索引是誰。它可用於Hot階段。
    • Shrink 減少一個索引的主分片數,可用於Warm階段。需要注意的是當shink完成後索引名會由原來的<origin-index-name>變為shrink-<origin-index-name>.
    • Force merge 可觸發一個索引分片的segment merge,同時釋放掉被刪除文檔的佔用空間。用於Warm階段。
    • Allocate 可指定一個索引的副本數,用於warm, cold階段。
  • HOT為必須的階段外,其他為非必須階段,可以任意選擇配置。在日誌類場景下不需要WARN和COLD階段,下文只配置了HOT與DELETE階段。

設置索引生命周期策略和索引模板即可以通過Kibana可視化介面設置也可以通過ES提供的Rest API介面進行設置,我們先通過Kibaba頁面來配置,首先通過點擊左側菜單的Management-Stack Management,然後左側菜單再點擊索引生命周期策略
image-20220627181243265

點擊索引生命周期策略頁面的右上角創建策略

image-20220627182820571

這裡如果是測試可以將存在時間設置為分鐘級別,便於觀察,創建完畢後查看剛創建的demo-log-policy

image-20220627183119412

也可以通過ES提供的Rest API介面進行設置,通過Kibana點擊左側菜單的Management-開發工具進入控制台tab頁,然後輸入如下生命周期設置策略,返回結果

image-20220627183244325

PUT _ilm/policy/demo-log-policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_size": "200gb",
            "max_primary_shard_size": "50gb",
            "max_age": "7d"
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "15d",
        "actions": {
          "set_priority": {
            "priority": 50
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "set_priority": {
            "priority": 0
          }
        }
      },
      "delete": {
        "min_age": "60d",
        "actions": {
          "delete": {
            "delete_searchable_snapshot": true
          }
        }
      }
    }
  }
}

索引模板

點擊索引管理-索引模板,創建模板

image-20220627190551074

驗證模板後提交查看已創建的模板,創建完成後可以通過在索引聲明周期綁定模板,也可以直接在模板里增加綁定語句設置

image-20220627190926548

當然也可以通過ES提供的Rest API介面進行設置

PUT _index_template/demo-log-template
{
  "version": 1,
  "priority": 10,
  "template": {
    "settings": {
      "index": {
        "lifecycle": {
          "name": "demo-log-policy",
          "rollover_alias": "demo-log"
        },
        "number_of_shards": "2",
        "number_of_replicas": "1"
      }
    },
    "mappings": {
      "_source": {
        "excludes": [],
        "includes": [],
        "enabled": true
      },
      "_routing": {
        "required": false
      },
      "dynamic": true,
      "numeric_detection": false,
      "date_detection": true,
      "dynamic_date_formats": [
        "strict_date_optional_time",
        "yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"
      ],
      "dynamic_templates": []
    }
  },
  "index_patterns": [
    "demo-log-*"
  ],
  "_meta": {
    "description": "測試索引模板"
  }
}

索引

先創建初始索引

PUT demo-log-000001
{
  "aliases": {
    "demo-log": {
      "is_write_index": true
    }
  }
}

image-20220627191536794

如果前面索引生命周期模板的各個周期保留時間設置較短如為分鐘,手動提交日誌到索引和查看,需要實時查看其效果則可以增加如下設置和演示操作

PUT /_cluster/settings
{
  "transient": {
    "indices.lifecycle.poll_interval": "10s" 
  }
}

POST /demo-log/_doc
{
	"message":"world2"
}

GET /demo-log/_search
{  
  "query": {
    "match_all": {}
  }
}

Logstash

修改配置和啟動,vi config/logstash.conf

input {
  beats {
    port => 5044
  }
}
output {
  elasticsearch {
    hosts => ["//192.168.5.52:9200","//192.168.5.53:9200","//192.168.12.27:9200"]
    index => "%{app_id}"
  }
}

FileBeat

FileBeat和Logstash部署和配置可以詳細查看前面的文章《數倉選型必列入考慮的OLAP列式資料庫ClickHouse(中)》,修改配置和啟動, parsers.multiline實現多行合併一行配置,比如Java異常堆棧日誌列印合併在一行。

vi filebeat.yml

filebeat.inputs:
- type: filestream
  id: demo-log
  enabled: true
  paths:
    # Filebeat處理文件的絕對路徑
    - /home/itxs/demo/logs/*.log
  # 使用 fields 模組添加欄位
  fields:
    app_id: demo-log
  # 將新增的欄位放在頂級
  fields_under_root: true
  parsers:
    - multiline:
        type: pattern
        pattern: '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}'
        negate: true
        match: after
processors:
- drop_fields:
    fields: ["log","input","agent","ecs"]

output.logstash:
  hosts: ["192.168.12.28:5044"]

採集/home/itxs/demo/logs/目錄的數據,由App產生日誌,然後通過Kibana的數據視圖-創建數據視圖,匹配我們前面創建的索引和別名

image-20220627193801129

最後通過Kibana左側菜單的Analytics-Discover選擇demo視圖然後可以搜索日誌,最後日誌查詢結果如下

image-20220627192914163

**本人部落格網站 **IT小神 www.itxiaoshen.com