自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深度解析:Elasticsearch 寫入請(qǐng)求處理流程

開發(fā)
對(duì)于 Elasticsearch 寫入一篇文檔相信大家不陌生,但是Elasticsearch 的底層究竟是如何處理的呢,接下來(lái)讓我們一起來(lái)一探究竟。

版本:Elasticsearch 8.x

今天來(lái)看下 Elasticsearch 中的寫入流程。

不想看過程可以直接跳轉(zhuǎn)文章末尾查看總結(jié)部分。最后附上個(gè)人理解的一個(gè)圖。

從我們發(fā)出寫入請(qǐng)求,到 Elasticsearch 接收請(qǐng)求,處理請(qǐng)求,保存數(shù)據(jù)到磁盤,這個(gè)過程中經(jīng)歷了哪些處理呢?Elasticsearch 又做了哪些操作?對(duì)于 Elasticsearch 寫入一篇文檔相信大家不陌生,但是Elasticsearch 的底層究竟是如何處理的呢,讓我們一起來(lái)一探究竟。

寫入流程

(1) 客戶端發(fā)送寫請(qǐng)求時(shí),發(fā)送給任意一個(gè)節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)就是所謂的協(xié)調(diào)節(jié)點(diǎn)(coordinating node)。(對(duì)應(yīng)圖中的序號(hào)1)

(2) 計(jì)算文檔要寫入的分片位置,使用 Hash 取模算法(最新版 Hash 算法)(對(duì)應(yīng)圖中序號(hào)2)。

routing_factor = num_routing_shards / num_primary_shards
shard_num = (hash(_routing) % num_routing_shards) / routing_factor

(3) 協(xié)調(diào)節(jié)點(diǎn)進(jìn)行路由,將請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的 primary sharding 所在的 datanode(對(duì)應(yīng)圖中序號(hào)2)。

(4) datanode 節(jié)點(diǎn)上的 primary sharding 處理請(qǐng)求,寫入數(shù)據(jù)到索引庫(kù),并且將數(shù)據(jù)同步到對(duì)應(yīng)的 replica sharding(對(duì)應(yīng)圖中序號(hào)3)。

(5) 等 primary sharding 和 replica sharding 都保存好之后返回響應(yīng)(對(duì)應(yīng)圖中序號(hào) 4,5,6)。

路由分片算法

在7.13版本之前,計(jì)算方式如下:

shard_num = hash(_routing) % num_primary_shards

從7.13 版本開始,不包括 7.13 ,計(jì)算方式就改為了上述步驟2的計(jì)算方式。

routing_factor = num_routing_shards / num_primary_shards
shard_num = (hash(_routing) % num_routing_shards) / routing_factor
  • num_routing_shards 就是配置文件中 index.number_of_routing_shard 的值。
  • num_primary_shard 就是配置文件中 index.number_of_shard 的值。
  • _routing 默認(rèn)就是文檔的 ID,但是我們可以自定義該路由值。

等待激活的分片

此處以 Create index API 舉例說明,其中有一個(gè)請(qǐng)求參數(shù) wait_for_active_shards。 該參數(shù)的作用就是寫入請(qǐng)求發(fā)送到ES之后,需要等待多少數(shù)量的分片處于激活狀態(tài)后再繼續(xù)執(zhí)行后續(xù)操作。如果所需要數(shù)量的分片副本不足,則寫入操作需等待并重試,直到所有的分片副本都已經(jīng)啟動(dòng)或者發(fā)生超時(shí)。

默認(rèn)情況下,寫入操作僅等待主分片處于活動(dòng)狀態(tài)后繼續(xù)執(zhí)行(即 wait_for_active_shard=1)。

  • (可選)的字符串值。
  • 默認(rèn)1。
  • 可以設(shè)置為all,或者任意一個(gè)正整數(shù),最多是索引的副本分片數(shù)+1(number_of_replicas+1)。

該設(shè)置極大的降低了寫操作未寫入所需數(shù)量分片副本的機(jī)會(huì),但是并沒有完全避免。

寫入原理

先來(lái)一個(gè)官網(wǎng)的寫入流程圖(地址在文末獲?。?。

Elasticsearh 寫入流程圖

近實(shí)時(shí)

對(duì)于 Elasticsearch 的寫入流程來(lái)說,就三部分:

  • 寫入到內(nèi)存緩沖區(qū)。
  • 寫入打開新的 segment。
  • 寫入 disk。

為什么稱為近實(shí)時(shí),是因?yàn)樵趯懭氲絻?nèi)存緩沖區(qū)的時(shí)候,我們是還無(wú)法進(jìn)行檢索的,等到寫入到segment之后,就可以進(jìn)行檢索到了,所以這是近實(shí)時(shí)的原因。

因?yàn)橄鄬?duì)于寫到磁盤,打開 segment 寫入文件系統(tǒng)緩存的代價(jià)比寫入磁盤的代價(jià)低的多。

第一步、寫入文檔到內(nèi)存緩沖區(qū)(此時(shí)文檔不可被檢索)。

第二步、緩沖區(qū)的內(nèi)容寫入到 segment,但是還未提交(可被檢索)。

在 Elasticsearch 中,寫入和打開一個(gè)新segment的過程稱為 refresh,refresh操作會(huì)自上次刷新(refresh)以來(lái)執(zhí)行的所有操作都可用搜索。

refresh觸發(fā)的方式有如下三種:

  • 刷新間隔到了自動(dòng)刷新。
  • URL增加?refresh參數(shù),需要傳空或者true。
  • 調(diào)用Refresh API手動(dòng)刷新

默認(rèn)情況下,Elasticsearch 每秒定期刷新,但是僅限于在過去的30s內(nèi)收到的一個(gè)或者多個(gè) search請(qǐng)求。這個(gè)也就是近實(shí)時(shí)的一個(gè)點(diǎn),文檔的更改不會(huì)立即顯示在下一次的檢索中,需要等待 refresh 操作完成之后才可以檢索出來(lái)。

我們可以通過如下方式觸發(fā)refresh操作或者調(diào)整自動(dòng)刷新的間隔。

POST /_refresh 
POST /blogs/_refresh

調(diào)整刷新間隔,每 30s 刷新:

PUT /my_logs
{
  "settings": {
    "refresh_interval": "30s" 
  }
}

關(guān)閉自動(dòng)刷新:

PUT /my_logs/_settings
{ "refresh_interval": -1 } 

設(shè)置為每秒自動(dòng)刷新:

PUT /my_logs/_settings
{ "refresh_interval": "1s" 

refresh_interval 需要一個(gè) 持續(xù)時(shí)間 值, 例如 1s (1 秒) 或 2m (2 分鐘)。 一個(gè)絕對(duì)值 1 表示的是 1毫秒 --無(wú)疑會(huì)使你的集群陷入癱瘓。

段(segment)合并

由于 refresh 操作會(huì)每秒自動(dòng)刷新生成一個(gè)新的段(segment),這樣的話短時(shí)間內(nèi),segment會(huì)暴增,segment數(shù)量太多,每一個(gè)都會(huì)造成文件句柄、內(nèi)存、CPU的大量消耗,還有一個(gè)更重要的點(diǎn)就是,每個(gè)檢索請(qǐng)求也會(huì)輪流檢查每一個(gè)segment,所以segment越多,檢索也就越慢。

Elasticsearch 通過在后臺(tái)自動(dòng)合并 segment 來(lái)解決這個(gè)問題的。小的segment被合并到大的segment,然后大的segment在被合并到更大的segment。

segment 合并的時(shí)候會(huì)自動(dòng)將已刪除的文檔從文件系統(tǒng)中刪除,已經(jīng)刪除的文檔或者更新文檔的舊版本不會(huì)被合并到新的 segment中。

  • 當(dāng) index 的時(shí)候,refresh操作會(huì)創(chuàng)建新的segment,并將segment打開以供檢索。
  • 合并進(jìn)行會(huì)選擇一小部分大小相似的segment,在后臺(tái)將他們合并到更大的segment中,這個(gè)操作不會(huì)中斷 index 與 search 操作。

optimize API

optimize API 不應(yīng)該用在經(jīng)常更新的索引上。

該 optimize API 可以控制分片最大的 segment數(shù)量,對(duì)于有的索引,例如日志,每天、每周、每月的日志被單獨(dú)存在一個(gè)索引上,老得索引一般都是只讀的,也不太可能發(fā)生變化,所以我們就可以使用這個(gè) optimize API 優(yōu)化老的索引,將每個(gè)分片合并為一個(gè)單獨(dú)的segment。這樣既可以節(jié)省資源,也可以加快檢索速度。

合并索引中的每個(gè)分片為一個(gè)單獨(dú)的段:

POST /logstash-2014-10/_optimize?max_num_segments=1 

持久化

上述的refresh操作是 Elasticsearch 近實(shí)時(shí) 的原因,那么數(shù)據(jù)的持久化就要看fsync操作把數(shù)據(jù)從文件系統(tǒng)緩沖區(qū)flush到磁盤了。所以只有當(dāng)translog被fsync操作或者是提交時(shí),translog中的數(shù)據(jù)才會(huì)持久化到磁盤。

如果沒有持久化操作,當(dāng) Elasticsearch 宕機(jī)發(fā)生故障的時(shí)候,就會(huì)發(fā)生數(shù)據(jù)丟失了,所以 Elasticsearch 依賴于translog進(jìn)行數(shù)據(jù)恢復(fù)。

在 Elasticsearch 進(jìn)行提交操作的時(shí)候,成本是非常高的,所以策略就是在寫入到內(nèi)存緩沖區(qū)的時(shí)候,同步寫入一份數(shù)據(jù)到translog,所有的index與delete操作都會(huì)在內(nèi)部的lucene索引處理后且未確認(rèn)提交之前寫入teanslog。

如果發(fā)生了異常,當(dāng)分片數(shù)據(jù)恢復(fù)時(shí),已經(jīng)確認(rèn)提交但是并沒有被上次lucene提交操作包含在內(nèi)的最近操作就可以在translog中進(jìn)行恢復(fù)。

Elasticsearch 的 flush操作是執(zhí)行 Lucene提交并開始生成新的translog的過程,為了確保translog文件不能過大,flush操作在后臺(tái)自動(dòng)執(zhí)行,否則在恢復(fù)的時(shí)候也會(huì)因?yàn)槲募^大花費(fèi)大量的時(shí)間。

對(duì)于translog有如下設(shè)置選項(xiàng):

  • index.translog.durability 默認(rèn)設(shè)置為request ,意思就是只有當(dāng)主分片和副本分片fsync且提交translog之后,才會(huì)向客戶端響應(yīng)index,delete,update,bulk請(qǐng)求成功。
  • index.translog.durability 設(shè)置為async,則 Elasticsearch 會(huì)在每個(gè)index.translog.sync_interval 提交 translog,如果遇到節(jié)點(diǎn)恢復(fù),則在這個(gè)區(qū)間執(zhí)行的操作就可能丟失。

對(duì)于上述的幾個(gè)參數(shù),都可以動(dòng)態(tài)更新:

(1) index.translog.sync_interval:將 translog fsync到磁盤并提交的頻率。默認(rèn)5s,不允許小于100ms。

(2) index.translog.durability:是否在每次index,delete,update,bulk操作之后提交translog。

  • request: 默認(rèn),fsync 每次請(qǐng)求之后提交,如果發(fā)生故障,所有已確認(rèn)的寫入操作到已經(jīng)提交到磁盤
  • async: fsync在后臺(tái)每個(gè)sync_interval時(shí)間間隔提交。如果發(fā)生故障,自上次提交以來(lái)所有已確認(rèn)的寫入操作將被丟棄。

(3) index.translog.flush_threshold_size:防止 translog 文件過大的設(shè)置,一旦達(dá)到設(shè)置的該值,就會(huì)發(fā)生 flush 操作,并生成一個(gè)新的 commit point。默認(rèn)512mb。

總結(jié)

(1) 一個(gè)文檔被index之后,添加內(nèi)存緩存區(qū),同時(shí)寫入 translog。

(2) refresh 操作完成后,緩存被清空,但是 translog 不會(huì)

  • 內(nèi)存緩沖區(qū)的文檔被寫入到一個(gè)新的segment中,且沒有進(jìn)行fsync操作。
  • segment 打開,可供檢索。
  • 內(nèi)存緩沖區(qū)清空。

(3) 更多的文檔被添加到內(nèi)存緩沖區(qū)并追加到 translog。

(4) 每隔一段時(shí)間,translog 變得越來(lái)越大,索引被刷新(flush),一個(gè)新的 translog 被創(chuàng)建,并且一個(gè)提交執(zhí)行。

  • 所有內(nèi)存緩沖區(qū)的文檔都被寫入到一個(gè)新的段。
  • 緩沖區(qū)被清空。
  • 一個(gè)提交點(diǎn)寫入磁盤。
  • 文件系統(tǒng)緩存通過fsync被刷新(flush)。
  • 老的 translog 被刪除。

translog 提供所有還沒有被刷到磁盤的操作的一個(gè)持久化記錄。當(dāng) Elasticsearch 啟動(dòng)的時(shí)候,它會(huì)從磁盤中使用的最后一個(gè)提交點(diǎn)(commit point)去恢復(fù)已知的 segment ,并且會(huì)重放 translog 中所有在最后一次提交后發(fā)生的變更操作。

translog 也被用來(lái)提供實(shí)時(shí)的CRUD,當(dāng)我們通過ID進(jìn)行查詢、更新、刪除一個(gè)文檔、它會(huì)嘗試在相應(yīng)的 segment 中檢索之前,首先檢查 translog 中任何最近的變更操作。也就是說這個(gè)是可以實(shí)時(shí)獲取到文檔的最新版本。

最后送上一個(gè)我自己理解的圖,參考了官網(wǎng)的描述,以及網(wǎng)上畫的,如有錯(cuò)誤歡迎指出。

責(zé)任編輯:趙寧寧 來(lái)源: 醉魚Java
相關(guān)推薦

2022-07-04 09:15:10

Spring請(qǐng)求處理流程

2019-11-27 11:10:58

TomcatOverviewAcceptor

2010-08-09 11:14:36

Flex事件處理

2011-06-16 15:17:16

2010-01-06 15:16:58

Ubuntu啟動(dòng)流程

2020-10-20 06:41:59

Elasticsear日志

2012-08-30 09:48:02

Struts2Java

2023-12-14 13:28:00

Spring流程Web

2021-10-20 06:47:50

Elasticsear場(chǎng)景引擎

2023-10-10 08:52:36

射與分析相開源

2023-12-06 07:14:28

前端API中間件

2011-07-28 18:25:27

Cocoa 異步請(qǐng)求 libxml2

2024-10-12 12:55:26

2024-07-15 00:00:00

POST瀏覽器網(wǎng)絡(luò)

2010-03-02 17:43:31

WCF框架處理流程

2021-10-04 09:14:18

ElasticSear深度分頁(yè)

2009-03-25 17:41:50

NehalemIntel服務(wù)器

2010-09-17 10:50:35

sip請(qǐng)求

2024-01-11 12:14:31

Async線程池任務(wù)

2020-02-25 15:47:05

ElasticsearLucene地方
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)