ELK-Elaticsearch 集羣篇

重要配置項的修改

Elasticsearch 已經有了 很好 的默認值, 特別是涉及到性能相關的配置或者選項。 如果你有疑問,最好就不要動它。

官方已經目睹了數十個因爲錯誤的設置而導致毀滅的集羣, 因爲它的管理者總認爲改動一個配置或者選項就可以帶來 100 倍的提升。

其它數據庫可能需要調優,但總得來說,Elasticsearch 不需要。 如果你遇到了性能問題,解決方法通常是更好的數據佈局或者更多的節點。 在 Elasticsearch 中很少有“神奇的配置項”, 如果存在,官方也已經幫你優化了!

下面有些 邏輯上的 配置在生產環境中是應該調整的。 這些調整可能會讓你的工作更加輕鬆,又或者因爲沒辦法設定一個默認值(因爲它取決於你的集羣佈局)。

下面的需要修改的配置項均在 elasticsearch.yml 文件中修改。


指定集羣名字

Elasticsearch 默認啓動的集羣名字叫 elasticsearch 。 你最好給你的生產環境的集羣改個名字,改名字的目的很簡單, 就是防止某人的筆記本電腦加入了集羣這種意外。

官方建議,簡單修改成 elasticsearch_production 會很省心。

cluster.name: elasticsearch_production

指定節點名字

同樣,最好也修改你的節點名字。

因爲,Elasticsearch 會在你的節點每次啓動的時候隨機給它指定一個名字。

這樣就是導致羣集每次在啓動的時候,節點會得到一個新的名字。這會使日誌變得很混亂,因爲所有節點的名稱都是不斷變化的。

建議給每個節點設置一個有意義的、清楚的、描述性的名字:

node.name: elasticsearch_005_data

指定相關路徑

默認情況下, Elasticsearch 會把插件、日誌以及你最重要的數據放在安裝目錄下。這會帶來不幸的事故, 如果你重新安裝 Elasticsearch 的時候不小心把安裝目錄覆蓋了。如果你不小心,你就可能把你的全部數據刪掉了。

最好的選擇就是把你的數據目錄配置到安裝目錄以外的地方, 同樣你也可以選擇轉移你的插件和日誌目錄。

path.data: /path/to/data1,/path/to/data2 

# Path to log files:
path.logs: /path/to/logs

# Path to where plugins are installed:
path.plugins: /path/to/plugins
  • 注意:你可以通過逗號分隔指定多個目錄。

數據可以保存到多個不同的目錄, 如果將每個目錄分別掛載不同的硬盤,這可是一個簡單且高效實現一個軟磁盤陣列( RAID 0 )的辦法。

集羣優化

elasticsearch節點怎麼脫離集羣初始化?
index.number_of_shards: 1
index.number_of_replicas: 0
2個屬性會禁用分佈式,這兩個屬性的設置直接影響集羣中索引和搜索操作的執行

關於性能和安全的提示

Elasticsearch 試圖將全部的條帶化分片放到單個驅動器來保證最小程度的數據丟失。這意味着 分片 0 將完全被放置在單個驅動器上。 Elasticsearch 沒有一個條帶化的分片跨越在多個驅動器,因爲一個驅動器的損失會破壞整個分片。

這對性能產生的影響是:如果您添加多個驅動器來提高一個單獨索引的性能,可能幫助不大,因爲 大多數節點只有一個分片和這樣一個積極的驅動器。多個數據路徑只是幫助如果你有許多索引/分片在單個節點上。


設置最新主節點數

minimum_master_nodes 設定對你的集羣的穩定 極其 重要。

當你的集羣中有兩個 masters(注:主節點)的時候,這個配置有助於防止 腦裂 。

如果你的集羣發生了腦裂,那麼你的集羣就會處在丟失數據的危險中,因爲主節點被認爲是這個集羣的最高統治者,它決定了什麼時候新的索引可以創建,分片是如何移動的等等。如果你有 兩個 masters 節點, 你的數據的完整性將得不到保證,因爲你有兩個節點認爲他們有集羣的控制權,就會導致衝突。

此設置應該始終被配置爲 master 候選節點的法定個數(大多數個)。法定個數就是 ( master 候選節點個數 / 2) + 1 。 這裏有幾個例子:

  • 如果你有 10 個節點(能保存數據,同時能成爲 master),法定數就是 6 。
  • 如果你有 3 個候選 master 節點,和 100 個 data 節點,法定數就是 2 ,你只要數數那些可以做 master 的節點數就可以了。
  • 如果你有兩個節點,你遇到難題了。法定數當然是 2 ,但是這意味着如果有一個節點掛掉,你整個集羣就不可用了。 設置成 1 可以保證集羣的功能,但是就無法保證集羣腦裂了,像這樣的情況,你最好至少保證有 3 個節點。

建議這樣配置:

discovery.zen.minimum_master_nodes: 2

但是由於 ELasticsearch 是動態的,你可以很容易的添加和刪除節點, 但是這會改變這個法定個數。 你不得不修改每一個索引節點的配置並且重啓你的整個集羣只是爲了讓配置生效。

解決辦法是同時添加如下的配置項:

PUT /_cluster/settings
{
    "persistent" : {
        "discovery.zen.minimum_master_nodes" : 2
    }
}

這個配置允許通過 API 調用的方式動態進行配置。

==這將成爲一個永久的配置,並且無論你配置項裏配置的如何,這個將優先生效。==

==當你添加和刪除 master 節點的時候,你需要通過 API 的方式更改這個配置。==


關於集羣恢復涉及到的配置

當你集羣重啓時,幾個配置項影響你的分片恢復的表現。 首先,我們需要明白如果什麼也沒配置將會發生什麼。

想象一下假設你有 10 個節點,每個節點只保存一個分片,這個分片是一個主分片或者是一個副本分片,或者說有一個有 5 個主分片/1 個副本分片的索引。當處於某種原因,你不得不暫時關閉所有集羣節點,之後再重新啓動所有節點。

就在你重啓所有節點的過程中,不管處於什麼原因,恰巧有 5 個節點沒有和其他 5 個節點同時啓動。
這時,你會有 5 個節點在線上,這五個節點會相互通信,選出一個 master,從而形成一個集羣。 他們注意到數據不再均勻分佈,因爲有 5 個節點在集羣中丟失了,所以他們之間會立即啓動分片複製。

最後,你的其它 5 個節點打開加入了集羣。這些節點會發現 它們 的數據正在被複制到其他節點,所以他們刪除本地數據(因爲這份數據要麼是多餘的,要麼是過時的)。 然後整個集羣重新進行平衡,因爲集羣的大小已經從 5 變成了 10。

在這整個過程中,你的節點會消耗磁盤和網絡帶寬,來回移動數據,因爲沒有更好的辦法。對於有 TB 數據的大集羣, 這種無用的數據傳輸需要 很長時間 。

假如等待所有的節點都重啓好了,整個集羣的相關功能再上線,這樣所有的本地的數據就都不需要移動了。

所以我們可以做一些配置來來緩解這種情況的發生。

  • 對於上面的情況,首先我們要給 ELasticsearch 一個 嚴格 的限制:
gateway.recover_after_nodes: 8

這個值的設定取決於個人喜好:整個集羣提供服務之前你希望有多少個節點在線?
這裏我們設置爲 8,這意味着至少要有 8 個節點(數據節點或者 master 節點)在線,該集羣纔可用,才進行數據恢復。

  • 此外,我們還需要告訴 elasticsearch 集羣中的每個成員,該集羣應該有多少個節點,以及我們願意等待這些節點恢復在線狀態,付出多少時間。
gateway.expected_nodes: 10
gateway.recover_after_time: 5m

這意味着 Elasticsearch 會採取如下操作:

等待集羣至少存在 8 個節點
等待 5 分鐘,或者10 個節點上線後,才進行數據恢復,這取決於哪個條件先達到。
這三個設置可以在集羣重啓的時候避免過多的分片交換。這可能會讓數據恢復從 數個小時 縮短爲 幾秒鐘。

gateway.expected_nodes
預計在羣集中的(數據或主節點)數量。一旦預期的節點數量加入到羣集中,本地碎片的恢復就會開始。默認爲0
gateway.expected_master_nodes
預計將在羣集中的主節點的數量。當主節點加入集羣時,本地碎片的恢復將立即開始。默認爲0
gateway.expected_data_nodes
預計將在羣集中的數據節點的數量。只要預期的數據節點已加入羣集,就會立即恢復本地碎片。默認爲0
gateway.recover_after_time
如果未達到預期的節點數量,則無論恢復嘗試恢復,恢復過程都會等待配置的時間量。默認爲5m如果expected_nodes配置其中一個設置。

一旦recover_after_time持續時間超時,只要滿足以下條件,恢復就會開始:

gateway.recover_after_nodes   #只要這麼多數據或主節點已加入羣集,就可以進行恢復。
gateway.recover_after_master_nodes  # 只要這麼多的主節點已經加入羣集就可以恢復。
gateway.recover_after_data_nodes  # 只要這麼多的數據節點已經加入羣集就可以恢復

==注意:這些配置只能設置在 config/elasticsearch.yml 文件中或者是在命令行裏(它們不能動態更新)它們只在整個集羣重啓的時候有實質性作用。==

  • 故障檢測,集羣中 master 是如何確認其他成員存活的

一種是 master 主動 ping 各個成員
一種是 各個成員主動確認自己還活着

以下設置使用discovery.zen.fd前綴控制故障檢測過程 :

設置 描述
ping_interval 一個節點多久被ping一次。默認爲1s。
ping_timeout 等待ping響應需要多長時間,默認爲 30s。
ping_retries 有多少ping故障/超時會導致節點被視爲失敗。默認爲3。

使用單播代替組播編輯

Elasticsearch 默認被配置爲使用單播發現,以防止節點無意中加入集羣。只有在同一臺機器上運行的節點纔會自動組成集羣。

雖然組播仍然 作爲插件提供, 但它應該永遠不被使用在生產環境了,否在你得到的結果就是一個節點意外的加入到了你的生產環境,僅僅是因爲他們收到了一個錯誤的組播信號。

使用單播,你可以爲 Elasticsearch 提供一些它應該去嘗試連接的節點列表。 當一個節點聯繫到單播列表中的成員時,它就會得到整個集羣所有節點的狀態,然後它會聯繫 master 節點,並加入集羣。

這意味着你的單播列表不需要包含你的集羣中的所有節點, 它只是需要足夠的節點,當一個新節點聯繫上其中一個並且說上話就可以了。如果你使用 master 候選節點作爲單播列表,你只要列出三個就可以了。

這個配置可以配置成下面的樣子:

discovery.zen.ping.unicast.hosts: ["host1", "host2:port"]

不需要修改的配置

在 Elasticsearch 中有一些熱點,人們可能不可避免的會碰到。 我們理解的,所有的調整就是爲了優化,但是這些調整,你真的不需要理會它。因爲它們經常會被亂用,從而造成系統的不穩定或者糟糕的性能,甚至兩者都有可能。


垃圾回收器( GC )

Elasticsearch 默認的垃圾回收器( GC )是 CMS。 這個垃圾回收器可以和應用並行處理,以便它可以最小化停頓。 然而,它有兩個 stop-the-world 階段,處理大內存也有點吃力。

儘管有這些缺點,它還是目前對於像 Elasticsearch 這樣低延遲需求軟件的最佳垃圾回收器。官方建議使用 CMS。

現在有一款新的垃圾回收器,叫 G1 垃圾回收器( G1GC )。 這款新的 GC 被設計,旨在比 CMS 更小的暫停時間,以及對大內存的處理能力。 它的原理是把內存分成許多區域,並且預測哪些區域最有可能需要回收內存。通過優先收集這些區域( garbage first ),產生更小的暫停時間,從而能應對更大的內存。

遺憾的是,G1GC 還是太新了,經常發現新的 bugs。這些錯誤通常是段( segfault )類型,便造成硬盤的崩潰。 Lucene 的測試套件對垃圾回收算法要求嚴格,看起來這些缺陷 G1GC 並沒有很好地解決,還不能足夠穩定的滿足 Elasticsearch 和 Lucene 的要求。


線程池

許多人 喜歡 調整線程池。 無論什麼原因,人們都對增加線程數無法抵抗。索引太多了?增加線程!搜索太多了?增加線程!節點空閒率低於 95%?增加線程!

Elasticsearch 默認的線程設置已經是很合理的了。對於所有的線程池(除了 搜索 ),線程個數是根據 CPU 核心數設置的。 如果你有 8 個核,你可以同時運行的只有 8 個線程,只分配 8 個線程給任何特定的線程池是有道理的。

搜索線程池設置的大一點,配置爲 int(( 核心數 * 3 )/ 2 )+ 1 。

大多數 I/O 的操作是由 Lucene 線程管理的,而不是 Elasticsearch。

此外,線程池通過傳遞彼此之間的工作配合。你不必再因爲它正在等待磁盤寫操作而擔心網絡線程阻塞, 因爲網絡線程早已把這個工作交給另外的線程池,並且網絡進行了響應。

最後,你的處理器的計算能力是有限的,擁有更多的線程會導致你的處理器頻繁切換線程上下文。 一個處理器同時只能運行一個線程。所以當它需要切換到其它不同的線程的時候,它會存儲當前的狀態(寄存器等等),然後加載另外一個線程。 如果幸運的話,這個切換髮生在同一個核心,如果不幸的話,這個切換可能發生在不同的核心,這就需要在內核間總線上進行傳輸。

這個上下文的切換,會給 CPU 時鐘週期帶來管理調度的開銷;在現代的 CPUs 上,開銷估計高達 30 μs。也就是說線程會被堵塞超過 30 μs,如果這個時間用於線程的運行,極有可能早就結束了。

人們經常稀裏糊塗的設置線程池的值。8 個核的 CPU,我們遇到過有人配了 60、100 甚至 1000 個線程。 這些設置只會讓 CPU 實際工作效率更低。

所以,下次請不要調整線程池的線程數。如果你真 想調整 , 一定要關注你的 CPU 核心數,最多設置成核心數的兩倍,再多了都是浪費。

堆內存: 大小 和 交換

就是 java 虛擬機的內存設置。
最新版的 5.x 設置堆內存是在 jvm.options 文件中:

下面的是默認值 2 G

-Xms2g
-Xmx2g

==確保堆內存最小值( Xms )與最大值( Xmx )的大小是相同的,防止程序在運行時改變堆內存大小, 這是一個很耗系統資源的過程==

官方建議通過設置環境變量來設置這個值:

export ES_HEAP_SIZE=10g
  • 把你的內存的(少於)一半給 Lucene編輯

假如,不會有剩餘的內存交給 Lucene。 這將嚴重地影響全文檢索的性能。

==如果你不需要對分詞字符串做聚合計算(例如,不需要 fielddata )可以考慮降低堆內存。堆內存越小,Elasticsearch(更快的 GC)和 Lucene(更多的內存用於緩存)的性能越好。==

不用分配大於 32 G的內存給 Elasticsearch

這裏有另外一個原因不分配大內存給 Elasticsearch。事實上 , JVM 在內存小於 32 GB 的時候會採用一個內存對象指針壓縮技術。

一旦你越過那個神奇的 ~32 GB 的邊界,指針就會切回普通對象的指針。 每個對象的指針都變長了,就會使用更多的 CPU 內存帶寬,也就是說你實際上失去了更多的內存。事實上,當內存到達 40–50 GB 的時候,有效內存才相當於使用內存對象指針壓縮技術時候的 32 GB 內存。

這段描述的意思就是說:即便你有足夠的內存,也儘量不要 超過 32 GB。因爲它浪費了內存,降低了 CPU 的性能,還要讓 GC 應對大內存。


我有一個 1 TB 內存的機器!

這個 32 GB 的分割線是很重要的。那如果你的機器有很大的內存怎麼辦呢? 一臺有着 512–768 GB內存的服務器愈發常見。

首先,我們建議避免使用這樣的高配機器(參考 硬件)。

但是如果你已經有了這樣的機器,你有三個可選項:

1. 你主要做全文檢索嗎?考慮給 Elasticsearch 4 - 32 GB 的內存, 讓 Lucene 通過操作系統文件緩存來利用餘下的內存。那些內存都會用來緩存 segments,帶來極速的全文檢索。

2. 你需要更多的排序和聚合?而且大部分的聚合計算是在數字、日期、地理點和 非分詞 字符串上?你很幸運,你的聚合計算將在內存友好的 doc values 上完成! 給 Elasticsearch 4 到 32 GB 的內存,其餘部分爲操作系統緩存內存中的 doc values。

3. 你在對分詞字符串做大量的排序和聚合(例如,標籤或者 SigTerms,等等)不幸的是,這意味着你需要 fielddata,意味着你需要堆空間。考慮在單個機器上運行兩個或多個節點,而不是擁有大量 RAM 的一個節點。仍然要堅持 50% 原則。

假設你有個機器有 128 GB 的內存,你可以創建兩個節點,每個節點內存分配不超過 32 GB。 也就是說不超過 64 GB 內存給 ES 的堆內存,剩下的超過 64 GB 的內存給 Lucene。

如果你選擇這一種,你需要配置

cluster.routing.allocation.same_shard.host: true 。

這會防止同一個分片(shard)的主副本存在同一個物理機上(因爲如果存在一個機器上,副本的高可用性就沒有了)

Swapping 是性能的墳墓

有必要說的更清楚一點:內存交換 到磁盤對服務器性能來說是 致命 的。想想看:一個內存操作必須能夠被快速執行。

如果內存交換到磁盤上,一個 100 微秒的操作可能變成 10 毫秒。 再想想那麼多 10 微秒的操作時延累加起來。 不難看出 swapping 對於性能是多麼可怕。

最好的辦法就是在你的操作系統中完全禁用 swap。這樣可以暫時禁用:

sudo swapoff -a

如果需要永久禁用,你可能需要修改 /etc/fstab 文件,這要參考你的操作系統相關文檔。

如果你並不打算完全禁用 swap,也可以選擇降低 swappiness 的值。 這個值決定操作系統交換內存的頻率。 這可以預防正常情況下發生交換,但仍允許操作系統在緊急情況下發生交換。

對於大部分Linux操作系統,可以在 sysctl 中這樣配置:

vm.swappiness = 1 
  • swappiness 設置爲 1 比設置爲 0 要好,因爲在一些內核版本 swappiness 設置爲 0 會觸發系統 OOM-killer(注:Linux 內核的 Out of Memory(OOM)killer 機制)。

最後,如果上面的方法都不合適,你需要打開配置文件中的 mlockall 開關。 它的作用就是允許 JVM 鎖住內存,禁止操作系統交換出去。在你的 elasticsearch.yml 文件中,設置如下:

bootstrap.mlockall: true

設置文件描述符數量

max_file_descriptors 字段顯示 Elasticsearch 進程可以訪問的可用文件描述符數量。

Elasticsearch 對各種文件混合使用了 NioFs( 注:非阻塞文件系統)和 MMapFs ( 注:內存映射文件系統)。請確保你配置的最大映射數量,以便有足夠的虛擬內存可用於 mmapped 文件。這可以暫時設置:

sysctl -w vm.max_map_count=262144
或者你可以在 /etc/sysctl.conf 通過修改 vm.max_map_count 永久設置它。

部署之後

動態更新集羣的相關設置

Elasticsearch 裏很多設置都是動態的,可以通過 API 修改。需要強制重啓節點(或者集羣)的配置修改都要極力避免。 而且雖然通過靜態配置項也可以完成這些變更,我們建議你還是用 API 來實現。

集羣更新 API 有兩種工作模式:

臨時(Transient)
這些變更在集羣重啓之前一直會生效。一旦整個集羣重啓,這些配置就被清除。
永久(Persistent)
這些變更會永久存在直到被顯式修改。即使全集羣重啓它們也會存活下來並覆蓋掉靜態配置文件裏的選項。

臨時或永久配置需要在 JSON 體裏分別指定:

PUT /_cluster/settings
{
    "persistent" : {
        # 這裏面的設置項會永久生效
        "discovery.zen.minimum_master_nodes" : 2 
    },
    "transient" : {
        # ;這裏面的設置之會臨時生效
        "indices.store.throttle.max_bytes_per_sec" : "50mb" 
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章