Elasticsearch 介紹
概要
Elasticsearch 是一個(gè)分布式搜索引擎,底層基于 Lucene 實(shí)現(xiàn)甲锡。Elasticsearch 屏蔽了 Lucene 的底層細(xì)節(jié)捶朵,提供了分布式特性刽严,同時(shí)對(duì)外提供了 Restful API监透。Elasticsearch 以其易用性迅速贏得了許多用戶瑟慈,被用在網(wǎng)站搜索、日志分析等諸多方面仔雷。由于 ES 強(qiáng)大的橫向擴(kuò)展能力蹂析,甚至很多人也會(huì)直接把 ES 當(dāng)做 NoSQL 來(lái)用。
基本概念
全文搜索(Full-text Search)
全文檢索是指計(jì)算機(jī)索引程序通過(guò)掃描文章中的每一個(gè)詞碟婆,對(duì)每一個(gè)詞建立一個(gè)索引电抚,指明該詞在文章中出現(xiàn)的次數(shù)和位置,當(dāng)用戶查詢(xún)時(shí)竖共,檢索程序就根據(jù)事先建立的索引進(jìn)行查找蝙叛,并將查找的結(jié)果反饋給用戶的檢索方式。
?在全文搜索的世界中公给,存在著幾個(gè)龐大的帝國(guó)借帘,也就是主流工具,主要有:
- Apache Lucene
- Elasticsearch
- Solr
- Ferret
倒排索引(Inverted Index)
該索引表中的每一項(xiàng)都包括一個(gè)屬性值和具有該屬性值的各記錄的地址淌铐。由于不是由記錄來(lái)確定屬性值肺然,而是由屬性值來(lái)確定記錄的位置,因而稱(chēng)為倒排索引(inverted index)腿准。Elasticsearch能夠?qū)崿F(xiàn)快速际起、高效的搜索功能,正是基于倒排索引原理释涛。
節(jié)點(diǎn) & 集群(Node & Cluster)
Elasticsearch 本質(zhì)上是一個(gè)分布式數(shù)據(jù)庫(kù)加叁,允許多臺(tái)服務(wù)器協(xié)同工作,每臺(tái)服務(wù)器可以運(yùn)行多個(gè)Elasticsearch實(shí)例唇撬。單個(gè)Elasticsearch實(shí)例稱(chēng)為一個(gè)節(jié)點(diǎn)(Node)它匕,一組節(jié)點(diǎn)構(gòu)成一個(gè)集群(Cluster)。
Document (文檔)
文檔指的是用戶提交給 ES 的一條數(shù)據(jù)窖认。需要注意的是豫柬,這里的文檔并非指的是一個(gè)純字符串文本告希,在 ES 中文檔指的是一條 JSON 數(shù)據(jù)。如果對(duì) MongoDB 有了解的話烧给,這里文檔的含義和 MongoDB 中的基本類(lèi)似燕偶。
JSON 數(shù)據(jù)中可以包含多個(gè)字段,這些字段可以類(lèi)比為 MySQL 中每個(gè)表的字段础嫡。
例如:
{
"message": "this is my blog",
"author": "cyhone"
}
這樣我們后期進(jìn)行搜索和查詢(xún)的時(shí)候指么,也可以分別針對(duì) message
字段和 author
字段進(jìn)行搜索。
Index (索引)
Index(索引) 可以理解為是文檔的集合榴鼎,同在一個(gè)索引中的文檔共同建立倒排索引伯诬。
也有很多人會(huì)把索引類(lèi)比于 MySQL 中 schema 的概念。但在 ES 中 Index 更加靈活巫财,用起來(lái)也更加方便盗似。
此外,提交給同一個(gè)索引中的文檔平项,最好擁有相同的結(jié)構(gòu)赫舒。這樣對(duì)于 ES 來(lái)說(shuō),不管是存儲(chǔ)還是查詢(xún)闽瓢,都更容易優(yōu)化接癌。
類(lèi)型(Type)
Document 可以分組,比如employee這個(gè) Index 里面鸳粉,可以按部門(mén)分組扔涧,也可以按職級(jí)分組。這種分組就叫做 Type届谈,它是虛擬的邏輯分組,用來(lái)過(guò)濾 Document弯汰,類(lèi)似關(guān)系型數(shù)據(jù)庫(kù)中的數(shù)據(jù)表艰山。
?不同的 Type 應(yīng)該有相似的結(jié)構(gòu)(Schema),性質(zhì)完全不同的數(shù)據(jù)(比如 products 和 logs)應(yīng)該存成兩個(gè) Index咏闪,而不是一個(gè) Index 里面的兩個(gè) Type(雖然可以做到)曙搬。
文檔元數(shù)據(jù)(Document metadata)
文檔元數(shù)據(jù)為_(kāi)index, _type, _id, 這三者可以唯一表示一個(gè)文檔,_index表示文檔在哪存放鸽嫂,_type表示文檔的對(duì)象類(lèi)別纵装,_id為文檔的唯一標(biāo)識(shí)。
字段(Fields)
每個(gè)Document都類(lèi)似一個(gè)JSON結(jié)構(gòu)据某,它包含了許多字段橡娄,每個(gè)字段都有其對(duì)應(yīng)的值,多個(gè)字段組成了一個(gè) Document癣籽,可以類(lèi)比關(guān)系型數(shù)據(jù)庫(kù)數(shù)據(jù)表中的字段挽唉。
?在 Elasticsearch 中滤祖,文檔(Document)歸屬于一種類(lèi)型(Type),而這些類(lèi)型存在于索引(Index)中瓶籽,下圖展示了Elasticsearch與傳統(tǒng)關(guān)系型數(shù)據(jù)庫(kù)的類(lèi)比:
整體結(jié)構(gòu)
下圖是ES的主要結(jié)構(gòu)圖:
包含了這些模塊:
Transport Client/Node Client/REST API:三種訪問(wèn)es集群的方式
Transport(Netty):通信模塊匠童,數(shù)據(jù)傳輸,底層采用netty框架
Index塑顺、Search…:支持搜索汤求,索引等常用操作
Discovery:節(jié)點(diǎn)發(fā)現(xiàn),集群之間通信的基石
Plugins:很多服務(wù)以插件形式提供严拒,官方和社區(qū)支持的ik扬绪、head、river糙俗、discovery gce…
Script:提供腳本支持勒奇,內(nèi)置painless,groovy等巧骚,默認(rèn)painless
Store/Snapshot:文件存儲(chǔ)與訪問(wèn)赊颠,快照創(chuàng)建和恢復(fù)
translog、cluster state劈彪、segments:es主要文件類(lèi)型竣蹦,其中translog、cluster state是es添加的數(shù)據(jù)沧奴,多個(gè)segments段組成一個(gè)完整的lucene索引
Monitor:監(jiān)控模塊痘括,監(jiān)控jvm,文件系統(tǒng)滔吠,操作系統(tǒng)等運(yùn)行情況
File System:es支持可以在多種文件系統(tǒng)上運(yùn)行纲菌,本地、共享型疮绷、HDFS翰舌、亞馬遜云平臺(tái)等
相關(guān)原理
ES的RESTful
ElasticSearch提供了易用但功能強(qiáng)大的RESTful API以用于與集群進(jìn)行交互,這些API大體可分為如下四類(lèi):
- 檢查集群冬骚、節(jié)點(diǎn)椅贱、索引等健康與否,以及獲取其相關(guān)狀態(tài)與統(tǒng)計(jì)信息只冻;
- 管理集群庇麦、節(jié)點(diǎn)、索引數(shù)據(jù)及元數(shù)據(jù)喜德;
- 執(zhí)行CRUD操作及搜索操作山橄;
- 執(zhí)行高級(jí)搜索操作,例如paging住诸、filtering驾胆、scripting涣澡、faceting、aggregations及其它操作丧诺;
ES的讀寫(xiě)原理
下圖為ES的讀寫(xiě)原理流程圖:
ES寫(xiě)數(shù)據(jù)過(guò)程
- 客戶端隨機(jī)選擇一個(gè)node發(fā)送請(qǐng)求過(guò)去入桂,這個(gè)node就是coordinating node(協(xié)調(diào)節(jié)點(diǎn))
- coordinating node,對(duì)document進(jìn)行路由驳阎,將請(qǐng)求轉(zhuǎn)發(fā)給對(duì)應(yīng)的node(有primary shard)
- 實(shí)際的node上的primary shard處理請(qǐng)求抗愁,然后將數(shù)據(jù)同步到replica node
- coordinating node,如果發(fā)現(xiàn)primary node和所有replica node都搞定之后呵晚,就返回響應(yīng)結(jié)果給客戶端
在寫(xiě)primary的過(guò)程中同時(shí)還要持久到本地 :
先寫(xiě)入buffer蜘腌,在buffer里的時(shí)候數(shù)據(jù)是搜索不到的;同時(shí)將數(shù)據(jù)寫(xiě)入translog日志文件
如果buffer快滿了饵隙,或者到一定時(shí)間撮珠,就會(huì)將buffer數(shù)據(jù)refresh到一個(gè)新的segment file中,但是此時(shí)數(shù)據(jù)不是直接進(jìn)入segment file的磁盤(pán)文件的金矛,而是先進(jìn)入os cache的芯急。這個(gè)過(guò)程就是refresh。每隔1秒鐘驶俊,es將buffer中的數(shù)據(jù)寫(xiě)入一個(gè)新的segment file娶耍,每秒鐘會(huì)產(chǎn)生一個(gè)新的磁盤(pán)文件,segment file饼酿,這個(gè)segment file中就存儲(chǔ)最近1秒內(nèi)buffer中寫(xiě)入的數(shù)據(jù)榕酒。但是如果buffer里面此時(shí)沒(méi)有數(shù)據(jù),那當(dāng)然不會(huì)執(zhí)行refresh操作咯故俐,每秒創(chuàng)建換一個(gè)空的segment file想鹰,如果buffer里面有數(shù)據(jù),默認(rèn)1秒鐘執(zhí)行一次refresh操作药版,刷入一個(gè)新的segment file中杖挣。操作系統(tǒng)里面,磁盤(pán)文件其實(shí)都有一個(gè)東西刚陡,叫做os cache,操作系統(tǒng)緩存株汉,就是說(shuō)數(shù)據(jù)寫(xiě)入磁盤(pán)文件之前筐乳,會(huì)先進(jìn)入os cache,先進(jìn)入操作系統(tǒng)級(jí)別的一個(gè)內(nèi)存緩存中去乔妈。只要buffer中的數(shù)據(jù)被refresh操作蝙云,刷入os cache中,就代表這個(gè)數(shù)據(jù)就可以被搜索到了路召。為什么叫es是準(zhǔn)實(shí)時(shí)的勃刨?NRT波材,near real-time,準(zhǔn)實(shí)時(shí)身隐。默認(rèn)是每隔1秒refresh一次的廷区,所以es是準(zhǔn)實(shí)時(shí)的,因?yàn)閷?xiě)入的數(shù)據(jù)1秒之后才能被看到贾铝∠肚幔可以通過(guò)es的restful api或者java api,手動(dòng)執(zhí)行一次refresh操作垢揩,就是手動(dòng)將buffer中的數(shù)據(jù)刷入os cache中玖绿,讓數(shù)據(jù)立馬就可以被搜索到。只要數(shù)據(jù)被輸入os cache中叁巨,buffer就會(huì)被清空了斑匪,因?yàn)椴恍枰A鬮uffer了,數(shù)據(jù)在translog里面已經(jīng)持久化到磁盤(pán)去一份了
只要數(shù)據(jù)進(jìn)入os cache锋勺,此時(shí)就可以讓這個(gè)segment file的數(shù)據(jù)對(duì)外提供搜索了
重復(fù)1~3步驟蚀瘸,新的數(shù)據(jù)不斷進(jìn)入buffer和translog,不斷將buffer數(shù)據(jù)寫(xiě)入一個(gè)又一個(gè)新的segment file中去宙刘,每次refresh完buffer清空苍姜,translog保留。隨著這個(gè)過(guò)程推進(jìn)悬包,translog會(huì)變得越來(lái)越大衙猪。當(dāng)translog達(dá)到一定長(zhǎng)度的時(shí)候,就會(huì)觸發(fā)commit操作布近。buffer中的數(shù)據(jù)垫释,倒是好,每隔1秒就被刷到os cache中去撑瞧,然后這個(gè)buffer就被清空了棵譬。所以說(shuō)這個(gè)buffer的數(shù)據(jù)始終是可以保持住不會(huì)填滿es進(jìn)程的內(nèi)存的。每次一條數(shù)據(jù)寫(xiě)入buffer预伺,同時(shí)會(huì)寫(xiě)入一條日志到translog日志文件中去订咸,所以這個(gè)translog日志文件是不斷變大的,當(dāng)translog日志文件大到一定程度的時(shí)候酬诀,就會(huì)執(zhí)行commit操作脏嚷。
commit操作發(fā)生第一步,就是將buffer中現(xiàn)有數(shù)據(jù)refresh到os cache中去瞒御,清空buffer
將一個(gè)commit point寫(xiě)入磁盤(pán)文件父叙,里面標(biāo)識(shí)著這個(gè)commit point對(duì)應(yīng)的所有segment file
強(qiáng)行將os cache中目前所有的數(shù)據(jù)都fsync到磁盤(pán)文件中去,translog日志文件的作用是什么?就是在你執(zhí)行commit操作之前趾唱,數(shù)據(jù)要么是停留在buffer中涌乳,要么是停留在os cache中,無(wú)論是buffer還是os cache都是內(nèi)存甜癞,一旦這臺(tái)機(jī)器死了夕晓,內(nèi)存中的數(shù)據(jù)就全丟了。所以需要將數(shù)據(jù)對(duì)應(yīng)的操作寫(xiě)入一個(gè)專(zhuān)門(mén)的日志文件带欢,translog日志文件中运授,一旦此時(shí)機(jī)器宕機(jī),再次重啟的時(shí)候乔煞,es會(huì)自動(dòng)讀取translog日志文件中的數(shù)據(jù)吁朦,恢復(fù)到內(nèi)存buffer和os cache中去。commit操作:1渡贾、寫(xiě)commit point逗宜;2、將os cache數(shù)據(jù)fsync強(qiáng)刷到磁盤(pán)上去空骚;3纺讲、清空translog日志文件
將現(xiàn)有的translog清空,然后再次重啟啟用一個(gè)translog囤屹,此時(shí)commit操作完成熬甚。默認(rèn)每隔30分鐘會(huì)自動(dòng)執(zhí)行一次commit,但是如果translog過(guò)大肋坚,也會(huì)觸發(fā)commit乡括。整個(gè)commit的過(guò)程,叫做flush操作智厌。我們可以手動(dòng)執(zhí)行flush操作诲泌,就是將所有os cache數(shù)據(jù)刷到磁盤(pán)文件中去。不叫做commit操作铣鹏,flush操作敷扫。es中的flush操作,就對(duì)應(yīng)著commit的全過(guò)程诚卸。我們也可以通過(guò)es api葵第,手動(dòng)執(zhí)行flush操作,手動(dòng)將os cache中的數(shù)據(jù)fsync強(qiáng)刷到磁盤(pán)上去合溺,記錄一個(gè)commit point羹幸,清空translog日志文件。
translog其實(shí)也是先寫(xiě)入os cache的辫愉,默認(rèn)每隔5秒刷一次到磁盤(pán)中去,所以默認(rèn)情況下将硝,可能有5秒的數(shù)據(jù)會(huì)僅僅停留在buffer或者translog文件的os cache中恭朗,如果此時(shí)機(jī)器掛了屏镊,會(huì)丟失5秒鐘的數(shù)據(jù)。但是這樣性能比較好痰腮,最多丟5秒的數(shù)據(jù)而芥。也可以將translog設(shè)置成每次寫(xiě)操作必須是直接fsync到磁盤(pán),但是性能會(huì)差很多膀值。
如果是刪除操作棍丐,commit的時(shí)候會(huì)生成一個(gè).del文件,里面將某個(gè)doc標(biāo)識(shí)為deleted狀態(tài)沧踏,那么搜索的時(shí)候根據(jù).del文件就知道這個(gè)doc被刪除了
如果是更新操作歌逢,就是將原來(lái)的doc標(biāo)識(shí)為deleted狀態(tài),然后新寫(xiě)入一條數(shù)據(jù)
buffer每次refresh一次翘狱,就會(huì)產(chǎn)生一個(gè)segment file秘案,所以默認(rèn)情況下是1秒鐘一個(gè)segment file,segment file會(huì)越來(lái)越多潦匈,此時(shí)會(huì)定期執(zhí)行merge
每次merge的時(shí)候阱高,會(huì)將多個(gè)segment file合并成一個(gè),同時(shí)這里會(huì)將標(biāo)識(shí)為deleted的doc給物理刪除掉茬缩,然后將新的segment file寫(xiě)入磁盤(pán)赤惊,這里會(huì)寫(xiě)一個(gè)commit point,標(biāo)識(shí)所有新的segment file凰锡,然后打開(kāi)segment file供搜索使用未舟,同時(shí)刪除舊的segment file。es里的寫(xiě)流程寡夹,有4個(gè)底層的核心概念处面,refresh、flush菩掏、translog魂角、merge。當(dāng)segment file多到一定程度的時(shí)候智绸,es就會(huì)自動(dòng)觸發(fā)merge操作野揪,將多個(gè)segment file給merge成一個(gè)segment file。
ES讀數(shù)據(jù)過(guò)程
查詢(xún)瞧栗,GET某一條數(shù)據(jù)斯稳,寫(xiě)入了某個(gè)document,這個(gè)document會(huì)自動(dòng)給你分配一個(gè)全局唯一的id迹恐,doc id挣惰,同時(shí)也是根據(jù)doc id進(jìn)行hash路由到對(duì)應(yīng)的primary shard上面去。也可以手動(dòng)指定doc id,比如用訂單id憎茂,用戶id珍语。
你可以通過(guò)doc id來(lái)查詢(xún),會(huì)根據(jù)doc id進(jìn)行hash竖幔,判斷出來(lái)當(dāng)時(shí)把doc id分配到了哪個(gè)shard上面去板乙,從那個(gè)shard去查詢(xún)。
客戶端發(fā)送請(qǐng)求到任意一個(gè)node拳氢,成為coordinate node
coordinate node對(duì)document進(jìn)行路由募逞,將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的node,此時(shí)會(huì)使用round-robin隨機(jī)輪詢(xún)算法馋评,在primary shard以及其所有replica中隨機(jī)選擇一個(gè)放接,讓讀請(qǐng)求負(fù)載均衡
接收請(qǐng)求的node返回document給coordinate node
coordinate node返回document給客戶端
ES搜索數(shù)據(jù)過(guò)程
- 客戶端發(fā)送請(qǐng)求到一個(gè)coordinate node
- 協(xié)調(diào)節(jié)點(diǎn)將搜索請(qǐng)求轉(zhuǎn)發(fā)到所有的shard對(duì)應(yīng)的primary shard或replica shard也可以
- query phase:每個(gè)shard將自己的搜索結(jié)果(其實(shí)就是一些doc id),返回給協(xié)調(diào)節(jié)點(diǎn)栗恩,由協(xié)調(diào)節(jié)點(diǎn)進(jìn)行數(shù)據(jù)的合并透乾、排序、分頁(yè)等操作磕秤,產(chǎn)出最終結(jié)果
- fetch phase:接著由協(xié)調(diào)節(jié)點(diǎn)乳乌,根據(jù)doc id去各個(gè)節(jié)點(diǎn)上拉取實(shí)際的document數(shù)據(jù),最終返回給客戶端