1. 程式人生 > >elasticsearch 增刪改查底層原理

elasticsearch 增刪改查底層原理

elasticsearch專欄:https://www.cnblogs.com/hello-shf/category/1550315.html

一、預備知識

在對document的curd進行深度分析之前,我們不得不瞭解以下幾個小的知識點,不瞭解一下幾個知識點我們將很難理解document是如何進行增刪改查的。

 

1.1、路由(索引)與primary shard不可變

大家有沒有考慮過這個問題,當你索引一個文件,它被儲存在單獨一個主分片上。Elasticsearch是如何知道文件屬於哪個分片的呢?當你建立一個新文件,它是如何知道是應該儲存在分片1還是分片2上的呢? 程序不能是隨機的,因為我們將來要檢索文件。事實上,它根據一個簡單的演算法決定:

shard = hash(routing) % number_of_primary_shards 

routing值是一個任意字串,它預設是 _id 但也可以自定義。這個 routing 字串通過哈 希函式生成一個數字,然後除以主切片的數量得到一個餘數(remainder),餘數的範圍永遠 是 0 到 number_of_primary_shards - 1 ,這個數字就是特定文件所在的分片。

這也解釋了為什麼主分片的數量只能在建立索引時定義且不能修改:如果主分片的數量在未來改變了,所有先前的路由值就失效了,文件也就永遠找不到了。

我們演示一下這個路由的過程。假設我們有三個節點,一個student索引,對應有三個primary shard和一個replica shard。此時叢集如圖1所示

向該節點中插入一個document,並且我們指定_id(在es中_id可以自定義es也可以自動生成)假如_id = 1000,根據我們上面描述,此時會按照如下演算法計算其會命中哪個shard。假設此時hash(1000)= 13;

shard = hash(routing) % number_of_primary_shards
即:
shard = 13 % 3 = 1;(假設hash(1000) = 13)
注:因為es的hash函式具體是怎麼計算的不得而知,也不重要,我們主要是關注其原理。

 根據計算可得該插入請求會命中P1,shard此時會將該document插入到P1。是不是很簡單。

以上也可就是es路由的過程,也可稱為es索引(這個索引是動詞,理解一下)過程。

 

1.2、shard負載均衡與節點對等

在es叢集中每個節點,每個shard(包括primary shard和replica shard)都具備處理任何請求的能力。這意味著在es叢集中節點間是高度的負載均衡的,即並不是只有主節點是流量的入口,每個節點都具備處理請求的能力。primary shard和replica shard也是高度負載均衡的,因為並不是只有primary shard才具備處理curd的能力,replica shard可處理檢索的請求。這也是es的效能為什麼表現這麼好的原因之一。

 

二、document增、刪、改

2.1、增刪改過程分析

新建、索引和刪除請求都是寫(write)操作,它們必須在primary shard上成功完成才能複製到相關的replica shard分片上。

關於新增document索引過程可以參考《es的索引過程》

 

 

 

 如上圖所示,從客戶端發起請求到es叢集向客戶端響應大致可以分為以上6個階段。

階段1:

  客戶端向node1發起增、刪、改請請求。node1將作為協調節點(coordinate node)進行相關工作。

階段2:

  node1根據文件 _id 計算出命中的primary shard為P1,然後將請求轉發到node2,P1分片位於node2上面。

階段3:

  node2在P1上處理該請求。如果請求處理成功,node2將會把請求繼續轉發到其副本R1上。R1位於node3。

階段4:

  node3在R1上處理完該請求,如果成功,node3會將處理成功的訊息返回給node2。

階段5:

  node2收到P1副本處理成功的訊息,也就意味著該請求已經處理完成。然後將處理結果返回給node1節點。

階段6:

  協調節點node1收到響應結果後,將該結果返回給客戶端。

整個過程就完成了。

看到這裡大家是不是也在思考一個請求進來,我還要等待所有的分片都處理完成這個操作才算是完成,這樣是不是很影響響應速度。基於這個思考,es同樣也給我們提供了自定義引數的支援,比如我們可以使用replication引數來指定primary shard是不是要等到replica shard處理完成後才能響應到客戶端。但是,該配置配置引數並不推薦使用,大家知道有這麼個東西就行了。

replication:預設值為 sync  該值意味著primary shard需要等到其所有的副本分片都完成後才會響應客戶端。如果我們將該值設定為 async ,意味著primary shard完成後就會返回給客戶端,但是並不意味著其不會將請求轉發到副本上,主分片依然會將請求轉發到replica shard上,只不過我們不再確定副本是不是也完成了該請求,這樣將不能保證資料的一致性。  

2.1、寫一致性保障

首先需要說明的一點,增刪改其實都是一個寫操作,所以這裡的寫指的是增刪改三個操作。 這裡我們所說的寫一致性指的是primary shard和replica shard上資料的一致性。es API為我們提供了一個可自定的引數consistency。該引數可以讓我們自定義處理一次增刪改請求,是不是必須要求所有分片都是active的才會執行。 該引數可選的值有三個:one,all,quorum(default,預設)。
1 one:要求我們這個寫操作,只要有一個primary shard是active活躍可用的,就可以執行。
2 all:要求我們這個寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執行這個寫操作
3 quorum:預設的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執行這個寫操作

 上面三點其實很好理解,只有quorum所謂的“大部分”感覺不是那麼的明確。下面有個公式,當叢集中的active(可用)分片數量達到如下公式結果時寫操作就是可以執行的。否則該操作將無法進行。

int( (primary + number_of_replicas) / 2 ) + 1

依然用我們上面的例子,假設我們建立了一個student索引,並且設定primary shard為3個,replica shard有1個(這個1個是相對於索引來說的,對於主分片該數字1意味著每個primary shard都對應的存在一個副本)。也就意味著primary=3,number_of_replicas=1(依然是相對於索引)。shard總數為6。

此時計算上面公式可知:

int((3+1)/2) + 1 = 3
也就是說當叢集中可用的shard數量>=3寫操作就是可以執行的。 說了這麼多好像還沒解釋以上跟寫一致性有什麼關係。es對寫一致性的保證就是通過quorum來保證的,以為quorum要求es叢集中的可用shard數量達到一定要求才能執行。也就間接保證了shard的資料一致性。 具體使用也很簡單
PUT /index/type/id?consistency=quorum

 當然如果我們不指定就是使用預設的,也就是quorum。

 

三、document檢索

document的檢索過程和增刪改略有不同:文件能夠從主分片(primary shard)或任意一個複製分片(replicashard)被檢索。

 

檢索過程大致可以分為4個階段

階段1:

  客戶端向node1傳送檢索請求。node1將作為協調節點(coordinate node)進行相關工作。

階段2:

  node1根據文件 _id 計算出命中的primary shard為P1,node1會找到P1的所有副本,然後通過round-robin隨機輪詢演算法,在primary shard以及其所有replica中隨機選擇一個,讓讀請求負載均衡。假如此時隨機選取的是P1,node1會將該請求轉發到P1對應的節點上。

階段3:

  P1處理完該請求將結果返回給協調節點node1。

階段4:

  協調節點node1收到該node2的相應結果,進而將該結果返回給客戶端。

可能的情況是,一個被索引的文件已經存在於主分片上卻還沒來得及同步到複製分片上。這時複製分片會報告文件未找到,主分片會成功返回文件。一旦索引請求成功返回給使用者,文件則在主分片和複製分片都是可用的。 對與mget和bulk批量請求,與單文件檢索還有一點區別,差別是協調節點需要計算每個文件所在的分片。它把多文件請求拆成每個分片的對文件請求,然後轉發每個參與的節點。一旦接收到每個節點的應答,然後整理這些響應組合為一個單獨的響應,最後返回給客戶端。        

 

  參考文獻:

  《elasticsearch-權威指南》

 

  如有錯誤的地方還請留言指正。

  原創不易,轉載請註明原文地址:https://www.cnblogs.com/hello-shf/p/11543480.