溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Elasticsearch基本原理是什么

發(fā)布時間:2021-10-23 16:56:02 來源:億速云 閱讀:111 作者:iii 欄目:編程語言

本篇內(nèi)容介紹了“Elasticsearch基本原理是什么”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!

搜索引擎是對數(shù)據(jù)的檢索,所以我們先從生活中的數(shù)據(jù)說起。我們生活中的數(shù)據(jù)總體分為兩種:

  • 結(jié)構(gòu)化數(shù)據(jù)

  • 非結(jié)構(gòu)化數(shù)據(jù)


結(jié)構(gòu)化數(shù)據(jù):也稱作行數(shù)據(jù),是由二維表結(jié)構(gòu)來邏輯表達和實現(xiàn)的數(shù)據(jù),嚴格地遵循數(shù)據(jù)格式與長度規(guī)范,主要通過關(guān)系型數(shù)據(jù)庫進行存儲和管理。指具有固定格式或有限長度的數(shù)據(jù),如數(shù)據(jù)庫,元數(shù)據(jù)等。


非結(jié)構(gòu)化數(shù)據(jù):又可稱為全文數(shù)據(jù),不定長或無固定格式,不適于由數(shù)據(jù)庫二維表來表現(xiàn),包括所有格式的辦公文檔、XML、HTML、Word 文檔,郵件,各類報表、圖片和咅頻、視頻信息等。


說明:如果要更細致的區(qū)分的話,XML、HTML 可劃分為半結(jié)構(gòu)化數(shù)據(jù)。因為它們也具有自己特定的標(biāo)簽格式,所以既可以根據(jù)需要按結(jié)構(gòu)化數(shù)據(jù)來處理,也可抽取出純文本按非結(jié)構(gòu)化數(shù)據(jù)來處理。


根據(jù)兩種數(shù)據(jù)分類,搜索也相應(yīng)的分為兩種:

  • 結(jié)構(gòu)化數(shù)據(jù)搜索

  • 非結(jié)構(gòu)化數(shù)據(jù)搜索


對于結(jié)構(gòu)化數(shù)據(jù),因為它們具有特定的結(jié)構(gòu),所以我們一般都是可以通過關(guān)系型數(shù)據(jù)庫(MySQL,Oracle 等)的二維表(Table)的方式存儲和搜索,也可以建立索引。


對于非結(jié)構(gòu)化數(shù)據(jù),也即對全文數(shù)據(jù)的搜索主要有兩種方法:

  • 順序掃描

  • 全文檢索


順序掃描:通過文字名稱也可了解到它的大概搜索方式,即按照順序掃描的方式查詢特定的關(guān)鍵字。


例如給你一張報紙,讓你找到該報紙中“平安”的文字在哪些地方出現(xiàn)過。你肯定需要從頭到尾把報紙閱讀掃描一遍然后標(biāo)記出關(guān)鍵字在哪些版塊出現(xiàn)過以及它的出現(xiàn)位置。


這種方式無疑是最耗時的最低效的,如果報紙排版字體小,而且版塊較多甚至有多份報紙,等你掃描完你的眼睛也差不多了。


全文搜索:對非結(jié)構(gòu)化數(shù)據(jù)順序掃描很慢,我們是否可以進行優(yōu)化?把我們的非結(jié)構(gòu)化數(shù)據(jù)想辦法弄得有一定結(jié)構(gòu)不就行了嗎?


將非結(jié)構(gòu)化數(shù)據(jù)中的一部分信息提取出來,重新組織,使其變得有一定結(jié)構(gòu),然后對此有一定結(jié)構(gòu)的數(shù)據(jù)進行搜索,從而達到搜索相對較快的目的。


這種方式就構(gòu)成了全文檢索的基本思路。這部分從非結(jié)構(gòu)化數(shù)據(jù)中提取出的然后重新組織的信息,我們稱之為索引。


這種方式的主要工作量在前期索引的創(chuàng)建,但是對于后期搜索卻是快速高效的。

先說說 Lucene


通過對生活中數(shù)據(jù)的類型作了一個簡短了解之后,我們知道關(guān)系型數(shù)據(jù)庫的 SQL 檢索是處理不了這種非結(jié)構(gòu)化數(shù)據(jù)的。


這種非結(jié)構(gòu)化數(shù)據(jù)的處理需要依賴全文搜索,而目前市場上開放源代碼的最好全文檢索引擎工具包就屬于 Apache 的 Lucene了。


但是 Lucene 只是一個工具包,它不是一個完整的全文檢索引擎。Lucene 的目的是為軟件開發(fā)人員提供一個簡單易用的工具包,以方便的在目標(biāo)系統(tǒng)中實現(xiàn)全文檢索的功能,或者是以此為基礎(chǔ)建立起完整的全文檢索引擎。


目前以 Lucene 為基礎(chǔ)建立的開源可用全文搜索引擎主要是 Solr 和 Elasticsearch。


Solr 和 Elasticsearch 都是比較成熟的全文搜索引擎,能完成的功能和性能也基本一樣。


但是 ES 本身就具有分布式的特性和易安裝使用的特點,而 Solr 的分布式需要借助第三方來實現(xiàn),例如通過使用 ZooKeeper 來達到分布式協(xié)調(diào)管理。


不管是 Solr 還是 Elasticsearch 底層都是依賴于 Lucene,而 Lucene 能實現(xiàn)全文搜索主要是因為它實現(xiàn)了倒排索引的查詢結(jié)構(gòu)。


如何理解倒排索引呢?假如現(xiàn)有三份數(shù)據(jù)文檔,文檔的內(nèi)容如下分別是:

  • Java is the best programming language.

  • PHP is the best programming language.

  • Javascript is the best programming language.


為了創(chuàng)建倒排索引,我們通過分詞器將每個文檔的內(nèi)容域拆分成單獨的詞(我們稱它為詞條或 Term),創(chuàng)建一個包含所有不重復(fù)詞條的排序列表,然后列出每個詞條出現(xiàn)在哪個文檔。


結(jié)果如下所示:


Term          Doc_1    Doc_2   Doc_3
-------------------------------------
Java        |   X   |        |
is          |   X   |   X    |   X
the         |   X   |   X    |   X
best        |   X   |   X    |   X
programming |   x   |   X    |   X
language    |   X   |   X    |   X
PHP         |       |   X    |
Javascript  |       |        |   X
-------------------------------------
        

這種結(jié)構(gòu)由文檔中所有不重復(fù)詞的列表構(gòu)成,對于其中每個詞都有一個文檔列表與之關(guān)聯(lián)。


這種由屬性值來確定記錄的位置的結(jié)構(gòu)就是倒排索引。帶有倒排索引的文件我們稱為倒排文件。


我們將上面的內(nèi)容轉(zhuǎn)換為圖的形式來說明倒排索引的結(jié)構(gòu)信息,如下圖所示:

Elasticsearch基本原理是什么

其中主要有如下幾個核心術(shù)語需要理解:

  • 詞條(Term):索引里面最小的存儲和查詢單元,對于英文來說是一個單詞,對于中文來說一般指分詞后的一個詞。

  • 詞典(Term Dictionary):或字典,是詞條 Term 的集合。搜索引擎的通常索引單位是單詞,單詞詞典是由文檔集合中出現(xiàn)過的所有單詞構(gòu)成的字符串集合,單詞詞典內(nèi)每條索引項記載單詞本身的一些信息以及指向“倒排列表”的指針。

  • 倒排表(Post list):一個文檔通常由多個詞組成,倒排表記錄的是某個詞在哪些文檔里出現(xiàn)過以及出現(xiàn)的位置。

    每條記錄稱為一個倒排項(Posting)。倒排表記錄的不單是文檔編號,還存儲了詞頻等信息。

  • 倒排文件(Inverted File):所有單詞的倒排列表往往順序地存儲在磁盤的某個文件里,這個文件被稱之為倒排文件,倒排文件是存儲倒排索引的物理文件。


從上圖我們可以了解到倒排索引主要由兩個部分組成:

  • 詞典

  • 倒排文件


詞典和倒排表是 Lucene 中很重要的兩種數(shù)據(jù)結(jié)構(gòu),是實現(xiàn)快速檢索的重要基石。詞典和倒排文件是分兩部分存儲的,詞典在內(nèi)存中而倒排文件存儲在磁盤上。

ES 核心概念

一些基礎(chǔ)知識的鋪墊之后我們正式進入今天的主角 Elasticsearch 的介紹。


ES 是使用 Java 編寫的一種開源搜索引擎,它在內(nèi)部使用 Lucene 做索引與搜索,通過對 Lucene 的封裝,隱藏了 Lucene 的復(fù)雜性,取而代之的提供一套簡單一致的 RESTful API。


然而,Elasticsearch 不僅僅是 Lucene,并且也不僅僅只是一個全文搜索引擎。 


它可以被下面這樣準(zhǔn)確的形容:

  • 一個分布式的實時文檔存儲,每個字段可以被索引與搜索。

  • 一個分布式實時分析搜索引擎。

  • 能勝任上百個服務(wù)節(jié)點的擴展,并支持 PB 級別的結(jié)構(gòu)化或者非結(jié)構(gòu)化數(shù)據(jù)。


官網(wǎng)對 Elasticsearch 的介紹是 Elasticsearch 是一個分布式、可擴展、近實時的搜索與數(shù)據(jù)分析引擎。


我們通過一些核心概念來看下 Elasticsearch 是如何做到分布式,可擴展和近實時搜索的。

              

集群(Cluster)

ES 的集群搭建很簡單,不需要依賴第三方協(xié)調(diào)管理組件,自身內(nèi)部就實現(xiàn)了集群的管理功能。


ES 集群由一個或多個 Elasticsearch 節(jié)點組成,每個節(jié)點配置相同的 cluster.name 即可加入集群,默認值為 “elasticsearch”。


確保不同的環(huán)境中使用不同的集群名稱,否則最終會導(dǎo)致節(jié)點加入錯誤的集群。


一個 Elasticsearch 服務(wù)啟動實例就是一個節(jié)點(Node)。節(jié)點通過 node.name 來設(shè)置節(jié)點名稱,如果不設(shè)置則在啟動時給節(jié)點分配一個隨機通用唯一標(biāo)識符作為名稱。   

①發(fā)現(xiàn)機制

那么有一個問題,ES 內(nèi)部是如何通過一個相同的設(shè)置 cluster.name 就能將不同的節(jié)點連接到同一個集群的?答案是 Zen Discovery。


Zen Discovery 是 Elasticsearch 的內(nèi)置默認發(fā)現(xiàn)模塊(發(fā)現(xiàn)模塊的職責(zé)是發(fā)現(xiàn)集群中的節(jié)點以及選舉 Master 節(jié)點)。


它提供單播和基于文件的發(fā)現(xiàn),并且可以擴展為通過插件支持云環(huán)境和其他形式的發(fā)現(xiàn)。


Zen Discovery 與其他模塊集成,例如,節(jié)點之間的所有通信都使用 Transport 模塊完成。節(jié)點使用發(fā)現(xiàn)機制通過 Ping 的方式查找其他節(jié)點。


Elasticsearch 默認被配置為使用單播發(fā)現(xiàn),以防止節(jié)點無意中加入集群。只有在同一臺機器上運行的節(jié)點才會自動組成集群。


如果集群的節(jié)點運行在不同的機器上,使用單播,你可以為 Elasticsearch 提供一些它應(yīng)該去嘗試連接的節(jié)點列表。


當(dāng)一個節(jié)點聯(lián)系到單播列表中的成員時,它就會得到整個集群所有節(jié)點的狀態(tài),然后它會聯(lián)系 Master 節(jié)點,并加入集群。


這意味著單播列表不需要包含集群中的所有節(jié)點, 它只是需要足夠的節(jié)點,當(dāng)一個新節(jié)點聯(lián)系上其中一個并且說上話就可以了。


如果你使用 Master 候選節(jié)點作為單播列表,你只要列出三個就可以了。這個配置在 elasticsearch.yml 文件中:


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

節(jié)點啟動后先 Ping ,如果 discovery.zen.ping.unicast.hosts 有設(shè)置,則 Ping 設(shè)置中的 Host ,否則嘗試 ping localhost 的幾個端口。


Elasticsearch 支持同一個主機啟動多個節(jié)點,Ping 的 Response 會包含該節(jié)點的基本信息以及該節(jié)點認為的 Master 節(jié)點。


選舉開始,先從各節(jié)點認為的 Master 中選,規(guī)則很簡單,按照 ID 的字典序排序,取第一個。如果各節(jié)點都沒有認為的 Master ,則從所有節(jié)點中選擇,規(guī)則同上。


這里有個限制條件就是 discovery.zen.minimum_master_nodes ,如果節(jié)點數(shù)達不到最小值的限制,則循環(huán)上述過程,直到節(jié)點數(shù)足夠可以開始選舉。


最后選舉結(jié)果是肯定能選舉出一個 Master ,如果只有一個 Local 節(jié)點那就選出的是自己。


如果當(dāng)前節(jié)點是 Master ,則開始等待節(jié)點數(shù)達到 discovery.zen.minimum_master_nodes,然后提供服務(wù)。


如果當(dāng)前節(jié)點不是 Master ,則嘗試加入 Master 。Elasticsearch 將以上服務(wù)發(fā)現(xiàn)以及選主的流程叫做 Zen Discovery 。


由于它支持任意數(shù)目的集群( 1- N ),所以不能像 Zookeeper 那樣限制節(jié)點必須是奇數(shù),也就無法用投票的機制來選主,而是通過一個規(guī)則。


只要所有的節(jié)點都遵循同樣的規(guī)則,得到的信息都是對等的,選出來的主節(jié)點肯定是一致的。


但分布式系統(tǒng)的問題就出在信息不對等的情況,這時候很容易出現(xiàn)腦裂(Split-Brain)的問題。


大多數(shù)解決方案就是設(shè)置一個 Quorum 值,要求可用節(jié)點必須大于 Quorum(一般是超過半數(shù)節(jié)點),才能對外提供服務(wù)。


而 Elasticsearch 中,這個 Quorum 的配置就是 discovery.zen.minimum_master_nodes 。 

②節(jié)點的角色

每個節(jié)點既可以是候選主節(jié)點也可以是數(shù)據(jù)節(jié)點,通過在配置文件 ../config/elasticsearch.yml 中設(shè)置即可,默認都為 true。


node.master: true  //是否候選主節(jié)點
node.data: true    //是否數(shù)據(jù)節(jié)點
    

數(shù)據(jù)節(jié)點負責(zé)數(shù)據(jù)的存儲和相關(guān)的操作,例如對數(shù)據(jù)進行增、刪、改、查和聚合等操作,所以數(shù)據(jù)節(jié)點(Data 節(jié)點)對機器配置要求比較高,對 CPU、內(nèi)存和 I/O 的消耗很大。


通常隨著集群的擴大,需要增加更多的數(shù)據(jù)節(jié)點來提高性能和可用性。


候選主節(jié)點可以被選舉為主節(jié)點(Master 節(jié)點),集群中只有候選主節(jié)點才有選舉權(quán)和被選舉權(quán),其他節(jié)點不參與選舉的工作。


主節(jié)點負責(zé)創(chuàng)建索引、刪除索引、跟蹤哪些節(jié)點是群集的一部分,并決定哪些分片分配給相關(guān)的節(jié)點、追蹤集群中節(jié)點的狀態(tài)等,穩(wěn)定的主節(jié)點對集群的健康是非常重要的。

Elasticsearch基本原理是什么

一個節(jié)點既可以是候選主節(jié)點也可以是數(shù)據(jù)節(jié)點,但是由于數(shù)據(jù)節(jié)點對 CPU、內(nèi)存核 I/O 消耗都很大。

所以如果某個節(jié)點既是數(shù)據(jù)節(jié)點又是主節(jié)點,那么可能會對主節(jié)點產(chǎn)生影響從而對整個集群的狀態(tài)產(chǎn)生影響。

因此為了提高集群的健康性,我們應(yīng)該對 Elasticsearch 集群中的節(jié)點做好角色上的劃分和隔離??梢允褂脦讉€配置較低的機器群作為候選主節(jié)點群。

主節(jié)點和其他節(jié)點之間通過 Ping 的方式互檢查,主節(jié)點負責(zé) Ping 所有其他節(jié)點,判斷是否有節(jié)點已經(jīng)掛掉。其他節(jié)點也通過 Ping 的方式判斷主節(jié)點是否處于可用狀態(tài)。

雖然對節(jié)點做了角色區(qū)分,但是用戶的請求可以發(fā)往任何一個節(jié)點,并由該節(jié)點負責(zé)分發(fā)請求、收集結(jié)果等操作,而不需要主節(jié)點轉(zhuǎn)發(fā)。

這種節(jié)點可稱之為協(xié)調(diào)節(jié)點,協(xié)調(diào)節(jié)點是不需要指定和配置的,集群中的任何節(jié)點都可以充當(dāng)協(xié)調(diào)節(jié)點的角色。

③腦裂現(xiàn)象

同時如果由于網(wǎng)絡(luò)或其他原因?qū)е录褐羞x舉出多個 Master 節(jié)點,使得數(shù)據(jù)更新時出現(xiàn)不一致,這種現(xiàn)象稱之為腦裂,即集群中不同的節(jié)點對于 Master 的選擇出現(xiàn)了分歧,出現(xiàn)了多個 Master 競爭。

“腦裂”問題可能有以下幾個原因造成:

  • 網(wǎng)絡(luò)問題:集群間的網(wǎng)絡(luò)延遲導(dǎo)致一些節(jié)點訪問不到 Master,認為 Master 掛掉了從而選舉出新的 Master,并對 Master 上的分片和副本標(biāo)紅,分配新的主分片。

  • 節(jié)點負載:主節(jié)點的角色既為 Master 又為 Data,訪問量較大時可能會導(dǎo)致 ES 停止響應(yīng)(假死狀態(tài))造成大面積延遲,此時其他節(jié)點得不到主節(jié)點的響應(yīng)認為主節(jié)點掛掉了,會重新選取主節(jié)點。

  • 內(nèi)存回收:主節(jié)點的角色既為 Master 又為 Data,當(dāng) Data 節(jié)點上的 ES 進程占用的內(nèi)存較大,引發(fā) JVM 的大規(guī)模內(nèi)存回收,造成 ES 進程失去響應(yīng)。


為了避免腦裂現(xiàn)象的發(fā)生,我們可以從原因著手通過以下幾個方面來做出優(yōu)化措施:

  • 適當(dāng)調(diào)大響應(yīng)時間,減少誤判。通過參數(shù) discovery.zen.ping_timeout 設(shè)置節(jié)點狀態(tài)的響應(yīng)時間,默認為 3s,可以適當(dāng)調(diào)大。

    如果 Master 在該響應(yīng)時間的范圍內(nèi)沒有做出響應(yīng)應(yīng)答,判斷該節(jié)點已經(jīng)掛掉了。調(diào)大參數(shù)(如 6s,discovery.zen.ping_timeout:6),可適當(dāng)減少誤判。

  • 選舉觸發(fā)。我們需要在候選集群中的節(jié)點的配置文件中設(shè)置參數(shù) discovery.zen.munimum_master_nodes 的值。

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

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

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

  • 角色分離。即是上面我們提到的候選主節(jié)點和數(shù)據(jù)節(jié)點進行角色分離,這樣可以減輕主節(jié)點的負擔(dān),防止主節(jié)點的假死狀態(tài)發(fā)生,減少對主節(jié)點“已死”的誤判。   

分片(Shards)

ES 支持 PB 級全文搜索,當(dāng)索引上的數(shù)據(jù)量太大的時候,ES 通過水平拆分的方式將一個索引上的數(shù)據(jù)拆分出來分配到不同的數(shù)據(jù)塊上,拆分出來的數(shù)據(jù)庫塊稱之為一個分片。


這類似于 MySQL 的分庫分表,只不過 MySQL 分庫分表需要借助第三方組件而 ES 內(nèi)部自身實現(xiàn)了此功能。


在一個多分片的索引中寫入數(shù)據(jù)時,通過路由來確定具體寫入哪一個分片中,所以在創(chuàng)建索引的時候需要指定分片的數(shù)量,并且分片的數(shù)量一旦確定就不能修改。


分片的數(shù)量和下面介紹的副本數(shù)量都是可以通過創(chuàng)建索引時的 Settings 來配置,ES 默認為一個索引創(chuàng)建 5 個主分片, 并分別為每個分片創(chuàng)建一個副本。

PUT /myIndex
{
   "settings" : {
      "number_of_shards" : 5,
      "number_of_replicas" : 1
   }
}

ES 通過分片的功能使得索引在規(guī)模上和性能上都得到提升,每個分片都是 Lucene 中的一個索引文件,每個分片必須有一個主分片和零到多個副本。                

副本(Replicas)

副本就是對分片的 Copy,每個主分片都有一個或多個副本分片,當(dāng)主分片異常時,副本可以提供數(shù)據(jù)的查詢等操作。


主分片和對應(yīng)的副本分片是不會在同一個節(jié)點上的,所以副本分片數(shù)的最大值是 N-1(其中 N 為節(jié)點數(shù))。


對文檔的新建、索引和刪除請求都是寫操作,必須在主分片上面完成之后才能被復(fù)制到相關(guān)的副本分片。


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


一旦所有的副本分片都報告寫成功才會向協(xié)調(diào)節(jié)點報告成功,協(xié)調(diào)節(jié)點向客戶端報告成功。

Elasticsearch基本原理是什么

從上圖可以看出為了達到高可用,Master 節(jié)點會避免將主分片和副本分片放在同一個節(jié)點上。


假設(shè)這時節(jié)點 Node1 服務(wù)宕機了或者網(wǎng)絡(luò)不可用了,那么主節(jié)點上主分片 S0 也就不可用了。


幸運的是還存在另外兩個節(jié)點能正常工作,這時 ES 會重新選舉新的主節(jié)點,而且這兩個節(jié)點上存在我們所需要的 S0 的所有數(shù)據(jù)。


我們會將 S0 的副本分片提升為主分片,這個提升主分片的過程是瞬間發(fā)生的。此時集群的狀態(tài)將會為  Yellow。


為什么我們集群狀態(tài)是 Yellow 而不是 Green 呢?雖然我們擁有所有的 2 個主分片,但是同時設(shè)置了每個主分片需要對應(yīng)兩份副本分片,而此時只存在一份副本分片。所以集群不能為 Green 的狀態(tài)。

如果我們同樣關(guān)閉了 Node2 ,我們的程序依然可以保持在不丟失任何數(shù)據(jù)的情況下運行,因為 Node3 為每一個分片都保留著一份副本。

如果我們重新啟動 Node1 ,集群可以將缺失的副本分片再次進行分配,那么集群的狀態(tài)又將恢復(fù)到原來的正常狀態(tài)。

如果 Node1 依然擁有著之前的分片,它將嘗試去重用它們,只不過這時 Node1 節(jié)點上的分片不再是主分片而是副本分片了,如果期間有更改的數(shù)據(jù)只需要從主分片上復(fù)制修改的數(shù)據(jù)文件即可。


小結(jié):

  • 將數(shù)據(jù)分片是為了提高可處理數(shù)據(jù)的容量和易于進行水平擴展,為分片做副本是為了提高集群的穩(wěn)定性和提高并發(fā)量。

  • 副本是乘法,越多消耗越大,但也越保險。分片是除法,分片越多,單分片數(shù)據(jù)就越少也越分散。

  • 副本越多,集群的可用性就越高,但是由于每個分片都相當(dāng)于一個 Lucene 的索引文件,會占用一定的文件句柄、內(nèi)存及 CPU。

    并且分片間的數(shù)據(jù)同步也會占用一定的網(wǎng)絡(luò)帶寬,所以索引的分片數(shù)和副本數(shù)也不是越多越好。               

映射(Mapping)

映射是用于定義 ES 對索引中字段的存儲類型、分詞方式和是否存儲等信息,就像數(shù)據(jù)庫中的 Schema ,描述了文檔可能具有的字段或?qū)傩?、每個字段的數(shù)據(jù)類型。

只不過關(guān)系型數(shù)據(jù)庫建表時必須指定字段類型,而 ES 對于字段類型可以不指定然后動態(tài)對字段類型猜測,也可以在創(chuàng)建索引時具體指定字段的類型。

對字段類型根據(jù)數(shù)據(jù)格式自動識別的映射稱之為動態(tài)映射(Dynamic Mapping),我們創(chuàng)建索引時具體定義字段類型的映射稱之為靜態(tài)映射或顯示映射(Explicit Mapping)。

在講解動態(tài)映射和靜態(tài)映射的使用前,我們先來了解下 ES 中的數(shù)據(jù)有哪些字段類型?之后我們再講解為什么我們創(chuàng)建索引時需要建立靜態(tài)映射而不使用動態(tài)映射。

ES(v6.8)中字段數(shù)據(jù)類型主要有以下幾類:

Elasticsearch基本原理是什么

Text 用于索引全文值的字段,例如電子郵件正文或產(chǎn)品說明。這些字段是被分詞的,它們通過分詞器傳遞 ,以在被索引之前將字符串轉(zhuǎn)換為單個術(shù)語的列表。

分析過程允許 Elasticsearch 搜索單個單詞中每個完整的文本字段。文本字段不用于排序,很少用于聚合。

Keyword 用于索引結(jié)構(gòu)化內(nèi)容的字段,例如電子郵件地址,主機名,狀態(tài)代碼,郵政編碼或標(biāo)簽。它們通常用于過濾,排序,和聚合。Keyword 字段只能按其確切值進行搜索。

通過對字段類型的了解我們知道有些字段需要明確定義的,例如某個字段是 Text 類型還是 Keyword 類型差別是很大的,時間字段也許我們需要指定它的時間格式,還有一些字段我們需要指定特定的分詞器等等。

如果采用動態(tài)映射是不能精確做到這些的,自動識別常常會與我們期望的有些差異。

所以創(chuàng)建索引的時候一個完整的格式應(yīng)該是指定分片和副本數(shù)以及 Mapping 的定義,如下:

PUT my_index 
{
   "settings" : {
      "number_of_shards" : 5,
      "number_of_replicas" : 1
   }
  "mappings": {
    "_doc": { 
      "properties": { 
        "title":    { "type": "text"  }, 
        "name":     { "type": "text"  }, 
        "age":      { "type": "integer" },  
        "created":  {
          "type":   "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  }
}

ES 的基本使用

在決定使用 Elasticsearch 的時候首先要考慮的是版本問題,Elasticsearch (排除 0.x 和 1.x)目前有如下常用的穩(wěn)定的主版本:2.x,5.x,6.x,7.x(current)。

你可能會發(fā)現(xiàn)沒有 3.x 和 4.x,ES 從 2.4.6 直接跳到了 5.0.0。其實是為了 ELK(ElasticSearch,Logstash,Kibana)技術(shù)棧的版本統(tǒng)一,免的給用戶帶來混亂。

在 Elasticsearch 是 2.x (2.x 的最后一版 2.4.6 的發(fā)布時間是 July 25, 2017) 的情況下,Kibana 已經(jīng)是 4.x(Kibana 4.6.5 的發(fā)布時間是 July 25, 2017)。

那么在 Kibana 的下一主版本肯定是 5.x 了,所以 Elasticsearch 直接將自己的主版本發(fā)布為 5.0.0 了。

統(tǒng)一之后,我們選版本就不會猶豫困惑了,我們選定 Elasticsearch 的版本后再選擇相同版本的 Kibana 就行了,不用擔(dān)憂版本不兼容的問題。

Elasticsearch 是使用 Java 構(gòu)建,所以除了注意 ELK 技術(shù)的版本統(tǒng)一,我們在選擇 Elasticsearch 的版本的時候還需要注意 JDK 的版本。

因為每個大版本所依賴的 JDK 版本也不同,目前 7.2 版本已經(jīng)可以支持 JDK11。                

安裝使用

①下載和解壓 Elasticsearch,無需安裝解壓后即可用,解壓后目錄如上圖:

  • bin:二進制系統(tǒng)指令目錄,包含啟動命令和安裝插件命令等。

  • config:配置文件目錄。

  • data:數(shù)據(jù)存儲目錄。

  • lib:依賴包目錄。

  • logs:日志文件目錄。

  • modules:模塊庫,例如 x-pack 的模塊。

  • plugins:插件目錄。

②安裝目錄下運行 bin/elasticsearch 來啟動 ES。

③默認在 9200 端口運行,請求 curl http://localhost:9200/ 或者瀏覽器輸入 http://localhost:9200,得到一個 JSON 對象,其中包含當(dāng)前節(jié)點、集群、版本等信息。

{
  "name" : "U7fp3O9",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "-Rj8jGQvRIelGd9ckicUOA",
  "version" : {
    "number" : "6.8.1",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "1fad4e1",
    "build_date" : "2019-06-18T13:16:52.517138Z",
    "build_snapshot" : false,
    "lucene_version" : "7.7.0",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}
                

集群健康狀態(tài)

要檢查群集運行狀況,我們可以在 Kibana 控制臺中運行以下命令 GET /_cluster/health,得到如下信息:


{
  "cluster_name" : "wujiajian",
  "status" : "yellow",
  "timed_out" : false,
  "number_of_nodes" : 1,
  "number_of_data_nodes" : 1,
  "active_primary_shards" : 9,
  "active_shards" : 9,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 5,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0,
  "task_max_waiting_in_queue_millis" : 0,
  "active_shards_percent_as_number" : 64.28571428571429
}
    

集群狀態(tài)通過 綠,黃,紅 來標(biāo)識:

  • 綠色:集群健康完好,一切功能齊全正常,所有分片和副本都可以正常工作。

  • 黃色:預(yù)警狀態(tài),所有主分片功能正常,但至少有一個副本是不能正常工作的。此時集群是可以正常工作的,但是高可用性在某種程度上會受影響。

  • 紅色:集群不可正常使用。某個或某些分片及其副本異常不可用,這時集群的查詢操作還能執(zhí)行,但是返回的結(jié)果會不準(zhǔn)確。對于分配到這個分片的寫入請求將會報錯,最終會導(dǎo)致數(shù)據(jù)的丟失。

當(dāng)集群狀態(tài)為紅色時,它將會繼續(xù)從可用的分片提供搜索請求服務(wù),但是你需要盡快修復(fù)那些未分配的分片。

ES 機制原理

ES 的基本概念和基本操作介紹完了之后,我們可能還有很多疑惑:

  • 它們內(nèi)部是如何運行的?

  • 主分片和副本分片是如何同步的?

  • 創(chuàng)建索引的流程是什么樣的?

  • ES 如何將索引數(shù)據(jù)分配到不同的分片上的?以及這些索引數(shù)據(jù)是如何存儲的?

  • 為什么說 ES 是近實時搜索引擎而文檔的 CRUD (創(chuàng)建-讀取-更新-刪除) 操作是實時的?

  • 以及 Elasticsearch 是怎樣保證更新被持久化在斷電時也不丟失數(shù)據(jù)?

  • 還有為什么刪除文檔不會立刻釋放空間?

帶著這些疑問我們進入接下來的內(nèi)容。                  

寫索引原理

下圖描述了 3 個節(jié)點的集群,共擁有 12 個分片,其中有 4 個主分片(S0、S1、S2、S3)和 8 個副本分片(R0、R1、R2、R3),每個主分片對應(yīng)兩個副本分片,節(jié)點 1 是主節(jié)點(Master 節(jié)點)負責(zé)整個集群的狀態(tài)。

Elasticsearch基本原理是什么

寫索引是只能寫在主分片上,然后同步到副本分片。這里有四個主分片,一條數(shù)據(jù) ES 是根據(jù)什么規(guī)則寫到特定分片上的呢?

這條索引數(shù)據(jù)為什么被寫到 S0 上而不寫到 S1 或 S2 上?那條數(shù)據(jù)為什么又被寫到 S3 上而不寫到 S0 上了?

首先這肯定不會是隨機的,否則將來要獲取文檔的時候我們就不知道從何處尋找了。

實際上,這個過程是根據(jù)下面這個公式?jīng)Q定的:

shard = hash(routing) % number_of_primary_shards

Routing 是一個可變值,默認是文檔的 _id ,也可以設(shè)置成一個自定義的值。

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

這個在 0 到 number_of_primary_shards-1 之間的余數(shù),就是我們所尋求的文檔所在分片的位置。

這就解釋了為什么我們要在創(chuàng)建索引的時候就確定好主分片的數(shù)量并且永遠不會改變這個數(shù)量:因為如果數(shù)量變化了,那么所有之前路由的值都會無效,文檔也再也找不到了。

由于在 ES 集群中每個節(jié)點通過上面的計算公式都知道集群中的文檔的存放位置,所以每個節(jié)點都有處理讀寫請求的能力。

在一個寫請求被發(fā)送到某個節(jié)點后,該節(jié)點即為前面說過的協(xié)調(diào)節(jié)點,協(xié)調(diào)節(jié)點會根據(jù)路由公式計算出需要寫到哪個分片上,再將請求轉(zhuǎn)發(fā)到該分片的主分片節(jié)點上。

假如此時數(shù)據(jù)通過路由計算公式取余后得到的值是 shard=hash(routing)%4=0。

則具體流程如下:

  • 客戶端向 ES1 節(jié)點(協(xié)調(diào)節(jié)點)發(fā)送寫請求,通過路由計算公式得到值為 0,則當(dāng)前數(shù)據(jù)應(yīng)被寫到主分片 S0 上。

  • ES1 節(jié)點將請求轉(zhuǎn)發(fā)到 S0 主分片所在的節(jié)點 ES3,ES3 接受請求并寫入到磁盤。

  • 并發(fā)將數(shù)據(jù)復(fù)制到兩個副本分片 R0 上,其中通過樂觀并發(fā)控制數(shù)據(jù)的沖突。一旦所有的副本分片都報告成功,則節(jié)點 ES3 將向協(xié)調(diào)節(jié)點報告成功,協(xié)調(diào)節(jié)點向客戶端報告成功。

存儲原理

上面介紹了在 ES 內(nèi)部索引的寫處理流程,這個流程是在 ES 的內(nèi)存中執(zhí)行的,數(shù)據(jù)被分配到特定的分片和副本上之后,最終是存儲到磁盤上的,這樣在斷電的時候就不會丟失數(shù)據(jù)。

具體的存儲路徑可在配置文件 ../config/elasticsearch.yml 中進行設(shè)置,默認存儲在安裝目錄的 Data 文件夾下。

建議不要使用默認值,因為若 ES 進行了升級,則有可能導(dǎo)致數(shù)據(jù)全部丟失:

path.data: /path/to/data  //索引數(shù)據(jù)
path.logs: /path/to/logs  //日志記錄

①分段存儲

索引文檔以段的形式存儲在磁盤上,何為段?索引文件被拆分為多個子文件,則每個子文件叫作段,每一個段本身都是一個倒排索引,并且段具有不變性,一旦索引的數(shù)據(jù)被寫入硬盤,就不可再修改。

在底層采用了分段的存儲模式,使它在讀寫時幾乎完全避免了鎖的出現(xiàn),大大提升了讀寫性能。

段被寫入到磁盤后會生成一個提交點,提交點是一個用來記錄所有提交后段信息的文件。

一個段一旦擁有了提交點,就說明這個段只有讀的權(quán)限,失去了寫的權(quán)限。相反,當(dāng)段在內(nèi)存中時,就只有寫的權(quán)限,而不具備讀數(shù)據(jù)的權(quán)限,意味著不能被檢索。

段的概念提出主要是因為:在早期全文檢索中為整個文檔集合建立了一個很大的倒排索引,并將其寫入磁盤中。

如果索引有更新,就需要重新全量創(chuàng)建一個索引來替換原來的索引。這種方式在數(shù)據(jù)量很大時效率很低,并且由于創(chuàng)建一次索引的成本很高,所以對數(shù)據(jù)的更新不能過于頻繁,也就不能保證時效性。

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

  • 新增,新增很好處理,由于數(shù)據(jù)是新的,所以只需要對當(dāng)前文檔新增一個段就可以了。

  • 刪除,由于不可修改,所以對于刪除操作,不會把文檔從舊的段中移除而是通過新增一個 .del 文件,文件中會列出這些被刪除文檔的段信息。

    這個被標(biāo)記刪除的文檔仍然可以被查詢匹配到, 但它會在最終結(jié)果被返回前從結(jié)果集中移除。

  • 更新,不能修改舊的段來進行反映文檔的更新,其實更新相當(dāng)于是刪除和新增這兩個動作組成。會將舊的文檔在 .del 文件中標(biāo)記刪除,然后文檔的新版本被索引到一個新的段中。

    可能兩個版本的文檔都會被一個查詢匹配到,但被刪除的那個舊版本文檔在結(jié)果集返回前就會被移除。

段被設(shè)定為不可修改具有一定的優(yōu)勢也有一定的缺點,優(yōu)勢主要表現(xiàn)在:

  • 不需要鎖。如果你從來不更新索引,你就不需要擔(dān)心多進程同時修改數(shù)據(jù)的問題。

  • 一旦索引被讀入內(nèi)核的文件系統(tǒng)緩存,便會留在哪里,由于其不變性。只要文件系統(tǒng)緩存中還有足夠的空間,那么大部分讀請求會直接請求內(nèi)存,而不會命中磁盤。這提供了很大的性能提升。

  • 其它緩存(像 Filter 緩存),在索引的生命周期內(nèi)始終有效。它們不需要在每次數(shù)據(jù)改變時被重建,因為數(shù)據(jù)不會變化。

  • 寫入單個大的倒排索引允許數(shù)據(jù)被壓縮,減少磁盤 I/O 和需要被緩存到內(nèi)存的索引的使用量。

段的不變性的缺點如下:

  • 當(dāng)對舊數(shù)據(jù)進行刪除時,舊數(shù)據(jù)不會馬上被刪除,而是在 .del 文件中被標(biāo)記為刪除。而舊數(shù)據(jù)只能等到段更新時才能被移除,這樣會造成大量的空間浪費。

  • 若有一條數(shù)據(jù)頻繁的更新,每次更新都是新增新的標(biāo)記舊的,則會有大量的空間浪費。

  • 每次新增數(shù)據(jù)時都需要新增一個段來存儲數(shù)據(jù)。當(dāng)段的數(shù)量太多時,對服務(wù)器的資源例如文件句柄的消耗會非常大。

  • 在查詢的結(jié)果中包含所有的結(jié)果集,需要排除被標(biāo)記刪除的舊數(shù)據(jù),這增加了查詢的負擔(dān)。

②延遲寫策略

介紹完了存儲的形式,那么索引寫入到磁盤的過程是怎樣的?是否是直接調(diào) Fsync 物理性地寫入磁盤?

答案是顯而易見的,如果是直接寫入到磁盤上,磁盤的 I/O 消耗上會嚴重影響性能。

那么當(dāng)寫數(shù)據(jù)量大的時候會造成 ES 停頓卡死,查詢也無法做到快速響應(yīng)。如果真是這樣 ES 也就不會稱之為近實時全文搜索引擎了。

為了提升寫的性能,ES 并沒有每新增一條數(shù)據(jù)就增加一個段到磁盤上,而是采用延遲寫的策略。

每當(dāng)有新增的數(shù)據(jù)時,就將其先寫入到內(nèi)存中,在內(nèi)存和磁盤之間是文件系統(tǒng)緩存。

當(dāng)達到默認的時間(1 秒鐘)或者內(nèi)存的數(shù)據(jù)達到一定量時,會觸發(fā)一次刷新(Refresh),將內(nèi)存中的數(shù)據(jù)生成到一個新的段上并緩存到文件緩存系統(tǒng) 上,稍后再被刷新到磁盤中并生成提交點。

這里的內(nèi)存使用的是 ES 的 JVM 內(nèi)存,而文件緩存系統(tǒng)使用的是操作系統(tǒng)的內(nèi)存。

新的數(shù)據(jù)會繼續(xù)的被寫入內(nèi)存,但內(nèi)存中的數(shù)據(jù)并不是以段的形式存儲的,因此不能提供檢索功能。

由內(nèi)存刷新到文件緩存系統(tǒng)的時候會生成新的段,并將段打開以供搜索使用,而不需要等到被刷新到磁盤。

在 Elasticsearch 中,寫入和打開一個新段的輕量的過程叫做 Refresh (即內(nèi)存刷新到文件緩存系統(tǒng))。

默認情況下每個分片會每秒自動刷新一次。這就是為什么我們說 Elasticsearch 是近實時搜索,因為文檔的變化并不是立即對搜索可見,但會在一秒之內(nèi)變?yōu)榭梢姟?/p>

我們也可以手動觸發(fā) Refresh,POST /_refresh 刷新所有索引,POST /nba/_refresh 刷新指定的索引。

Tips:盡管刷新是比提交輕量很多的操作,它還是會有性能開銷。當(dāng)寫測試的時候, 手動刷新很有用,但是不要在生產(chǎn)>環(huán)境下每次索引一個文檔都去手動刷新。而且并不是所有的情況都需要每秒刷新。

可能你正在使用 Elasticsearch 索引大量的日志文件, 你可能想優(yōu)化索引速度而不是>近實時搜索。

這時可以在創(chuàng)建索引時在 Settings 中通過調(diào)大 refresh_interval = "30s" 的值 , 降低每個索引的刷新頻率,設(shè)值時需要注意后面帶上時間單位,否則默認是毫秒。當(dāng) refresh_interval=-1 時表示關(guān)閉索引的自動刷新

雖然通過延時寫的策略可以減少數(shù)據(jù)往磁盤上寫的次數(shù)提升了整體的寫入能力,但是我們知道文件緩存系統(tǒng)也是內(nèi)存空間,屬于操作系統(tǒng)的內(nèi)存,只要是內(nèi)存都存在斷電或異常情況下丟失數(shù)據(jù)的危險。

為了避免丟失數(shù)據(jù),Elasticsearch 添加了事務(wù)日志(Translog),事務(wù)日志記錄了所有還沒有持久化到磁盤的數(shù)據(jù)。

Elasticsearch基本原理是什么

添加了事務(wù)日志后整個寫索引的流程如上圖所示:

  • 一個新文檔被索引之后,先被寫入到內(nèi)存中,但是為了防止數(shù)據(jù)的丟失,會追加一份數(shù)據(jù)到事務(wù)日志中。

    不斷有新的文檔被寫入到內(nèi)存,同時也都會記錄到事務(wù)日志中。這時新數(shù)據(jù)還不能被檢索和查詢。

  • 當(dāng)達到默認的刷新時間或內(nèi)存中的數(shù)據(jù)達到一定量后,會觸發(fā)一次  Refresh,將內(nèi)存中的數(shù)據(jù)以一個新段形式刷新到文件緩存系統(tǒng)中并清空內(nèi)存。這時雖然新段未被提交到磁盤,但是可以提供文檔的檢索功能且不能被修改。

  • 隨著新文檔索引不斷被寫入,當(dāng)日志數(shù)據(jù)大小超過 512M 或者時間超過 30 分鐘時,會觸發(fā)一次 Flush。

    內(nèi)存中的數(shù)據(jù)被寫入到一個新段同時被寫入到文件緩存系統(tǒng),文件系統(tǒng)緩存中數(shù)據(jù)通過 Fsync 刷新到磁盤中,生成提交點,日志文件被刪除,創(chuàng)建一個空的新日志。

通過這種方式當(dāng)斷電或需要重啟時,ES 不僅要根據(jù)提交點去加載已經(jīng)持久化過的段,還需要工具 Translog 里的記錄,把未持久化的數(shù)據(jù)重新持久化到磁盤上,避免了數(shù)據(jù)丟失的可能。

③段合并

由于自動刷新流程每秒會創(chuàng)建一個新的段 ,這樣會導(dǎo)致短時間內(nèi)的段數(shù)量暴增。而段數(shù)目太多會帶來較大的麻煩。

每一個段都會消耗文件句柄、內(nèi)存和 CPU 運行周期。更重要的是,每個搜索請求都必須輪流檢查每個段然后合并查詢結(jié)果,所以段越多,搜索也就越慢。

Elasticsearch 通過在后臺定期進行段合并來解決這個問題。小的段被合并到大的段,然后這些大的段再被合并到更大的段。

段合并的時候會將那些舊的已刪除文檔從文件系統(tǒng)中清除。被刪除的文檔不會被拷貝到新的大段中。合并的過程中不會中斷索引和搜索。

Elasticsearch基本原理是什么

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

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

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

Elasticsearch 在默認情況下會對合并流程進行資源限制,所以搜索仍然有足夠的資源很好地執(zhí)行。

性能優(yōu)化                 

存儲設(shè)備

磁盤在現(xiàn)代服務(wù)器上通常都是瓶頸。Elasticsearch 重度使用磁盤,你的磁盤能處理的吞吐量越大,你的節(jié)點就越穩(wěn)定。

這里有一些優(yōu)化磁盤 I/O 的技巧:

  • 使用 SSD。就像其他地方提過的, 他們比機械磁盤優(yōu)秀多了。

  • 使用 RAID 0。條帶化 RAID 會提高磁盤 I/O,代價顯然就是當(dāng)一塊硬盤故障時整個就故障了。不要使用鏡像或者奇偶校驗 RAID 因為副本已經(jīng)提供了這個功能。

  • 另外,使用多塊硬盤,并允許 Elasticsearch 通過多個 path.data 目錄配置把數(shù)據(jù)條帶化分配到它們上面。

  • 不要使用遠程掛載的存儲,比如 NFS 或者 SMB/CIFS。這個引入的延遲對性能來說完全是背道而馳的。

  • 如果你用的是 EC2,當(dāng)心 EBS。即便是基于 SSD 的 EBS,通常也比本地實例的存儲要慢。

內(nèi)部索引優(yōu)化


Elasticsearch基本原理是什么

Elasticsearch 為了能快速找到某個 Term,先將所有的 Term 排個序,然后根據(jù)二分法查找 Term,時間復(fù)雜度為 logN,就像通過字典查找一樣,這就是 Term Dictionary。

現(xiàn)在再看起來,似乎和傳統(tǒng)數(shù)據(jù)庫通過 B-Tree 的方式類似。但是如果 Term 太多,Term Dictionary 也會很大,放內(nèi)存不現(xiàn)實,于是有了 Term Index。

就像字典里的索引頁一樣,A 開頭的有哪些 Term,分別在哪頁,可以理解 Term Index是一棵樹。

這棵樹不會包含所有的 Term,它包含的是 Term 的一些前綴。通過 Term Index 可以快速地定位到 Term Dictionary 的某個 Offset,然后從這個位置再往后順序查找。

在內(nèi)存中用 FST 方式壓縮 Term Index,F(xiàn)ST 以字節(jié)的方式存儲所有的 Term,這種壓縮方式可以有效的縮減存儲空間,使得 Term Index 足以放進內(nèi)存,但這種方式也會導(dǎo)致查找時需要更多的 CPU 資源。

對于存儲在磁盤上的倒排表同樣也采用了壓縮技術(shù)減少存儲所占用的空間。                  

調(diào)整配置參數(shù)

調(diào)整配置參數(shù)建議如下:

  • 給每個文檔指定有序的具有壓縮良好的序列模式 ID,避免隨機的 UUID-4 這樣的 ID,這樣的 ID 壓縮比很低,會明顯拖慢 Lucene。

  • 對于那些不需要聚合和排序的索引字段禁用 Doc values。Doc Values 是有序的基于 document=>field value 的映射列表。

  • 不需要做模糊檢索的字段使用 Keyword 類型代替 Text 類型,這樣可以避免在建立索引前對這些文本進行分詞。

  • 如果你的搜索結(jié)果不需要近實時的準(zhǔn)確度,考慮把每個索引的 index.refresh_interval 改到 30s 。

    如果你是在做大批量導(dǎo)入,導(dǎo)入期間你可以通過設(shè)置這個值為 -1 關(guān)掉刷新,還可以通過設(shè)置 index.number_of_replicas: 0 關(guān)閉副本。別忘記在完工的時候重新開啟它。

  • 避免深度分頁查詢建議使用 Scroll 進行分頁查詢。普通分頁查詢時,會創(chuàng)建一個 from+size 的空優(yōu)先隊列,每個分片會返回 from+size 條數(shù)據(jù),默認只包含文檔 ID 和得分 Score 給協(xié)調(diào)節(jié)點。

    如果有 N 個分片,則協(xié)調(diào)節(jié)點再對(from+size)×n 條數(shù)據(jù)進行二次排序,然后選擇需要被取回的文檔。當(dāng) from 很大時,排序過程會變得很沉重,占用 CPU 資源嚴重。

  • 減少映射字段,只提供需要檢索,聚合或排序的字段。其他字段可存在其他存儲設(shè)備上,例如 Hbase,在 ES 中得到結(jié)果后再去 Hbase 查詢這些字段。

  • 創(chuàng)建索引和查詢時指定路由 Routing 值,這樣可以精確到具體的分片查詢,提升查詢效率。路由的選擇需要注意數(shù)據(jù)的分布均衡。

JVM 調(diào)優(yōu)

JVM 調(diào)優(yōu)建議如下:

  • 確保堆內(nèi)存最小值( Xms )與最大值( Xmx )的大小是相同的,防止程序在運行時改變堆內(nèi)存大小。

    Elasticsearch 默認安裝后設(shè)置的堆內(nèi)存是 1GB??赏ㄟ^ ../config/jvm.option 文件進行配置,但是最好不要超過物理內(nèi)存的50%和超過 32GB。

  • GC 默認采用 CMS 的方式,并發(fā)但是有 STW 的問題,可以考慮使用 G1 收集器。

  • ES 非常依賴文件系統(tǒng)緩存(Filesystem Cache),快速搜索。一般來說,應(yīng)該至少確保物理上有一半的可用內(nèi)存分配到文件系統(tǒng)緩存。


“Elasticsearch基本原理是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI