Elasticsearch學習筆記

江北、發表於2020-07-05

前言

  • 為什麼es查詢和聚合都這麼快?底層是如何實現的?
  • 資料在es叢集中如何儲存的?如何做到自動分散式的?
  • 為什麼es的主分片數設定了之後就不能調整,而副本分片數可以調整?
  • 如何優化索引方式和查詢方式,有效利用快取,提高查詢效率?
  • 如果保證不停服的情況下,平滑升級或擴容?
  • 如何優化查詢效率?

相信看完Elasticsearch權威指南這本書,所有疑問都將得到解答

一. 基本概念

1. 分片

  • 最小級別的工作單元,儲存索引中一部分資料。是一個Lucene例項,本身就是一個完整的搜尋引擎。但是應用程式不會直接與分片通訊。
  • 可以想象成容器,節點間資料遷移以分片為單位
  • 分為主分片和副分片(主分片的副本)
  • 索引建立的時候,主分片的數量就固定了,但是副本分片數量可調整
  • 預設一個索引分配5個主分片
  • 主分片所在節點掛掉後,重新選舉主節點,並將副分片升級為主分片
  • 故障節點重新啟動後,會同步故障期間未同步到到資料

2. 文件

  • 根物件序列化成json物件
  • 每次對文件的操作(包括修改,刪除),_version都會加一
  • 文件是不可修改的。update是先刪除,再新建一個新的
  • 刪除的文件並不會被立即移除,只是標記為刪除。之後後臺再清理
  • 自己設定文件的版本:新增version_type=external引數

3. 衝突解決

  • 通過版本號實現樂觀鎖解決衝突問題

4. 文件後設資料

  • _index 文件儲存的地方
  • _type 文件代表的物件的類(7.x的版本將去掉_type)
  • _id 文件的唯一標識。可手動設定也可自動生成(22位長)

5. 叢集架構圖

兩個節點,三個主分片,一個副分片的效果圖

Elasticsearch學習筆記

擴充套件到三個節點到效果圖

Elasticsearch學習筆記

6. 叢集狀態

叢集狀態是一個資料結構,叢集狀態存在每個客戶端中。儲存以下資訊

  • 級別設定
  • 叢集節點
  • 索引以及相關的對映,別名等資訊
  • 索引的分片,以及分配的節點

叢集狀態-status

  • green:所有主分片和副分片都已經分配
  • yellow:所有主分片都已分配,至少有一個副本分片沒有分配
  • red:至少一個主分片(或全部副分片)缺失

二. 叢集工作原理

1. 資料是如何在分散式系統儲存的

  • 文件通過路由存放到分片
  • 通過以下演算法得出該文件儲存時的分片編號
    shard = hash(routing) % number_of_primary_shards
    複製程式碼
  • routing是任意字串,預設是_id
  • 主分片的數量不可改變,否則之前的路由失效,文件就找不到了
  • 自定義路由可以保證有關聯性的文件被儲存在同一個分片

2. 主分片和複製分片如何互動?

  • 請求能夠被髮送給任意節點
  • 每個節點都有能力處理任意請求
  • 每個節點都知道任意文件所在節點(儲存的叢集狀態),並轉發請求
  • 傳送請求時最好迴圈每個節點以負載均衡

2.1 write操作(新建、刪除、索引)

順序步驟

Elasticsearch學習筆記

  • 客戶端傳送請求(新建,刪除,索引)到node1節點
  • 節點使用hash演算法得出分片編號0,因為分片0在節點3,將請求轉發到節點3
  • node3成功儲存資料到主分片,如果成功,轉發請求到node1和node2到副節點
  • 所有複製節點成功,傳送成功回覆到請求節點1,節點1再返回給客戶端
可調的引數
  • replication:預設為sync,主分片得到複製分片成功響應才返回。async表示請求在主分片執行成功就返回,依舊轉發請求到副分片,不過不知道成功與否
  • consistency:主分片嘗試寫入時,需要規定數量(quorum)或過半的分片可用。可為one,all,quorum(預設)。quorum只有在number_of_replicas大於1時才生效
    int((primary[總是1] + number_of_replicas) /2 + 1)
    複製程式碼
  • timeout:分片不足時,等待時間。預設1min

2.2 read操作

Elasticsearch學習筆記

  • 客戶端傳送get請求到node1
  • 節點使用hash演算法,得到文件所屬到主分片為0分片
  • 找到分片0的副分片所在節點為node1,node2,node3
  • 通過某種策略選定某個副分片節點,比如node2
  • node2返回文件給node1
  • 然後node1返回給客戶端

2.3 update操作

順序步驟

Elasticsearch學習筆記

  • 客戶端給node1傳送更新請求
  • 通過雜湊演算法得到主分片位置,轉發請求到node3
  • node3檢索出文件,修改_source欄位到json文件,然後重建索引。如果有其他程式修改了文件,它以retry_on_conflict設定的次數重複這一步,都未成功則放棄
  • node3更新成功則傳送整個新文件(並不是修改請求)到node1和node2的複製節點重建索引,都成功則返回給node1,再返回給客戶端

2.4 多文件模式

mget 多文件read

Elasticsearch學習筆記

  • 客戶端傳送mget請求給node1
  • node1為每個分片構建一個請求,並轉發到對應分片所在節點
  • 當所有回覆被接收,node1組合這些響應,返回給客戶端
bulk 多文件write

Elasticsearch學習筆記

  • 客戶端向node1傳送請求
  • node1為每個分片構建批量請求,然後轉發到這些主分片上
  • 主分片按序執行,每一個完成時,傳送到副分片上
  • 所有操作都完成後節點整理響應返回給客戶端

3. 索引是如何建立的

3.1 基本概念

  • 對映(mapping):用於欄位確認,每個欄位匹配為確認的資料型別
  • 分析(analysis):全文文字分詞,以建立倒排索引
  • 倒排索引:由文件中單詞的唯一列表和單詞在文件中的位置組成,用於快速檢索結果而設計

3.2 分析(analysis)

分析的過程
  • 分析由分析器(analyzer)完成
  • 分析過程先標記一段文字為單獨的詞(item)
  • 然後標準化(比如全部轉為小寫)item,以提高搜尋性
  • 分析的詳情可通過_analyze API檢視
分析器包括的元件

es提供很多可用直接使用的元件,可自定義組合使用

  • 字元過濾器(character filter):字串先經過這做一些過濾操作
  • 分詞器(tokenizer):將文字切分為單詞,比如空格,逗號等。中文可用專門的分詞器
  • 標記過濾器(token filter):修改詞語,比如轉小寫,去掉語氣詞,增加同義詞
內建的分析器
  • 標準分析器:預設使用這個。標準切分,去掉大部分符號,最後轉為小寫
  • 空格分析器:按空格切分,不轉換為小寫
  • 語言分析器:根據特定語言的特性做分析
查詢方式
  • 欄位查詢:精確匹配,查詢前不會將被查詢的字串分析
  • 全文查詢:查詢前會先用分析器分析要查詢的字串
手動指定分析器
  • 當往es中加入字串時,es會自動用標準分析器做分詞,但是可能某些字元就是普通的id,標籤等欄位,不需要做分析,可手動指定對映
建立索引時查詢分析器的順序
  • mapping檔案中指定欄位的analyzer
  • 文件本身的_analyzer欄位
  • mapping檔案中指定型別的預設analyzer
  • mapping檔案中全域性預設的analyzer
  • 節點級別預設的analyzer
  • 標準analyzer
查詢索引時查詢分析器的順序
  • 查詢引數中的analyzer
  • mapping檔案中指定欄位的analyzer
  • mapping檔案中指定型別的analyzer
  • mapping檔案中全域性預設的analyzer
  • 節點級別預設的analyzer
  • standard analyzer

3.3 對映

作用

定義欄位型別,欄位的資料型別以及被es處理的方式。

支援的欄位型別
型別 表示的資料型別
String string
Whole Number byte short integer long
Floating point float double
Boolean boolean
Date date

新的欄位如果沒有配置對映,es會自動猜測欄位型別

自定義欄位對映可實現的功能
  • 區分全文字串(需要分詞)和精確字串(不需要分詞)
  • 使用特定語言的分析器
  • 優化部分匹配欄位
  • 指定自定義日期格式
對映包含的引數
  • properties:列出了可能包含的每個欄位的對映
  • 後設資料欄位:_type, _id, _source
  • dynamic:確定欄位新增時的策略(_source會一直儲存)
    • ture 自動新增
    • false 忽略欄位
    • strict 丟擲異常
  • 設定項:如analyzer
  • 其他設定
自定義欄位對映注意點
  • 要對映的欄位引數為type, 除了string外,很少需要對映其他type
  • string欄位的index欄位,控制字串以什麼方式被索引。
    含義
    analyzed 分詞索引
    not_analyzed 不分詞索引
    no 不索引
  • string欄位選擇anlyzed為index時,analyzer指定分析器。如:simple, english, whitespace
  • 更新對映只能新增欄位,不能修改已經被新增的欄位。否則會導致出錯索引不到
文件欄位的屬性
  • type
  • index
  • analyzer
  • ip
  • geo_point
  • geo_shape
後設資料_source欄位
  • 作用: 用於儲存原始json欄位
  • 為什麼需要
    • 搜尋結果能得到完整文件
    • 缺少它,部分更新請求不起作用
    • 更新對映檔案時,可直接取內容
    • 更易排查錯誤
  • 怎麼禁用:enabled:false
  • 使用:搜尋時可以通過_source指定只返回哪些列
後設資料_all欄位
  • 查詢不知道指定哪個欄位時,使用_all。也可禁用。使用_all時,會將其他所有欄位的值作為一個大的字串進行索引
動態模版

dynamic_templates 設定通過欄位名或型別動態匹配不同的對映

  • match_mapping_type 模版使用的資料型別
  • match 模版使用的欄位名
  • path 模版使用的欄位全路徑(巢狀json)

三. 結構化查詢語言

1. 過濾

概述

文件的欄位是否包含特定值,比查詢更快,結果可快取

原則上全文索引或者需要其他相關性評分的使用查詢語句,其他情況都用過濾。

重要的過濾語句

  • term:精確匹配
  • terms:多個條件的精確匹配
  • range:範圍過濾
  • exists:是否包含指定欄位
  • missing:沒有某個欄位
  • bool:合併多個過濾查詢結果
    • must:and
    • must_not:not
    • shoud:or

過濾順序

  • 過濾順序對效能有很大影響
  • 更詳細的過濾條件應該放在最前,以便排除更多的文件
  • 被快取的過濾應該放到不會快取的過濾前面(快取參考後面章節)

2. 查詢

簡述

每個文件的欄位與特定欄位的匹配程度如何,比過濾慢,結果不可快取

重要的查詢語句

  • math_all:查詢所有文件
  • match:標準查詢,全文和精確都支援

    match指定多個值時,內部分詞後會執行多個match並放入bool查詢。預設為or。可通過operator引數改為“and”

  • multi_match:同時搜尋多個欄位,支援萬用字元
  • bool:同bool過濾,多的是要計算_score

3. 相關性排序

排序方式

  • _score:預設排序方式,預設倒序

  • 欄位排序:_score不需要計算,預設正序

  • 多級排序:可指定多個欄位。先用第一個欄位排序,第一個相同時排第二個

  • 字串引數排序:

    被分析的欄位進行強制排序會消耗大量記憶體

相關性簡介

相似度演算法:TF/IDF(檢索詞詞頻/反向文件頻率)
  • TF: 詞頻,出現在當前文件次數越多,相關性越大
  • IDF:反轉文件頻率,所有文件數與出現這個詞的檔案數百分比,詞出現頻率越大,IDF越小
  • 由於效能問題,每個分片只會計算該分片內的IDF,而不是所有文件
  • boost引數可以設定權重

4. 分散式搜尋的執行方式

概述

搜尋包括查詢多個分片,並將多個分片元資訊合併,然後再根據後設資料獲取真正資料兩個步驟。

查詢多個索引和查詢一個索引完全一致,無非是多查了幾個分片。擴充套件的時候,可以不用將舊資料遷移到新索引,直接新建索引,然後查詢兩個索引,或者別名索引即可

查詢(query)

Elasticsearch學習筆記

  • 客戶端傳送search給node3,建立一個from+size的空優先順序佇列

  • 廣播請求到每個分片,每個分片在本地執行查詢,並放到一個大小為from+size的本地優先順序佇列裡

  • 每個節點返回查詢結果(id和_score)給node3,node3將結果全域性排序

    • 多個請求會輪詢所有的分片副本以負載均衡,提高系統吞吐率
    • 多索引的工作機制和單索引類似,只不過多了些分片
    • 深度分頁會導致排序過程非常繁重,佔用巨大cpu和寬頻

取回(fetch)

Elasticsearch學習筆記

  • 協調節點辨別出哪些文件需要取回,並向相應分片傳送請求
  • 每個分片載入文件,並做相關處理(比如高亮),然後返回給協調節點
  • 協調節點將資料返回給客戶端

搜尋選項(可選引數)

  • preference:控制使用哪個分片或節點處理請求
  • timeout:協調節點等待多久就放棄其他節點的結果
  • routing:限制只搜尋哪些分片,對於大規模系統很有用
  • search_type:query_then_fetch為預設的搜尋型別
    • count:當不需要結果,只需要數量時
    • query_and_fetch:查詢並且取回
    • dfs_query_and_fetch,dfs_query_then_fetch
    • scan:掃描,和scroll一起使用。可高效取回大量資料。禁用排序實現

掃描和滾屏

scroll

類似傳統資料庫的遊標,搜尋的是查詢時的索引快照,查詢結束之前的修改不會感知到

scan

不排序,只要有結果就返回

四. 分片內部原理

1. 索引動態更新原理

1.1 倒排索引-保證文件可被搜尋

1.2 倒排索引的內容是不可變的

1.3 不可變的同時動態新增段

查詢的時候,所有段依次查詢,然後聚合結果,通過這種方式,新文件以最小代價加入文件

Elasticsearch學習筆記

Elasticsearch學習筆記

  • 新的文件首先寫入記憶體區的索引快取
  • buffer中包括新的段包含的倒排索引,段名等
  • buffer被提交
  • 新段被開啟,文件可被索引
  • 記憶體快取被清除,等待新文件

1.4 刪除和更新

因為段不可變,更新和刪除操作並不是真的刪除,是通過新增.del檔案和新建段檔案,查詢返回前將標記為del的檔案從結果中刪除

1.5 近實時搜尋

因為從buffer刷入磁碟代價很大。es允許一旦一個檔案被快取,就可以設定段開啟,檔案可以被搜尋到

1.6 重新整理

每個分片預設每秒開啟一個新段,所以新的改動需要1s後才能看到。可以設定refresh_interval減少重新整理的頻率

1.7 持久化變更

新增緩衝buffer的同時,通過新增事務日誌(預設512M),保證資料被完整持久化。每次flush(每30分鐘,或事務日誌過大)到磁碟時,段被全部提交,清空事務日誌

1.8 合併段

通過每秒自動重新整理段,不用多久段資料就劇增。每個段消耗計算機資源,且每次查詢都要依次檢查每個段,段越多查詢越慢。es後臺合併段解決該問題。 合併大的段會消耗io和cpu資源。

1.9 Optimize API

強制合併段。對於資料不再變動的索引很有效,對資料還在動態增長的索引不要使用。

2. 快取

概述

  • 快取針對過濾查詢
  • 核心是一個位元組集儲存哪些文件符合過濾條件
  • 快取的位元組集是增量更新的
  • 每個過濾器都是獨立快取的,且可複用
  • 大部分枝葉過濾器(如term)會被快取,而組合過濾器(如bool)不會被快取

不可被快取的情況

  • 指令碼過濾器,指令碼對es是不透明的
  • Geo(地址)過濾器,不太會被重用
  • 日期範圍精確到毫秒不會被快取,整數會被快取

過濾時間範圍的使用建議

  • 對於時間精確到毫秒的查詢,可拆分為日期+日期時間兩個過濾條件,前者會被快取,且順序不要改變

五. 全文檢索

1. 全文檢索包括兩個方面

  • 相關度(Relevance):TF/IDF,地理位置相近度,模糊相似度或其他演算法
  • 分析(Analysis):分詞,建立倒排索引

2. 全文查詢分類

  • 低階查詢:term查詢。沒有分析階段,會精確匹配特定短語
  • 全文檢索:match,query_string等查詢。有分析階段。
    • date,integer型別:精確查詢
    • not_analyzed的string型別:分析查詢詞語(比如轉小寫),執行單個短語查詢
    • analyzed的string型別:先解析查詢語句,生成短語列表。查詢後再合併查詢結果

六. 聚合

1. 基本概念

桶(buckets)

滿足特定條件的文件的集合。類似於sql裡面的group by

指標(metrics)

對桶內的文件進行統計計算。類似sql裡面的count,sum,max等統計方法

2. 近似聚合

2.1 概述

  • 分散式演算法三個因子模型同時只能選擇滿足兩項:精確,實時,大資料
  • ea選擇大資料和實時。會提供準確但不是100%精確的結果,以犧牲一點小的估算錯誤作為代價,換來告訴的執行效率和極小的記憶體消耗
  • 兩個近似演算法:cardinality, percentiles

2.2 cardinality 基數度量

  • 類似sql的distinct
  • 是一個近似演算法。基於HyperLogLot++(HLL)演算法的。HLL先對輸入做雜湊運算,根據hash運算的記過中的bits做概率估算得到基數。HLL 論文
  • 演算法特性
    • 可配置精度:引數為precision_threshold (精度更高=跟多記憶體)
    • precision_threshold範圍為0-4000,資料結構使用記憶體為:precision_threshold * 8
    • 設定為100時,可保證百萬級別的資料量誤差維持5%以內
    • 小的資料集精度非常高
    • 可配置使用的固定記憶體量
  • 優化:預先計算hash值,不過效能的瓶頸由聚合時轉移到索引時(必須重新建索引,新增hash欄位),需要根據業務場景來確定。

2.3 percentiles 百分位數度量

  • 展現了以某個具體百分比執行觀察到的數值,通常用於找出異常。
  • 也是一個近似演算法。使用TDigest演算法
  • 演算法特性
    • 極端百分比的情況下,資料更準確。比如1%或99%。這由資料結構決定。
    • 小資料集精度非常準確

3. significant_terms

  • sigterms和其他聚合不同,用於發現資料集中醫學異常指標
  • 通過統計資料並對比正常資料找到可能有異常頻次的指標

4. 聚合的資料結構

4.1 Doc Values

  • 聚合,排序使用Doc Values的資料結構

  • 將文件對映到他們包含的詞項

    Elasticsearch學習筆記

  • 在索引時和倒排索引同時生成。基於segment且不可變。

  • Doc values資料存放到磁碟中,不是由jvm管理。

  • 採用列式儲存,資料整齊排布,便於壓縮

  • 不支援analyzed欄位

  • 除了analyzed的字串,預設所有欄位都開啟doc values。如果你永遠不會對某些欄位進行聚合,排序操作,可以禁用doc values。可以節省磁碟空間和索引速度

4.2 Fielddata

  • anaylzed的字串,使用Fielddata這種資料結構支援聚合,fielddata儲存在記憶體堆中,舊版本沒有doc values時是用的fielddata
  • anaylzed的過程會消耗極大記憶體,且生成大量token,對聚合很不友好
  • fieldata會一直存在記憶體中,直到被驅逐或節點崩潰。注意觀察它的大小。
  • dielddata不會在建索引時存在,是查詢時建立的
  • indices.fielddata.cache.size:百分比或實際大小。 控制為 fielddata 分配的堆空間大小。每次聚合查詢時,分析欄位會載入到Fielddata中,如果查詢結果中 fielddata 大小超過了指定的大小 ,其他的值將會被回收從而獲得空間。
  • 如果沒有足夠空間可以將 fielddata 保留在記憶體中,Elasticsearch 就會時刻從磁碟過載資料,並回收其他資料以獲得更多空間。記憶體的回收機制會導致重度磁碟I/O,並且在記憶體中生成很多垃圾,這些垃圾必須在晚些時候被回收掉。
  • 監控filddata: GET /_stats/fielddata?fields=*

5. 聚合優化

  • 針對大量資料的巢狀聚合查詢,效率極低。預設的查詢方式為深度優先。
  • 可以使用廣度優先處理聚合數量遠遠小於總組數的情況。引數為collect_mode: breadth_first

七. 地理位置

1. 設定欄位型別為地理位置

地理座標點不能被動態對映欄位檢測,需要顯式申明對應欄位型別(type引數)為geo_point

2. geo_point格式

  • 字串: "40.715, -74.011", 維度在前,精度在後
  • 陣列: [40.715, -74.011], 維度在前,精度在後
  • 物件: {"lat": 40.715, "lon": -74.011}

3. 過濾方式

  • geo_bounding_box :: 落在指定矩形框中的座標點
  • geo_distance :: 給定距離內的點
  • geo_distance_range :: 距離範圍內的點
  • geo_polygon :: 落在多邊形中的點

4. 使用注意

  • 地理座標過濾器使用代價很高,它會將所有文件的地理位置資訊載入記憶體,然後計算。使用時謹慎,或放到過濾的最後
  • bool過濾器預設會將地理資訊過濾排到最後
  • 預設是不被快取的
  • 每個經緯度組合需要16自己的記憶體,可設定壓縮格式,減少精度,減少記憶體
  • 合理設定精度:geohash_prefix和geohash_precision兩個引數。再結合geohash過濾器可高效查詢

5. geohash

  • 把世界分為4*8=32個單元的各自,每一個格子用一個字母或數字標識。這些單元有被繼續分解成32個更小的單元,不斷重複
  • 長度越長,精度越高
  • 有同一字首的geohash,位置靠的近,共同字首越長,距離越近
  • 剛好相鄰的位置也有可能geohash完全不同

6. 地理位置聚合

  • geo_distance 距離聚合:將文件以指定中心店為圓心的圓環分組
  • geohash_grid網格聚合:將文件按geohash單元分組,以便在地圖上呈現
  • geo_bounds: 邊界聚合:包含座標點的矩形框

7. 地理形狀(geo_shape)

  • 地理形狀是通過一個個geohash單元畫出來的

八. 資料建模

1. 關聯關係

關聯關係的處理,使用扁平化的儲存,將資料冗餘到同一個索引,提高查詢效率

2. 巢狀物件

設計

內部儲存

普通對json含有陣列時,內部儲存會被扁平化,導致邏輯關係丟失。需改為nested關係,而不是預設的object。巢狀物件內部會被索引為分離的隱藏文件

查詢

使用特殊的nested查詢或nested過濾

排序

3. 父子關係

原理

  • 和nested差不多,區別是nested是儲存在同一個文件中,而父子關係是完全不同的文件
  • 父子文件需儲存在同一個分片中
  • 父子關係對映儲存在doc-values的資料結構中,完全存在記憶體
  • 適合父文件少,子文件多的情況

優勢

  • 更新父文件時,不用更新子文件索引
  • 建立刪除修改子文件時,不影響父文件和其他文件

劣勢

  • 查詢速度比巢狀型別慢5-10倍
  • 不適合父文件多的情況

設計父子關係

  • 指定某一文件type為另一文件type的parent
  • 建立父文件時,和普通文件沒區別
  • 建立子文件時,必須通過parent指定父文件id。作用是建立關聯關係並保證分配到同一個分片(使用父文件id做hash計算)
  • 儘量少使用父子關係,僅父文件比較少的時候

4. 擴容設計

擴容思路

  • 首先檢視是否有低效率的查詢可以優化
  • 是否缺少足夠的記憶體
  • 是否開啟了swap
  • 已經建立好的索引,不可修改分片數,可通過重新索引,將舊資料遷移到新索引中
  • 搜尋效能取決於最慢節點的響應時間,合理設定分片使之負載均衡
  • 因為單索引和多索引沒有區別,可通過設定多索引以擴容

分片數量設定

  • 基於現有的資料量和定期的增長量,預估資料總量
  • 基於現有的硬體資訊,設定單個分片,0個副本,找到單個分片在當前硬體條件下能支援的最大文件數
  • 用總數量/單個分片的最大數,大致可估算出分片數

基於時間的資料流場景優化

  • 按時間切分索引
  • 舊資料不會被改變,使用optimize api進行段合併。
  • 大多數索引會有大概 50–150 個段,哪怕它們存有 TB 級別的數十億條文件。段數量過大表明合併出現了問題(比如,合併速度跟不上段的建立)
  • 不過段合併消耗掉你節點上全部的I/O資源,從而有可能使叢集失去響應。 如果你想要對索引執行optimize,你需要先把索引移到一個安全的節點,再執行。
  • 為了不影響正常索引,段合併後臺限制磁碟讀寫速率為20MB/s,可根據實際情況調整,比如SSD盤,引數為indices.store.throttle.max_bytes_per_sec。甚至在沒有查詢時,設定為none,即沒有限制,合併完再改回去。
  • 並且,對還在寫資料的索引進行優化(Optimize)操作將會是一個糟糕的想法, 因為優化操作將消耗節點上大量 I/O 並對現有索引造成衝擊
  • 我們可以臨時移除副本分片,進行優化,然後再恢復副本分片
  • 去除副本之前,可通過snapshot restore api備份資料
  • 更舊的不會被使用的資料,關閉索引。關閉後除了磁碟,不會佔用其他資源。flush(清空事務日誌)->close(關閉索引)
  • 資料歸檔:snapshot restore api將資料儲存到hdfs或其他地方

基於使用者的資料流場景

  • 指定路由:保證同類資料會分發到同一分片。查詢時也傳入路由引數,確保只查詢特定的分片,多分片查詢帶來的效能損耗
  • 使用別名,指定特定的名字對應特定的路由值和過濾器。以達到多個名稱共享一個索引的效果。看起來像多個索引一樣。
  • 當某個分片資料量劇增到需要單獨建索引時,使用_alias操作:指定action的remove和add引數,實現平滑遷移。

九. 管理,監控

1. 重要的引數配置

  • cluster.name
  • node.name
  • path.data
  • path.logs
  • path.plugins
  • discovery.zen.minum_master_nodes: 最小主節點數,防止腦裂(多個主節點)
  • discover.zen.ping.unicast.hosts: 叢集單播列表
  • gateway.recover_after_nodes 至少多少個節點,叢集才可用
  • gateway.expected_node 叢集期待有多少個節點
  • gateway.recover_fater_time 等待多久才進行資料恢復
  • logger.discovery 日誌級別
  • index.search.slowlog.threshold.query.warn : "10s" 查詢慢與10s的輸出warn日誌
  • index.search.slowlog.threshold.fetch.debug: "500ms" 查詢慢與500ms的輸出debug日誌
  • index.indexing.slowlog.threshold.index.info: "5s 查詢慢與5s的輸出info日誌
  • index.unassigned.node_left.delayed_timeout 修改延時分片時間
  • cluster.routing.allocation.enable" : "none" 禁止分片分配

2. 不要修改的配置

  • 不要更改垃圾回收器,預設使用CMS。不要更換為新一代的G1
  • 執行緒數量,預設為cpu核數。IO操作是由Lucene執行緒完成,不是es。

3. 堆記憶體的配置

  • 預設為1G,實際生產環境必須修改
  • 保證Xms和Xmx一樣,防止執行時改變堆記憶體大小,這非常消耗資源
  • 記憶體分片不要超過本機記憶體的一半。因為Lucene本身也會需要記憶體和快取。
  • 如果不需要對分詞做聚合運算,可降低堆記憶體。堆記憶體越小,Elasticsearch(更快的 GC)和 Lucene(更多的記憶體用於快取)的效能越好。
  • 記憶體不要超過32G。每個物件的指標都變長了,就會使用更多的 CPU 記憶體頻寬,也就是說你實際上失去了更多的記憶體。果你想保證其安全可靠,設定堆記憶體為 31 GB 是一個安全的選擇
  • 如果記憶體很大,可以考慮給一個機器分配多個es例項,但總的堆記憶體還是不要超過一半。同時配置cluster.routing.allocation.same_shard.host: true。防止同一個分片(主副)在一個機器上
  • 設定bootstrap.mlockall: true,鎖住記憶體,不讓發生記憶體swapping

4. 運維及優化

  • 日誌檔案預設存放在安裝目錄下的logs檔案裡,"logger.discovery" : "DEBUG"可設定日誌級別
  • 可以設定輸出慢查詢日誌
  • 如果不需要實時準確,把index.refresh_interval改到30s,做大批量倒入時,把這個值設為-1,倒入完畢後重新設定回來
  • 大批量倒入時,index.number_of_replicas設為0,關閉副本,提高效率
  • 儘量使用es自動生成的id,避免版本查詢影響效率。如果使用自己的id,使用壓縮效能良好的,避免使用太過隨機的id
  • 延遲分片:防止節點掉線然後又重啟導致的大量資料遷移問題。因為掉線的節點上的資料可能會因為失效而全部被刪除,然後重新複製。引數為index.unassigned.node_left.delayed_timeout

5. 滾動重啟

  • 保證不停叢集功能的情況下逐一對每個節點進行升級或維護
  • 先停止索引新的資料
  • 禁止分片分配。cluster.routing.allocation.enable" : "none"
  • 關閉單個節點,並執行升級維護
  • 啟動節點,並等待加入叢集
  • 重啟分片分配。cluster.routing.allocation.enable" : "all"
  • 對其他節點重複以上步驟
  • 恢復索引更新資料

相關文章