Elasticsearch 架構(gòu)以及源碼概覽

Elasticsearch 架構(gòu)以及源碼概覽

Elasticsearch是最近兩年異軍突起的一個(gè)兼有搜索引擎和NoSQL數(shù)據(jù)庫功能的開源系統(tǒng),基于Java/Lucene構(gòu)建。最近研究了一下,感覺 Elasticsearch 的架構(gòu)以及其開源的生態(tài)構(gòu)建都有許多可借鑒之處,所以整理成文章分享下。本文的代碼以及架構(gòu)分析主要基于 Elasticsearch 2.X 最新穩(wěn)定版。

Elasticsearch 看名字就能大概了解下它是一個(gè)彈性的搜索引擎。首先彈性隱含的意思是分布式,單機(jī)系統(tǒng)是沒法彈起來的,然后加上靈活的伸縮機(jī)制,就是這里的 Elastic 包含的意思。它的搜索存儲(chǔ)功能主要是 Lucene 提供的,Lucene 相當(dāng)于其存儲(chǔ)引擎,它在之上封裝了索引,查詢,以及分布式相關(guān)的接口。

Elasticsearch 中的幾個(gè)概念

集群(Cluster)一組擁有共同的 cluster name 的節(jié)點(diǎn)。

節(jié)點(diǎn)(Node) 集群中的一個(gè) Elasticearch 實(shí)例。

索引(Index) 相當(dāng)于關(guān)系數(shù)據(jù)庫中的database概念,一個(gè)集群中可以包含多個(gè)索引。這個(gè)是個(gè)邏輯概念。

主分片(Primary shard) 索引的子集,索引可以切分成多個(gè)分片,分布到不同的集群節(jié)點(diǎn)上。分片對應(yīng)的是 Lucene 中的索引。

副本分片(Replica shard)每個(gè)主分片可以有一個(gè)或者多個(gè)副本。

類型(Type)相當(dāng)于數(shù)據(jù)庫中的table概念,mapping是針對 Type 的。同一個(gè)索引里可以包含多個(gè) Type。

Mapping 相當(dāng)于數(shù)據(jù)庫中的schema,用來約束字段的類型,不過 Elasticsearch 的 mapping 可以自動(dòng)根據(jù)數(shù)據(jù)創(chuàng)建。

文檔(Document) 相當(dāng)于數(shù)據(jù)庫中的row。

字段(Field)相當(dāng)于數(shù)據(jù)庫中的column。

分配(Allocation) 將分片分配給某個(gè)節(jié)點(diǎn)的過程,包括分配主分片或者副本。如果是副本,還包含從主分片復(fù)制數(shù)據(jù)的過程。

分布式以及 Elastic

分布式系統(tǒng)要解決的第一個(gè)問題就是節(jié)點(diǎn)之間互相發(fā)現(xiàn)以及選主的機(jī)制。如果使用了 Zookeeper/Etcd 這樣的成熟的服務(wù)發(fā)現(xiàn)工具,這兩個(gè)問題都一并解決了。但 Elasticsearch 并沒有依賴這樣的工具,帶來的好處是部署服務(wù)的成本和復(fù)雜度降低了,不用預(yù)先依賴一個(gè)服務(wù)發(fā)現(xiàn)的集群,缺點(diǎn)當(dāng)然是將復(fù)雜度帶入了 Elasticsearch 內(nèi)部。

服務(wù)發(fā)現(xiàn)以及選主 ZenDiscovery

節(jié)點(diǎn)啟動(dòng)后先ping(這里的ping是 Elasticsearch 的一個(gè)RPC命令。如果 discovery.zen.ping.unicast.hosts 有設(shè)置,則ping設(shè)置中的host,否則嘗試ping localhost 的幾個(gè)端口, Elasticsearch 支持同一個(gè)主機(jī)啟動(dòng)多個(gè)節(jié)點(diǎn))

Ping的response會(huì)包含該節(jié)點(diǎn)的基本信息以及該節(jié)點(diǎn)認(rèn)為的master節(jié)點(diǎn)。

選舉開始,先從各節(jié)點(diǎn)認(rèn)為的master中選,規(guī)則很簡單,按照id的字典序排序,取第一個(gè)。

如果各節(jié)點(diǎn)都沒有認(rèn)為的master,則從所有節(jié)點(diǎn)中選擇,規(guī)則同上。這里有個(gè)限制條件就是 discovery.zen.minimum_master_nodes,如果節(jié)點(diǎn)數(shù)達(dá)不到最小值的限制,則循環(huán)上述過程,直到節(jié)點(diǎn)數(shù)足夠可以開始選舉。

最后選舉結(jié)果是肯定能選舉出一個(gè)master,如果只有一個(gè)local節(jié)點(diǎn)那就選出的是自己。

如果當(dāng)前節(jié)點(diǎn)是master,則開始等待節(jié)點(diǎn)數(shù)達(dá)到 minimum_master_nodes,然后提供服務(wù)。

如果當(dāng)前節(jié)點(diǎn)不是master,則嘗試加入master。

Elasticsearch 將以上服務(wù)發(fā)現(xiàn)以及選主的流程叫做 ZenDiscovery 。由于它支持任意數(shù)目的集群(1-N),所以不能像 Zookeeper/Etcd 那樣限制節(jié)點(diǎn)必須是奇數(shù),也就無法用投票的機(jī)制來選主,而是通過一個(gè)規(guī)則,只要所有的節(jié)點(diǎn)都遵循同樣的規(guī)則,得到的信息都是對等的,選出來的主節(jié)點(diǎn)肯定是一致的。但分布式系統(tǒng)的問題就出在信息不對等的情況,這時(shí)候很容易出現(xiàn)腦裂(Split-Brain)的問題,大多數(shù)解決方案就是設(shè)置一個(gè)quorum值,要求可用節(jié)點(diǎn)必須大于quorum(一般是超過半數(shù)節(jié)點(diǎn)),才能對外提供服務(wù)。而 Elasticsearch 中,這個(gè)quorum的配置就是 discovery.zen.minimum_master_nodes 。 說到這里要吐槽下 Elasticsearch 的方法和變量命名,它的方法和配置中的master指的是master的候選節(jié)點(diǎn),也就是說可能成為master的節(jié)點(diǎn),并不是表示當(dāng)前的master,我就被它的一個(gè) isMasterNode 方法坑了,開始一直沒能理解它的選舉規(guī)則。

彈性伸縮 Elastic

Elasticsearch 的彈性體現(xiàn)在兩個(gè)方面: 1. 服務(wù)發(fā)現(xiàn)機(jī)制讓節(jié)點(diǎn)很容易加入和退出。 2. 豐富的設(shè)置以及allocation API。

Elasticsearch 節(jié)點(diǎn)啟動(dòng)的時(shí)候只需要配置discovery.zen.ping.unicast.hosts,這里不需要列舉集群中所有的節(jié)點(diǎn),只要知道其中一個(gè)即可。當(dāng)然為了避免重啟集群時(shí)正好配置的節(jié)點(diǎn)掛掉,最好多配置幾個(gè)節(jié)點(diǎn)。節(jié)點(diǎn)退出時(shí)只需要調(diào)用 API 將該節(jié)點(diǎn)從集群中排除 (Shard Allocation Filtering),系統(tǒng)會(huì)自動(dòng)遷移該節(jié)點(diǎn)上的數(shù)據(jù),然后關(guān)閉該節(jié)點(diǎn)即可。當(dāng)然最好也將不可用的已知節(jié)點(diǎn)從其他節(jié)點(diǎn)的配置中去除,避免下次啟動(dòng)時(shí)出錯(cuò)。

分片(Shard)以及副本(Replica)分布式存儲(chǔ)系統(tǒng)為了解決單機(jī)容量以及容災(zāi)的問題,都需要有分片以及副本機(jī)制。Elasticsearch 沒有采用節(jié)點(diǎn)級別的主從復(fù)制,而是基于分片。它當(dāng)前還未提供分片切分(shard-splitting)的機(jī)制,只能創(chuàng)建索引的時(shí)候靜態(tài)設(shè)置。

(elasticsearch 官方博客的圖片)


比如上圖所示,開始設(shè)置為5個(gè)分片,在單個(gè)節(jié)點(diǎn)上,后來擴(kuò)容到5個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)有一個(gè)分片。如果繼續(xù)擴(kuò)容,是不能自動(dòng)切分進(jìn)行數(shù)據(jù)遷移的。官方文檔的說法是分片切分成本和重新索引的成本差不多,所以建議干脆通過接口重新索引。

Elasticsearch 的分片默認(rèn)是基于id 哈希的,id可以用戶指定,也可以自動(dòng)生成。但這個(gè)可以通過參數(shù)(routing)或者在mapping配置中修改。當(dāng)前版本默認(rèn)的哈希算法是MurmurHash3

Elasticsearch 禁止同一個(gè)分片的主分片和副本分片在同一個(gè)節(jié)點(diǎn)上,所以如果是一個(gè)節(jié)點(diǎn)的集群是不能有副本的。

恢復(fù)以及容災(zāi)

分布式系統(tǒng)的一個(gè)要求就是要保證高可用。前面描述的退出流程是節(jié)點(diǎn)主動(dòng)退出的場景,但如果是故障導(dǎo)致節(jié)點(diǎn)掛掉,Elasticsearch 就會(huì)主動(dòng)allocation。但如果節(jié)點(diǎn)丟失后立刻allocation,稍后節(jié)點(diǎn)恢復(fù)又立刻加入,會(huì)造成浪費(fèi)。Elasticsearch的恢復(fù)流程大致如下:

集群中的某個(gè)節(jié)點(diǎn)丟失網(wǎng)絡(luò)連接

master提升該節(jié)點(diǎn)上的所有主分片的在其他節(jié)點(diǎn)上的副本為主分片

cluster集群狀態(tài)變?yōu)?yellow ,因?yàn)楦北緮?shù)不夠

等待一個(gè)超時(shí)設(shè)置的時(shí)間,如果丟失節(jié)點(diǎn)回來就可以立即恢復(fù)(默認(rèn)為1分鐘,通過 index.unassigned.node_left.delayed_timeout 設(shè)置)。如果該分片已經(jīng)有寫入,則通過translog進(jìn)行增量同步數(shù)據(jù)。

否則將副本分配給其他節(jié)點(diǎn),開始同步數(shù)據(jù)。

但如果該節(jié)點(diǎn)上的分片沒有副本,則無法恢復(fù),集群狀態(tài)會(huì)變?yōu)閞ed,表示可能要丟失該分片的數(shù)據(jù)了。

分布式集群的另外一個(gè)問題就是集群整個(gè)重啟后可能導(dǎo)致不預(yù)期的分片重新分配(部分節(jié)點(diǎn)沒有啟動(dòng)完成的時(shí)候,集群以為節(jié)點(diǎn)丟失),浪費(fèi)帶寬。所以 Elasticsearch 通過以下靜態(tài)配置(不能通過API修改)控制整個(gè)流程,以10個(gè)節(jié)點(diǎn)的集群為例:

gateway.recover_after_nodes: 8

gateway.expected_nodes: 10

gateway.recover_after_time: 5m

比如10個(gè)節(jié)點(diǎn)的集群,按照上面的規(guī)則配置,當(dāng)集群重啟后,首先系統(tǒng)等待 minimum_master_nodes(6)個(gè)節(jié)點(diǎn)加入才會(huì)選出master, recovery操作是在 master節(jié)點(diǎn)上進(jìn)行的,由于我們設(shè)置了 recover_after_nodes(8),系統(tǒng)會(huì)繼續(xù)等待到8個(gè)節(jié)點(diǎn)加入, 才開始進(jìn)行recovery。當(dāng)開始recovery的時(shí)候,如果發(fā)現(xiàn)集群中的節(jié)點(diǎn)數(shù)小于expected_nodes,也就是還有部分節(jié)點(diǎn)未加入,于是開始recover_after_time 倒計(jì)時(shí)(如果節(jié)點(diǎn)數(shù)達(dá)到expected_nodes則立刻進(jìn)行 recovery),5分鐘后,如果剩余的節(jié)點(diǎn)依然沒有加入,則會(huì)進(jìn)行數(shù)據(jù)recovery。

搜索引擎 Search

Elasticsearch 除了支持 Lucene 本身的檢索功能外,在之上做了一些擴(kuò)展。 1. 腳本支持

Elasticsearch 默認(rèn)支持groovy腳本,擴(kuò)展了 Lucene 的評分機(jī)制,可以很容易的支持復(fù)雜的自定義評分算法。它默認(rèn)只支持通過sandbox方式實(shí)現(xiàn)的腳本語言(如lucene expression,mustache),groovy必須明確設(shè)置后才能開啟。Groovy的安全機(jī)制是通過java.security.AccessControlContext設(shè)置了一個(gè)class白名單來控制權(quán)限的,1.x版本的時(shí)候是自己做的一個(gè)白名單過濾器,但限制策略有漏洞,導(dǎo)致一個(gè)遠(yuǎn)程代碼執(zhí)行漏洞。 2. 默認(rèn)會(huì)生成一個(gè) _all 字段,將所有其他字段的值拼接在一起。這樣搜索時(shí)可以不指定字段,并且方便實(shí)現(xiàn)跨字段的檢索。 3. Suggester Elasticsearch 通過擴(kuò)展的索引機(jī)制,可以實(shí)現(xiàn)像google那樣的自動(dòng)完成suggestion以及搜索詞語錯(cuò)誤糾正的suggestion。

NoSQL 數(shù)據(jù)庫

Elasticsearch 可以作為數(shù)據(jù)庫使用,主要依賴于它的以下特性:

默認(rèn)在索引中保存原始數(shù)據(jù),并可獲取。這個(gè)主要依賴 Lucene 的store功能。

實(shí)現(xiàn)了translog,提供了實(shí)時(shí)的數(shù)據(jù)讀取能力以及完備的數(shù)據(jù)持久化能力(在服務(wù)器異常掛掉的情況下依然不會(huì)丟數(shù)據(jù))。Lucene 因?yàn)橛?IndexWriter buffer, 如果進(jìn)程異常掛掉,buffer中的數(shù)據(jù)是會(huì)丟失的。所以 Elasticsearch 通過translog來確保不丟數(shù)據(jù)。同時(shí)通過id直接讀取文檔的時(shí)候,Elasticsearch 會(huì)先嘗試從translog中讀取,之后才從索引中讀取。也就是說,即便是buffer中的數(shù)據(jù)尚未刷新到索引,依然能提供實(shí)時(shí)的數(shù)據(jù)讀取能力。Elasticsearch 的translog 默認(rèn)是每次寫請求完成后統(tǒng)一fsync一次,同時(shí)有個(gè)定時(shí)任務(wù)檢測(默認(rèn)5秒鐘一次)。如果業(yè)務(wù)場景需要更大的寫吞吐量,可以調(diào)整translog相關(guān)的配置進(jìn)行優(yōu)化。

dynamic-mapping以及 schema-free

Elasticsearch 的dynamic-mapping相當(dāng)于根據(jù)用戶提交的數(shù)據(jù),動(dòng)態(tài)檢測字段類型,自動(dòng)給數(shù)據(jù)庫表建立表結(jié)構(gòu),也可以動(dòng)態(tài)增加字段,所以它叫做schema-free,而不是schema-less。這種方式的好處是用戶能一定程度享受schema-less的好處,不用提前建立表結(jié)構(gòu),同時(shí)因?yàn)閷?shí)際上是有schema的,可以做查詢上的優(yōu)化,檢索效率要比純schema-less的數(shù)據(jù)庫高許多。但缺點(diǎn)就是已經(jīng)創(chuàng)建的索引不能變更數(shù)據(jù)類型(Elasticsearch 寫入數(shù)據(jù)的時(shí)候如果類型不匹配會(huì)自動(dòng)嘗試做類型轉(zhuǎn)換,如果失敗就會(huì)報(bào)錯(cuò),比如數(shù)字類型的字段寫入字符串”123”是可以的,但寫入”abc”就不可以。),要損失一定的自由度。

另外 Elasticsearch 提供的index-template功能方便用戶動(dòng)態(tài)創(chuàng)建索引的時(shí)候預(yù)先設(shè)定索引的相關(guān)參數(shù)以及type mapping,比如按天創(chuàng)建日志庫,template可以設(shè)置為對 log-* 的索引都生效。

這兩個(gè)功能我建議新的數(shù)據(jù)庫都可以借鑒下。

豐富的QueryDSL功能

Elasticsearch 的query語法基本上和sql對等的,除了join查詢,以及嵌套臨時(shí)表查詢不能支持。不過 Elasticsearch 支持嵌套對象以及parent外部引用查詢,所以一定程度上可以解決關(guān)聯(lián)查詢的需求。另外group by這種查詢可以通過其aggregation實(shí)現(xiàn)。Elasticsearch 提供的aggregation能力非常強(qiáng)大,其生態(tài)圈里的 Kibana 主要就是依賴aggregation來實(shí)現(xiàn)數(shù)據(jù)分析以及可視化的。

系統(tǒng)架構(gòu)

Elasticsearch 的依賴注入用的是guice,網(wǎng)絡(luò)使用netty,提供http rest和RPC兩種協(xié)議。

Elasticsearch 之所以用guice,而不是用spring做依賴注入,關(guān)鍵的一個(gè)原因是guice可以幫它很容易的實(shí)現(xiàn)模塊化,通過代碼進(jìn)行模塊組裝,可以很精確的控制依賴注入的管理范圍。比如 Elasticsearch 給每個(gè)shard單獨(dú)生成一個(gè)injector,可以將該shard相關(guān)的配置以及組件注入進(jìn)去,降低編碼和狀態(tài)管理的復(fù)雜度,同時(shí)刪除shard的時(shí)候也方便回收相關(guān)對象。這方面有興趣使用guice的可以借鑒。

ClusterState

前面我們分析了 Elasticsearch 的服務(wù)發(fā)現(xiàn)以及選舉機(jī)制,它是內(nèi)部自己實(shí)現(xiàn)的。服務(wù)發(fā)現(xiàn)工具做的事情其實(shí)就是跨服務(wù)器的狀態(tài)同步,多個(gè)節(jié)點(diǎn)修改同一個(gè)數(shù)據(jù)對象,需要有一種機(jī)制將這個(gè)數(shù)據(jù)對象同步到所有的節(jié)點(diǎn)。Elasticsearch 的ClusterState 就是這樣一個(gè)數(shù)據(jù)對象,保存了集群的狀態(tài),索引/分片的路由表,節(jié)點(diǎn)列表,元數(shù)據(jù)等,還包含一個(gè)ClusterBlocks,相當(dāng)于分布式鎖,用于實(shí)現(xiàn)分布式的任務(wù)同步。

主節(jié)點(diǎn)上有個(gè)單獨(dú)的進(jìn)程處理 ClusterState 的變更操作,每次變更會(huì)更新版本號。變更后會(huì)通過PRC接口同步到其他節(jié)點(diǎn)。主節(jié)知道其他節(jié)點(diǎn)的ClusterState 的當(dāng)前版本,發(fā)送變更的時(shí)候會(huì)做diff,實(shí)現(xiàn)增量更新。

Rest 和 RPC


Elasticsearch 的rest請求的傳遞流程如上圖(這里對實(shí)際流程做了簡化): 1. 用戶發(fā)起http請求,Elasticsearch 的9200端口接受請求后,傳遞給對應(yīng)的RestAction。 2. RestAction做的事情很簡單,將rest請求轉(zhuǎn)換為RPC的TransportRequest,然后調(diào)用NodeClient,相當(dāng)于用客戶端的方式請求RPC服務(wù),只不過transport層會(huì)對本節(jié)點(diǎn)的請求特殊處理。

這樣做的好處是將http和RPC兩層隔離,增加部署的靈活性。部署的時(shí)候既可以同時(shí)開啟RPC和http服務(wù),也可以用client模式部署一組服務(wù)專門提供http rest服務(wù),另外一組只開啟RPC服務(wù),專門做data節(jié)點(diǎn),便于分擔(dān)壓力。

Elasticsearch 的RPC的序列化機(jī)制使用了 Lucene 的壓縮數(shù)據(jù)類型,支持vint這樣的變長數(shù)字類型,省略了字段名,用流式方式按順序?qū)懭胱侄蔚闹?。每個(gè)需要傳輸?shù)膶ο蠖夹枰獙?shí)現(xiàn):

void writeTo(StreamOutput out)

T readFrom(StreamInput in)

兩個(gè)方法。雖然這樣實(shí)現(xiàn)開發(fā)成本略高,增刪字段也不太靈活,但對 Elasticsearch 這樣的數(shù)據(jù)庫系統(tǒng)來說,不用考慮跨語言,增刪字段肯定要考慮兼容性,這樣做效率最高。所以 Elasticsearch 的RPC接口只有java client可以直接請求,其他語言的客戶端都走的是rest接口。

網(wǎng)絡(luò)層

Elasticsearch 的網(wǎng)絡(luò)層抽象很值得借鑒。它抽象出一個(gè) Transport 層,同時(shí)兼有client和server功能,server端接收其他節(jié)點(diǎn)的連接,client維持和其他節(jié)點(diǎn)的連接,承擔(dān)了節(jié)點(diǎn)之間請求轉(zhuǎn)發(fā)的功能。Elasticsearch 為了避免傳輸流量比較大的操作堵塞連接,所以會(huì)按照優(yōu)先級創(chuàng)建多個(gè)連接,稱為channel。

recovery: 2個(gè)channel專門用做恢復(fù)數(shù)據(jù)。如果為了避免恢復(fù)數(shù)據(jù)時(shí)將帶寬占滿,還可以設(shè)置恢復(fù)數(shù)據(jù)時(shí)的網(wǎng)絡(luò)傳輸速度。

bulk: 3個(gè)channel用來傳輸批量請求等基本比較低的請求。

regular: 6個(gè)channel用來傳輸通用正常的請求,中等級別。

state: 1個(gè)channel保留給集群狀態(tài)相關(guān)的操作,比如集群狀態(tài)變更的傳輸,高級別。

ping: 1個(gè)channel專門用來ping,進(jìn)行故障檢測。

(3個(gè)節(jié)點(diǎn)的集群連接示意,來源 Elasticsearch 官方博客)

每個(gè)節(jié)點(diǎn)默認(rèn)都會(huì)創(chuàng)建13個(gè)到其他節(jié)點(diǎn)的連接,并且節(jié)點(diǎn)之間是互相連接的,每增加一個(gè)節(jié)點(diǎn),該節(jié)點(diǎn)會(huì)到每個(gè)節(jié)點(diǎn)創(chuàng)建13個(gè)連接,而其他每個(gè)節(jié)點(diǎn)也會(huì)創(chuàng)建13個(gè)連回來的連接。

線程池

由于java不支持綠色線程(fiber/coroutine),我前面的《并發(fā)之痛》那篇文章也分析了線程池的問題,線程池里保留多少線程合適?如何避免慢的任務(wù)占用線程池,導(dǎo)致其他比較快的任務(wù)也得不到執(zhí)行?很多應(yīng)用系統(tǒng)里,為了避免這種情況,會(huì)隨手創(chuàng)建線程池,最后導(dǎo)致系統(tǒng)里充塞了大的量的線程池,浪費(fèi)資源。而 Elasticsearch 的解決方案是分優(yōu)先級的線程池。它默認(rèn)創(chuàng)建了10多個(gè)線程池,按照不同的優(yōu)先級以及不同的操作進(jìn)行劃分。然后提供了4種類型的線程池,不同的線程池使用不同的類型:

CACHED 最小為0,無上限,無隊(duì)列(SynchronousQueue,沒有緩沖buffer),有存活時(shí)間檢測的線程池。通用的,希望能盡可能支撐的任務(wù)。

DIRECT 直接在調(diào)用者的線程里執(zhí)行,其實(shí)這不算一種線程池方案,主要是為了代碼邏輯上的統(tǒng)一而創(chuàng)造的一種線程類型。

FIXED 固定大小的線程池,帶有緩沖隊(duì)列。用于計(jì)算和IO的耗時(shí)波動(dòng)較小的操作。

SCALING 有最小值,最大值的伸縮線程池,隊(duì)列是基于LinkedTransferQueue 改造的實(shí)現(xiàn),和java內(nèi)置的Executors生成的伸縮線程池的區(qū)別是優(yōu)先增加線程,增加到最大值后才會(huì)使用隊(duì)列,和java內(nèi)置的線程池規(guī)則相反。用于計(jì)算和IO耗時(shí)都不太穩(wěn)定,需要限制系統(tǒng)承載最大任務(wù)上限的操作。

這種解決方案雖然要求每個(gè)用到線程池的地方都需要評估下執(zhí)行成本以及應(yīng)該用什么樣的線程池,但好處是限制了線程池的泛濫,也緩解了不同類型的任務(wù)互相之間的影響。

腦洞時(shí)間

以后每篇分析架構(gòu)的文章,我都最后會(huì)提幾個(gè)和該系統(tǒng)相關(guān)的改進(jìn)或者擴(kuò)展的想法,稱為腦洞時(shí)間,作為一種鍛煉。不過只提供想法,不深入分析可行性以及實(shí)現(xiàn)。

支持shard-spliting

這個(gè)被人吐糟了好長時(shí)間,官方就是不愿意提供。我簡單構(gòu)想了下,感覺實(shí)現(xiàn)這個(gè)應(yīng)該也不復(fù)雜。一種實(shí)現(xiàn)方式是按照傳統(tǒng)的數(shù)據(jù)庫sharding機(jī)制,1分2,2分4,4分8等,主要擴(kuò)展點(diǎn)在數(shù)據(jù)遷移以及routing的機(jī)制上。但這種方式?jīng)]辦法實(shí)現(xiàn)1分3,3分5,這樣的sharding。另外一個(gè)辦法就是基于當(dāng)前官方推薦的重建索引的機(jī)制,只是對外封裝成resharding的接口,先給舊索引創(chuàng)建別名,客戶端通過別名訪問索引,然后設(shè)定新索引的sharding數(shù)目,后臺(tái)創(chuàng)建新的索引,倒數(shù)據(jù),等數(shù)據(jù)追上的時(shí)候,切換別名,進(jìn)行完整性檢查,這樣整個(gè)resharding的機(jī)制可以自動(dòng)化了。

支持mapreduce

認(rèn)為Elasticsearch 可以借鑒 Mongo 的輕量mapreduce機(jī)制,這樣可以支持更豐富的聚合查詢。

支持語音以及圖片檢索

當(dāng)前做語音和圖片識(shí)別的庫或者服務(wù)的開發(fā)者可以提供一個(gè) Elasticsearch 插件,把語音以及圖片轉(zhuǎn)換成文本進(jìn)行索引查詢,應(yīng)用場景應(yīng)該也不少。

用ForkJoinPool來替代 Elasticsearch 當(dāng)前的線程池方案

ForkJoinPool加上java8的CompletableFuture,一定程度上可以模擬coroutine效果,再加上最新版本的netty內(nèi)部已經(jīng)默認(rèn)用了ForkJoinPool,Elasticsearch 這種任務(wù)有需要拆子任務(wù)的場景,很適合使用ForkJoinPool。

Elasticsearch 的開源產(chǎn)品啟示

還記得10年前在大學(xué)時(shí)候搗鼓 Lucene,弄校園內(nèi)搜索,還弄了個(gè)基于詞典的分詞工具。畢業(yè)后第一份工作也是用 Lucene 做站內(nèi)搜索。當(dāng)時(shí)搭建的服務(wù)和 Elasticsearch 類似,提供更新和管理索引的api給業(yè)務(wù)程序,當(dāng)然沒有 Elasticsearch 這么強(qiáng)大。當(dāng)時(shí)是有想過做類似的一個(gè)開源產(chǎn)品的,后來發(fā)現(xiàn)apache已經(jīng)出了 Solr(2004年的時(shí)候就創(chuàng)建了,2008年1.3發(fā)布,已經(jīng)相對成熟),感覺應(yīng)該沒啥機(jī)會(huì)了。但 Elasticsearch 硬是在這種情況下成長起來了(10年創(chuàng)建,14年才發(fā)布1.0)。 二者的功能以及性能幾乎都不相上下(開始性能上有些差距,但 Solr 有改進(jìn),差不多追上了),參看文末比較鏈接。

我覺得一方面是 Elasticsearch 的簡單友好的分布式機(jī)制占了先機(jī),也正好趕上了移動(dòng)互聯(lián)網(wǎng)爆發(fā)移動(dòng)應(yīng)用站內(nèi)搜索需求高漲的時(shí)代。第一波站內(nèi)搜索是web時(shí)代,也是 Lucene 誕生的時(shí)代,但web的站內(nèi)搜索可以簡單的利用搜索引擎服務(wù)的自定義站點(diǎn)實(shí)現(xiàn),而應(yīng)用的站內(nèi)搜索就只能靠自己搭了。另外一方面是 Elasticsearch 的周邊生態(tài)以及目標(biāo)市場看把握的非常精準(zhǔn)。Elasticsearch 現(xiàn)在的主要目標(biāo)市場已經(jīng)從站內(nèi)搜索轉(zhuǎn)移到了監(jiān)控與日志數(shù)據(jù)的收集存儲(chǔ)和分析,也就是大家常談?wù)摰腅LK。

Elasticsearch 現(xiàn)在主要的應(yīng)用場景有三塊。站內(nèi)搜索,主要和 Solr 競爭,屬于后起之秀。NoSQL json文檔數(shù)據(jù)庫,主要搶占 Mongo 的市場,它在讀寫性能上優(yōu)于 Mongo(見文末比較鏈接),同時(shí)也支持地理位置查詢,還方便地理位置和文本混合查詢,屬于歪打正著。監(jiān)控,統(tǒng)計(jì)以及日志類時(shí)間序的數(shù)據(jù)的存儲(chǔ)和分析以及可視化,這方面是引領(lǐng)者。

據(jù)說 Elasticsearch 的創(chuàng)始人當(dāng)初創(chuàng)建 Elasticsearch 的時(shí)候是為了給喜歡做菜的媳婦搭建個(gè)菜譜的搜索網(wǎng)站,雖然菜譜搜索網(wǎng)站最后一直沒做出來,但誕生了 Elasticsearch。所以程序員堅(jiān)持一個(gè)業(yè)余項(xiàng)目也是很重要的,萬一無心插柳就成蔭了呢?

相關(guān)閱讀

solr vs elasticsearch 功能比較

elasticsearch vs solr 性能比較

Shard Allocation Filtering

MurmurHash3

Elasitcsearch 重新索引接口

MongoDB vs. Elasticsearch: The Quest of the Holy Performances

Elasticsearch 早期版本的遠(yuǎn)程代碼執(zhí)行漏洞

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容