在生產環境中, 要保證服務在各種極限情況下的穩定和高可用, 所以在部署ES叢集時, 需要考慮伺服器的記憶體、CPU、磁碟, 叢集的網路、節點個數, 並且要優化JVM的各項引數. 首先從這些方面著手進行部署前的規劃.
1 伺服器的記憶體
ES非常消耗記憶體 —— 不是JVM用到的記憶體, 而是機器的實體記憶體, 因為ES在執行期間對JVM Heap(堆記憶體)的需求較小.
ES底層是基於Lucene建立的, 而Lucene是基於磁碟中的檔案來讀寫和儲存索引資料(包括倒排索引、正排索引);
Lucene的特點是基於OS File System Cache(作業系統的檔案快取系統), 它會盡可能地把頻繁訪問的磁碟檔案快取在作業系統的記憶體中, 從而提高對磁碟檔案的讀寫效能.
關於Lucene的更多資料, 可參考: https://www.cnblogs.com/shoufeng/category/1259723.html.
可以這樣說: ES的效能很大程度上(80%)取決於分配給JVM Heap記憶體之後、伺服器的剩餘記憶體大小.
—— 這些剩餘記憶體會快取Lucene的索引檔案, 快取的越多, 索引的讀寫效能都越高, 尤其是檢索和聚合操作, 它們需要讀取幾乎所有的索引資料.
實踐建議: 資料量過億, 建議單臺伺服器的記憶體至少要有64GB.
2 伺服器的CPU
ES叢集對CPU的要求比較低, 一般來說2~8個CPU Core即可滿足叢集的需求.
實踐建議: 儘可能使用多核處理器, 因為併發處理能力會更好.
3 伺服器的磁碟
ES生產環境中, 磁碟的讀寫能力是非常重要的, 尤其對於大量寫操作的叢集, 比如電商公司將每天的實時日誌資料以高併發的方式寫入ES叢集.
(1) 在磁碟的使用上, 推薦使用SSD(固態硬碟), 而不是(HDD)機械硬碟.
使用SSD, 就需要配置SSD的I/O Scheduler —— 資料寫入磁碟時, IO Scheduler會決定將資料從OS Cache刷入到磁碟的時機.
大部分SSD的預設IO Scheduler是CFQ (completely fair queuing), 它會為每個程式都分配一些時間片(time slice), 然後通過磁碟的物理佈局來決定如何將資料寫入磁碟 (對各個程式的資料寫入進行優化), 進而提升寫入磁碟的效能.
但是預設的CFQ並不高效. 對SSD來說, 推薦使用Deadline/Noop Scheduler, 它基於寫操作被Pending的時間長短來進行寫磁碟優化, 而Noop Scheduler就是一個簡單的FIFO(先進先出)佇列機制.
(2) 此外, 使用RAID 0
也是一種提升磁碟讀寫速度的高效方式, 無論是HDD, 或者SSD都支援RAID 0.
RAID 0也被稱之為條帶式(striping)儲存機制, 在RAID各種級別中效能是最高的, 它的基本原理是:
把連續的資料分散儲存到多個磁碟上進行讀寫, 也就是對資料進行條帶式儲存 —— 磁碟的讀寫請求被分散到多個磁碟上並行執行.
沒有必要使用映象或者RAID的其他模式, 因為我們並不需要通過RAID來實現資料的高可用儲存 —— 這方面的工作ES的Replica副本機制已經實現了.
(3) 最後, 要避免使用與網路相關的儲存模式 (network-attached storage, NAS), 比如基於網路的分散式儲存模式.
雖然很多供應商都說他們的NAS解決方案效能非常高, 而且比本地儲存的可靠性更高, 但在實際使用上還是會有很多風險: 網路傳輸可能存在比較高的時延, 還可能存在單點故障.
實踐建議: 推薦使用SSD, 並調整其IO Scheduler為Deadline/Noop Scheduler, 這可以帶來很大的效能提升, 理想情況下可能達到上百倍.
4 叢集的網路
對ES這種分散式系統來說, 快速可靠的網路是非常重要的:
高速網路通訊可以讓ES節點間的通訊時延降低;
高頻寬可以讓Shard的移動、恢復, 以及分配等操作更加快速.
不低於千兆網路卡對大多數叢集來說都已足夠, 但要避免一個叢集橫跨多個資料中心, 比如異地多機房部署一個叢集 —— 跨地域跨機房會降低網路通訊和資料傳輸的效率.
① ES叢集是一種p2p模式的分散式系統架構, 並不是master-slave主從分散式系統.
② ES叢集中, 所有節點都是平等的, 任意兩個節點之間的通訊都很頻繁, 如果部署在異地多機房, 就會導致各個節點之間頻繁跨地域通訊, 通訊時延會非常高, 甚至有可能造成叢集執行頻繁出現異常.
③ 與NAS儲存模式一樣, 很多供應商都聲稱他們的跨地域多資料中心是可靠、低時延的, 即使果真如此, 一旦網路出現故障, 整個叢集就會不可用. 大多數情況下, 跨地域多機房部署一個ES叢集帶來的效益要遠遠低於維護這類叢集所付出的額外成本.
實踐建議: 不低於千兆網路卡, 且不要垮多個資料中心, 尤其不要跨地域多機房.
5 叢集的節點個數
ES叢集的節點個數:
① 建議部署少個節點, 但每個節點對應伺服器的資源都必須充足;
② 不建議在一臺高效能伺服器上部署多個節點: 不僅降低了叢集的可用性, 而且叢集的維護複雜度也變得更高了.
儘量避免部署大量的低資源的伺服器, 因為對運維和管理而言, 管理5個物理機組成的叢集, 要比管理10個虛擬機器組成的叢集要簡單簡單太多.
實踐建議: 小規模、高配置, 但無需超高配置, 會造成資源的浪費.
6 JVM的引數設定
ES的版本越新, 使用的JDK的版本也應該越新, 既提高效能, 也避免一些不常見的系統Bug(包括Lucene和JDK的).
以本系列博文為例, 示例的ES版本為6.6.0, 使用的JDK版本是jdk1.8.0_151
.
(1) 如果通過Java API操作ES服務, 那麼編譯Java程式的JVM版本最好與ES伺服器所執行的JVM版本一致.
ES中用到了很多與JVM版本相關的特性, 比如本地序列化機制 (包括IP地址、異常資訊等等), 而JVM在不同的minor版本中可能會修改序列化機制, 版本不同可能會導致序列化異常.
(2) 同時官方強烈建議: 不要隨意調整JVM的引數設定.
ES是一個非常複雜的分散式軟體系統, 它預設的JVM配置經過了大量真實業務場景下的檢驗, 除非你很明確地知道自己的服務瓶頸出在哪幾個引數上, 否則不要調整.
ES服務中, JVM Heap堆記憶體的大小一般不超過伺服器實體記憶體的一半, 以1/4為宜, 且最多不宜超過32GB.
7 叢集的資料量
對很多中小型公司, 建議ES叢集承載的資料量在百億級規模以內.
(1) ES的常見使用場景有:
① 構建業務搜尋功能模組, 且多是垂直領域的搜尋: 以網站或APP為例, 資料規模相對比較大, 通常是百萬級到億級;
② 進行資料分析: 需要消耗更大的記憶體, 但支援的資料規模要小很多, 通常是十萬級到千萬級;
③ 用於大規模資料的實時OLAP(聯機處理分析), 經典的如ELK Stack, 資料規模可能達到千億或更多, 叢集規模可能達到幾十上百節點.
(2) 資料量特別大時的處理思路:
如果應用的資料量特別大, 日增量幾十上百萬, 那就不建議將資料全量寫入ES中, ES也不適合這種資料無限膨脹的場景 —— ES消耗記憶體, 無限膨脹的資料量會導致無法提供足夠的記憶體來支撐大規模資料的快速檢索.
此時可以考慮: 將部分熱資料 (比如最近一月的資料) 存放到ES中做高頻高效能搜尋, 將大量的、較少訪問的冷資料存放至大資料系統 (比如Hadoop) 中做離線批量處理.
不同資料規模與記憶體容量下的檢索效能表現: 如果伺服器的記憶體可以將ES所需的檔案全部納入到OS Cache中, 就能達到ms(毫秒)級的檢索效能; 否則檢索會大量訪問磁碟, 檢索時間就會上升到s(秒)級.
8 總結
要提升ES的效能, 最重要的是規劃合理的資料量, 配置足夠的實體記憶體用作OS Cache, 儘可能減少從磁碟中訪問資料.
版權宣告
出處: 部落格園 馬瘦風的部落格(https://www.cnblogs.com/shoufeng)
感謝閱讀, 如果文章有幫助或啟發到你, 點個[好文要頂?] 或 [推薦?] 吧?
本文版權歸博主所有, 歡迎轉載, 但 [必須在文章頁面明顯位置標明原文連結], 否則博主保留追究相關人員法律責任的權利.