前言:本文爲學習整理實踐他人成果的記錄型博客。在此統一感謝各原做者,若是你對基礎知識不甚瞭解,能夠經過查看Elasticsearch權威指南中文版, 此處注意你的elasticsearch版本,版本不同,可能有誤差
Q1: Elasticsearch是如何實現Master選舉的
- Elasticsearch的選主是ZenDiscovery模塊負責的,主要包含Ping(節點之間經過這個RPC來發現彼此)和Unicast(單播模塊包含一個主機列表以控制哪些節點須要ping通)這兩部分;
- 對全部能夠成爲master的節點(node.master: true)根據nodeId字典排序,每次選舉每一個節點都把本身所知道節點排一次序,而後選出第一個(第0位)節點,暫且認爲它是master節點。
- 若是對某個節點的投票數達到必定的值(能夠成爲master節點數n/2+1)而且該節點本身也選舉本身,那這個節點就是master。不然從新選舉一直到知足上述條件。
master節點的職責主要包括集羣、節點和索引的管理,不負責文檔級別的管理;data節點能夠關閉http功能。html
Q2: Elasticsearch是如何避免腦裂現象的
- 當集羣中master候選的個數不小於3個(node.master: true)。能夠經過discovery.zen.minimum_master_nodes這個參數的設置來避免腦裂,設置爲(N/2)+1。
這裏node.master : true 是說明你是有資格成爲master,並非指你就是master。是皇子,不是皇帝。假若有10個皇子,這裏應該設置爲(10/2)+1=6,這6個皇子合謀作決策,選出新的皇帝。另外的4個皇子,即便他們全聚一塊兒也才四我的,不足合謀的最低人數限制,他們不能選出新皇帝。假如discovery.zen.minimum_master_nodes 設置的個數爲5,有剛好有10個master備選節點,會出現什麼狀況呢?5個皇子組成一波,選一個皇帝出來,另外5個皇子也夠了人數限制,他們也能選出一個皇帝來。此時一個天下兩個皇帝,在es中就是腦裂。node
- 假如集羣master候選節點爲2的時候,這種狀況是不合理的,最好把另一個node.master改爲false。若是咱們不改節點設置,仍是套上面的(N/2)+1公式,此時discovery.zen.minimum_master_nodes應該設置爲2。這就出現一個問題,兩個master備選節點,只要有一個掛,就選不出master了。
我仍是用皇子的例子來講明。假如先皇在位的時候規定,必須他的兩個皇子都在的時候,才能從中2選1 繼承皇位。萬一有個皇子出意外掛掉了,就剩下一個皇子,天下不就沒有新皇帝了麼。linux
Q3: 客戶端在和集羣鏈接時,如何選擇特定的節點執行請求的?
- TransportClient利用transport模塊遠程鏈接一個elasticsearch集羣。它並不加入到集羣中,只是簡單的得到一個或者多個初始化的transport地址,並以 輪詢 的方式與這些地址進行通訊。
Q4: Elasticsearch 文檔索引過程描述
- 協調節點默認使用文檔ID參與計算(也支持經過routing),以便爲路由提供合適的分片。
shard = hash(document_id) % (num_of_primary_shards)api
- 當分片所在的節點接收到來自協調節點的請求後,會將請求寫入到Memory Buffer,而後定時(默認是每隔1秒)寫入到Filesystem Cache,這個從Momery Buffer到Filesystem Cache的過程就叫作refresh;
- 固然在某些狀況下,存在Momery Buffer和Filesystem Cache的數據可能會丟失,ES是經過translog的機制來保證數據的可靠性的。其實現機制是接收到請求後,同時也會寫入到translog中,當Filesystem cache中的數據寫入到磁盤中時,纔會清除掉,這個過程叫作flush。
- 在flush過程當中,內存中的緩衝將被清除,內容被寫入一個新段,段的fsync將建立一個新的提交點,並將內容刷新到磁盤,舊的translog將被刪除並開始一個新的translog。
- flush觸發的時機是定時觸發(默認30分鐘)或者translog變得太大(默認爲512M)時。
關於Lucene的segement(也就是上文中所說的段)的補充:
- Lucene索引是由多個段組成,段自己是一個功能齊全的倒排索引。
- 段是不可變的,容許Lucene將新的文檔增量地添加到索引中,而不用從頭重建索引
- 對於每個搜索請求而言,索引中的全部段都會被搜索,而且每一個段會消耗CPU的時鐘周、文件句柄和內存。這意味着段的數量越多,搜索性能會越低。
- 爲了解決這個問題,Elasticsearch會合並小段到一個較大的段,提交新的合併段到磁盤,並刪除那些舊的小段
Q5: Elasticsearch 文檔更新和刪除過程描述
- 刪除和更新也都是寫操做,可是Elasticsearch中的文檔是不可變的,所以不能被刪除或者改動以展現其變動;
- 磁盤上的每一個段都有一個相應的.del文件。當刪除請求發送後,文檔並無真的被刪除,而是在.del文件中被標記爲刪除。該文檔依然能匹配查詢,可是會在結果中被過濾掉。當段合併時,在.del文件中被標記爲刪除的文檔將不會被寫入新段。
- 在新的文檔被建立時,Elasticsearch會爲該文檔指定一個版本號,當執行更新時,舊版本的文檔在.del文件中被標記爲刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,可是會在結果中被過濾掉。
Q6: Elasticsearch搜索的過程描述
- 搜索被執行成一個兩階段過程,咱們稱之爲 Query Then Fetch
- 在初始查詢階段時,查詢會廣播到索引中每個分片拷貝(主分片或者副本分片)。 每一個分片在本地執行搜索並構建一個匹配文檔的大小爲 from + size 的優先隊列。PS:在搜索的時候是會查詢Filesystem Cache的,可是有部分數據還在Memory Buffer,因此搜索是近實時的。
- 每一個分片返回各自優先隊列中 全部文檔的 ID 和排序值 給協調節點,它合併這些值到本身的優先隊列中來產生一個全局排序後的結果列表。
- 接下來就是 取回階段,協調節點辨別出哪些文檔須要被取回並向相關的分片提交多個 GET 請求。每一個分片加載並豐富文檔,若是有須要的話,接着返回文檔給協調節點。一旦全部的文檔都被取回了,協調節點返回結果給客戶端。
Query Then Fetch的搜索類型在文檔相關性打分的時候參考的是本分片的數據,這樣在文檔數量較少的時候可能不夠準確,DFS Query Then Fetch增長了一個預查詢的處理,詢問Term和Document frequency,這個評分更準確,可是性能會變差。緩存
Q7: 在併發狀況下,Elasticsearch若是保證讀寫一致?
- 能夠經過版本號使用樂觀併發控制,以確保新版本不會被舊版本覆蓋,由應用層來處理具體的衝突;
- 另外對於寫操做,一致性級別支持quorum/one/all,默認爲quorum,即只有當大多數分片可用時才容許寫操做。但即便大多數可用,也可能存在由於網絡等緣由致使寫入副本失敗,這樣該副本被認爲故障,分片將會在一個不一樣的節點上重建。
- 對於讀操做,能夠設置replication爲sync(默認),這使得操做在主分片和副本分片都完成後纔會返回;若是設置replication爲async時,也能夠經過設置搜索請求參數_preference爲primary來查詢主分片,確保文檔是最新版本。
Q8: Elasticsearch在部署時,對Linux的設置有哪些優化方法?
- 64 GB 內存的機器是很是理想的, 可是32 GB 和16 GB 機器也是很常見的。少於8 GB 會拔苗助長。
- 若是你要在更快的 CPUs 和更多的核心之間選擇,選擇更多的核心更好。多個內核提供的額外併發遠賽過稍微快一點點的時鐘頻率。
- 若是你負擔得起 SSD,它將遠遠超出任何旋轉介質。 基於 SSD 的節點,查詢和索引性能都有提高。若是你負擔得起,SSD 是一個好的選擇。
- 即便數據中心們近在咫尺,也要避免集羣跨越多個數據中心。絕對要避免集羣跨越大的地理距離。
- 請確保運行你應用程序的 JVM 和服務器的 JVM 是徹底同樣的。 在 Elasticsearch 的幾個地方,使用 Java 的本地序列化。
- 經過設置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time能夠在集羣重啓的時候避免過多的分片交換,這可能會讓數據恢復從數個小時縮短爲幾秒鐘。
- Elasticsearch 默認被配置爲使用單播發現,以防止節點無心中加入集羣。只有在同一臺機器上運行的節點纔會自動組成集羣。最好使用單播代替組播。
- 不要隨意修改垃圾回收器(CMS)和各個線程池的大小。
- 把你的內存的(少於)一半給 Lucene(但不要超過 32 GB!),經過ES_HEAP_SIZE 環境變量設置。
- 內存交換到磁盤對服務器性能來講是致命的。若是內存交換到磁盤上,一個 100 微秒的操做可能變成 10 毫秒。 再想一想那麼多 10 微秒的操做時延累加起來。 不難看出 swapping 對於性能是多麼可怕。
- Lucene 使用了大量的文件。同時,Elasticsearch 在節點和 HTTP 客戶端之間進行通訊也使用了大量的套接字。 全部這一切都須要足夠的文件描述符。你應該增長你的文件描述符,設置一個很大的值,如 64,000。
索引階段性能提高方法補充
- 使用批量請求並調整其大小:每次批量數據 5–15 MB 大是個不錯的起始點。
- 段和段合併:Elasticsearch 默認值是 20 MB/s,對機械磁盤應該是個不錯的設置。若是你用的是 SSD,能夠考慮提升到 100–200 MB/s。若是你在作批量導入,徹底不在乎搜索,你能夠完全關掉合併限流。另外還能夠增長 index.translog.flush_threshold_size 設置,從默認的 512 MB 到更大一些的值,好比 1 GB,這能夠在一次清空觸發的時候在事務日誌裏積累出更大的段。
- 若是你的搜索結果不須要近實時的準確度,考慮把每一個索引的index.refresh_interval 改到30s。
- 若是你在作大批量導入,考慮經過設置index.number_of_replicas: 0 關閉副本。
Q9: 對於GC方面,在使用Elasticsearch時要注意什麼?
- 查看:https://elasticsearch.cn/article/32
- 倒排詞典的索引須要常駐內存,沒法GC,須要監控data node上segment memory增加趨勢。
- 各種緩存,field cache, filter cache, indexing cache, bulk queue等等,要設置合理的大小,而且要應該根據最壞的狀況來看heap是否夠用,也就是各種緩存所有佔滿的時候,還有heap空間能夠分配給其餘任務嗎?避免採用clear cache等「自欺欺人」的方式來釋放內存。
- 避免返回大量結果集的搜索與聚合。確實須要大量拉取數據的場景,能夠採用scan & scroll api來實現。
- cluster stats駐留內存並沒有法水平擴展,超大規模集羣能夠考慮分拆成多個集羣經過tribe node鏈接。
- 想知道heap夠不夠,必須結合實際應用場景,並對集羣的heap使用狀況作持續的監控。