Elasticsearch 是一個兼有搜索引擎和NoSQL數據庫功能的開源系統,基於Java/Lucene構建,可以用於全文搜索,結構化搜索以及近實時分析。可以說Lucene是當今最先進,最高效的全功能開源搜索引擎框架。 說明: Lucene:只是一個框架,要充分利用它的功能,需要使用JAVA,並且在程序中集成Lucene,學習成本高,Lucene確實非常復雜。 Elasticsearch 是 面向文檔型數據庫,這意味着它存儲的是整個對象或者 文檔,它不但會存儲它們,還會為他們建立索引,這樣你就可以搜索他們了
目錄:
- 應用場景
- solr VS ES
- 核心概念
- ES模塊結構
- 分片示例
應用場景
- 站內搜索:主要和 Solr 競爭,屬於后起之秀
- NoSQL json文檔數據庫:主要搶占 Mongo 的市場,它在讀寫性能上優於 Mongo ,同時也支持地理位置查詢,還方便地理位置和文本混合查詢,屬於歪打正着 (對比測試參見:http://blog.quarkslab.com/mongodb-vs-elasticsearch-the-quest-of-the-holy-performances.html)
- 監控:統計以及日志類時間序的數據的存儲和分析以及可視化,這方面是引領者
- 國外:Wikipedia使用 ES 提供全文搜索並高亮關鍵字、StackOverflow結合全文搜索與地理位置查詢、Github使用Elasticsearch檢索1300億行的代碼
- 國內:百度(在casio、雲分析、網盟、預測、文庫、直達號、錢包、風控等業務上都應用了ES,單集群每天導入30TB+數據,總共每天60TB+)、新浪 (見大數據架構--log),阿里巴巴、騰訊等公司均有對ES的使用
- 使用比較廣泛的平台ELK(ElasticSearch, Logstash, Kibana)
solr VS ES
- Solr是Apache Lucene項目的開源企業搜索平台。其主要功能包括全文檢索、命中標示、分面搜索、動態聚類、數據庫集成,以及富文本(如Word、PDF)的處理。
- Solr是高度可擴展的,並提供了分布式搜索和索引復制。Solr是最流行的企業級搜索引擎,Solr4 還增加了NoSQL支持。
- Solr是用Java編寫、運行在Servlet容器(如 Apache Tomcat 或Jetty)的一個獨立的全文搜索服務器。 Solr采用了 Lucene Java 搜索庫為核心的全文索引和搜索,並具有類似REST的HTTP/XML和JSON的API。
- Solr強大的外部配置功能使得無需進行Java編碼,便可對 其進行調整以適應多種類型的應用程序。Solr有一個插件架構,以支持更多的高級定制
- Elasticsearch 與 Solr 的比較總結
-
- 二者安裝都很簡單
- Solr 利用 Zookeeper 進行分布式管理,而 Elasticsearch 自身帶有分布式協調管理功能
- Solr 支持更多格式的數據,而 Elasticsearch 僅支持json文件格式
- Solr 官方提供的功能更多,而 Elasticsearch 本身更注重於核心功能,高級功能多有第三方插件提供
- Solr 在傳統的搜索應用中表現好於 Elasticsearch,但在處理實時搜索應用時效率明顯低於 Elasticsearch
- Solr 是傳統搜索應用的有力解決方案,但 Elasticsearch 更適用於新興的實時搜索應用
核心概念
- 集群(Cluster): 包含一個或多個具有相同 cluster.name 的節點.
- 集群內節點協同工作,共享數據,並共同分擔工作負荷。
- 由於節點是從屬集群的,集群會自我重組來均勻地分發數據.
- cluster Name是很重要的,因為每個節點只能是群集的一部分,當該節點被設置為相同的名稱時,就會自動加入群集。
- 集群中通過選舉產生一個mater節點,它將負責管理集群范疇的變更,例如創建或刪除索引,添加節點到集群或從集群刪除節點。master 節點無需參與文檔層面的變更和搜索,這意味着僅有一個 master 節點並不會因流量增長而成為瓶頸。任意一個節點都可以成為 master 節點。我們例舉的集群只有一個節點,因此它會扮演 master 節點的角色。
- 作為用戶,我們可以訪問包括 master 節點在內的集群中的任一節點。每個節點都知道各個文檔的位置,並能夠將我們的請求直接轉發到擁有我們想要的數據的節點。無論我們訪問的是哪個節點,它都會控制從擁有數據的節點收集響應的過程,並返回給客戶端最終的結果。這一切都是由 Elasticsearch 透明管理的
- 節點(node): 一個節點是一個邏輯上獨立的服務,可以存儲數據,並參與集群的索引和搜索功能, 一個節點也有唯一的名字,群集通過節點名稱進行管理和通信.
- 索引(Index): 索引與關系型數據庫實例(Database)相當。索引只是一個 邏輯命名空間,它指向一個或多個分片(shards),內部用Apache Lucene實現索引中數據的讀寫
- 文檔類型(Type):相當於數據庫中的table概念。每個文檔在ElasticSearch中都必須設定它的類型。文檔類型使得同一個索引中在存儲結構不同文檔時,只需要依據文檔類型就可以找到對應的參數映射(Mapping)信息,方便文檔的存取
- 文檔(Document) :相當於數據庫中的row, 是可以被索引的基本單位。例如,你可以有一個的客戶文檔,有一個產品文檔,還有一個訂單的文檔。文檔是以JSON格式存儲的。在一個索引中,您可以存儲多個的文檔。請注意,雖然在一個索引中有多分文檔,但這些文檔的結構是一致的,並在第一次存儲的時候指定, 文檔屬於一種 類型(type),各種各樣的類型存在於一個 索引 中。你也可以通過類比傳統的關系數據庫得到一些大致的相似之處:
關系數據庫 ⇒ 數據庫 ⇒ 表 ⇒ 行 ⇒ 列(Columns) Elasticsearch ⇒ 索引 ⇒ 類型 ⇒ 文檔 ⇒ 字段(Fields)
- 模擬示意圖如:
- Mapping: 相當於數據庫中的schema,用來約束字段的類型,不過 Elasticsearch 的 mapping 可以自動根據數據創建
- 分片(shard) :是 工作單元(worker unit) 底層的一員,用來分配集群中的數據,它只負責保存索引中所有數據的一小片。
-
- 分片是一個獨立的Lucene實例,並且它自身也是一個完整的搜索引擎。
- 文檔存儲並且被索引在分片中,但是我們的程序並不會直接與它們通信。取而代之,它們直接與索引進行通信的
- 把分片想象成一個數據的容器。數據被存儲在分片中,然后分片又被分配在集群的節點上。當你的集群擴展或者縮小時,elasticsearch 會自動的在節點之間遷移分配分片,以便集群保持均衡
- 分片分為 主分片(primary shard) 以及 從分片(replica shard) 兩種。在你的索引中,每一個文檔都屬於一個主分片
- 從分片只是主分片的一個副本,它用於提供數據的冗余副本,在硬件故障時提供數據保護,同時服務於搜索和檢索這種只讀請求
- 索引中的主分片的數量在索引創建后就固定下來了,但是從分片的數量可以隨時改變。
- 一個索引默認設置了5個主分片,每個主分片有一個從分片對應
ES模塊結構
- 模塊結構圖如下
- Gateway: 代表ES的持久化存儲方式,包含索引信息,ClusterState(集群信息),mapping,索引碎片信息,以及transaction log等
- 對於分布式集群來說,當一個或多個節點down掉了,能夠保證我們的數據不能丟,最通用的解放方案就是對失敗節點的數據進行復制,通過控制復制的份數可以保證集群有很高的可用性,復制這個方案的精髓主要是保證操作的時候沒有單點,對一個節點的操作會同步到其他的復制節點上去。
- ES一個索引會拆分成多個碎片,每個碎片可以擁有一個或多個副本(創建索引的時候可以配置),這里有個例子,每個索引分成3個碎片,每個碎片有2個副本,如下:
$ curl -XPUT http://localhost:9200/twitter/ -d ' index : number_of_shards : 3 number_of_replicas : 2
-
每個操作會自動路由主碎片所在的節點,在上面執行操作,並且同步到其他復制節點,通過使用“non blocking IO”模式所有復制的操作都是並行執行的,也就是說如果你的節點的副本越多,你網絡上的流量消耗也會越大。復制節點同樣接受來自外面的讀操作,意義就是你的復制節點越多,你的索引的可用性就越強,對搜索的可伸縮行就更好,能夠承載更多的操作
- 第一次啟動的時候,它會去持久化設備讀取集群的狀態信息(創建的索引,配置等)然后執行應用它們(創建索引,創建mapping映射等),每一次shard節點第一次實例化加入復制組,它都會從長持久化存儲里面恢復它的狀態信息
- Lucence Directory: 是lucene的框架服務發現以及選主 ZenDiscovery: 用來實現節點自動發現,還有Master節點選取,假如Master出現故障,其它的這個節點會自動選舉,產生一個新的Master
- 它是Lucene存儲的一個抽象,由此派生了兩個類:FSDirectory和RAMDirectory,用於控制索引文件的存儲位置。使用FSDirectory類,就是存儲到硬盤;使用RAMDirectory類,則是存儲到內存
- 一個Directory對象是一份文件的清單。文件可能只在被創建的時候寫一次。一旦文件被創建,它將只被讀取或者刪除。在讀取的時候進行寫入操作是允許的
- Discovery
-
- 節點啟動后先ping(這里的ping是 Elasticsearch 的一個RPC命令。如果 discovery.zen.ping.unicast.hosts 有設置,則ping設置中的host,否則嘗試ping localhost 的幾個端口, Elasticsearch 支持同一個主機啟動多個節點)
- Ping的response會包含該節點的基本信息以及該節點認為的master節點
- 選舉開始,先從各節點認為的master中選,規則很簡單,按照id的字典序排序,取第一個
- 如果各節點都沒有認為的master,則從所有節點中選擇,規則同上。這里有個限制條件就是 discovery.zen.minimum_master_nodes,如果節點數達不到最小值的限制,則循環上述過程,直到節點數足夠可以開始選舉
- 最后選舉結果是肯定能選舉出一個master,如果只有一個local節點那就選出的是自己
- 如果當前節點是master,則開始等待節點數達到 minimum_master_nodes,然后提供服務, 如果當前節點不是master,則嘗試加入master.
- ES支持任意數目的集群(1-N),所以不能像 Zookeeper/Etcd 那樣限制節點必須是奇數,也就無法用投票的機制來選主,而是通過一個規則,只要所有的節點都遵循同樣的規則,得到的信息都是對等的,選出來的主節點肯定是一致的. 但分布式系統的問題就出在信息不對等的情況,這時候很容易出現腦裂(Split-Brain)的問題,大多數解決方案就是設置一個quorum值,要求可用節點必須大於quorum(一般是超過半數節點),才能對外提供服務。而 Elasticsearch 中,這個quorum的配置就是 discovery.zen.minimum_master_nodes 。
- memcached
-
- 通過memecached協議來訪問ES的接口,支持二進制和文本兩種協議.通過一個名為transport-memcached插件提供
- Memcached命令會被映射到REST接口,並且會被同樣的REST層處理,memcached命令列表包括:get/set/delete/quit
- River : 代表es的一個數據源,也是其它存儲方式(如:數據庫)同步數據到es的一個方法。它是以插件方式存在的一個es服務,通過讀取river中的數據並把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的,river這個功能將會在后面的文件中重點說到
分片示例
- 啟用一個既沒有數據,也沒有索引的單一節點, 如下圖
- 在空的單節點集群中上創建一個叫做 blogs 的索引,設置3個主分片和一組從分片(每個主分片有一個從分片對應),代碼如下:
PUT /blogs { "settings" : { "number_of_shards" : 3, "number_of_replicas" : 1 } }
-
集群示例圖如下: (此時集群健康狀態為: yellow 三個從分片還沒有被分配到節點上)
- 主分片(primary shards) 啟動並且運行了,這時集群已經可以成功的處理任意請求,但是 從分片(replica shards) 沒有完全被激活。事實上,當前這三個從分片都處於 unassigned(未分配)的狀態,它們還未被分配到節點上。在同一個節點上保存相同的數據副本是沒有必要的,如果這個節點故障了,就等同於所有的數據副本也丟失了
- 啟動第二個節點,配置第二個節點與第一個節點的 cluster.name 相同(./config/elasticsearch.yml文件中的配置),它就能自動發現並加入到第一個節點的集群中,如下圖:
- cluster-health 的狀態為 green,這意味着所有的6個分片(三個主分片和三個從分片)都已激活,文檔在主節點和從節點上都能被檢索
- 隨着應用需求的增長,啟動第三個節點進行橫向擴展,集群內會自動重組,如圖
- 在 Node 1 和 Node 2 中分別會有一個分片被移動到 Node 3 上,這樣一來,每個節點上就都只有兩個分片了。這意味着每個節點的硬件資源(CPU、RAM、I/O)被更少的分片共享,所以每個分片就會有更好的性能表現
- 一共有6個分片(3個主分片和3個從分片),因此最多可以擴展到6個節點,每個節點上有一個分片,這樣每個分片都可以使用到所在節點100%的資源了
- 主分片的數量在索引創建的時候就已經指定了,實際上,這個數字定義了能存儲到索引中的數據最大量(具體的數量取決於你的數據,硬件的使用情況)。例如,讀請求——搜索或者文檔恢復就可以由主分片或者從分片來執行,所以當你擁有更多份數據的時候,你就擁有了更大的吞吐量
- 從分片的數量可以在運行的集群中動態的調整,這樣我們就可以根據實際需求擴展或者縮小規模。接下來,我們來增加一下從分片組的數量:
PUT /blogs/_settings { "number_of_replicas" : 2 }
-
現在 blogs 的索引總共有9個分片:3個主分片和6個從分片, 又會變成一個節點一個分片的狀態了,最終得到了三倍搜索性能的三節點集群
- 說明:僅僅是在同樣數量的節點上增加從分片的數量是根本不能提高性能的,因為每個分片都有訪問系統資源的權限。你需要升級硬件配置以提高吞吐量。
- 嘗試一下,把第一個節點殺掉,我們的集群就會如下圖所示:
- 被殺掉的節點是主節點,主分片 1 和 2 在我們殺掉 Node 1 后就丟失了,我們的索引在丟失主節點的時候是不能正常工作的。如果我們在這個時候檢查集群健康狀態,將會顯示 red:存在不可用的主節點
- 而為了集群的正常工作必須需要一個主節點,所以首先進行的進程就是從各節點中選擇了一個新的主節點:Node 2
- 新的主節點所完成的第一件事情就是將這些在 Node 2 和 Node 3 上的從分片提升為主分片,然后集群的健康狀態就變回至 yellow。這個提升的進程是瞬間完成了,就好像按了一下開關
- 如果再次殺掉 Node 2 的時候,我們的程序依舊可以在沒有丟失任何數據的情況下運行,因為 Node 3 中依舊擁有每個分片的備份
- 如果我們重啟 Node 1,集群就能夠重新分配丟失的從分片,這樣結果就會與三節點兩從集群一致。如果 Node 1 依舊還有舊節點的內容,系統會嘗試重新利用他們,並只會復制在故障期間的變更數據