Elasticsearch系列---補充幾個知識點

概要

bulk api有趣的json格式

前面《簡單入門實戰》一節中,有介紹bulk的使用示例,你們必定很奇怪,還有這麼有趣的JSON格式,必須嚴格照他的換行來作,我想把JSON搞得美觀可讀性好一點,竟然給我報錯!java

{"action": {"meta"}}\n
{"data"}\n
{"action": {"meta"}}\n
{"data"}\n

它爲何要這樣規定?node

咱們想一想bulk設計的初衷,批處理的執行效率確定是第一優先級,此時效率>可讀性,若是咱們容許隨意換行,用標準格式的JSON串,會有什麼區別?算法

若是是標準格式的JSON串,處理流程通常會是這樣:json

  1. 將整個json數組所有加載,解析爲JSONArray對象,這時內存中同時有json串文本和JSONArray對象。
  2. 循環遍歷JSONArray對象,獲取每一個請求中的document進行路由信息。
  3. 把路由到同一個shard的請求合在一組,開闢一個新的請求數組,將JSONObject放在數組裏。
  4. 序列化請求數組,發送到對應的節點上去。
  5. 收集各節點的響應,彙總後返回給Coordinate Node。
  6. Coordinate Node收到全部的彙總信息,返回給客戶端。

這種方式惟一的缺點就是佔用內存多,一份json串,解析爲JSONArray對象,內存佔用翻番,bulk裏面多則幾千條請求,若是JSON報文大一點,這內存耗費不是開玩笑的,若是bulk佔用的內存過多,就可能會擠壓其餘請求的內存使用量,如搜索請求、數據分析請求等,總體性能會急速降低,嚴重的狀況可能會觸發Full GC,會致使整個JVM工做線程暫停。segmentfault

再看看現有的格式定義:除了delete操做佔一行,其餘操做都是佔兩行的,ES收到bulk請求時,就能夠簡單的按行進行切割,也不用轉成json對象了,切割完的JSON讀取裏面的meta信息,直接路由到相應的shard,收集完響應返回便可。
這樣的好處切割邏輯更簡單,都是處理小json字符串,內存快拿快放,整個ES避免對內存的大塊佔用,儘量保證性能。api

增刪改文檔內部原理

增刪改的過程總體與查詢文檔過程一致,只是多了一個數據同步的步驟,整個過程如圖所示:數組

增刪改過程圖示

類似的步驟不贅述。
步驟3的前提是primary shard操做成功,異步請求,全部的replica都返回成功後,node2響應操做成功的消息給Coordinate Node,最後Coordinate Node向客戶端返回成功消息,此時全部的primary shard和replica shard均已完成數據同步,數據是一致的。架構

查詢文檔內部原理

當咱們使用客戶端(Java或Restful API)向Elasticsearch搜索文檔數據時,能夠向任意一個node發送請求,此時接受請求的node就是Coordinate Node,整個過程如圖所示:併發

查詢過程圖示

  1. Coordinate Node接收到請求後,根據_id信息或routing信息,肯定該document的路由信息,即在哪一個shard裏,好比說P0。
  2. Coordinate Node轉發請求,使用round-robin隨機輪詢算法 ,在primary shard或replica shard隨機挑一個,讓讀請求負載均衡,如node-3的R0-1
  3. 接收請求的node-3搜索完成後,響應結果給Coordinate Node。
  4. Coordinate Node將響應結果返回給客戶端。

注意一個問題,若是document還在創建索引過程當中,可能只有primary shard有,任何一個replica shard都沒有,此時可能會沒法讀取到document,可是等document完成索引創建後,primary shard和replica shard就都有了,這個時間間隔,大概1秒左右。負載均衡

寫一致性要求

Elasticsearch在嘗試執行一個寫操做時,能夠帶上consistency參數,聲明咱們的寫一致性的級別,正確地使用這個級別,爲了不因分區故障執行寫操做,致使數據不一致,這個參數有三個值供選擇:

  • one:只要有一個primary shard是active活躍可用的,就能夠執行寫操做
  • all:必須全部的primary shard和replica shard都是活躍的,才能夠執行這個寫操做
  • quorum:默認的值,要求全部的shard中,必須是大部分的shard都是活躍的,可用的,才能夠執行這個寫操做
這個大部分,該怎麼算呢?

這個大部分,叫規定數量(quorum),有個計算公式:

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

  • primary 即一個索引下的primary shard數量;
  • number_of_replicas即每一個primary shard擁有的副本數量,注意不是一個索引全部的副本數量。

若是一個索引有3個primary shard,每一個shard擁有1個replica shard,共6個shard,這樣number_of_replicas就是1,代入公式計算:
quorum = int ((3 + 1) / 2) + 1 = 3

因此6個shard中必須有3個是活躍的,才讓你寫,若是你只啓用2個node,這樣活躍的replica shard只會有1個,加上primarys shard ,結果最可能是2。這樣是達不到quorun的值,所以將沒法索引和刪除任何文檔。
此時你必須啓動3個節點,才能知足quorum寫一致性的要求。

quorum不夠時的超時處理

若是寫操做檢查前,活躍的shard不夠致使沒法寫入時,Elasticsearch會等待,但願宕機的node可以恢復,默認60秒,可使用timeout參數修改默認值。

單node的寫一致性

照上面的公式算,1個node的,1個索引1個primary shard,number_of_replicas爲1的狀況,計算公式:

quorum = int ((1 + 1) / 2) + 1 = 2

實際只有一個primary shard是活躍的,豈不是永遠沒法寫入?我研發機器只啓動一個node,不照樣增刪改查?

原來是Elasticsearch爲了不單一node的沒法寫入問題,加了判斷邏輯:只有number_of_replicas大於1的時候,quorum纔會生效。

小結

本篇從性能優先的角度簡單對bulk的設計做了一些補充,並對文檔查詢,寫操做的原理過程,一致性級別,quorum的計算作了一些簡單講解,謝謝。

專一Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區
Java架構社區.jpg

相關文章
相關標籤/搜索