ElasticSearch_高级_(集群+分片)
ElasticSearch_高級_(集群+分片)
文章目錄
- ElasticSearch_高級_(集群+分片)
- 課程內容
- 1.spring data elasticsearch
- 1.1 spring data 框架介紹
- 1.2 spring data elasticsearch
- 1.3 spring data elasticsearch版本
- 1.4 框架集成
- 1.4.1 依賴
- 1.4.2 yml配置
- 1.4.3 document映射
- 1.4.4 dao數據訪問
- 1.4.5 springboot啟動類
- 1.4.6 接口測試
- 2.cap定理
- 2.1 CAP定理的證明
- 2.2 取舍策略
- 3. elasticsearch集群
- 3.1 集群安裝
- 3.1.1 環境搭建
- 3.1.2 head插件
- nodejs安裝
- elasticsearch-head插件安裝
- 3.2 elasticsearch中的集群核心概念
- 集群Cluster
- 節點Node
- 分片(Shards)
- 副本(Replicas)
- 分配(Allocation)
- 節點類型
- 3.3 系統架構
- 3.4 elasticsearch分片
- 3.5 分片控制
- 3.5.1 寫流程
- 3.5.2 讀流程
- 4.分片原理
- 4.1 倒排索引
- 4.2 文檔搜索
- 4.3 動態更新索引
- 4.4 近實時搜索
- 4.5 段合并
- 5.優化建議
- 5.1 硬件選擇
- 5.2 分片策略
- 5.2.1 合理設置分片數
- 5.2.2 推遲分片分配
- 5.3 路由選擇
- 5.4 寫入速度優化
- 5.4.1 批量數據提交
- 5.4.2 優化存儲設備
- 5.4.3 減少Refresh的次數
- 5.4.4 加大Flush設置
- 5.4.5 減少副本的數量
- 5.4.6 內存設置
- 5.5 重要配置
- 6.面試題
- 6.1 為什么要使用Elasticsearch?
- 6.2 Elasticsearch的master選舉流程?
- 7.x之前選主流程
- 7.x之后選主流程
- 6.3 Elasticsearch集群腦裂問題?
- 6.4 Elasticsearch索引文檔的流程?
- 6.5 **Elasticsearch更新和刪除文檔的流程?**
- 6.6 Elasticsearch搜索的流程?
- 6.7 Elasticsearch 在部署時,對 Linux 的設置有哪些優化方法?
- 6.8 GC方面,在使用Elasticsearch時要注意什么?
- 6.9 在并發情況下,Elasticsearch如果保證讀寫一致?
- 6.10 如何監控 Elasticsearch 集群狀態?
- 6.11 Elasticsearch中的集群、節點、索引、文檔、類型是什么?
- 6.12 Elasticsearch中的倒排索引是什么?
課程內容
- spring data elasticsearch
- CAP定理
- elasticsearch集群
- 分片原理
- elasticsearch優化建議
- elasticsearch常見面試題
1.spring data elasticsearch
1.1 spring data 框架介紹
Spring Data是一個用于簡化數據庫、非關系型數據庫、索引庫訪問,并支持云服務的開源框架。其主要目標是使得對數據的訪問變得方便快捷,并支持map-reduce框架和云計算數據服務。 Spring Data可以極大的簡化JPA(Elasticsearch…)的寫法,可以在幾乎不用寫實現的情況下,實現對數據的訪問和操作。除了CRUD外,還包括如分頁、排序等一些常用的功能。
Spring Data的官網:https://spring.io/projects/spring-data
常用模塊:
1.2 spring data elasticsearch
Spring Data Elasticsearch 基于 spring data API 簡化 Elasticsearch操作,將原始操作Elasticsearch的客戶端API 進行封裝 。Spring Data為Elasticsearch項目提供集成搜索引擎。Spring Data Elasticsearch POJO的關鍵功能區域為中心的模型與Elastichsearch交互文檔和輕松地編寫一個存儲索引庫數據訪問層。
1.3 spring data elasticsearch版本
springboot2.3.x版本可以兼容elasticsearch7.x版本。
1.4 框架集成
1.4.1 依賴
pom.xml
<parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.boot</groupId><version>2.3.6.RELEASE</version> </parent> <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency> </dependencies>1.4.2 yml配置
application.yml
spring:elasticsearch:rest:uris: http://localhost:92001.4.3 document映射
@Data @Document(indexName = "goods") public class Goods implements Serializable {@Field(type = FieldType.Keyword)private String id;@Field(type = FieldType.Text)private String goodsName;@Field(type = FieldType.Integer)private Integer store;@Field(type = FieldType.Double)private double price;}1.4.4 dao數據訪問
@Repository public interface GoodsDao extends ElasticsearchRepository<Goods, String> { }1.4.5 springboot啟動類
package com.atguigu;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication public class Application {public static void main(String[] args) {SpringApplication.run(Application.class,args);}}1.4.6 接口測試
@Autowiredprivate GoodsDao goodsDao;/*** 添加文檔* */@Testpublic void saveTest(){Goods goods = new Goods();goods.setId("1");goods.setGoodsName("華為手機");goods.setStore(100);goods.setPrice(5000);goodsDao.save(goods);System.out.println("添加成功...");}/*** 根據ID查詢文檔* */@Testpublic void findById(){Goods goods = goodsDao.findById("1").get();System.out.println(goods);}2.cap定理
-
CAP 定理,又被叫作布魯爾定理。對于設計分布式系統(不僅僅是分布式事務)的架構師來說,CAP 就是你的入門理論。
-
分布式系統(distributed system)正變得越來越重要,大型網站幾乎都是分布式的。
-
分布式系統的最大難點,就是各個節點的狀態如何同步。CAP 定理是這方面的基本定理,也是理解分布式系統的起點。
C (一致性):指數據在多個副本之間能夠保持一致的特性(嚴格的一致性)在分布式系統中的所有數據備份,在同一時刻是否同樣的值。(所有節點在同一時間具有相同的數據)
一致性(Consistency)是指多副本(Replications)問題中的數據一致性。可以分為強一致性、與弱一致性。
① 強一致性
*簡言之,在任意時刻,所有節點中的數據是一樣的。*
例如,對于關系型數據庫,要求更新過的數據能被后續的訪問都能看到,這是強一致性。
② 弱一致性
數據更新后,如果能容忍后續的訪問只能訪問到部分或者全部訪問不到,則是弱一致性。
*最終一致性就屬于弱一致性。*
A (可用性):指系統提供的服務必須一直處于可用的狀態,每次只要收到用戶的請求,服務器就必須給出回應。在合理的時間內返回合理的響應(不是錯誤和超時的響應)
*只有非故障節點才能滿足業務正常;只有在合理的時間內,用戶才能接受;只有返回合理的響應,用戶才能接受。*
P (網絡分區容錯性):網絡節點之間無法通信的情況下,節點被隔離,產生了網絡分區, 整個系統仍然是可以工作的 . 大多數分布式系統都分布在多個子網絡。每個子網絡就叫做一個區(partition)。分區容錯的意思是,區間通信可能失敗。比如,一臺服務器放在中國,另一臺服務器放在美國,這就是兩個區,它們之間可能無法通信。
- 什么是分區?
*在分布式系統中,不同的節點分布在不同的子網絡中,由于一些特殊的原因,這些子節點之間出現了網絡不通的狀態,但他們的內部子網絡是正常的。從而導致了整個系統的環境被切分成了若干個孤立的區域。這就是分區。*
- CAP原則的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。
2.1 CAP定理的證明
現在我們就來證明一下,為什么不能同時滿足三個特性?
假設有兩臺服務器,一臺放著應用A和數據庫V,一臺放著應用B和數據庫V,他們之間的網絡可以互通,也就相當于分布式系統的兩個部分。
在滿足一致性的時候,兩臺服務器 N1和N2,一開始兩臺服務器的數據是一樣的,DB0=DB0。在滿足可用性的時候,用戶不管是請求N1或者N2,都會得到立即響應。在滿足分區容錯性的情況下,N1和N2有任何一方宕機,或者網絡不通的時候,都不會影響N1和N2彼此之間的正常運作。
當用戶通過N1中的A應用請求數據更新到服務器DB0后,這時N1中的服務器DB0變為DB1,通過分布式系統的數據同步更新操作,N2服務器中的數據庫V0也更新為了DB1,這時,用戶通過B向數據庫發起請求得到的數據就是即時更新后的數據DB1。
上面是正常運作的情況,但分布式系統中,最大的問題就是網絡傳輸問題,現在假設一種極端情況,N1和N2之間的網絡斷開了,但我們仍要支持這種網絡異常,也就是滿足分區容錯性,那么這樣能不能同時滿足一致性和可用性呢?
假設N1和N2之間通信的時候網絡突然出現故障,有用戶向N1發送數據更新請求,那N1中的數據DB0將被更新為DB1,由于網絡是斷開的,N2中的數據庫仍舊是DB0;
如果這個時候,有用戶向N2發送數據讀取請求,由于數據還沒有進行同步,應用程序沒辦法立即給用戶返回最新的數據DB1,怎么辦呢?有二種選擇,第一,犧牲數據一致性,響應舊的數據DB0給用戶;第二,犧牲可用性,阻塞等待,直到網絡連接恢復,數據更新操作完成之后,再給用戶響應最新的數據DB1。
上面的過程比較簡單,但也說明了要滿足分區容錯性的分布式系統,只能在一致性和可用性兩者中,選擇其中一個。也就是說分布式系統不可能同時滿足三個特性。這就需要我們在搭建系統時進行取舍了,那么,怎么取舍才是更好的策略呢?
2.2 取舍策略
現如今,對于多數大型互聯網應用的場景,主機眾多、部署分散,而且現在的集群規模越來越大,節點只會越來越多,所以節點故障、網絡故障是常態,因此分區容錯性也就成為了一個分布式系統必然要面對的問題。那么就只能在C和A之間進行取舍。
*原因是*
因為,在分布式系統中,網絡無法 100% 可靠,分區其實是一個必然現象,隨著網絡節點出現問題,產生了分區, 這時候其他節點和出錯節點的數據必然會不一致,這時候就要面臨選擇,
是選擇停掉所有的服務,等網絡節點修復后恢復數據,以此來保證一致性(PC),
還是選擇繼續提供服務,放棄強一致性的要求,以此來保證整體的可用性(PA)。
所以,最多滿足兩個條件:
| CA | 滿足原子和可用,放棄分區容錯。說白了,就是一個整體的應用。 |
| CP | 滿足原子和分區容錯,也就是說,要放棄可用。當系統被分區,為了保證原子性,必須放棄可用性,讓服務停用。 |
| AP | 滿足可用性和分區容錯,當出現分區,同時為了保證可用性,必須讓節點繼續對外服務,這樣必然導致失去原子性。 |
在分布式系統設計中AP的應用較多,即保證分區容忍性和可用性,犧牲數據的強一致性(寫操作后立刻讀取到最新數據),保證數據最終一致性。比如:訂單退款,今日退款成功,明日賬戶到賬,只要在預定的用戶可以接受的時間內退款事務走完即可。
順便一提,CAP 理論中是忽略網絡延遲,也就是當事務提交時,從節點 A 復制到節點 B 沒有延遲,但是在現實中這個是明顯不可能的,所以總會有一定的時間是不一致。
但是,有個特殊情況需要注意:但對于傳統的項目就可能有所不同,拿銀行的轉賬系統來說,涉及到金錢的對于數據一致性不能做出一絲的讓步,C必須保證,出現網絡故障的話,寧可停止服務,可以在A和P之間做取舍。
*總而言之,沒有最好的策略,好的系統應該是根據業務場景來進行架構設計的,只有適合的才是最好的。*
3. elasticsearch集群
單臺Elasticsearch服務器提供服務,往往都有最大的負載能力,超過這個閾值,服務器性能就會大大降低甚至不可用,所以生產環境中,一般都是運行在指定服務器集群中。
除了負載能力,單點服務器也存在其他問題:
- 單臺機器存儲容量有限
- 單服務器容易出現單點故障,無法實現高可用
- 單服務的并發處理能力有限
配置服務器集群時,集群中節點數量沒有限制,大于等于2個節點就可以看做是集群了。一般出于高性能及高可用方面來考慮集群中節點數量都是3個以上。
3.1 集群安裝
3.1.1 環境搭建
一般集群建議3臺機器以上,這里我們就使用1臺機器來安裝集群環境。一般生產環境都是使用linux服務器,所以我們這里就是linux環境下安裝es集群。
| node-1 | 192.168.6.100 | 9201 | 9301 |
| node-2 | 192.168.6.100 | 9202 | 9302 |
| node-3 | 192.168.6.100 | 9203 | 9303 |
各個機器集群環境安裝之前,先把之前的data數據目錄刪除。
node-1:
#集群名稱 cluster.name: my-application #節點名稱 node.name: node-1 #配置允許的訪問網絡 network.host: 0.0.0.0 #http服務端口 http.port: 9201 #配置集群間通信的端口號 transport.tcp.port: 9301 #是否允許為主節點,默認true node.master: true #是否為數據節點,默認true node.data: true #初始配置選舉master節點 cluster.initial_master_nodes: ["node-1"] #節點發現 discovery.seed_hosts: ["localhost:9301", "localhost:9302","localhost:9303"] #elasticsearch-head 跨域解決 http.cors.allow-origin: "*" http.cors.enabled: truenode-2:
#集群名稱 cluster.name: my-application #節點名稱 node.name: node-2 #配置允許的訪問網絡 network.host: 0.0.0.0 #http服務端口 http.port: 9202 #配置集群間通信的端口號 transport.tcp.port: 9302 #是否允許為主節點,默認true node.master: true #是否為數據節點,默認true node.data: true #初始配置選舉master節點 cluster.initial_master_nodes: ["node-1"] #節點發現 discovery.seed_hosts: ["localhost:9301", "localhost:9302","localhost:9303"]node-3:
#集群名稱 cluster.name: my-application #節點名稱 node.name: node-3 #配置允許的訪問網絡 network.host: 0.0.0.0 #http服務端口 http.port: 9203 #配置集群間通信的端口號 transport.tcp.port: 9303 #是否允許為主節點,默認true node.master: true #是否為數據節點,默認true node.data: true #初始配置選舉master節點 cluster.initial_master_nodes: ["node-1"] #節點發現 discovery.seed_hosts: ["localhost:9301", "localhost:9302","localhost:9303"]依次啟動node-1、node-2、node-3節點。
啟動完畢后查看節點健康狀態:
3.1.2 head插件
kibana中查看集群相關的信息不是那么的直觀,這里介紹一款第三方瀏覽器插件(elasticsearch-head)來查看和管理集群。
elasticsearch-head是一個nodesjs項目,所以要先安裝nodejs環境。
nodejs安裝
#下載nodejs(可以直接copy資料中的node-v12.18.1-linux-x64.tar.xz): #注意:我的軟件放在/opt目錄下。 wget https://nodejs.org/dist/v12.18.1/node-v12.18.1-linux-x64.tar.xz#解壓文件: tar -Jxf node-v12.18.1-linux-x64.tar.xz mv node-v12.18.1-linux-x64 nodejs#配置軟鏈接環境(注意目錄地址是否正確): ln -s /opt/nodejs/bin/node /usr/local/bin/node ln -s /opt/nodejs/bin/npm /usr/local/bin/npm驗證nodejs環境(node -v):
elasticsearch-head插件安裝
#上傳資料中的文件(該文件是nodejs編譯后的)elasticsearch-head-compile-after.tar.gz #1.解壓文件 tar zxvf elasticsearch-head-compile-after.tar.gz#2.修改Gruntfile.js(/解壓目錄/Gruntfile.js)找到代碼中的93行[:93],將192.168.100.100修改為自己的IPserver: {options: {hostname: '192.168.6.100',port: 9100,base: '.',keepalive: true}}#3.修改app.js(/解壓目錄/_stie/app.js)找到4354行[:4354],將http://localhost:9200修改為對應的IP this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://192.168.6.100:9200";#4.啟動head(/opt/es/elasticsearch-head為解壓目錄) cd /opt/es/elasticsearch-head/node_modules/grunt #后臺啟動 nohup ./grunt server >/dev/null 2>&1 &測試訪問(head端口9100):http://192.1686.100:9100/
3.2 elasticsearch中的集群核心概念
集群Cluster
一個集群就是由一個或多個服務器節點組織在一起,共同持有整個的數據,并一起提供索引和搜索功能。一個Elasticsearch集群有一個唯一的名字標識,這個名字默認就是”elasticsearch”。這個名字是重要的,因為一個節點只能通過指定某個集群的名字,來加入這個集群。
節點Node
? 集群中包含很多服務器,一個節點就是其中的一個服務器。作為集群的一部分,它存儲數據,參與集群的索引和搜索功能。
? 一個節點也是由一個名字來標識的,默認情況下,這個名字是一個隨機的漫威漫畫角色的名字,這個名字會在啟動的時候賦予節點。這個名字對于管理工作來說挺重要的,因為在這個管理過程中,你會去確定網絡中的哪些服務器對應于Elasticsearch集群中的哪些節點。
? 一個節點可以通過配置集群名稱的方式來加入一個指定的集群。默認情況下,每個節點都會被安排加入到一個叫做“elasticsearch”的集群中,這意味著,如果你在你的網絡中啟動了若干個節點,并假定它們能夠相互發現彼此,它們將會自動地形成并加入到一個叫做“elasticsearch”的集群中。
? 在一個集群里,只要你想,可以擁有任意多個節點。而且,如果當前你的網絡中沒有運行任何Elasticsearch節點,這時啟動一個節點,會默認創建并加入一個叫做“elasticsearch”的集群。
分片(Shards)
? 一個索引可以存儲超出單個節點硬件限制的大量數據。比如,一個具有10億文檔數據的索引占據1TB的磁盤空間,而任一節點都可能沒有這樣大的磁盤空間。或者單個節點處理搜索請求,響應太慢。為了解決這個問題,Elasticsearch提供了將索引劃分成多份的能力,每一份就稱之為分片。當你創建一個索引的時候,你可以指定你想要的分片的數量。每個分片本身也是一個功能完善并且獨立的“索引”,這個“索引”可以被放置到集群中的任何節點上。
分片很重要,主要有兩方面的原因:
1)允許你水平分割 / 擴展你的內容容量。
2)允許你在分片之上進行分布式的、并行的操作,進而提高性能/吞吐量。
至于一個分片怎樣分布,它的文檔怎樣聚合和搜索請求,是完全由Elasticsearch管理的,對于作為用戶的你來說,這些都是透明的,無需過分關心。
副本(Replicas)
? 在一個網絡 / 云的環境里,失敗隨時都可能發生,在某個分片/節點不知怎么的就處于離線狀態,或者由于任何原因消失了,這種情況下,有一個故障轉移機制是非常有用并且是強烈推薦的。為此目的,Elasticsearch允許你創建分片的一份或多份拷貝,這些拷貝叫做復制分片(副本)。
? 復制分片之所以重要,有兩個主要原因:
- 在分片/節點失敗的情況下,提供了高可用性。因為這個原因,注意到復制分片從不與原/主要(original/primary)分片置于同一節點上是非常重要的。
- 擴展你的搜索量/吞吐量,因為搜索可以在所有的副本上并行運行。
總之,每個索引可以被分成多個分片。一個索引也可以被復制0次(意思是沒有復制)或多次。一旦復制了,每個索引就有了主分片(作為復制源的原來的分片)和復制分片(主分片的拷貝)之別。分片和復制的數量可以在索引創建的時候指定。在索引創建之后,你可以在任何時候動態地改變復制的數量,但是你事后不能改變分片的數量。默認情況下,Elasticsearch中的每個索引被分片1個主分片和1個復制,這意味著,如果你的集群中至少有兩個節點,你的索引將會有1個主分片和另外1個復制分片(1個完全拷貝),這樣的話每個索引總共就有2個分片,我們需要根據索引需要確定分片個數。
分配(Allocation)
將分片分配給某個節點的過程,包括分配主分片或者副本。如果是副本,還包含從主分片復制數據的過程。這個過程是由master節點完成的。
節點類型
es集群中的節點類型分為:Master、DataNode。
-
master:
Elasticsearch啟動時,會選舉出來一個Master節點。當某個節點啟動后,使用Zen Discovery機制找到集群中的其他節點,并建立連接。
discovery.seed_hosts: [“host1”, “host2”, “host3”]
并從候選主節點中選舉出一個主節點。
cluster.initial_master_nodes: [“node-1”, “node-2”,“node-3”]
Master節點主要負責:
-
管理索引(創建索引、刪除索引)、分配分片
-
維護元數據
-
管理集群節點狀態
不負責數據寫入和查詢,比較輕量級。一個ElasticSearch集群中,只有一個Master節點。在生產環境中,內存可以相對
小一點,但要確保機器穩定。
-
-
DataNode:
在Elasticsearch集群中,會有N個DataNode節點。DataNode節點主要負責:
- 數據寫入、數據檢索,大部分Elasticsearch的壓力都在DataNode節點上
在生產環境中,內存最好配置大一些。
3.3 系統架構
? 一個運行中的 Elasticsearch 實例稱為一個節點,而集群是由一個或者多個擁有相同 cluster.name 配置的節點組成, 它們共同承擔數據和負載的壓力。當有節點加入集群中或者從集群中移除節點時,集群將會重新平均分布所有的數據。
? 當一個節點被選舉成為主節點時, 它將負責管理集群范圍內的所有變更,例如增加、刪除索引,或者增加、刪除節點等。 而主節點并不需要涉及到文檔級別的變更和搜索等操作,所以當集群只擁有一個主節點的情況下,即使流量的增加它也不會成為瓶頸。 任何節點都可以成為主節點。我們的示例集群就只有一個節點,所以它同時也成為了主節點。
? 作為用戶,我們可以將請求發送到集群中的任何節點 ,包括主節點。 每個節點都知道任意文檔所處的位置,并且能夠將我們的請求直接轉發到存儲我們所需文檔的節點。 無論我們將請求發送到哪個節點,它都能負責從各個包含我們所需文檔的節點收集回數據,并將最終結果返回給客戶端。 Elasticsearch 對這一切的管理都是透明的。
3.4 elasticsearch分片
我們可以在建立索引的時候創建分片信息:
#number_of_shards:主分片數量(7.x版本之后如果不指定數量默認為1),number_of_replicas:每個主分片對應的副本數量 PUT /users {"settings": {"number_of_shards": 3,"number_of_replicas": 2} }head中數據查看說明:
★ 代表當前節點為master節點
● 表示DataNode節點
粗線框格子為主分片,細線框為副本分片,主分片與副本分片不能同時在一臺機器上。
剛才的例子中,我們創建了3個主分片,然后又為每個主分片配置了兩個副本分片,加起來一共9個分片。分片序號分別為0、1、2代表不同的數據段存儲。其中0號分片的主分片在node-3機器上,node-1和node-2是它的備份分片。
注意:主分片數量一旦指定后就不允許更改,否則會影響后續的數據操作(分片位置路由是取模主分片數量)。
雖然主分片數量不可用更改,但是副本數量可以修改:
#修改副本數 PUT users/_settings {"number_of_replicas": 0 }3.5 分片控制
3.5.1 寫流程
新建和刪除請求都是寫操作, 必須在主分片上面完成之后才能被復制到相關的副本分片
-
第一步: 客戶端選擇DataNode節點發送請求,如上圖架構,假設發送到node-2節點上。此時被選擇的node-2節點也稱為coordinating node(協調節點)
-
第二步: 協調節點根據路由規則計算分片索引位置。并將請求發送到分片索引對應的主分片機器上(這里假設分片計算后的值為0,那么請求會命中到node-3節點上)。
- 計算分片索引位置: shard = hash(routing) % number_of_primary_shards,routing可以自己設定,一般默認為文檔的ID。
-
第三步: 當主分片文檔寫入完成后,同時將數據推送到與之對應的副本分片進行寫入操作
-
第四步: 當分片完成了寫入后再由協調節點將操作結果返回給客戶端
3.5.2 讀流程
- 第一步:客戶端選擇DataNode節點發送請求,如上圖架構,假設發送到node-2節點上。此時被選擇的node-2節點也稱為coordinating node(協調節點)
- 第二步: 協調節點將從客戶端獲取到的請求數據轉發到其它節點
- 第三步: 其它節點將查詢結果文檔ID、節點、分片信息返回給協調節點
- 第四步: 協調節點通過文檔ID、節點信息等發送get請求給其它節點進行數據獲取,最后進行匯總排序將數據返回給客戶端
4.分片原理
4.1 倒排索引
Elasticsearch 使用一種稱為****倒排索引****的結構,它適用于快速的全文搜索。
見其名,知其意,有倒排索引,肯定會對應有正向索引。正向索引(forward index),反向索引(inverted index)更熟悉的名字是倒排索引。
所謂的正向索引,就是搜索引擎會將待搜索的文件都對應一個文件ID,搜索時將這個ID和搜索關鍵字進行對應,形成K-V對,然后對關鍵字進行統計計數
但是互聯網上收錄在搜索引擎中的文檔的數目是個天文數字,這樣的索引結構根本無法滿足實時返回排名結果的要求。所以,搜索引擎會將正向索引重新構建為倒排索引,即把文件ID對應到關鍵詞的映射轉換為關鍵詞到文件ID的映射,每個關鍵詞都對應著一系列的文件,這些文件中都出現這個關鍵詞。
一個倒排索引由文檔中所有不重復詞的列表構成,對于其中每個詞,有一個包含它的文檔列表。例如,假設我們有兩個文檔,每個文檔的 content 域包含如下內容:
-
The quick brown fox jumped over the lazy dog
-
Quick brown foxes leap over lazy dogs in summer
為了創建倒排索引,我們首先將每個文檔的 content 域拆分成單獨的 詞(我們稱它為 詞條 或 tokens ),創建一個包含所有不重復詞條的排序列表,然后列出每個詞條出現在哪個文檔。結果如下所示:
現在,如果我們想搜索 quick brown ,我們只需要查找包含每個詞條的文檔:
兩個文檔都匹配,但是第一個文檔比第二個匹配度更高。如果我們使用僅計算匹配詞條數量的簡單相似性算法,那么我們可以說,對于我們查詢的相關性來講,第一個文檔比第二個文檔更佳。
4.2 文檔搜索
早期的全文檢索會為整個文檔集合建立一個很大的倒排索引并將其寫入到磁盤。 一旦新的索引就緒,舊的就會被其替換,這樣最近的變化便可以被檢索到。
倒排索引被寫入磁盤后是 不可改變 的:它永遠不會修改。
不變性有重要的價值:
-
不需要鎖。如果你從來不更新索引,你就不需要擔心多進程同時修改數據的問題。
-
一旦索引被讀入內核的文件系統緩存,便會留在哪里,由于其不變性。只要文件系統緩存中還有足夠的空間,那么大部分讀請求會直接請求內存,而不會命中磁盤。這提供了很大的性能提升。
-
其它緩存(像filter緩存),在索引的生命周期內始終有效。它們不需要在每次數據改變時被重建,因為數據不會變化。
-
寫入單個大的倒排索引允許數據被壓縮,減少磁盤 I/O 和 需要被緩存到內存的索引的使用量。
當然,一個不變的索引也有不好的地方。主要事實是它是不可變的! 你不能修改它。如果你需要讓一個新的文檔可被搜索,你需要重建整個索引。這要么對一個索引所能包含的數據量造成了很大的限制,要么對索引可被更新的頻率造成了很大的限制。
4.3 動態更新索引
如何在保留不變性的前提下實現倒排索引的更新?
答案是: **用更多的索引。**通過增加新的補充索引來反映新近的修改,而不是直接重寫整個倒排索引。每一個倒排索引都會被輪流查詢到,從最早的開始查詢完后再對結果進行合并。
Elasticsearch 基于 Lucene, 這個java庫引入了按段搜索的概念。 每一 段本身都是一個倒排索引。 但索引在 Lucene 中除表示所有段的集合外, 還增加了提交點的概念 — 一個列出了所有已知段的文件。
按段搜索會以如下流程執行:
(1) 一個新的段—一個追加的倒排索引—被寫入磁盤。
(2) 一個新的包含新段名字的 提交點 被寫入磁盤
(3) 磁盤進行同步 — 所有在文件系統緩存中等待的寫入都刷新到磁盤,以確保它們被寫入物理文件
新的段被開啟,讓它包含的文檔可見以被搜索
內存緩存被清空,等待接收新的文檔
當一個查詢被觸發,所有已知的段按順序被查詢。詞項統計會對所有段的結果進行聚合,以保證每個詞和每個文檔的關聯都被準確計算。 這種方式可以用相對較低的成本將新文檔添加到索引。
段是不可改變的,所以既不能把文檔從舊的段中移除,也不能修改舊的段來進行反映文檔的更新。 取而代之的是,每個提交點會包含一個 .del 文件,文件中會列出這些被刪除文檔的段信息。
當一個文檔被 “刪除” 時,它實際上只是在 .del 文件中被標記刪除。一個被標記刪除的文檔仍然可以被查詢匹配到,但它會在最終結果被返回前從結果集中移除。
文檔更新也是類似的操作方式:當一個文檔被更新時,舊版本文檔被標記刪除,文檔的新版本被索引到一個新的段中。 可能兩個版本的文檔都會被一個查詢匹配到,但被刪除的那個舊版本文檔在結果集返回前就已經被移除。
4.4 近實時搜索
- 分段數據先寫入到內存緩存中,同時文檔操作也會記錄translog日志
- 內存的數據對查詢不可見,默認間隔1s將內存中數據寫入到文件系統緩存中,這里面的數據對查詢可見。
- 文件系統緩存數據間隔30分鐘再將數據刷入磁盤中。
- 如果文件系統緩存數據在沒有刷新到硬盤時宕機了,可以從translog中恢復數據到磁盤,數據恢復完成后translog數據也會清理。
4.5 段合并
? 由于自動刷新流程每秒會創建一個新的段 ,這樣會導致短時間內的段數量暴增。而段數目太多會帶來較大的麻煩。 每一個段都會消耗文件句柄、內存和cpu運行周期。更重要的是,每個搜索請求都必須輪流檢查每個段;所以段越多,搜索也就越慢。
? Elasticsearch通過在后臺進行段合并來解決這個問題。小的段被合并到大的段,然后這些大的段再被合并到更大的段。
? 段合并的時候會將那些舊的已刪除文檔從文件系統中清除。被刪除的文檔(或被更新文檔的舊版本)不會被拷貝到新的大段中。
? 啟動段合并不需要你做任何事。進行索引和搜索時會自動進行。
當索引的時候,刷新(refresh)操作會創建新的段并將段打開以供搜索使用。
合并進程選擇一小部分大小相似的段,并且在后臺將它們合并到更大的段中。這并不會中斷索引和搜索。
-
新的段被刷新(flush)到了磁盤。 ** 寫入一個包含新段且排除舊的和較小的段的新提交點。
-
新的段被打開用來搜索。
-
老的段被刪除。
合并大的段需要消耗大量的I/O和CPU資源,如果任其發展會影響搜索性能。Elasticsearch在默認情況下會對合并流程進行資源限制,所以搜索仍然 有足夠的資源很好地執行。
5.優化建議
5.1 硬件選擇
Elasticsearch的基礎是 Lucene,所有的索引和文檔數據是存儲在本地的磁盤中,具體的路徑可在 ES 的配置文件…/config/elasticsearch.yml中配置,如下:
#----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
#path.data: /path/to/data
#
# Path to log files:
#
#path.logs: /path/to/logs
#
磁盤在現代服務器上通常都是瓶頸。Elasticsearch 重度使用磁盤,你的磁盤能處理的吞吐量越大,你的節點就越穩定。這里有一些優化磁盤 I/O 的技巧:
l 使用 SSD。就像其他地方提過的, 他們比機械磁盤優秀多了。
l 使用 RAID 0。條帶化 RAID 會提高磁盤 I/O,代價顯然就是當一塊硬盤故障時整個就故障了。不要使用鏡像或者奇偶校驗 RAID 因為副本已經提供了這個功能。
l 另外,使用多塊硬盤,并允許 Elasticsearch 通過多個 path.data 目錄配置把數據條帶化分配到它們上面。
l 不要使用遠程掛載的存儲,比如 NFS 或者 SMB/CIFS。這個引入的延遲對性能來說完全是背道而馳的。
5.2 分片策略
5.2.1 合理設置分片數
分片和副本的設計為 ES 提供了支持分布式和故障轉移的特性,但并不意味著分片和副本是可以無限分配的。而且索引的分片完成分配后由于索引的路由機制,我們是不能重新修改分片數的。
可能有人會說,我不知道這個索引將來會變得多大,并且過后我也不能更改索引的大小,所以為了保險起見,還是給它設為 1000 個分片吧。但是需要知道的是,一個分片并不是沒有代價的。需要了解:
l 一個分片的底層即為一個 Lucene 索引,會消耗一定文件句柄、內存、以及 CPU 運轉。
l 每一個搜索請求都需要命中索引中的每一個分片,如果每一個分片都處于不同的節點還好, 但如果多個分片都需要在同一個節點上競爭使用相同的資源就有些糟糕了。
l 用于計算相關度的詞項統計信息是基于分片的。如果有許多分片,每一個都只有很少的數據會導致很低的相關度。
一個業務索引具體需要分配多少分片可能需要架構師和技術人員對業務的增長有個預先的判斷,橫向擴展應當分階段進行。為下一階段準備好足夠的資源。 只有當你進入到下一個階段,你才有時間思考需要作出哪些改變來達到這個階段。一般來說,我們遵循一些原則:
l 控制每個分片占用的硬盤容量不超過ES的最大JVM的堆空間設置(一般設置不超過32G,參考下文的JVM設置原則),因此,如果索引的總容量在500G左右,那分片大小在16個左右即可;當然,最好同時考慮原則2。
l 考慮一下node數量,一般一個節點有時候就是一臺物理機,如果分片數過多,大大超過了節點數,很可能會導致一個節點上存在多個分片,一旦該節點故障,即使保持了1個以上的副本,同樣有可能會導致數據丟失,集群無法恢復。所以, 一般都設置分片數不超過節點數的3倍。
l 主分片,副本和節點最大數之間數量,我們分配的時候可以參考以下關系:
節點數<=主分片數*(副本數+1)
5.2.2 推遲分片分配
對于節點瞬時中斷的問題,默認情況,集群會等待一分鐘來查看節點是否會重新加入,如果這個節點在此期間重新加入,重新加入的節點會保持其現有的分片數據,不會觸發新的分片分配。這樣就可以減少 ES 在自動再平衡可用分片時所帶來的極大開銷。
通過修改參數 delayed_timeout ,可以延長再均衡的時間,可以全局設置也可以在索引級別進行修改:
PUT /_all/_settings {"settings": {"index.unassigned.node_left.delayed_timeout": "5m" } }5.3 路由選擇
當我們查詢文檔的時候,Elasticsearch 如何知道一個文檔應該存放到哪個分片中呢?它其實是通過下面這個公式來計算出來:
shard = hash(routing) % number_of_primary_shards
routing 默認值是文檔的 id,也可以采用自定義值,比如用戶 id。
不帶 routing 查詢
在查詢的時候因為不知道要查詢的數據具體在哪個分片上,所以整個過程分為 2 個步驟
-
分發:請求到達協調節點后,協調節點將查詢請求分發到每個分片上。
-
聚合: 協調節點搜集到每個分片上查詢結果,在將查詢的結果進行排序,之后給用戶返回結果。
帶 routing 查詢
查詢的時候,可以直接根據 routing 信息定位到某個分配查詢,不需要查詢所有的分配,經過協調節點排序。
向上面自定義的用戶查詢,如果 routing 設置為 userid 的話,就可以直接查詢出數據來,效率提升很多。
5.4 寫入速度優化
ES的默認配置,是綜合了數據可靠性、寫入速度、搜索實時性等因素。實際使用時,我們需要根據公司要求,進行偏向性的優化。
針對于搜索性能要求不高,但是對寫入要求較高的場景,我們需要盡可能的選擇恰當寫優化策略。綜合來說,可以考慮以下幾個方面來提升寫索引的性能:
-
加大 Translog Flush ,目的是降低 Iops、Writeblock。
-
增加 Index Refresh 間隔,目的是減少 Segment Merge 的次數。
-
調整 Bulk 線程池和隊列。
-
優化節點間的任務分布。
-
優化 Lucene 層的索引建立,目的是降低 CPU 及 IO。
5.4.1 批量數據提交
ES 提供了 Bulk API 支持批量操作,當我們有大量的寫任務時,可以使用 Bulk 來進行批量寫入。
通用的策略如下:Bulk 默認設置批量提交的數據量不能超過 100M。數據條數一般是根據文檔的大小和服務器性能而定的,但是單次批處理的數據大小應從 5MB~15MB 逐漸增加,當性能沒有提升時,把這個數據量作為最大值。
5.4.2 優化存儲設備
ES 是一種密集使用磁盤的應用,在段合并的時候會頻繁操作磁盤,所以對磁盤要求較高,當磁盤速度提升之后,集群的整體性能會大幅度提高。
5.4.3 減少Refresh的次數
Lucene 在新增數據時,采用了延遲寫入的策略,默認情況下索引的 refresh_interval 為 1 秒。
Lucene 將待寫入的數據先寫到內存中,超過 1 秒(默認)時就會觸發一次 Refresh,然后 Refresh 會把內存中的的數據刷新到操作系統的文件緩存系統中。
如果我們對搜索的實效性要求不高,可以將 Refresh 周期延長,例如 30 秒。
這樣還可以有效地減少段刷新次數,但這同時意味著需要消耗更多的Heap內存。
5.4.4 加大Flush設置
Flush 的主要目的是把文件緩存系統中的段持久化到硬盤,當 Translog 的數據量達到 512MB 或者 30 分鐘時,會觸發一次 Flush。
index.translog.flush_threshold_size 參數的默認值是 512MB,我們進行修改。
增加參數值意味著文件緩存系統中可能需要存儲更多的數據,所以我們需要為操作系統的文件緩存系統留下足夠的空間。
5.4.5 減少副本的數量
ES 為了保證集群的可用性,提供了 Replicas(副本)支持,然而每個副本也會執行分析、索引及可能的合并過程,所以 Replicas 的數量會嚴重影響寫索引的效率。
當寫索引時,需要把寫入的數據都同步到副本節點,副本節點越多,寫索引的效率就越慢。
如果我們需要大批量進行寫入操作,可以先禁止 Replica 復制,設置 index.number_of_replicas: 0 關閉副本。在寫入完成后,Replica 修改回正常的狀態。
5.4.6 內存設置
ES 默認安裝后設置的內存是 1GB,對于任何一個現實業務來說,這個設置都太小了。
如果是通過解壓安裝的 ES,則在 ES 安裝文件中包含一個 jvm.option 文件,添加如下命令來設置 ES 的堆大小,Xms 表示堆的初始大小,Xmx 表示可分配的最大內存,都是 1GB。
確保 Xmx 和 Xms 的大小是相同的,其目的是為了能夠在 Java 垃圾回收機制清理完堆區后不需要重新分隔計算堆區的大小而浪費資源,可以減輕伸縮堆大小帶來的壓力。
假設你有一個 64G 內存的機器,按照正常思維思考,你可能會認為把 64G 內存都給 ES 比較好,但現實是這樣嗎, 越大越好?雖然內存對 ES 來說是非常重要的,但是答案是否定的!
因為 ES 堆內存的分配需要滿足以下兩個原則:
- 不要超過物理內存的 50%:Lucene 的設計目的是把底層 OS 里的數據緩存到內存中。
Lucene 的段是分別存儲到單個文件中的,這些文件都是不會變化的,所以很利于緩存,同時操作系 統也會把這些段文件緩存起來,以便更快的訪問。
如果我們設置的堆內存過大,Lucene 可用的內存將會減少,就會嚴重影響降低 Lucene 的全文本查 詢性能。
- 堆內存的大小最好不要超過 32GB:在 Java 中,所有對象都分配在堆上,然后有一個 Klass Pointer 指針指向它的類元數據。
這個指針在 64 位的操作系統上為 64 位,64 位的操作系統可以使用更多的內存(2^64)。在 32 位 的系統上為 32 位,32 位的操作系統的最大尋址空間為 4GB(2^32)。
但是 64 位的指針意味著更大的浪費,因為你的指針本身大了。浪費內存不算,更糟糕的是,更大的 指針在主內存和緩存器(例如 LLC, L1等)之間移動數據的時候,會占用更多的帶寬。
最終我們都會采用 31 G 設置
-Xms 31g
-Xmx 31g
假設你有個機器有 128 GB 的內存,你可以創建兩個節點,每個節點內存分配不超過 32 GB。 也就是說不超過 64 GB 內存給 ES 的堆內存,剩下的超過 64 GB 的內存給 Lucene
5.5 重要配置
| cluster.name | elasticsearch | 配置 ES 的集群名稱,默認值是ES,建議改成與所存數據相關的名稱,ES 會自動發現在同一網段下的集群名稱相同的節點 |
| node.name | node-1 | 集群中的節點名,在同一個集群中不能重復。節點的名稱一旦設置,就不能再改變了。當然,也可以設置成服務器的主機名稱,例如 node.name:${HOSTNAME}。 |
| node.master | true | 指定該節點是否有資格被選舉成為 Master 節點,默認是 True,如果被設置為 True,則只是有資格成為 Master 節點,具體能否成為 Master 節點,需要通過選舉產生。 |
| node.data | true | 指定該節點是否存儲索引數據,默認為 True。數據的增、刪、改、查都是在 Data 節點完成的。 |
| index.number_of_shards | 1 | 設置都索引分片個數,默認是 1 片。也可以在創建索引時設置該值,具體設置為多大都值要根據數據量的大小來定。如果數據量不大,則設置成 1 時效率最高 |
| index.number_of_replicas | 1 | 設置默認的索引副本個數,默認為 1 個。副本數越多,集群的可用性越好,但是寫索引時需要同步的數據越多。 |
| transport.tcp.compress | true | 設置在節點間傳輸數據時是否壓縮,默認為 False,不壓縮 |
| discovery.zen.minimum_master_nodes | 1 | 設置在選舉 Master 節點時需要參與的最少的候選主節點數,默認為 1。如果使用默認值,則當網絡不穩定時有可能會出現腦裂。合理的數值為(master_eligible_nodes/2)+1,其中 master_eligible_nodes 表示集群中的候選主節點數 |
| discovery.zen.ping.timeout | 3s | 設置在集群中自動發現其他節點時 Ping 連接的超時時間,默認為 3 秒。在較差的網絡環境下需要設置得大一點,防止因誤判該節點的存活狀態而導致分片的轉移 |
6.面試題
6.1 為什么要使用Elasticsearch?
系統中的數據,隨著業務的發展,時間的推移,將會非常多,而業務中往往采用模糊查詢進行數據的搜索,而模糊查詢會導致查詢引擎放棄索引,導致系統查詢數據時都是全表掃描,在百萬級別的數據庫中,查詢效率是非常低下的,而我們使用ES做一個全文索引,將經常查詢的系統功能的某些字段,比如說電商系統的商品表中商品名,描述、價格還有id這些字段我們放入ES索引庫里,可以提高查詢速度。
6.2 Elasticsearch的master選舉流程?
參考: https://blog.csdn.net/qq_33330687/article/details/105681994
7.x之前選主流程
采用Bully算法,它假定所有節點都有一個唯一的ID,使用該ID對節點進行排序。任何時候的當前Leader都是參與集群的最高ID節點。該算法的優點是易于實現。但是,當擁有最大ID的節點處于不穩定狀態的場景下會有問題。例如,Master負載過重而假死,集群擁有第二大ID的節點被選為新主,這時原來的Master恢復,再次被選為新主,然后又假死。
ES 通過推遲選舉,直到當前的 Master 失效來解決上述問題,只要當前主節點不掛掉,就不重新選主。但是容易產生腦裂(雙主),為此,再通過“法定得票人數過半”解決腦裂問題。
7.x之后選主流程
7.X之后的ES,采用一種新的選主算法,實際上是 Raft 的實現,但并非嚴格按照 Raft 論文實現,而是做了一些調整。
raft選舉過程:
- 選舉超時時間:150~300ms的隨機數
- term每次選舉+1
- 同一個任期內每個節點只能有一張選票
- 選票超過半數則當選為leader
- 當leader被選舉后,其它剩余投票將廢棄
6.3 Elasticsearch集群腦裂問題?
“腦裂”問題可能的成因:
-
網絡問題:集群間的網絡延遲導致一些節點訪問不到master,認為master掛掉了從而選舉出新的master,并對master上的分片和副本標紅,分配新的主分片
-
節點負載:主節點的角色既為master又為data,訪問量較大時可能會導致ES停止響應造成大面積延遲,此時其他節點得不到主節點的響應認為主節點掛掉了,會重新選取主節點。
-
內存回收:data節點上的ES進程占用的內存較大,引發JVM的大規模內存回收,造成ES進程失去響應。
腦裂問題解決方案:
***減少誤判:***discovery.zen.ping_timeout節點狀態的響應時間,默認為3s,可以適當調大,如果master在該響應時間的范圍內沒有做出響應應答,判斷該節點已經掛掉了。調大參數(如6s,discovery.zen.ping_timeout:6),可適當減少誤判。
選舉觸發: discovery.zen.minimum_master_nodes:1
7.x之前版本:
該參數是用于控制選舉行為發生的最小集群主節點數量。當備選主節點的個數大于等于該參數的值, 且備選主節點中有該參數個節點認為主節點掛了,進行選舉。官方建議為(n/2)+1,n為主節點個數 (即有資格成為主節點的節點個數)
7.x之后版本:
不需要手動配置,系統自己會維護最小集群節點數
角色分離:即master節點與data節點分離,限制角色
主節點配置為:node.master: true node.data: false
從節點配置為:node.master: false node.data: true
6.4 Elasticsearch索引文檔的流程?
- 協調節點默認使用文檔ID參與計算(也支持通過routing),以便為路由提供合適的分片:
*shard = hash(document_id) % (num_of_primary_shards)*
-
當分片所在的節點接收到來自協調節點的請求后,會將請求寫入到Memory Buffer,然后定時(默認是每隔1秒)寫入到Filesystem Cache,這個從Memory Buffer到Filesystem Cache的過程就叫做refresh;
-
當然在某些情況下,存在Momery Buffer和Filesystem Cache的數據可能會丟失,ES是通過translog的機制來保證數據的可靠性的。其實現機制是接收到請求后,同時也會寫入到translog中,當Filesystem cache中的數據寫入到磁盤中時,才會清除掉,這個過程叫做flush;
-
在flush過程中,內存中的緩沖將被清除,內容被寫入一個新段,段的fsync將創建一個新的提交點,并將內容刷新到磁盤,舊的translog將被刪除并開始一個新的translog。
-
flush觸發的時機是定時觸發(默認30分鐘)或者translog變得太大(默認為512M)時;
6.5 Elasticsearch更新和刪除文檔的流程?
-
刪除和更新也都是寫操作,但是Elasticsearch中的文檔是不可變的,因此不能被刪除或者改動以展示其變更;
-
磁盤上的每個段都有一個相應的.del文件。當刪除請求發送后,文檔并沒有真的被刪除,而是在.del文件中被標記為刪除。該文檔依然能匹配查詢,但是會在結果中被過濾掉。當段合并時,在.del文件中被標記為刪除的文檔將不會被寫入新段。
-
在新的文檔被創建時,Elasticsearch會為該文檔指定一個版本號,當執行更新時,舊版本的文檔在.del文件中被標記為刪除,新版本的文檔被索引到一個新段。舊版本的文檔依然能匹配查詢,但是會在結果中被過濾掉。
6.6 Elasticsearch搜索的流程?
-
搜索被執行成一個兩階段過程,我們稱之為 Query Then Fetch;
-
在初始查詢階段時,查詢會廣播到索引中每一個分片拷貝(主分片或者副本分片)。 每個分片在本地執行搜索并構建一個匹配文檔的大小為 from + size 的優先隊列。PS:在搜索的時候是會查詢Filesystem Cache的,但是有部分數據還在Memory Buffer,所以搜索是近實時的。
-
每個分片返回各自優先隊列中 所有文檔的 ID 和排序值 給協調節點,它合并這些值到自己的優先隊列中來產生一個全局排序后的結果列表。
-
接下來就是取回階段,協調節點辨別出哪些文檔需要被取回并向相關的分片提交多個 GET 請求。每個分片加載并豐富文檔,如果有需要的話,接著返回文檔給協調節點。一旦所有的文檔都被取回了,協調節點返回結果給客戶端。
6.7 Elasticsearch 在部署時,對 Linux 的設置有哪些優化方法?
-
64 GB 內存的機器是非常理想的, 但是32 GB 和16 GB 機器也是很常見的。少于8 GB 會適得其反。
-
如果你要在更快的 CPUs 和更多的核心之間選擇,選擇更多的核心更好。多個內核提供的額外并發遠勝過稍微快一點點的時鐘頻率。
-
如果你負擔得起 SSD,它將遠遠超出任何旋轉介質。 基于 SSD 的節點,查詢和索引性能都有提升。如果你負擔得起,SSD 是一個好的選擇。
-
即使數據中心們近在咫尺,也要避免集群跨越多個數據中心。絕對要避免集群跨越大的地理距離。
-
通過設置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time可以在集群重啟的時候避免過多的分片交換,這可能會讓數據恢復從數個小時縮短為幾秒鐘。
-
不要隨意修改垃圾回收器(CMS)和各個線程池的大小。
補充:索引階段性能提升方法
-
使用批量請求并調整其大小:每次批量數據 5–15 MB 大是個不錯的起始點。
-
如果你的搜索結果不需要近實時的準確度,考慮把每個索引的index.refresh_interval 改到30s。
-
如果你在做大批量導入,考慮通過設置index.number_of_replicas: 0 關閉副本。
6.8 GC方面,在使用Elasticsearch時要注意什么?
? 倒排詞典的索引需要常駐內存,無法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使用情況做持續的監控。
6.9 在并發情況下,Elasticsearch如果保證讀寫一致?
-
可以通過版本號使用樂觀并發控制,以確保新版本不會被舊版本覆蓋,由應用層來處理具體的沖突;
-
另外對于寫操作,一致性級別支持quorum/one/all,默認為quorum,即只有當大多數分片可用時才允許寫操作。但即使大多數可用,也可能存在因為網絡等原因導致寫入副本失敗,這樣該副本被認為故障,分片將會在一個不同的節點上重建。
-
對于讀操作,可以設置replication為sync(默認),這使得操作在主分片和副本分片都完成后才會返回;如果設置replication為async時,也可以通過設置搜索請求參數_preference為primary來查詢主分片,確保文檔是最新版本。
6.10 如何監控 Elasticsearch 集群狀態?
elasticsearch-head插件
通過 Kibana 監控 Elasticsearch。你可以實時查看你的集群健康狀態和性能,也可以分析過去的集群、索引和節點指標
GET /_cluster/health6.11 Elasticsearch中的集群、節點、索引、文檔、類型是什么?
-
集群是一個或多個節點(服務器)的集合,它們共同保存您的整個數據,并提供跨所有節點的聯合索引和搜索功能。群集由唯一名稱標識,默認情況下為“elasticsearch”。此名稱很重要,因為如果節點設置為按名稱加入群集,則該節點只能是群集的一部分。
-
節點是屬于集群一部分的單個服務器。它存儲數據并參與群集索引和搜索功能。
-
索引就像關系數據庫中的“數據庫”。它有一個定義多種類型的映射。索引是邏輯名稱空間,映射到一個或多個主分片,并且可以有零個或多個副本分片。 MySQL =>數據庫 Elasticsearch =>索引
-
文檔類似于關系數據庫中的一行。不同之處在于索引中的每個文檔可以具有不同的結構(字段),但是對于通用字段應該具有相同的數據類型。 MySQL => Databases => Tables => Columns / Rows Elasticsearch => Indices => Types =>具有屬性的文檔
-
類型是索引的邏輯類別/分區,其語義完全取決于用戶。
6.12 Elasticsearch中的倒排索引是什么?
倒排索引是搜索引擎的核心。搜索引擎的主要目標是在查找發生搜索條件的文檔時提供快速搜索。ES中的倒排索引其實就是lucene的倒排索引,區別于傳統的正向索引,倒排索引會再存儲數據時將關鍵詞和數據進行關聯,保存到倒排表中,然后查詢時,將查詢內容進行分詞后在倒排表中進行查詢,最后匹配數據即可。
總結
以上是生活随笔為你收集整理的ElasticSearch_高级_(集群+分片)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GNN:Weisfeiler-Lehma
- 下一篇: ETHEOS开发资源及工具集合