ES分布式文檔數據庫講解


簡介
ES是一個基於RESTful web接口並且構建在Apache Lucene之上的開源分布式搜索引擎。

同時ES還是一個分布式文檔數據庫,其中每個字段均可被索引,而且每個字段的數據均可被搜索,能夠橫向擴展至數以百計的服務器存儲以及處理PB級的數據。

可以在極短的時間內存儲、搜索和分析大量的數據。通常作為具有復雜搜索場景情況下的核心發動機。

ES就是為高可用和可擴展而生的。一方面可以通過升級硬件來完成系統擴展,稱為垂直或向上擴展(Vertical Scale/Scaling Up)。

另一方面,增加更多的服務器來完成系統擴展,稱為水平擴展或者向外擴展(Horizontal Scale/Scaling Out)。盡管ES能夠利用更強勁的硬件,但是垂直擴展畢竟還是有它的極限。真正的可擴展性來自於水平擴展,通過向集群中添加更多的節點來分擔負載,增加可靠性。ES天生就是分布式的,它知道如何管理多個節點來完成擴展和實現高可用性。意味應用不需要做任何的改動。

 

Gateway,代表ES索引的持久化存儲方式。在Gateway中,ES默認先把索引存儲在內存中,然后當內存滿的時候,再持久化到Gateway里。當ES集群關閉或重啟的時候,它就會從Gateway里去讀取索引數據。比如LocalFileSystem和HDFS、AS3等。

DistributedLucene Directory,它是Lucene里的一些列索引文件組成的目錄。它負責管理這些索引文件。包括數據的讀取、寫入,以及索引的添加和合並等。

River,代表是數據源。是以插件的形式存在於ES中。 

Mapping,映射的意思,非常類似於靜態語言中的數據類型。比如我們聲明一個int類型的變量,那以后這個變量只能存儲int類型的數據。比如我們聲明一個double類型的mapping字段,則只能存儲double類型的數據。

Mapping不僅是告訴ES,哪個字段是哪種類型。還能告訴ES如何來索引數據,以及數據是否被索引到等。

Search Moudle,搜索模塊,支持搜索的一些常用操作

Index Moudle,索引模塊,支持索引的一些常用操作

Disvcovery,主要是負責集群的master節點發現。比如某個節點突然離開或進來的情況,進行一個分片重新分片等。這里有個發現機制。

發現機制默認的實現方式是單播和多播的形式,即Zen,同時也支持點對點的實現。另外一種是以插件的形式,即EC2。

Scripting,即腳本語言。包括很多,這里不多贅述。如mvel、js、python等。   

Transport,代表ES內部節點,代表跟集群的客戶端交互。包括 Thrift、Memcached、Http等協議

RESTful Style API,通過RESTful方式來實現API編程。

3rd plugins,代表第三方插件。

Java(Netty),是開發框架。

JMX,是監控。

使用案例
1、將ES作為網站的主要后端系統

比如現在搭建一個博客系統,對於博客帖子的數據可以直接在ES上存儲,並且使用ES來進行檢索,統計。ES提供了持久化的存儲、統計和很多其他數據存儲的特性。

注意:但是像其他的NOSQL數據存儲一樣,ES是不支持事務的,如果要事務機制,還是考慮使用其他的數據庫做真實庫。

 

2、將ES添加到現有系統

有些時候不需要ES提供所有數據的存儲功能,只是想在一個數據存儲的基礎之上使用ES。比如已經有一個復雜的系統在運行,但是現在想加一個搜索的功能,就可以使用該方案。

 

3、將ES作為現有解決方案的后端部分

因為ES是開源的系統,提供了直接的HTTP接口,並且現在有一個大型的生態系統在支持他。比如現在我們想部署大規模的日志框架、用於存儲、搜索和分析海量的事件,考慮到現有的工具可以寫入和讀取ES,可以不需要進行任何開發,配置這些工具就可以去運作。

 

設計結構
1、邏輯設計

文檔

文檔是可以被索引的信息的基本單位,它包含幾個重要的屬性:

是自我包含的。一篇文檔同時包含字段和他們的取值。
是層次型的。文檔中還可以包含新的文檔,一個字段的取值可以是簡單的,例如location字段的取值可以是字符串,還可以包含其他字段和取值,比如可以同時包含城市和街道地址。
擁有靈活的結構。文檔不依賴於預先定義的模式。也就是說並非所有的文檔都需要擁有相同的字段,並不受限於同一個模式
{

  "name":"meeting",

  "location":"office",

  "organizer":"yanping"

}

{

  "name":"meeting",

  "location":{

    "name":"sheshouzuo",

       "date":"2019-6-28"

  },

  "memebers":["leio","shiyi"]

}

類型

類型是文檔的邏輯容器,類似於表格是行的容器。在不同的類型中,最好放入不同的結構的文檔。

字段

ES中,每個文檔,其實是以json形式存儲的。而一個文檔可以被視為多個字段的集合。

映射

每個類型中字段的定義稱為映射。例如,name字段映射為String。

索引

索引是映射類型的容器一個ES的索引非常像關系型世界中的數據庫,是獨立的大量文檔集合。

 

關系型數據庫與ES的結構上的對比

 

 

2、物理設計

節點

一個節點是一個ES的實例,在服務器上啟動ES之后,就擁有了一個節點,如果在另一個服務器上啟動ES,這就是另一個節點。甚至可以在一台服務器上啟動多個ES進程,在一台服務器上擁有多個節點。多個節點可以加入同一個集群。

當ElasticSearch的節點啟動后,它會利用多播(multicast)(或者單播,如果用戶更改了配置)尋找集群中的其它節點,並與之建立連接。這個過程如下圖所示:

 

節點主要有3種類型,第一種類型是client_node,主要是起到請求分發的作用,類似路由。第二種類型是master_node,是主的節點,所有的新增,刪除,數據分片都是由主節點操作(elasticsearch底層是沒有更新數據操作的,上層對外提供的更新實際上是刪除了再新增),當然也能承擔搜索操作。第三種類型是date_node,該類型的節點只能做搜索操作,具體會分配到哪個date_node,就是由client_node決定,而data_node的數據都是從master_node同步過來的

分片

一個索引可以存儲超出單個結點硬件限制的大量數據。比如,一個具有10億文檔的索引占據1TB的磁盤空間,而任一節點都沒有這樣大的磁盤空間;或者單個節點處理搜索請求,響應太慢。

 

為了解決這個問題,ES提供了將索引划分成多份的能力,這些份就叫做分片。當你創建一個索引的時候,你可以指定你想要的分片的數量。每個分片本身也是一個功能完善並且獨立的“索引”,這個“索引”可以被放置到集群中的任何節點上。

分片之所以重要,主要有兩方面的原因:

 

1、允許你水平分割/擴展你的內容容量

允許你在分片(潛在地,位於多個節點上)之上進行分布式的、並行的操作,進而提高性能/吞吐量

至於一個分片怎樣分布,它的文檔怎樣聚合回搜索請求,是完全由ES管理的,對於作為用戶的你來說,這些都是透明的。

 

2、在一個網絡/雲的環境里,失敗隨時都可能發生,在某個分片/節點不知怎么的就處於離線狀態,或者由於任何原因消失了。這種情況下,有一個故障轉移機制是非常有用並且是強烈推薦的。為此目的,ES允許你創建分片的一份或多份拷貝,這些拷貝叫做復制分片,或者直接叫復制。

復制之所以重要,主要有兩方面的原因:

(1)在分片/節點失敗的情況下,提供了高可用性。因為這個原因,注意到復制分片從不與原/主要(original/primary)分片置於同一節點上是非常重要的。

(2)擴展你的搜索量/吞吐量,因為搜索可以在所有的復制上並行運行

總之,每個索引可以被分成多個分片。一個索引也可以被復制0次(意思是沒有復制)或多次。一旦復制了,每個索引就有了主分片(作為復制源的原來的分片)和復制分片(主分片的拷貝)之別。分片和復制的數量可以在索引創建的時候指定。在索引創建之后,你可以在任何時候動態地改變復制數量,但是不能改變分片的數量。

 

默認情況下,ES中的每個索引被分片5個主分片和1個復制,這意味着,如果你的集群中至少有兩個節點,你的索引將會有5個主分片和另外5個復制分片(1個完全拷貝),這樣的話每個索引總共就有10個分片。一個索引的多個分片可以存放在集群中的一台主機上,也可以存放在多台主機上,這取決於你的集群機器數量。主分片和復制分片的具體位置是由ES內在的策略所決定的。

3、插件HEAD

elasticsearch-head是一個界面化的集群操作和管理工具

 

● node:即一個 Elasticsearch 的運行實例,使用多播或單播方式發現 cluster 並加入。

● cluster:包含一個或多個擁有相同集群名稱的 node,其中包含一個master node。

● index:類比關系型數據庫里的DB,是一個邏輯命名空間。

● alias:可以給 index 添加零個或多個alias,通過 alias 使用index 和根據index name 訪問index一樣,但是,alias給我們提供了一種切換index的能力,比如重建了index,取名● customer_online_v2,這時,有了alias,我要訪問新 index,只需要把 alias 添加到新 index 即可,並把alias從舊的 index 刪除。不用修改代碼。

● type:類比關系數據庫里的Table。其中,一個index可以定義多個type,但一般使用習慣僅配一個type。

● mapping:類比關系型數據庫中的 schema 概念,mapping 定義了 index 中的 type。mapping 可以顯示的定義,也可以在 document 被索引時自動生成,如果有新的 field,Elasticsearch 會自動推測出 field 的type並加到mapping中。

● document:類比關系數據庫里的一行記錄(record),document 是 Elasticsearch 里的一個 JSON 對象,包括零個或多個field。

● field:類比關系數據庫里的field,每個field 都有自己的字段類型。

● shard:是一個Lucene 實例。Elasticsearch 基於 Lucene,shard 是一個 Lucene 實例,被 Elasticsearch 自動管理。之前提到,index 是一個邏輯命名空間,shard 是具體的物理概念,建索引、查詢等都是具體的shard在工作。shard 包括primary shard 和 replica shard,寫數據時,先寫到primary shard,然后,同步到replica shard,查詢時,primary 和 replica 充當相同的作用。replica shard 可以有多份,也可以沒有,replica shard的存在有兩個作用,一是容災,如果primary shard 掛了,數據也不會丟失,集群仍然能正常工作;二是提高性能,因為replica 和 primary shard 都能處理查詢。另外,如上圖右側紅框所示,shard數和replica數都可以設置,但是,shard 數只能在建立index 時設置,后期不能更改,但是,replica 數可以隨時更改。但是,由於 Elasticsearch 很友好的封裝了這部分,在使用Elasticsearch 的過程中,我們一般僅需要關注 index 即可,不需關注shard。

 

shard、node、cluster 在物理上構成了 Elasticsearch 集群,field、type、index 在邏輯上構成一個index的基本概念,在使用 Elasticsearch 過程中,我們一般關注到邏輯概念就好,就像我們在使用MySQL 時,我們一般就關注DB Name、Table和schema即可,而不會關注DBA維護了幾個MySQL實例、master 和 slave 等怎么部署的一樣。

ES中的索引原理
(1)傳統的關系型數據庫

二叉樹查找效率是logN,同時插入新的節點不必移動全部節點,所以用樹型結構存儲索引,能同時兼顧插入和查詢的性能。因此在這個基礎上,再結合磁盤的讀取特性(順序讀/隨機讀),傳統關系型數據庫采用了B-Tree/B+Tree這樣的數據結構做索引

(2)ES

采用倒排索引

那么,倒排索引是個什么樣子呢?

 

首先,來搞清楚幾個概念,為此,舉個例子:

假設有個user索引,它有四個字段:分別是name,gender,age,address。畫出來的話,大概是下面這個樣子,跟關系型數據庫一樣

 

Term(單詞):一段文本經過分析器分析以后就會輸出一串單詞,這一個一個的就叫做Term

Term Dictionary(單詞字典):顧名思義,它里面維護的是Term,可以理解為Term的集合

Term Index(單詞索引):為了更快的找到某個單詞,我們為單詞建立索引

Posting List(倒排列表):倒排列表記錄了出現過某個單詞的所有文檔的文檔列表及單詞在該文檔中出現的位置信息,每條記錄稱為一個倒排項(Posting)。根據倒排列表,即可獲知哪些文檔包含某個單詞。(PS:實際的倒排列表中並不只是存了文檔ID這么簡單,還有一些其它的信息,比如:詞頻(Term出現的次數)、偏移量(offset)等,可以想象成是Python中的元組,或者Java中的對象)

(PS:如果類比現代漢語詞典的話,那么Term就相當於詞語,Term Dictionary相當於漢語詞典本身,Term Index相當於詞典的目錄索引)

我們知道,每個文檔都有一個ID,如果插入的時候沒有指定的話,Elasticsearch會自動生成一個,因此ID字段就不多說了

上面的例子,Elasticsearch建立的索引大致如下:

name字段:

 

age字段:

 

gender字段:

 

address字段:

 

Elasticsearch分別為每個字段都建立了一個倒排索引。比如,在上面“張三”、“北京市”、22 這些都是Term,而[1,3]就是Posting List。Posting list就是一個數組,存儲了所有符合某個Term的文檔ID。

只要知道文檔ID,就能快速找到文檔。可是,要怎樣通過我們給定的關鍵詞快速找到這個Term呢?

當然是建索引了,為Terms建立索引,最好的就是B-Tree索引(MySQL就是B樹索引最好的例子)。

我們查找Term的過程跟在MyISAM中記錄ID的過程大致是一樣的

MyISAM中,索引和數據是分開,通過索引可以找到記錄的地址,進而可以找到這條記錄

在倒排索引中,通過Term索引可以找到Term在Term Dictionary中的位置,進而找到Posting List,有了倒排列表就可以根據ID找到文檔了

(PS:可以這樣理解,類比MyISAM的話,Term Index相當於索引文件,Term Dictionary相當於數據文件)

(PS:其實,前面我們分了三步,我們可以把Term Index和Term Dictionary看成一步,就是找Term。因此,可以這樣理解倒排索引:通過單詞找到對應的倒排列表,根據倒排列表中的倒排項進而可以找到文檔記錄)

為了更進一步理解,用兩張圖來具現化這一過程:

 

(至於里面涉及的更加高深的數據壓縮技巧,以及多個field聯合查詢利用跳表的數據結構快速做運算來查詢,這些大家有興趣可以自己去了解)

 


原文鏈接:https://blog.csdn.net/zhenwei1994/article/details/94013059

                  https://www.cnblogs.com/heyanan/p/12695715.html

       https://baijiahao.baidu.com/s?id=1660973626296344382&wfr=spider&for=pc


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM