點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號(hào)”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
一、ElasticSearch基礎(chǔ):
1、什么是Elasticsearch:
Elasticsearch 是基于 Lucene 的 Restful 的分布式實(shí)時(shí)全文搜索引擎,每個(gè)字段都被索引并可被搜索,可以快速存儲(chǔ)、搜索、分析海量的數(shù)據(jù)。
全文檢索是指對(duì)每一個(gè)詞建立一個(gè)索引,指明該詞在文章中出現(xiàn)的次數(shù)和位置。當(dāng)查詢時(shí),根據(jù)事先建立的索引進(jìn)行查找,并將查找的結(jié)果反饋給用戶的檢索方式。這個(gè)過程類似于通過字典中的檢索字表查字的過程。
2、Elasticsearch 的基本概念:
(1)index 索引:索引類似于mysql 中的數(shù)據(jù)庫(kù),Elasticesearch 中的索引是存在數(shù)據(jù)的地方,包含了一堆有相似結(jié)構(gòu)的文檔數(shù)據(jù)。
(2)type 類型:類型是用來定義數(shù)據(jù)結(jié)構(gòu),可以認(rèn)為是 mysql 中的一張表,type 是 index 中的一個(gè)邏輯數(shù)據(jù)分類
(3)document 文檔:類似于 MySQL 中的一行,不同之處在于 ES 中的每個(gè)文檔可以有不同的字段,但是對(duì)于通用字段應(yīng)該具有相同的數(shù)據(jù)類型,文檔是es中的最小數(shù)據(jù)單元,可以認(rèn)為一個(gè)文檔就是一條記錄。
(4)Field 字段:Field是Elasticsearch的最小單位,一個(gè)document里面有多個(gè)field
(5)shard 分片:?jiǎn)闻_(tái)機(jī)器無法存儲(chǔ)大量數(shù)據(jù),es可以將一個(gè)索引中的數(shù)據(jù)切分為多個(gè)shard,分布在多臺(tái)服務(wù)器上存儲(chǔ)。有了shard就可以橫向擴(kuò)展,存儲(chǔ)更多數(shù)據(jù),讓搜索和分析等操作分布到多臺(tái)服務(wù)器上去執(zhí)行,提升吞吐量和性能。
(6)replica 副本:任何一個(gè)服務(wù)器隨時(shí)可能故障或宕機(jī),此時(shí) shard 可能會(huì)丟失,因此可以為每個(gè) shard 創(chuàng)建多個(gè) replica 副本。replica可以在shard故障時(shí)提供備用服務(wù),保證數(shù)據(jù)不丟失,多個(gè)replica還可以提升搜索操作的吞吐量和性能。primary shard(建立索引時(shí)一次設(shè)置,不能修改,默認(rèn)5個(gè)),replica shard(隨時(shí)修改數(shù)量,默認(rèn)1個(gè)),默認(rèn)每個(gè)索引10個(gè) shard,5個(gè)primary shard,5個(gè)replica shard,最小的高可用配置,是2臺(tái)服務(wù)器。
3、什么是倒排索引:
在搜索引擎中,每個(gè)文檔都有一個(gè)對(duì)應(yīng)的文檔 ID,文檔內(nèi)容被表示為一系列關(guān)鍵詞的集合。例如,某個(gè)文檔經(jīng)過分詞,提取了 20 個(gè)關(guān)鍵詞,每個(gè)關(guān)鍵詞都會(huì)記錄它在文檔中出現(xiàn)的次數(shù)和出現(xiàn)位置。那么,倒排索引就是 關(guān)鍵詞到文檔 ID 的映射,每個(gè)關(guān)鍵詞都對(duì)應(yīng)著一系列的文件,這些文件中都出現(xiàn)了該關(guān)鍵詞。有了倒排索引,搜索引擎可以很方便地響應(yīng)用戶的查詢。
要注意倒排索引的兩個(gè)重要細(xì)節(jié):
4、DocValues的作用:
倒排索引也是有缺陷的,假如我們需要對(duì)數(shù)據(jù)做一些聚合操作,比如排序/分組時(shí),lucene內(nèi)部會(huì)遍歷提取所有出現(xiàn)在文檔集合的排序字段,然后再次構(gòu)建一個(gè)最終的排好序的文檔集合list,這個(gè)步驟的過程全部維持在內(nèi)存中操作,而且如果排序數(shù)據(jù)量巨大的話,非常容易就造成solr內(nèi)存溢出和性能緩慢。
DocValues 就是 es 在構(gòu)建倒排索引的同時(shí),構(gòu)建了正排索引,保存了docId到各個(gè)字段值的映射,可以看作是以文檔為維度,從而實(shí)現(xiàn)根據(jù)指定字段進(jìn)行排序和聚合的功能。另外doc Values 保存在操作系統(tǒng)的磁盤中,當(dāng)docValues大于節(jié)點(diǎn)的可用內(nèi)存,ES可以從操作系統(tǒng)頁(yè)緩存中加載或彈出,從而避免發(fā)生內(nèi)存溢出的異常,docValues遠(yuǎn)小于節(jié)點(diǎn)的可用內(nèi)存,操作系統(tǒng)自然將所有Doc Values存于內(nèi)存中(堆外內(nèi)存),有助于快速訪問。
5、text 和 keyword類型的區(qū)別:
兩個(gè)的區(qū)別主要分詞的區(qū)別:keyword 類型是不會(huì)分詞的,直接根據(jù)字符串內(nèi)容建立倒排索引,keyword類型的字段只能通過精確值搜索到;Text 類型在存入 Elasticsearch 的時(shí)候,會(huì)先分詞,然后根據(jù)分詞后的內(nèi)容建立倒排索引
6、什么是停頓詞過濾:
停頓詞可以看成是沒有意義的詞,比如“的”、“而”,這類詞沒有必要建立索引
7、query 和 filter 的區(qū)別?
(1)query:查詢操作不僅僅會(huì)進(jìn)行查詢,還會(huì)計(jì)算分值,用于確定相關(guān)度;
(2)filter:查詢操作僅判斷是否滿足查詢條件,不會(huì)計(jì)算任何分值,也不會(huì)關(guān)心返回的排序問題,同時(shí),filter 查詢的結(jié)果可以被緩存,提高性能。
二、ES的寫入流程:
1、es 寫數(shù)據(jù)的過程:

(1)客戶端選擇一個(gè) node 發(fā)送請(qǐng)求過去,這個(gè) node 就是 coordinating node (協(xié)調(diào)節(jié)點(diǎn))
(2)coordinating node 對(duì) document 進(jìn)行路由,將請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的 node(有 primary shard)
(3)實(shí)際的 node 上的 primary shard 處理請(qǐng)求,然后將數(shù)據(jù)同步到 replica node
(4)coordinating node 等到 primary node 和所有 replica node 都執(zhí)行成功之后,就返回響應(yīng)結(jié)果給客戶端。
2、寫數(shù)據(jù)的底層原理:

(1)數(shù)據(jù)先寫入 memory buffer,然后定時(shí)(默認(rèn)每隔1s)將 memory buffer 中的數(shù)據(jù)寫入一個(gè)新的 segment 文件中,并進(jìn)入 Filesystem cache(同時(shí)清空 memory buffer),這個(gè)過程就叫做 refresh;
ES 的近實(shí)時(shí)性:數(shù)據(jù)存在 memory buffer 時(shí)是搜索不到的,只有數(shù)據(jù)被 refresh 到 Filesystem cache 之后才能被搜索到,而 refresh 是每秒一次, 所以稱 es 是近實(shí)時(shí)的,可以通過手動(dòng)調(diào)用 es 的 api 觸發(fā)一次 refresh 操作,讓數(shù)據(jù)馬上可以被搜索到;
(2)由于 memory Buffer 和 Filesystem Cache 都是基于內(nèi)存,假設(shè)服務(wù)器宕機(jī),那么數(shù)據(jù)就會(huì)丟失,所以 ES 通過 translog 日志文件來保證數(shù)據(jù)的可靠性,在數(shù)據(jù)寫入 memory buffer 的同時(shí),將數(shù)據(jù)寫入 translog 日志文件中,在機(jī)器宕機(jī)重啟時(shí),es 會(huì)自動(dòng)讀取 translog 日志文件中的數(shù)據(jù),恢復(fù)到 memory buffer 和 Filesystem cache 中去。
ES 數(shù)據(jù)丟失的問題:translog 也是先寫入 Filesystem cache,然后默認(rèn)每隔 5 秒刷一次到磁盤中,所以默認(rèn)情況下,可能有 5 秒的數(shù)據(jù)會(huì)僅僅停留在 memory buffer 或者 translog 文件的 Filesystem cache中,而不在磁盤上,如果此時(shí)機(jī)器宕機(jī),會(huì)丟失 5 秒鐘的數(shù)據(jù)。也可以將 translog 設(shè)置成每次寫操作必須是直接 fsync 到磁盤,但是性能會(huì)差很多。
(3)flush 操作:不斷重復(fù)上面的步驟,translog 會(huì)變得越來越大,當(dāng) translog 文件默認(rèn)每30分鐘或者 閾值超過 512M 時(shí),就會(huì)觸發(fā) commit 操作,即 flush操作。
① 將 buffer 中的數(shù)據(jù) refresh 到 Filesystem Cache 中去,清空 buffer;
② 創(chuàng)建一個(gè)新的 commit point(提交點(diǎn)),同時(shí)強(qiáng)行將 Filesystem Cache 中目前所有的數(shù)據(jù)都 fsync 到磁盤文件中;
③ 刪除舊的 translog 日志文件并創(chuàng)建一個(gè)新的 translog 日志文件,此時(shí) commit 操作完成
三、ES的更新和刪除流程:
刪除和更新都是寫操作,但是由于 Elasticsearch 中的文檔是不可變的,因此不能被刪除或者改動(dòng)以展示其變更;所以 ES 利用 .del 文件 標(biāo)記文檔是否被刪除,磁盤上的每個(gè)段都有一個(gè)相應(yīng)的.del 文件
(1)如果是刪除操作,文檔其實(shí)并沒有真的被刪除,而是在 .del 文件中被標(biāo)記為 deleted 狀態(tài)。該文檔依然能匹配查詢,但是會(huì)在結(jié)果中被過濾掉。
(2)如果是更新操作,就是將舊的 doc 標(biāo)識(shí)為 deleted 狀態(tài),然后創(chuàng)建一個(gè)新的 doc。
memory buffer 每 refresh 一次,就會(huì)產(chǎn)生一個(gè) segment 文件 ,所以默認(rèn)情況下是 1s 生成一個(gè) segment 文件,這樣下來 segment 文件會(huì)越來越多,此時(shí)會(huì)定期執(zhí)行 merge。每次 merge 的時(shí)候,會(huì)將多個(gè) segment 文件合并成一個(gè),同時(shí)這里會(huì)將標(biāo)識(shí)為 deleted 的 doc 給物理刪除掉,不寫入到新的 segment 中,然后將新的 segment 文件寫入磁盤,這里會(huì)寫一個(gè) commit point ,標(biāo)識(shí)所有新的 segment 文件,然后打開 segment 文件供搜索使用,同時(shí)刪除舊的 segment 文件
有關(guān)segment段合并過程,有興趣可以閱讀這個(gè)文章:https://blog.csdn.net/a745233700/article/details/117953198
四、ES的搜索流程:
搜索被執(zhí)行成一個(gè)兩階段過程,即 Query Then Fetch:
1、Query階段:
客戶端發(fā)送請(qǐng)求到 coordinate node,協(xié)調(diào)節(jié)點(diǎn)將搜索請(qǐng)求廣播到所有的 primary shard 或 replica shard。每個(gè)分片在本地執(zhí)行搜索并構(gòu)建一個(gè)匹配文檔的大小為 from + size 的優(yōu)先隊(duì)列。每個(gè)分片返回各自優(yōu)先隊(duì)列中 所有文檔的 ID 和排序值 給協(xié)調(diào)節(jié)點(diǎn),由協(xié)調(diào)節(jié)點(diǎn)及逆行數(shù)據(jù)的合并、排序、分頁(yè)等操作,產(chǎn)出最終結(jié)果。
2、Fetch階段:
協(xié)調(diào)節(jié)點(diǎn)根據(jù) doc id 去各個(gè)節(jié)點(diǎn)上查詢實(shí)際的 document 數(shù)據(jù),由協(xié)調(diào)節(jié)點(diǎn)返回結(jié)果給客戶端。
coordinate node 對(duì) doc id 進(jìn)行哈希路由,將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的 node,此時(shí)會(huì)使用 round-robin 隨機(jī)輪詢算法,在 primary shard 以及其所有 replica 中隨機(jī)選擇一個(gè),讓讀請(qǐng)求負(fù)載均衡。
接收請(qǐng)求的 node 返回 document 給 coordinate node 。
coordinate node 返回 document 給客戶端。
Query Then Fetch 的搜索類型在文檔相關(guān)性打分的時(shí)候參考的是本分片的數(shù)據(jù),這樣在文檔數(shù)量較少的時(shí)候可能不夠準(zhǔn)確,DFS Query Then Fetch 增加了一個(gè)預(yù)查詢的處理,詢問 Term 和 Document frequency,這個(gè)評(píng)分更準(zhǔn)確,但是性能會(huì)變差。
五、ES在高并發(fā)下如何保證讀寫一致性?
(1)對(duì)于更新操作:可以通過版本號(hào)使用樂觀并發(fā)控制,以確保新版本不會(huì)被舊版本覆蓋
每個(gè)文檔都有一個(gè)_version 版本號(hào),這個(gè)版本號(hào)在文檔被改變時(shí)加一。Elasticsearch使用這個(gè) _version 保證所有修改都被正確排序。當(dāng)一個(gè)舊版本出現(xiàn)在新版本之后,它會(huì)被簡(jiǎn)單的忽略。
利用_version的這一優(yōu)點(diǎn)確保數(shù)據(jù)不會(huì)因?yàn)樾薷臎_突而丟失。比如指定文檔的version來做更改。如果那個(gè)版本號(hào)不是現(xiàn)在的,我們的請(qǐng)求就失敗了。
(2)對(duì)于寫操作,一致性級(jí)別支持 quorum/one/all,默認(rèn)為 quorum,即只有當(dāng)大多數(shù)分片可用時(shí)才允許寫操作。但即使大多數(shù)可用,也可能存在因?yàn)榫W(wǎng)絡(luò)等原因?qū)е聦懭敫北臼?,這樣該副本被認(rèn)為故障,分片將會(huì)在一個(gè)不同的節(jié)點(diǎn)上重建。
one:要求我們這個(gè)寫操作,只要有一個(gè)primary shard是active活躍可用的,就可以執(zhí)行
all:要求我們這個(gè)寫操作,必須所有的primary shard和replica shard都是活躍的,才可以執(zhí)行這個(gè)寫操作
quorum:默認(rèn)的值,要求所有的shard中,必須是大部分的shard都是活躍的,可用的,才可以執(zhí)行這個(gè)寫操作
(3)對(duì)于讀操作,可以設(shè)置 replication 為 sync(默認(rèn)),這使得操作在主分片和副本分片都完成后才會(huì)返回;如果設(shè)置replication 為 async 時(shí),也可以通過設(shè)置搜索請(qǐng)求參數(shù) _preference 為 primary 來查詢主分片,確保文檔是最新版本。
六、ES如何選舉Master節(jié)點(diǎn):
1、Elasticsearch 的分布式原理:
Elasticsearch 會(huì)對(duì)存儲(chǔ)的數(shù)據(jù)進(jìn)行切分,將數(shù)據(jù)劃分到不同的分片上,同時(shí)每一個(gè)分片會(huì)保存多個(gè)副本,主要是為了保證分布式環(huán)境的高可用。在 Elasticsearch 中,節(jié)點(diǎn)是對(duì)等的,節(jié)點(diǎn)間會(huì)選取集群的 Master,由 Master 會(huì)負(fù)責(zé)集群狀態(tài)信息的改變,并同步給其他節(jié)點(diǎn)。
Elasticsearch 的性能會(huì)不會(huì)很低:只有建立索引和類型需要經(jīng)過 Master,數(shù)據(jù)的寫入有一個(gè)簡(jiǎn)單的 Routing 規(guī)則,可以路由到集群中的任意節(jié)點(diǎn),所以數(shù)據(jù)寫入壓力是分散在整個(gè)集群的。
2、Elasticsearch 如何 選舉 Master:
Elasticsearch 的選主是 ZenDiscovery 模塊負(fù)責(zé)的,主要包含Ping(節(jié)點(diǎn)之間通過這個(gè)RPC來發(fā)現(xiàn)彼此)和 Unicast(單播模塊包含一個(gè)主機(jī)列表以控制哪些節(jié)點(diǎn)需要ping通)這兩部分;
(1)確認(rèn)候選主節(jié)點(diǎn)的最少投票通過數(shù)量,elasticsearch.yml 設(shè)置的值 discovery.zen.minimum_master_nodes;
(2)對(duì)所有候選 master 的節(jié)點(diǎn)(node.master: true)根據(jù) nodeId 字典排序,每次選舉每個(gè)節(jié)點(diǎn)都把自己所知道節(jié)點(diǎn)排一次序,然后選出第一個(gè)(第0位)節(jié)點(diǎn),暫且認(rèn)為它是master節(jié)點(diǎn)。
(3)如果對(duì)某個(gè)節(jié)點(diǎn)的投票數(shù)達(dá)到閾值,并且該節(jié)點(diǎn)自己也選舉自己,那這個(gè)節(jié)點(diǎn)就是master。否則重新選舉一直到滿足上述條件。
補(bǔ)充:master節(jié)點(diǎn)的職責(zé)主要包括集群、節(jié)點(diǎn)和索引的管理,不負(fù)責(zé)文檔級(jí)別的管理;data節(jié)點(diǎn)可以關(guān)閉http功能。
3、Elasticsearch是如何避免腦裂現(xiàn)象:
(1)當(dāng)集群中 master 候選節(jié)點(diǎn)數(shù)量不小于3個(gè)時(shí)(node.master: true),可以通過設(shè)置最少投票通過數(shù)量(discovery.zen.minimum_master_nodes),設(shè)置超過所有候選節(jié)點(diǎn)一半以上來解決腦裂問題,即設(shè)置為 (N/2)+1;
(2)當(dāng)集群 master 候選節(jié)點(diǎn) 只有兩個(gè)時(shí),這種情況是不合理的,最好把另外一個(gè)node.master改成false。如果我們不改節(jié)點(diǎn)設(shè)置,還是套上面的(N/2)+1公式,此時(shí)discovery.zen.minimum_master_nodes應(yīng)該設(shè)置為2。這就出現(xiàn)一個(gè)問題,兩個(gè)master備選節(jié)點(diǎn),只要有一個(gè)掛,就選不出master了
七、建立索引階段性能提升方法:
(1)使用 SSD 存儲(chǔ)介質(zhì)
(2)使用批量請(qǐng)求并調(diào)整其大?。好看闻繑?shù)據(jù) 5–15 MB 大是個(gè)不錯(cuò)的起始點(diǎn)。
(3)如果你在做大批量導(dǎo)入,考慮通過設(shè)置 index.number_of_replicas: 0 關(guān)閉副本
(4)如果你的搜索結(jié)果不需要近實(shí)時(shí)的準(zhǔn)確度,考慮把每個(gè)索引的 index.refresh_interval 改到30s
(5)段和合并:Elasticsearch 默認(rèn)值是 20 MB/s。但如果用的是 SSD,可以考慮提高到 100–200 MB/s。如果你在做批量導(dǎo)入,完全不在意搜索,你可以徹底關(guān)掉合并限流。
(6)增加 index.translog.flush_threshold_size 設(shè)置,從默認(rèn)的 512 MB 到更大一些的值,比如 1 GB
八、ES的深度分頁(yè)與滾動(dòng)搜索scroll
(1)深度分頁(yè):
深度分頁(yè)其實(shí)就是搜索的深淺度,比如第1頁(yè),第2頁(yè),第10頁(yè),第20頁(yè),是比較淺的;第10000頁(yè),第20000頁(yè)就是很深了。搜索得太深,就會(huì)造成性能問題,會(huì)耗費(fèi)內(nèi)存和占用cpu。而且es為了性能,他不支持超過一萬條數(shù)據(jù)以上的分頁(yè)查詢。那么如何解決深度分頁(yè)帶來的問題,我們應(yīng)該避免深度分頁(yè)操作(限制分頁(yè)頁(yè)數(shù)),比如最多只能提供100頁(yè)的展示,從第101頁(yè)開始就沒了,畢竟用戶也不會(huì)搜的那么深。
(2)滾動(dòng)搜索:
一次性查詢1萬+數(shù)據(jù),往往會(huì)造成性能影響,因?yàn)閿?shù)據(jù)量太多了。這個(gè)時(shí)候可以使用滾動(dòng)搜索,也就是 scroll。滾動(dòng)搜索可以先查詢出一些數(shù)據(jù),然后再緊接著依次往下查詢。在第一次查詢的時(shí)候會(huì)有一個(gè)滾動(dòng)id,相當(dāng)于一個(gè)錨標(biāo)記 ,隨后再次滾動(dòng)搜索會(huì)需要上一次搜索滾動(dòng)id,根據(jù)這個(gè)進(jìn)行下一次的搜索請(qǐng)求。每次搜索都是基于一個(gè)歷史的數(shù)據(jù)快照,查詢數(shù)據(jù)的期間,如果有數(shù)據(jù)變更,那么和搜索是沒有關(guān)系的。
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/a745233700/article/details/115585342
