ElasticSearch學(xué)習(xí)

《本人也在學(xué)習(xí)中麻昼,如果有哪里不對歡迎指出》

介紹

Elasticsearch 是一個分布式可擴(kuò)展的實(shí)時搜索和分析引擎,一個建立在全文搜索引擎 Apache Lucene(TM) 基礎(chǔ)上的搜索引擎

目前被廣泛應(yīng)用于互聯(lián)網(wǎng)多種領(lǐng)域中,尤其是以下三個領(lǐng)域特別突出。

搜索領(lǐng)域,相對于solr喷楣,真正的后起之秀精偿,成為很多搜索系統(tǒng)的不二之選蜒谤。

Json文檔數(shù)據(jù)庫,相對于MongoDB俏让,讀寫性能更佳楞遏,而且支持更豐富的地理位置查詢以及數(shù)字、文本的混合查詢等首昔。

時序數(shù)據(jù)分析處理寡喝,目前是日志處理、監(jiān)控?cái)?shù)據(jù)的存儲勒奇、分析和可視化方面做得非常好预鬓,可以說是該領(lǐng)域的引領(lǐng)者了。

定義

節(jié)點(diǎn)(node):物理概念赊颠,一個運(yùn)行的Elasticearch實(shí)例格二,一般是一臺機(jī)器上的一個進(jìn)程劈彪。

索引(index):邏輯概念,包括配置信息mapping和倒排正排數(shù)據(jù)文件顶猜,一個索引的數(shù)據(jù)文件可能會分布于一臺機(jī)器沧奴,也有可能分布于多臺機(jī)器。索引的另外一層意思是倒排索引文件长窄。

分片(shard):為了支持更大量的數(shù)據(jù)滔吠,索引一般會按某個維度分成多個部分,每個部分就是一個分片挠日,分片被節(jié)點(diǎn)(Node)管理疮绷。一個節(jié)點(diǎn)(Node)一般會管理多個分片,這些分片可能是屬于同一份索引嚣潜,也有可能屬于不同索引矗愧,但是為了可靠性和可用性,同一個索引的分片盡量會分布在不同節(jié)點(diǎn)(Node)上郑原。分片有兩種唉韭,主分片和副本分片。每個分片都是一個獨(dú)立的Lucene索引犯犁,會消耗相應(yīng)的文件句柄, 內(nèi)存和CPU資源

副本(replica):es默認(rèn)為一個索引創(chuàng)建5個主分片(分別有一個副本分片属愤,copy),對于分布式搜索引擎酸役,分片及副本是高可用及快速搜索響應(yīng)的設(shè)計(jì)核心住诸。當(dāng)主分片丟失時,副本分片會自動選主

主分片和副本均可以處理查詢請求涣澡,唯一區(qū)別在于只有主分片才能處理索引(增刪改查贱呐?)請求

再上圖中,使用es默認(rèn)分片配置入桂。自動把5個分片分配到2個節(jié)點(diǎn)上奄薇,而且各自分片的副本都在其他節(jié)點(diǎn)上。

額外的副本可以帶來更大的容量抗愁,更高的吞吐能力及更強(qiáng)的容災(zāi)能力馁蒂,也更耗資源。

集群運(yùn)行中你無法調(diào)整分片設(shè)置蜘腌。如果需要調(diào)整分片數(shù)量沫屡,只能新建創(chuàng)建并對數(shù)據(jù)進(jìn)行重新索引(reindex,非常耗時)

基本概念

先說Elasticsearch的文件存儲撮珠,Elasticsearch是面向文檔型數(shù)據(jù)庫沮脖,一條數(shù)據(jù)在這里就是一個文檔,用JSON作為文檔序列化的格式,比如下面這條用戶數(shù)據(jù):

{

??? "name" :???? "John",

??? "sex" :????? "Male",

??? "age" :????? 25,

??? "birthDate": "1990/05/01",

??? "about" :??? "I love to go rock climbing",

??? "interests": [ "sports", "music" ]

}

用Mysql這樣的數(shù)據(jù)庫存儲就會容易想到建立一張User表勺届,有balabala的字段等驶俊,在Elasticsearch里這就是一個文檔,當(dāng)然這個文檔會屬于一個User的類型涮因,各種各樣的類型存在于一個索引當(dāng)中废睦。這里有一份簡易的將Elasticsearch和關(guān)系型數(shù)據(jù)術(shù)語對照表:

關(guān)系數(shù)據(jù)庫?????? ? 數(shù)據(jù)庫??????? ? 表????????? ? 行???????????? ? 列(Columns)

Elasticsearch? ? 索引(Index)?? ? 類型(type)? ? 文檔(Docments)? ? 字段(Fields)??

mapping相當(dāng)于數(shù)據(jù)庫表的定義

es集群架構(gòu)

部署方式

混合部署(左

分層部署(右

es數(shù)據(jù)層架構(gòu)

Elasticsearch的Index和meta,目前支持存儲在本地文件系統(tǒng)中养泡,同時支持niofs嗜湃,mmap,simplefs澜掩,smb等不同加載方式购披,性能最好的是直接將索引LOCK進(jìn)內(nèi)存的MMap方式。默認(rèn)肩榕,Elasticsearch會自動選擇加載方式刚陡,另外可以自己在配置文件中配置。

集群構(gòu)成

es集群由節(jié)點(diǎn)構(gòu)成株汉,節(jié)點(diǎn)有不同的類型筐乳。通過如下配置的true/false兩兩組合成4種類型

conf/elasticsearch.yml:

??? node.master:?true/false

??? node.data:?true/false

node.master為true的節(jié)點(diǎn)是master候選節(jié)點(diǎn),可以參與選舉乔妈。

node.data為true的節(jié)點(diǎn)是數(shù)據(jù)節(jié)點(diǎn)蝙云,會存儲分配在該節(jié)點(diǎn)上的分片數(shù)據(jù),并負(fù)責(zé)這些分片的寫入/查詢等

master和data都為false時路召,該節(jié)點(diǎn)類似與proxy節(jié)點(diǎn)勃刨,接受命令進(jìn)行轉(zhuǎn)發(fā),結(jié)果聚合等

節(jié)點(diǎn)發(fā)現(xiàn)

es通過內(nèi)部的ZenDiscovery模塊實(shí)現(xiàn)節(jié)點(diǎn)發(fā)現(xiàn)以及選主等功能股淡。

啟動一個es節(jié)點(diǎn)時身隐,通過單播方式,在給定的ip:port中唯灵,尋找具有相同集群名字并且可見的主節(jié)點(diǎn)贾铝。如果找到則加入集群,如果沒找到就新建集群

master選舉

原則

ES針對當(dāng)前集群中所有的Master Eligible Node進(jìn)行選舉得到master節(jié)點(diǎn)早敬,為了避免出現(xiàn)腦裂現(xiàn)象忌傻,ES選擇了分布式系統(tǒng)常見的quorum(多數(shù)派)思想,也就是只有獲得了超過半數(shù)選票的節(jié)點(diǎn)才能成為master搞监。在ES中使用??discovery.zen.minimum_master_nodes??屬性設(shè)置quorum,這個屬性一般設(shè)置為??eligibleNodesNum / 2 + 1?镰矿。

如何觸發(fā)選舉

當(dāng)滿足如下條件是琐驴,集群內(nèi)就會發(fā)生一次master選舉

當(dāng)前master eligible節(jié)點(diǎn)當(dāng)前狀態(tài)不是master

該master-eligible節(jié)點(diǎn)通過ZenDiscovery模塊的ping操作詢問其已知的集群其他節(jié)點(diǎn),沒有任何節(jié)點(diǎn)連接到master。

集群中無法連接到master的master eligible節(jié)點(diǎn)數(shù)量已達(dá)到??discovery.zen.minimum_master_nodes??所設(shè)定的值

一句話總結(jié)绝淡,當(dāng)包括自己在內(nèi)的大多數(shù)master_eligible節(jié)點(diǎn)認(rèn)為集群中沒有master宙刘,則可以開始選舉

如何選舉

當(dāng)某個節(jié)點(diǎn)決定要進(jìn)行一次選舉是,它會實(shí)現(xiàn)如下操作

尋找clusterStateVersion比自己高的master eligible的節(jié)點(diǎn)牢酵,向其發(fā)送選票

如果clusterStatrVersion一樣悬包,則計(jì)算自己能找到的master eligible節(jié)點(diǎn)(包括自己)中節(jié)點(diǎn)id最小的一個節(jié)點(diǎn),向該節(jié)點(diǎn)發(fā)送選舉投票馍乙。

這樣做有利有弊

利:選舉結(jié)果穩(wěn)定布近,不會出現(xiàn)選不出來的情況

弊:極端情況下,master選舉出來后負(fù)載過高丝格,導(dǎo)致假死撑瞧,重新選舉后,原master恢復(fù)后显蝌,又被選成master预伺,然后反復(fù)假死。

如果一個節(jié)點(diǎn)收到足夠多的投票(即??minimum_master_nodes??的設(shè)置)曼尊,并且它也向自己投票了酬诀,那么該節(jié)點(diǎn)成為master開始發(fā)布集群狀態(tài)

其他選舉方法

1.Zookeeper

事實(shí)上ES可以使用Zookeeper來進(jìn)行master選舉,方法如下

所有master eligible嘗試在zk上創(chuàng)建指定路徑

只有第一個節(jié)點(diǎn)能創(chuàng)建成功骆撇,該節(jié)點(diǎn)成為master瞒御,其余節(jié)點(diǎn)watch此路徑

一旦zk失去master的連接,該路徑被刪除艾船,其余master eligible繼續(xù)嘗試創(chuàng)建路徑葵腹,同樣只能有一個節(jié)點(diǎn)成功創(chuàng)建并成為master

重復(fù)以上步驟

Zookeeper來實(shí)現(xiàn)選主可以使得ES內(nèi)部的選舉算法變得非常的簡單,至于為什么ES要自己發(fā)明一套輪子就不是很清楚了屿岂。

2.raft

有兩個timeout :election timeout和heartbeat timeout

精髓在于隨機(jī)時間election timeout(150ms-300ms)践宴,到期從follower變成candidate,時間到期之后開始新一輪(term)的選舉并投了一票給自己。

candidate發(fā)送Request Vote message給其他節(jié)點(diǎn)

如果接受消息的節(jié)點(diǎn)還沒有投票诱建,就投票給該candidate蜘醋,并刷新自己的election timeout(重新倒計(jì)時,倒計(jì)時結(jié)束沒收到下一條心跳烤惊,則開始新的選舉)。candidate收到大多數(shù)票后成為leader吁朦,發(fā)送Append Entries?messages給followers柒室,followers響應(yīng)該消息,同時刷新自己的election timeout逗宜。直到follower停止接受心跳并成為candidate

3.raft與es比較

相同

與raft同為多數(shù)派原則雄右;

選出的leader一定擁有最新的已提交數(shù)據(jù)

不同

raft是論證過正確性的空骚;而es選舉沒有經(jīng)過論證,只能在實(shí)踐中做bug fix

raft有選舉周期(term)擂仍,可以保證每輪選舉參與人僅投一票囤屹;而es不能

raft選舉沒有傾向性,只要節(jié)點(diǎn)擁有最新已提交數(shù)據(jù)逢渔,則有機(jī)會成為master肋坚;es按NodeId排序,NodeId小的優(yōu)先級高肃廓。

小結(jié)

錯誤檢測

兩類

master定期檢測集群內(nèi)其他的節(jié)點(diǎn)智厌;master發(fā)現(xiàn)節(jié)點(diǎn)失聯(lián),則會執(zhí)行removeNode亿昏,然后同步集群狀態(tài)峦剔。然后選擇新的主分片或者副本,執(zhí)行數(shù)據(jù)復(fù)制等操作角钩。

集群內(nèi)其他節(jié)點(diǎn)定期檢測master吝沫;會清空pending在內(nèi)存中還未commit的新的集群狀態(tài),然后發(fā)起rejoin递礼,重新加入集群(如果達(dá)到選舉條件則觸發(fā)新master選舉)

都是通過ping

集群縮擴(kuò)容(水平)

這里只說DataNode惨险,

擴(kuò)容

配置好

conf/elasticsearch.yml:

??? node.master:?false

??? node.data:?true

??? cluster.name: es-cluster

??? node.name: node_Z

??? discovery.zen.ping.unicast.hosts: ["x.x.x.x",?"x.x.x.y",?"x.x.x.z"]

然后啟動節(jié)點(diǎn),節(jié)點(diǎn)會自動加入相同名字的集群脊髓,集群自動進(jìn)行rebalance辫愉。也可以通過ewroute api 手動操作

縮容

設(shè)置分配規(guī)則,禁止分片分配到要縮容的機(jī)器将硝,然后執(zhí)行rebalance恭朗。執(zhí)行完畢該節(jié)點(diǎn)即可安全下線。

索引

Elasticsearch索引的精髓:

一切設(shè)計(jì)都是為了提高搜索的性能

另一層意思:為了提高搜索的性能依疼,難免會犧牲某些其他方面痰腮,比如插入/更新,否則其他數(shù)據(jù)庫不用混了律罢。前面看到往Elasticsearch里插入一條記錄膀值,其實(shí)就是直接PUT一個json的對象,這個對象有多個fields误辑,比如上面例子中的name, sex, age, about, interests沧踏,那么在插入這些數(shù)據(jù)到Elasticsearch的同時,Elasticsearch還默默1的為這些字段建立索引--倒排索引巾钉,因?yàn)镋lasticsearch最核心功能是搜索翘狱。

什么是B-Tree索引?

上大學(xué)讀書時老師教過我們,二叉樹查找效率是logN砰苍,同時插入新的節(jié)點(diǎn)不必移動全部節(jié)點(diǎn)盒蟆,所以用樹型結(jié)構(gòu)存儲索引踏烙,能同時兼顧插入和查詢的性能师骗。因此在這個基礎(chǔ)上历等,再結(jié)合磁盤的讀取特性(順序讀/隨機(jī)讀),傳統(tǒng)關(guān)系型數(shù)據(jù)庫采用了B-Tree/B+Tree這樣的數(shù)據(jù)結(jié)構(gòu):


為了提高查詢的效率辟癌,減少磁盤尋道次數(shù)寒屯,將多個值作為一個數(shù)組通過連續(xù)區(qū)間存放,一次尋道讀取多個數(shù)據(jù)黍少,同時也降低樹的高度寡夹。

什么是倒排索引?


繼續(xù)上面的例子,假設(shè)有這么幾條數(shù)據(jù)(為了簡單厂置,去掉about, interests這兩個field):

| ID |????? Name????|? Age? |?? Sex?????|

| -- |:------------:|?-----:|?-----:|?

| 1? |?Kate?????????| 24??? |?Female

| 2? |?John?????????| 24??? |?Male

| 3? |?Bill?????????| 29??? |?Male

ID是Elasticsearch自建的文檔id菩掏,那么Elasticsearch建立的索引如下:

Name:

| Term |?Posting List?|

|? --? |:----:|

| Kate |?1?|

| John |?2?|

| Bill |?3?|

Age:

| Term |?Posting List?|

| -- |:----:|

| 24 |?[1,2]?|

| 29 |?3?|

Sex:

| Term |?Posting List?|

| -- |:----:|

| Female |?1?|

| Male |?[2,3]?|

Posting List

ElasticSearch分別為每個field都建立了一個倒排索引,Kate, John, 24, Female這些叫term昵济,而[1,2]就是Posting List智绸。Posting list就是一個int的數(shù)組,存儲了所有符合某個term的文檔id访忿。

看到這里瞧栗,不要認(rèn)為就結(jié)束了,精彩的部分才剛開始...

通過posting list這種索引方式似乎可以很快進(jìn)行查找海铆,比如要找age=24的同學(xué)迹恐,愛回答問題的小明馬上就舉手回答:我知道,id是1卧斟,2的同學(xué)殴边。但是,如果這里有上千萬的記錄呢珍语?如果是想通過name來查找呢锤岸?

Term Dictionary

Elasticsearch為了能快速找到某個term,將所有的term排個序廊酣,二分法查找term能耻,logN的查找效率,就像通過字典查找一樣亡驰,這就是Term Dictionary∠停現(xiàn)在再看起來,似乎和傳統(tǒng)數(shù)據(jù)庫通過B-Tree的方式類似啊凡辱,為什么說比B-Tree的查詢快呢戒职?

Term Index

B-Tree通過減少磁盤尋道次數(shù)來提高查詢性能,Elasticsearch也是采用同樣的思路透乾,直接通過內(nèi)存查找term洪燥,不讀磁盤磕秤,但是如果term太多,term dictionary也會很大捧韵,放內(nèi)存不現(xiàn)實(shí)市咆,于是有了Term Index,就像字典里的索引頁一樣再来,A開頭的有哪些term蒙兰,分別在哪頁,可以理解term index是一顆樹:


這棵樹不會包含所有的term芒篷,它包含的是term的一些前綴搜变。通過term index可以快速地定位到term dictionary的某個offset,然后從這個位置再往后順序查找针炉。


所以term index不需要存下所有的term挠他,而僅僅是他們的一些前綴與Term Dictionary的block之間的映射關(guān)系,再結(jié)合FST(Finite State Transducers)的壓縮技術(shù)篡帕,可以使term index緩存到內(nèi)存中殖侵。從term index查到對應(yīng)的term dictionary的block位置之后,再去磁盤上找term赂苗,大大減少了磁盤隨機(jī)讀的次數(shù)愉耙。

假設(shè)我們現(xiàn)在要將mop, moth, pop, star, stop and top(term index里的term前綴)映射到序號:0,1拌滋,2朴沿,3,4败砂,5(term dictionary的block位置)赌渣。最簡單的做法就是定義個Map<string, integer="">,大家找到自己的位置對應(yīng)入座就好了昌犹,但從內(nèi)存占用少的角度想想坚芜,有沒有更優(yōu)的辦法呢?答案就是:FST(理論依據(jù)在此斜姥,但我相信99%的人不會認(rèn)真看完的)


??表示一種狀態(tài)

-->表示狀態(tài)的變化過程鸿竖,上面的字母/數(shù)字表示狀態(tài)變化和權(quán)重

將單詞分成單個字母通過??和-->表示出來,0權(quán)重不顯示铸敏。如果??后面出現(xiàn)分支缚忧,就標(biāo)記權(quán)重,最后整條路徑上的權(quán)重加起來就是這個單詞對應(yīng)的序號杈笔。

FSTs are finite-state machines that map a term (byte sequence) to an arbitrary output.

FST以字節(jié)的方式存儲所有的term闪水,這種壓縮方式可以有效的縮減存儲空間,使得term index足以放進(jìn)內(nèi)存蒙具,但這種方式也會導(dǎo)致查找時需要更多的CPU資源球榆。

壓縮技巧

Elasticsearch里除了上面說到用FST壓縮term index外朽肥,對posting list也有壓縮技巧。?

小明喝完咖啡又舉手了:"posting list不是已經(jīng)只存儲文檔id了嗎持钉?還需要壓縮衡招?"

嗯,我們再看回最開始的例子右钾,如果Elasticsearch需要對同學(xué)的性別進(jìn)行索引(這時傳統(tǒng)關(guān)系型數(shù)據(jù)庫已經(jīng)哭暈在廁所……)蚁吝,會怎樣?如果有上千萬個同學(xué)舀射,而世界上只有男/女這樣兩個性別,每個posting list都會有至少百萬個文檔id怀伦。 Elasticsearch是如何有效的對這些文檔id壓縮的呢脆烟?

Frame Of Reference

增量編碼壓縮,將大數(shù)變小數(shù)房待,按字節(jié)存儲

首先邢羔,Elasticsearch要求posting list是有序的(為了提高搜索的性能,再任性的要求也得滿足)桑孩,這樣做的一個好處是方便壓縮拜鹤,看下面這個圖例:?


如果數(shù)學(xué)不是體育老師教的話,還是比較容易看出來這種壓縮技巧的流椒。

原理就是通過增量敏簿,將原來的大數(shù)變成小數(shù)僅存儲增量值,再精打細(xì)算按bit排好隊(duì)宣虾,最后通過字節(jié)存儲惯裕,而不是大大咧咧的盡管是2也是用int(4個字節(jié))來存儲。

Roaring bitmaps

說到Roaring bitmaps绣硝,就必須先從bitmap說起蜻势。Bitmap是一種數(shù)據(jù)結(jié)構(gòu),假設(shè)有某個posting list:

[1,3,4,7,10]

對應(yīng)的bitmap就是:

[1,0,1,1,0,0,1,0,0,1]

非常直觀鹉胖,用0/1表示某個值是否存在握玛,比如10這個值就對應(yīng)第10位,對應(yīng)的bit值是1甫菠,這樣用一個字節(jié)就可以代表8個文檔id挠铲,舊版本(5.0之前)的Lucene就是用這樣的方式來壓縮的,但這樣的壓縮方式仍然不夠高效淑蔚,如果有1億個文檔市殷,那么需要12.5MB的存儲空間,這僅僅是對應(yīng)一個索引字段(我們往往會有很多個索引字段)刹衫。于是有人想出了Roaring bitmaps這樣更高效的數(shù)據(jù)結(jié)構(gòu)醋寝。

Bitmap的缺點(diǎn)是存儲空間隨著文檔個數(shù)線性增長搞挣,Roaring bitmaps需要打破這個魔咒就一定要用到某些指數(shù)特性:

將posting list按照65535為界限分塊,比如第一塊所包含的文檔id范圍在0~65535之間音羞,第二塊的id范圍是65536~131071囱桨,以此類推。再用<商嗅绰,余數(shù)>的組合表示每一組id舍肠,這樣每組里的id范圍都在0~65535內(nèi)了,剩下的就好辦了窘面,既然每組id不會變得無限大翠语,那么我們就可以通過最有效的方式對這里的id存儲。


細(xì)心的小明這時候又舉手了:"為什么是以65535為界限?"

程序員的世界里除了1024外财边,65535也是一個經(jīng)典值肌括,因?yàn)樗?2^16-1,正好是用2個字節(jié)能表示的最大數(shù)酣难,一個short的存儲單位谍夭,注意到上圖里的最后一行“If a block has more than 4096 values, encode as a bit set, and otherwise as a simple array using 2 bytes per value”,如果是大塊憨募,用節(jié)省點(diǎn)用bitset存紧索,小塊就豪爽點(diǎn),2個字節(jié)我也不計(jì)較了菜谣,用一個short[]存著方便珠漂。

那為什么用4096來區(qū)分大塊還是小塊呢?

個人理解:都說程序員的世界是二進(jìn)制的葛菇,4096*2bytes = 8192bytes < 1KB, 磁盤一次尋道可以順序把一個小塊的內(nèi)容都讀出來甘磨,再大一位就超過1KB了,需要兩次讀眯停。

聯(lián)合索引

上面說了半天都是單field索引济舆,如果多個field索引的聯(lián)合查詢,倒排索引如何滿足快速查詢的要求呢莺债?

利用跳表(Skip list)的數(shù)據(jù)結(jié)構(gòu)快速做“與”運(yùn)算滋觉,或者

利用上面提到的bitset按位“與”

先看看跳表的數(shù)據(jù)結(jié)構(gòu):


將一個有序鏈表level0,挑出其中幾個元素到level1及l(fā)evel2齐邦,每個level越往上椎侠,選出來的指針元素越少,查找時依次從高level往低查找措拇,比如55我纪,先找到level2的31,再找到level1的47,最后找到55浅悉,一共3次查找趟据,查找效率和2叉樹的效率相當(dāng),但也是用了一定的空間冗余來換取的术健。

假設(shè)有下面三個posting list需要聯(lián)合索引:


如果使用跳表汹碱,對最短的posting list中的每個id,逐個在另外兩個posting list中查找看是否存在荞估,最后得到交集的結(jié)果咳促。

如果使用bitset,就很直觀了勘伺,直接按位與跪腹,得到的結(jié)果就是最后的交集。

分片

分片的額外成本

分片不是越多越好娇昙,每個分片都是有額外的成本:

每個分片本質(zhì)上就是一個Lucene索引尺迂,因此會消耗相應(yīng)的文件句柄,內(nèi)存和cpu資源

每個搜索請求會調(diào)度到索引的每個分片中冒掌,如果當(dāng)分片分到同一個節(jié)點(diǎn),競爭相同的硬件資源時蹲盘,性能會下降

ES使用詞頻統(tǒng)計(jì)來計(jì)算相關(guān)性. 當(dāng)然這些統(tǒng)計(jì)也會分配到各個分片上. 如果在大量分片上只維護(hù)了很少的數(shù)據(jù), 則將導(dǎo)致最終的文檔相關(guān)性較差

分片原則:

es推薦的最大JVM堆空間是30-32G股毫,所以把分片最大容量限制為30GB,然后根據(jù)數(shù)據(jù)量計(jì)算分片數(shù)召衔。例如铃诬,一個數(shù)據(jù)預(yù)計(jì)能達(dá)到200G的索引,推薦分8個左右分片苍凛。

不過, 你最好還是能描述出每個節(jié)點(diǎn)上只放一個索引分片的必要性. 在開始階段, 一個好的方案是根據(jù)你的節(jié)點(diǎn)數(shù)量按照1.5~3倍的原則來創(chuàng)建分片. 例如,如果你有3個節(jié)點(diǎn), 則推薦你創(chuàng)建的分片數(shù)最多不超過9(3x3)個.

隨著數(shù)據(jù)量的增加,如果你通過集群狀態(tài)API發(fā)現(xiàn)了問題,或者遭遇了性能退化,則只需要增加額外的節(jié)點(diǎn)即可. ES會自動幫你完成分片在不同節(jié)點(diǎn)上的分布平衡.

再強(qiáng)調(diào)一次, 雖然這里我們暫未涉及副本節(jié)點(diǎn)的介紹, 但上面的指導(dǎo)原則依然使用: 是否有必要在每個節(jié)點(diǎn)上只分配一個索引的分片. 另外, 如果給每個分片分配1個副本, 你所需的節(jié)點(diǎn)數(shù)將加倍. 如果需要為每個分片分配2個副本, 則需要3倍的節(jié)點(diǎn)數(shù). 更多詳情可以參考基于副本的集群.

總結(jié)和思考

Elasticsearch的索引思路:

將磁盤里的東西盡量搬進(jìn)內(nèi)存趣席,減少磁盤隨機(jī)讀取次數(shù)(同時也利用磁盤順序讀特性),結(jié)合各種奇技淫巧的壓縮算法醇蝴,用及其苛刻的態(tài)度使用內(nèi)存宣肚。

所以,對于使用Elasticsearch進(jìn)行索引時需要注意:

不需要索引的字段悠栓,一定要明確定義出來霉涨,因?yàn)槟J(rèn)是自動建索引的

同樣的道理,對于String類型的字段惭适,不需要analysis的也需要明確定義出來笙瑟,因?yàn)槟J(rèn)也是會analysis的

選擇有規(guī)律的ID很重要,隨機(jī)性太大的ID(比如java的UUID)不利于查詢

關(guān)于最后一點(diǎn)癞志,個人認(rèn)為有多個因素:

其中一個(也許不是最重要的)因素: 上面看到的壓縮算法往枷,都是對Posting list里的大量ID進(jìn)行壓縮的,那如果ID是順序的,或者是有公共前綴等具有一定規(guī)律性的ID错洁,壓縮比會比較高秉宿;

另外一個因素: 可能是最影響查詢性能的,應(yīng)該是最后通過Posting list里的ID到磁盤中查找Document信息的那步墓臭,因?yàn)镋lasticsearch是分Segment存儲的蘸鲸,根據(jù)ID這個大范圍的Term定位到Segment的效率直接影響了最后查詢的性能,如果ID是有規(guī)律的窿锉,可以快速跳過不包含該ID的Segment酌摇,從而減少不必要的磁盤讀次數(shù),具體可以參考這篇如何選擇一個高效的全局ID方案(評論也很精彩)

type keyword(not_analyzed) vs text(使用分詞)?

https://blog.csdn.net/wwd0501/article/details/78091720

刪除文檔的時候只是標(biāo)記成已刪除嗡载,es會在之后添加更多索引的時候在后臺自動刪除

通過文檔的version版本控制 進(jìn)行 樂觀并發(fā)控制

?bulk?請求不是原子操作——它們不能實(shí)現(xiàn)事務(wù)窑多。每個請求操作時分開的,所以每個請求的成功與否不干擾其它操作洼滚。

索引分片的作用

默認(rèn)索引5個分片及1個副本(每個分片都有一個副本埂息,共10個Lucene索引在集群中)

分片的優(yōu)點(diǎn):

修改記錄時:

ranslog是保證es數(shù)據(jù)安全的關(guān)鍵所在,增加flush的頻率可以減少數(shù)據(jù)丟失的風(fēng)險(xiǎn)遥巴,但是所帶來的是非常大的性能開銷千康,所以生產(chǎn)上要根據(jù)具體的業(yè)務(wù)需求來進(jìn)行配置的優(yōu)化。對實(shí)時要求不高的長久铲掐,可以考慮增加refresh的時間間隔拾弃,這會很有效的提升性能。

Lucene中存儲的索引主要分為三種類型

Invert Index摆霉,即倒排索引豪椿。通過term可以快速查找到包含該term的doc_id。如果Field配置分詞携栋,則分詞后的每個term都會進(jìn)入倒排索引搭盾,如果Field不指定分詞,那該Field的value值則會作為一個term進(jìn)入倒排婉支。(這里需要注意的是term的長度是有限制的鸯隅,如果對一個Field不采取分詞,那么不建議該Field存儲過長的值磅摹。關(guān)于term超長處理)

DocValues滋迈,即正排索引。采用的是類似數(shù)據(jù)庫的列式存儲户誓。對于一些特殊需求的字段可以選擇這種索引方式饼灿。

Store,即原文帝美。存儲整個完整Document的原始信息碍彭。

寫入

Elasticsearch采用多Shard方式,通過配置routing規(guī)則將數(shù)據(jù)分成多個數(shù)據(jù)子集,每個數(shù)據(jù)子集提供獨(dú)立的索引和搜索功能庇忌。當(dāng)寫入文檔的時候舞箍,根據(jù)routing規(guī)則,將文檔發(fā)送給特定Shard中建立索引皆疹。這樣就能實(shí)現(xiàn)分布式了疏橄。

每個Index由多個Shard組成,每個Shard有一個主節(jié)點(diǎn)和多個副本節(jié)點(diǎn)略就,副本個數(shù)可配捎迫。但每次寫入的時候,寫入請求會先根據(jù)_routing規(guī)則選擇發(fā)給哪個Shard表牢,Index Request中可以設(shè)置使用哪個Filed的值作為路由參數(shù)窄绒,如果沒有設(shè)置,則使用Mapping中的配置崔兴,如果mapping中也沒有配置彰导,則使用_id作為路由參數(shù),然后通過_routing的Hash值選擇出Shard敲茄,最后從集群的Meta中找出出該Shard的Primary節(jié)點(diǎn)位谋。

請求接著會發(fā)送給Primary Shard,在Primary Shard上執(zhí)行成功后堰燎,再從Primary Shard上將請求同時發(fā)送給多個Replica Shard倔幼,請求在多個Replica Shard上執(zhí)行成功并返回給Primary Shard后,寫入請求執(zhí)行成功爽待,返回結(jié)果給客戶端。

優(yōu)點(diǎn):可靠性高

缺點(diǎn):時延高

采用多個副本后翩腐,避免了單機(jī)或磁盤故障發(fā)生時鸟款,對已經(jīng)持久化后的數(shù)據(jù)造成損害,但是Elasticsearch里為了減少磁盤IO保證讀寫性能茂卦,一般是每隔一段時間(比如5分鐘)才會把Lucene的Segment寫入磁盤持久化何什,對于寫入內(nèi)存,但還未Flush到磁盤的Lucene數(shù)據(jù)等龙,如果發(fā)生機(jī)器宕機(jī)或者掉電处渣,那么內(nèi)存中的數(shù)據(jù)也會丟失臂容,這時候如何保證攻泼?

對于這種問題肤无,Elasticsearch學(xué)習(xí)了數(shù)據(jù)庫中的處理方式:增加CommitLog模塊亦渗,Elasticsearch中叫TransLog凌净。

update

Lucene中不支持部分字段的Update丁鹉,所以需要在Elasticsearch中實(shí)現(xiàn)該功能龟梦,具體流程如下:

收到Update請求后焙蹭,從Segment或者TransLog中讀取同id的完整Doc,記錄版本號為V1柑贞。

將版本V1的全量Doc和請求中的部分字段Doc合并為一個完整的Doc方椎,同時更新內(nèi)存中的VersionMap。獲取到完整Doc后钧嘶,Update請求就變成了Index請求棠众。

加鎖。

再次從versionMap中讀取該id的最大版本號V2有决,如果versionMap中沒有闸拿,則從Segment或者TransLog中讀取,這里基本都會從versionMap中獲取到疮薇。

檢查版本是否沖突(V1==V2)胸墙,如果沖突,則回退到開始的“Update doc”階段按咒,重新執(zhí)行迟隅。如果不沖突,則執(zhí)行最新的Add請求励七。

在Index Doc階段智袭,首先將Version + 1得到V3,再將Doc加入到Lucene中去掠抬,Lucene中會先刪同id下的已存在doc id吼野,然后再增加新Doc。寫入Lucene成功后两波,將當(dāng)前V3更新到versionMap中瞳步。

釋放鎖,部分更新的流程就結(jié)束了腰奋。

delete

執(zhí)行delete時单起,不會真正的刪除,而是標(biāo)記為刪除劣坊,查詢后會過濾掉嘀倒,等到segment merge的時候才真正的刪除。

es存儲模塊

可以允許用戶控制索引的存儲方式(存儲在磁盤)

簡單文件系統(tǒng)存儲?

index.store.type = simplefs

這是一個隨機(jī)訪問文件的文件存儲系統(tǒng)局冰,并發(fā)性能較差测蘑,多線程下存在性能瓶頸問題。如果我們想對ESSearch索引做持久化康二,推薦使用niofs碳胳。

新I/O文件系統(tǒng)存儲

index.store.type = niofs?

通過NIO將分片索引文件寫到文件系統(tǒng)上,允許多線程同時讀取文件赠摇。

MMap文件系統(tǒng)存儲(非windows系統(tǒng)默認(rèn))

index.store.type = mmapfs

將索引分片存儲到文件系統(tǒng)上固逗,再通過映射浅蚪,將索引文件映射到內(nèi)存中。map即為映射的意思烫罩。不過我們需要注意:索引文件映射到內(nèi)存過程中惜傲,我們需要劃分出與被映射文件大小一樣的虛擬內(nèi)存空間。

MMap FS / NIO FS

index.store.type = default_fs

它會為每個類型的文件選擇最好的文件系統(tǒng)贝攒。

查詢

es兩種使用場景盗誊,搜索和NoSQL

工作原理

搜索場景近實(shí)時二階段查(query then fetch)返回最滿足條件的TopN要求最終一致性

NoSQL場景實(shí)時一階段直接返回返回滿足條件的所有結(jié)果要求強(qiáng)一致性

搜索場景:近實(shí)時的,需要分散(scatter phase)查詢到多個節(jié)點(diǎn)中隘弊,得到結(jié)果哈踱,合并(gather phase)它們,按分值排序梨熙,返回給客戶开镣。

NoSQL場景:實(shí)時的,通過DocID直接查translog咽扇,查到具體值即返回邪财。

1.搜索場景

2.NoSQL場景(右)

兩類查詢

Search

一起查內(nèi)存和磁盤上的segment,將結(jié)果合并返回质欲,因?yàn)閮?nèi)存中的index需要一段時間refresh到新的segment树埠,所以是近實(shí)時的

Get

先查TransLog,查到即返回嘶伟,沒查到接著查磁盤中的TransLog怎憋,還沒查到就查磁盤中的Segment。實(shí)時的

我們可以在一定程度上控制查詢

搜索類型:

根據(jù)關(guān)注點(diǎn)九昧,注重性能或是注重相關(guān)性結(jié)果绊袋,選擇不同的搜索類型

QUERY_THEN_FETCH (默認(rèn))

第一次查詢匹配到的DocID,第二次查詢DocID對應(yīng)的完整文檔铸鹰。查一次shard愤炸,返回?cái)?shù)據(jù)量準(zhǔn)確,score不準(zhǔn)掉奄,速度一般

QUERY_AND_FEATCH

查一次,score和內(nèi)容一起返回凤薛,速度塊姓建,數(shù)據(jù)量過多,score不準(zhǔn)

DFS_QUERY_THEN_FEATCH?

對比第一種多了dfs操作缤苫,也就是在進(jìn)行查詢之前速兔, 先對所有分片發(fā)送請求, 把所有分片中的詞頻和文檔頻率等打分依據(jù)全部匯總到一塊活玲, 再執(zhí)行后面的操作涣狗。都準(zhǔn)谍婉,但是性能差。

DFS_QUERY_AND_FEATCH

搜索執(zhí)行偏好:

除了可以控制查詢方法镀钓,還可以控制在哪些分片上執(zhí)行查詢

隨機(jī)查詢數(shù)據(jù)(es默認(rèn)方式)

_local:優(yōu)先本地節(jié)點(diǎn)上的分片查詢數(shù)據(jù)穗熬,然后再去其他節(jié)點(diǎn)上的分片查詢。本地節(jié)點(diǎn)查沒有IO問題但可能會負(fù)載不均丁溅。

_primary:只在主分片中查詢

_primary_first:優(yōu)先主分片

_only_node:指定節(jié)點(diǎn)id中的分片查詢唤蔗,數(shù)據(jù)可能不完整

_perfer_node:優(yōu)先在指定節(jié)點(diǎn)中查詢

_shards:指定分片中查詢,數(shù)據(jù)可能不完整

es查詢存在兩個問題:

】呱汀(1)返回?cái)?shù)據(jù)量問題

〖斯瘛(2)返回?cái)?shù)據(jù)排名問題

解決思路:

??? (1)返回?cái)?shù)據(jù)數(shù)量問題

    第一步:先從每個分片匯總查詢的數(shù)據(jù)id,進(jìn)行排名涯穷,取前10條數(shù)據(jù)

    第二步:根據(jù)這10條數(shù)據(jù)id棍掐,到不同分片獲取數(shù)據(jù)

 (2)返回?cái)?shù)據(jù)排名問題

    將各個分片打分標(biāo)準(zhǔn)統(tǒng)一

ps:

es5.*以后就沒有string類型拷况,引入text作煌,keyword字段。

text:存儲數(shù)據(jù)時候蝠嘉,不會分詞建立索引

keyword:存儲數(shù)據(jù)時候最疆,會自動分詞,并生成索引

FAQ

全文搜索(使用es)的優(yōu)勢蚤告?適合什么樣的場景努酸?

特點(diǎn)(優(yōu)勢):

可以作為一個大型分布式集群,處理pb級數(shù)據(jù)杜恰。

近實(shí)時更新

3分鐘部署获诈,開箱即用,非常簡單

適合場景:

維基百科心褐;stack overflow問題和答案的全文檢索舔涎;github 千億行代碼搜索;電商網(wǎng)站 搜索商品逗爹;ELK 數(shù)據(jù)分析

怎么查詢的亡嫌?查詢原理是什么?

數(shù)據(jù)是怎么存儲的掘而?索引是怎么存儲的挟冠?

分布式相關(guān)的,怎么擴(kuò)展袍睡?怎么處理故障知染?

選舉怎么保證不腦裂(選出多個)?

多數(shù)派策略斑胜,設(shè)置?minimum_master_nodes?為?eligibleNodesNum / 2 + 1?即可

其實(shí)像百度google這樣的搜索引擎控淡,最核心的都是建立倒排索引嫌吠,只不過更復(fù)雜一點(diǎn),包括網(wǎng)頁抓去掺炭,停頓詞過濾等等辫诅。

搜索引擎三大內(nèi)容

爬取內(nèi)容

進(jìn)行分詞

建立反向索引

es集群中也有master和slave節(jié)點(diǎn)的區(qū)分

建立索引(mapping的時候也一樣)的時候就是先通知master,然后master再將集群狀態(tài)同步給slaves

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竹伸,一起剝皮案震驚了整個濱河市泥栖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌勋篓,老刑警劉巖吧享,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異譬嚣,居然都是意外死亡钢颂,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進(jìn)店門拜银,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殊鞭,“玉大人,你說我怎么就攤上這事尼桶〔俨樱” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵泵督,是天一觀的道長趾盐。 經(jīng)常有香客問我,道長小腊,這世上最難降的妖魔是什么救鲤? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮秩冈,結(jié)果婚禮上本缠,老公的妹妹穿的比我還像新娘。我一直安慰自己入问,他們只是感情好丹锹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芬失,像睡著了一般卷仑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上麸折,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機(jī)與錄音粘昨,去河邊找鬼垢啼。 笑死窜锯,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芭析。 我是一名探鬼主播锚扎,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼馁启!你這毒婦竟也來了驾孔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惯疙,失蹤者是張志新(化名)和其女友劉穎翠勉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體霉颠,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡对碌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蒿偎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朽们。...
    茶點(diǎn)故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖诉位,靈堂內(nèi)的尸體忽然破棺而出骑脱,到底是詐尸還是另有隱情,我是刑警寧澤苍糠,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布叁丧,位于F島的核電站,受9級特大地震影響椿息,放射性物質(zhì)發(fā)生泄漏歹袁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一寝优、第九天 我趴在偏房一處隱蔽的房頂上張望条舔。 院中可真熱鬧,春花似錦乏矾、人聲如沸孟抗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凄硼。三九已至,卻和暖如春捷沸,著一層夾襖步出監(jiān)牢的瞬間摊沉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工痒给, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留说墨,地道東北人骏全。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像尼斧,于是被迫代替她去往敵國和親姜贡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內(nèi)容