成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

求求你,別再問我Elasticsearch了!

存儲 存儲軟件 開發工具
如今,越來越多的企業在業務場景是使用 Elasticsearch(下文統一稱為 ES) 存儲自己的非結構化數據。

 如今,越來越多的企業在業務場景是使用 Elasticsearch(下文統一稱為 ES) 存儲自己的非結構化數據。

[[357043]] 

圖片來自 Pexels

例如電商業務實現商品站內搜索,數據指標分析,日志分析等,ES 作為傳統關系型數據庫的補充,提供了關系型數據庫不具備的一些能力。

ES 最先進入大眾視野的是其能夠實現全文搜索的能力,也是由于基于 Lucene 的實現,內部有一種倒排索引的數據結構。

本文作者將介紹 ES 的分布式架構,以及 ES 的存儲索引機制,本文不會詳細介紹 ES 的 API,會從整體架構層面進行分析。

什么是倒排索引

要講明白什么是倒排索引,首先我們先梳理下什么索引,比如一本書,書的目錄頁,有章節,章節名稱,我們想看哪個章節,我們通過目錄頁,查到對應章節和頁碼,就能定位到具體的章節內容。

通過目錄頁的章節名稱查到章節的頁碼,進而看到章節內容,這個過程就是一個索引的過程,那么什么是倒排索引呢?

比如查詢《java 編程思想》這本書的文章,翻開書本可以看到目錄頁,記錄這個章節名字和章節地址頁碼。

通過查詢章節名字“繼承”可以定位到“繼承”這篇章節的具體地址,查看到文章的內容,我們可以看到文章內容中包含很多“對象”這個詞。

那么如果我們要在這本書中查詢所有包含有“對象”這個詞的文章,那該怎么辦呢?

按照現在的索引方式無疑大海撈針,假設我們有一個“對象”--→文章的映射關系,不就可以了嗎?類似這樣的反向建立映射關系的就叫倒排索引。

如圖 1 所示,將文章進行分詞后得到關鍵詞,在根據關鍵詞建立倒排索引,關鍵詞構建成一個詞典,詞典中存放著一個個詞條(關鍵詞),每個關鍵詞都有一個列表與其對應。

 

圖 1

這個列表就是倒排表,存放的是章節文檔編號和詞頻等信息,倒排列表中的每個元素就是一個倒排項。

最后可以看到,整個倒排索引就像一本新華字典,所有單詞的倒排列表往往順序地存儲在磁盤的某個文件里,這個文件被稱之為倒排文件。

詞典和倒排文件是 Lucene 的兩種基本數據結構,但是存儲方式不同,詞典在內存中存儲,倒排文件在磁盤上。

本文不會去介紹分詞,tf-idf,BM25,向量空間相似度等構建倒排索引和查詢倒排索引所用到的技術,讀者只需要對倒排索引有個基本的認識即可。

ES 的集群架構

集群節點

一個 ES 集群可以有多個節點構成,一個節點就是一個 ES 服務實例,通過配置集群名稱 cluster.name 加入集群。

那么節點是如何通過配置相同的集群名稱加入集群的呢?要搞明白這個問題,我們必須先搞清楚 ES 集群中節點的角色。

ES 中節點有角色的區分的,通過配置文件 conf/elasticsearch.yml 中配置以下配置進行角色的設定。

  1. node.master: true/false 
  2. node.data: true/false 

集群中單個節點既可以是候選主節點也可以是數據節點,通過上面的配置可以進行兩兩組合形成四大分類:

  • 僅為候選主節點
  • 既是候選主節點也是數據節點
  • 僅為數據節點
  • 既不是候選主節點也不是數據節點

候選主節點:只有是候選主節點才可以參與選舉投票,也只有候選主節點可以被選舉為主節點。

主節點:負責索引的添加、刪除,跟蹤哪些節點是群集的一部分,對分片進行分配、收集集群中各節點的狀態等,穩定的主節點對集群的健康是非常重要。

數據節點:負責對數據的增、刪、改、查、聚合等操作,數據的查詢和存儲都是由數據節點負責,對機器的 CPU,IO 以及內存的要求比較高,一般選擇高配置的機器作為數據節點。

此外還有一種節點角色叫做協調節點,其本身不是通過設置來分配的,用戶的請求可以隨機發往任何一個節點,并由該節點負責分發請求、收集結果等操作,而不需要主節點轉發。

這種節點可稱之為協調節點,集群中的任何節點都可以充當協調節點的角色。每個節點之間都會保持聯系。

 

圖 2

發現機制

前文說到通過設置一個集群名稱,節點就可以加入集群,那么 ES 是如何做到這一點的呢?

這里就要講一講 ES 特殊的發現機制 ZenDiscovery。

ZenDiscovery 是 ES 的內置發現機制,提供單播和多播兩種發現方式,主要職責是集群中節點的發現以及選舉 Master 節點。

多播也叫組播,指一個節點可以向多臺機器發送請求。生產環境中 ES 不建議使用這種方式,對于一個大規模的集群,組播會產生大量不必要的通信。

單播,當一個節點加入一個現有集群,或者組建一個新的集群時,請求發送到一臺機器。

當一個節點聯系到單播列表中的成員時,它就會得到整個集群所有節點的狀態,然后它會聯系 Master 節點,并加入集群。

只有在同一臺機器上運行的節點才會自動組成集群。ES 默認被配置為使用單播發現,單播列表不需要包含集群中的所有節點,它只是需要足夠的節點,當一個新節點聯系上其中一個并且通信就可以了。

如果你使用 Master 候選節點作為單播列表,你只要列出三個就可以了。

這個配置在 elasticsearch.yml 文件中:

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

集群信息收集階段采用了 Gossip 協議,上面配置的就相當于一個 seed nodes,Gossip 協議這里就不多做贅述了。

ES 官方建議 unicast.hosts 配置為所有的候選主節點,ZenDiscovery 會每隔 ping_interval(配置項)ping 一次。

每次超時時間是 discovery.zen.ping_timeout(配置項),3 次(ping_retries 配置項)ping 失敗則認為節點宕機,宕機的情況下會觸發 failover,會進行分片重分配、復制等操作。

如果宕機的節點不是 Master,則 Master 會更新集群的元信息,Master 節點將最新的集群元信息發布出去,給其他節點。

其他節點回復 Ack,Master 節點收到 discovery.zen.minimum_master_nodes 的值 -1 個候選主節點的回復,則發送 Apply 消息給其他節點,集群狀態更新完畢。

如果宕機的節點是 Master,則其他的候選主節點開始 Master 節點的選舉流程。

①選主

Master 的選主過程中要確保只有一個 master,ES 通過一個參數 quorum 的代表多數派閾值,保證選舉出的 master 被至少 quorum 個的候選主節點認可,以此來保證只有一個 master。

選主的發起由候選主節點發起,當前候選主節點發現自己不是 master 節點,并且通過 ping 其他節點發現無法聯系到主節點。

并且包括自己在內已經有超過 minimum_master_nodes 個節點無法聯系到主節點,那么這個時候則發起選主。

選主流程圖如下:

 

圖 3

選主的時候按照集群節點的參數

排序后第一個節點即為 Master 節點。當一個候選主節點發起一次選舉時,它會按照上述排序策略選出一個它認為的 Master。

②腦裂

提到分布式系統選主,不可避免的會提到腦裂這樣一個現象,什么是腦裂呢?如果集群中選舉出多個 Master 節點,使得數據更新時出現不一致,這種現象稱之為腦裂。

簡而言之集群中不同的節點對于 Master 的選擇出現了分歧,出現了多個 Master 競爭。

一般而言腦裂問題可能有以下幾個原因造成:

  • 網絡問題:集群間的網絡延遲導致一些節點訪問不到 Master,認為 Master 掛掉了,而 master 其實并沒有宕機,而選舉出了新的 Master,并對 Master 上的分片和副本標紅,分配新的主分片。
  • 節點負載:主節點的角色既為 Master 又為 Data,訪問量較大時可能會導致 ES 停止響應(假死狀態)造成大面積延遲,此時其他節點得不到主節點的響應認為主節點掛掉了,會重新選取主節點。
  • 內存回收:主節點的角色既為 Master 又為 Data,當 Data 節點上的 ES 進程占用的內存較大,引發 JVM 的大規模內存回收,造成 ES 進程失去響應。

如何避免腦裂:我們可以基于上述原因,做出優化措施:

  • 適當調大響應超時時間,減少誤判。通過參數 discovery.zen.ping_timeout 設置節點 ping 超時時間,默認為 3s,可以適當調大。
  • 選舉觸發,我們需要在候選節點的配置文件中設置參數 discovery.zen.munimum_master_nodes 的值。

這個參數表示在選舉主節點時需要參與選舉的候選主節點的節點數,默認值是 1,官方建議取值(master_eligibel_nodes/2)+1,其中 master_eligibel_nodes 為候選主節點的個數。

這樣做既能防止腦裂現象的發生,也能最大限度地提升集群的高可用性,因為只要不少于 discovery.zen.munimum_master_nodes 個候選節點存活,選舉工作就能正常進行。

當小于這個值的時候,無法觸發選舉行為,集群無法使用,不會造成分片混亂的情況。

  • 角色分離,即是上面我們提到的候選主節點和數據節點進行角色分離,這樣可以減輕主節點的負擔,防止主節點的假死狀態發生,減少對主節點宕機的誤判。

索引如何寫入的

寫索引原理

①分片

ES 支持 PB 級全文搜索,通常我們數據量很大的時候,查詢性能都會越來越慢,我們能想到的一個方式的將數據分散到不同的地方存儲。

ES 也是如此,ES 通過水平拆分的方式將一個索引上的數據拆分出來分配到不同的數據塊上,拆分出來的數據庫塊稱之為一個分片 Shard,很像 MySQL 的分庫分表。

不同的主分片分布在不同的節點上,那么在多分片的索引中數據應該被寫入哪里?

肯定不能隨機寫,否則查詢的時候就無法快速檢索到對應的數據了,這需要有一個路由策略來確定具體寫入哪一個分片中,怎么路由我們下文會介紹。

在創建索引的時候需要指定分片的數量,并且分片的數量一旦確定就不能修改。

②副本

副本就是對分片的復制,每個主分片都有一個或多個副本分片,當主分片異常時,副本可以提供數據的查詢等操作。

主分片和對應的副本分片是不會在同一個節點上的,避免數據的丟失,當一個節點宕機的時候,還可以通過副本查詢到數據,副本分片數的最大值是 N-1(其中 N 為節點數)。

對 doc 的新建、索引和刪除請求都是寫操作,這些寫操作是必須在主分片上完成,然后才能被復制到對應的副本上。

ES 為了提高寫入的能力這個過程是并發寫的,同時為了解決并發寫的過程中數據沖突的問題,ES 通過樂觀鎖的方式控制,每個文檔都有一個 _version 號,當文檔被修改時版本號遞增。

一旦所有的副本分片都報告寫成功才會向協調節點報告成功,協調節點向客戶端報告成功。

 

圖 4

③Elasticsearch 的寫索引流程

上面提到了寫索引是只能寫在主分片上,然后同步到副本分片,那么如圖 4 所示,這里有四個主分片分別是 S0、S1、S2、S3,一條數據是根據什么策略寫到指定的分片上呢?

這條索引數據為什么被寫到 S0 上而不寫到 S1 或 S2 上?這個過程是根據下面這個公式決定的:

  1. shard = hash(routing) % number_of_primary_shards 

以上公式的值是在 0 到 number_of_primary_shards-1 之間的余數,也就是數據檔所在分片的位置。

routing 通過 Hash 函數生成一個數字,然后這個數字再除以 number_of_primary_shards(主分片的數量)后得到余數。

routing 是一個可變值,默認是文檔的 _id ,也可以設置成一個自定義的值。

在一個寫請求被發送到某個節點后,該節點按照前文所述,會充當協調節點,會根據路由公式計算出寫哪個分片,當前節點有所有其他節點的分片信息,如果發現對應的分片是在其他節點上,再將請求轉發到該分片的主分片節點上。

在 ES 集群中每個節點都通過上面的公式知道數據的在集群中的存放位置,所以每個節點都有接收讀寫請求的能力。

那么為什么在創建索引的時候就確定好主分片的數量,并且不可修改?因為如果數量變化了,那么所有之前路由計算的值都會無效,數據也就再也找不到了。

 

圖 5

如上圖 5 所示,當前一個數據通過路由計算公式得到的值是 shard=hash(routing)%4=0。

則具體流程如下:

  • 數據寫請求發送到 node1 節點,通過路由計算得到值為 1,那么對應的數據會應該在主分片 S1 上。
  • node1 節點將請求轉發到 S1 主分片所在的節點 node2,node2 接受請求并寫入到磁盤。
  • 并發將數據復制到三個副本分片 R1 上,其中通過樂觀并發控制數據的沖突。一旦所有的副本分片都報告成功,則節點 node2 將向 node1 節點報告成功,然后 node1 節點向客戶端報告成功。

這種模式下,只要有副本在,寫入延時最小也是兩次單分片的寫入耗時總和,效率會較低。

但是這樣的好處也很明顯,避免寫入后單個機器硬件故障導致數據丟失,在數據完整性和性能方面,一般都是優先選擇數據,除非一些允許丟數據的特殊場景。

在 ES 里為了減少磁盤 IO 保證讀寫性能,一般是每隔一段時間(比如 30 分鐘)才會把數據寫入磁盤持久化。

對于寫入內存,但還未 flush 到磁盤的數據,如果發生機器宕機或者掉電,那么內存中的數據也會丟失,這時候如何保證?

對于這種問題,ES 借鑒數據庫中的處理方式,增加 CommitLog 模塊,在 ES 中叫 transLog,在下面的 ES 存儲原理中會介紹。

存儲原理

上面介紹了在 ES 內部的寫索引處理流程,數據在寫入到分片和副本上后,目前數據在內存中,要確保數據在斷電后不丟失,還需要持久化到磁盤上。

我們知道 ES 是基于 Lucene 實現的,內部是通過 Lucene 完成的索引的創建寫入和搜索查詢。

Lucene 工作原理如下圖所示,當新添加一片文檔時,Lucene 進行分詞等預處理,然后將文檔索引寫入內存中,并將本次操作寫入事務日志(transLog)。

transLog 類似于 MySQL 的 binlog,用于宕機后內存數據的恢復,保存未持久化數據的操作日志。

默認情況下,Lucene 每隔 1s(refresh_interval 配置項)將內存中的數據刷新到文件系統緩存中,稱為一個 segment(段)。

一旦刷入文件系統緩存,segment 才可以被用于檢索,在這之前是無法被檢索的。

因此 refresh_interval 決定了 ES 數據的實時性,因此說 ES 是一個準實時的系統。

segment 在磁盤中是不可修改的,因此避免了磁盤的隨機寫,所有的隨機寫都在內存中進行。

隨著時間的推移,segment 越來越多,默認情況下,Lucene 每隔 30min 或 segment 空間大于 512M,將緩存中的 segment 持久化落盤,稱為一個 commit point,此時刪掉對應的 transLog。

當我們在進行寫操作的測試的時候,可以通過手動刷新來保障數據能夠被及時檢索到,但是不要在生產環境下每次索引一個文檔都去手動刷新,刷新操作會有一定的性能開銷。一般業務場景中并不都需要每秒刷新。

可以通過在 Settings 中調大 refresh_interval = "30s" 的值,來降低每個索引的刷新頻率,設值時需要注意后面帶上時間單位,否則默認是毫秒。

當 refresh_interval=-1 時表示關閉索引的自動刷新。

 

圖 6

索引文件分段存儲并且不可修改,那么新增、更新和刪除如何處理呢?

  • 新增,新增很好處理,由于數據是新的,所以只需要對當前文檔新增一個段就可以了。
  • 刪除,由于不可修改,所以對于刪除操作,不會把文檔從舊的段中移除而是通過新增一個 .del 文件,文件中會列出這些被刪除文檔的段信息,這個被標記刪除的文檔仍然可以被查詢匹配到, 但它會在最終結果被返回前從結果集中移除。
  • 更新,不能修改舊的段來進行文檔的更新,其實更新相當于是刪除和新增這兩個動作組成。會將舊的文檔在 .del 文件中標記刪除,然后文檔的新版本中被索引到一個新的段。可能兩個版本的文檔都會被一個查詢匹配到,但被刪除的那個舊版本文檔在結果集返回前就會被移除。

segment 被設定為不可修改具有一定的優勢也有一定的缺點。

優點:

  • 不需要鎖。如果你從來不更新索引,你就不需要擔心多進程同時修改數據的問題。
  • 一旦索引被讀入內核的文件系統緩存,便會留在哪里,由于其不變性。只要文件系統緩存中還有足夠的空間,那么大部分讀請求會直接請求內存,而不會命中磁盤。這提供了很大的性能提升.
  • 其它緩存(像 Filter 緩存),在索引的生命周期內始終有效。它們不需要在每次數據改變時被重建,因為數據不會變化。
  • 寫入單個大的倒排索引允許數據被壓縮,減少磁盤 I/O 和需要被緩存到內存的索引的使用量。

缺點:

  • 當對舊數據進行刪除時,舊數據不會馬上被刪除,而是在 .del 文件中被標記為刪除。而舊數據只能等到段更新時才能被移除,這樣會造成大量的空間浪費。
  • 若有一條數據頻繁的更新,每次更新都是新增新的,標記舊的,則會有大量的空間浪費。
  • 每次新增數據時都需要新增一個段來存儲數據。當段的數量太多時,對服務器的資源例如文件句柄的消耗會非常大。
  • 在查詢的結果中包含所有的結果集,需要排除被標記刪除的舊數據,這增加了查詢的負擔。

①段合并

由于每當刷新一次就會新建一個 segment(段),這樣會導致短時間內的段數量暴增,而 segment 數目太多會帶來較大的麻煩。

大量的 segment 會影響數據的讀性能。每一個 segment 都會消耗文件句柄、內存和 CPU 運行周期。

更重要的是,每個搜索請求都必須輪流檢查每個 segment 然后合并查詢結果,所以 segment 越多,搜索也就越慢。

因此 Lucene 會按照一定的策略將 segment 合并,合并的時候會將那些舊的已刪除文檔從文件系統中清除。被刪除的文檔不會被拷貝到新的大 segment 中。

合并的過程中不會中斷索引和搜索,倒排索引的數據結構使得文件的合并是比較容易的。

段合并在進行索引和搜索時會自動進行,合并進程選擇一小部分大小相似的段,并且在后臺將它們合并到更大的段中,這些段既可以是未提交的也可以是已提交的。

合并結束后老的段會被刪除,新的段被刷新到磁盤,同時寫入一個包含新段且排除舊的和較小的段的新提交點,新的段被打開,可以用來搜索。

段合并的計算量龐大,而且還要吃掉大量磁盤 I/O,并且段合并會拖累寫入速率,如果任其發展會影響搜索性能。

ES 在默認情況下會對合并流程進行資源限制,所以搜索性能可以得到保證。

 

圖 7

寫在最后

本文對 ES 的架構原理和索引存儲和寫機制進行介紹,ES 的整體架構體系相對比較巧妙,我們在進行系統設計的時候可以借鑒其設計思路,本文只介紹 ES 整體架構部分。

作者:官網商城開發團隊

編輯:陶家龍

出處:轉載自公眾號vivo互聯網技術(ID:vivoVMIC)

 

責任編輯:武曉燕 來源: vivo互聯網技術
相關推薦

2020-04-16 08:22:11

HTTPS加解密協議

2018-09-28 05:25:53

TopK算法代碼

2020-12-15 08:06:45

waitnotifyCondition

2020-09-24 14:40:55

Python 開發編程語言

2020-04-22 11:19:07

貪心算法動態規劃

2018-11-01 13:49:23

桶排序排序面試

2018-10-28 22:37:00

計數排序排序面試

2020-06-15 08:12:51

try catch代碼處理器

2022-10-27 21:34:28

數據庫機器學習架構

2021-01-22 10:09:23

簡歷求職者面試

2015-02-13 10:42:31

前端工具Dreamweaver

2020-11-09 08:22:29

程序員 IT科技

2020-03-30 17:20:54

B+樹SQL索引

2019-12-17 09:29:02

數據庫架構分庫分表

2021-05-11 07:10:18

標準庫DjangoOS

2018-11-06 11:40:19

時間復雜度面試算法

2019-07-08 10:00:52

Java內存模型并發

2020-12-04 10:05:00

Pythonprint代碼

2020-12-02 11:18:50

print調試代碼Python

2020-09-02 08:04:59

多線程互聯網高并發
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 五月激情婷婷在线 | 国产乱码久久久久久一区二区 | 日韩欧美一区二区在线播放 | 四虎影院新网址 | 亚洲色图综合 | 欧美一级久久久猛烈a大片 日韩av免费在线观看 | 亚洲欧美一区二区三区在线 | 亚洲综合国产精品 | 国产精品久久久久免费 | 久久中文字幕一区 | 欧美一区2区三区4区公司 | aaa在线| 狠狠爱一区二区三区 | 91高清免费观看 | 久久999| 91精品国产91久久久久久吃药 | 欧美日韩一区二区在线观看 | 日韩视频在线观看中文字幕 | 中文字幕一区二区三区在线乱码 | 欧美日韩视频在线第一区 | av片免费观看 | 曰批视频在线观看 | 国产精品av久久久久久久久久 | 国产午夜视频 | 午夜免费网站 | 国产美女一区 | 国产在线观看免费 | 欧美一区二区三区四区在线 | 亚洲午夜精品一区二区三区 | 免费99精品国产自在在线 | 91电影| 国产小视频在线看 | 99精品在线免费观看 | 国产精品美女 | 欧美一区免费在线观看 | 日韩中文字幕在线视频 | 三级黄视频在线观看 | 蜜桃一区二区三区 | 青青久在线视频 | 午夜影院视频在线观看 | 国产精品成人一区二区 |