Elasticsearch是一款用Java編寫的開源分佈式文檔存儲和搜索引擎,能夠用於near real-time存儲和數據檢索。html
在開始探索性能指標以前,讓咱們來看看Elasticsearch的工做原理,在elasticsearch中,集羣由一個或者更多的節點組成,以下圖: java
每一個節點是Elasticsearch的單個運行實例,其「elasticsearch.yml」配置文件指定其所屬的集羣(「cluster.name」)以及它能夠是什麼類型的節點。 配置文件中設置的任何屬性(包括集羣名稱)也能夠經過命令行參數指定。 上圖中的集羣由一個專用主節點和五個數據節點組成。node
三種最多見的es幾點類型有:mysql
在es中,相關聯的數據一般存儲在相同的索引中,每一個索引包含一組JSON格式的相關聯文檔。linux
Elasticsearch的全文搜索祕訣是Lucene的倒排索引。在索引(存入)數據的時候,es會自動爲每一個字段建立一個倒排索引,倒排索引將索引的詞(terms)映射(map)到包含該詞的文檔(document)中。sql
index被存儲在一個或多個主副shard中,每一個shard都是一個完整的Lucenes實例,是一個完整的迷你搜索引擎。 數據庫
建立索引時,能夠指定主分片的數量以及每一個主節點的副本數,默認爲五個分片和一個副本。索引建立後,分片數不能被修改。若是要修改可能須要reindex。副本數能夠在後期被修改。
爲了防止數據丟失,主節點的調度機制會確保主副分片不會出如今同一個數據節點上。緩存
Elasticsearch提供了大量的Metric,能夠幫助您檢測到問題的跡象,在遇到節點不可用、out-of-memory、long garbage collection times的時候採起相應措施。
一些關鍵的檢測以下:網絡
這裏提供了一個metric蒐集和監控的框架 Monitoring 101 series
全部這些指標均可以經過Elasticsearch的API以及Elasticsearch的Marvel和Datadog等通用監控工具訪問。併發
搜索請求是Elasticsearch中的兩個主要請求類型之一,另外一個是索引請求。 這些請求有時相似於傳統數據庫系統中的讀寫請求。 Elasticsearch提供與搜索過程的兩個主要階段(查詢和獲取)相對應的度量。 下圖顯示了從開始到結束的搜索請求的路徑。
1.客戶端向Node 2 發送搜索請求
2.Node 2(此時客串協調角色)將查詢請求發送到索引中的每個分片的副本
3.每一個分片(Lucene實例,迷你搜素引擎)在本地執行查詢,而後將結果交給Node 2。Node 2 sorts and compiles them into a global priority queue.
4.Node 2發現須要獲取哪些文檔,並向相關的分片發送多個GET請求。
5.每一個分片loads documents而後將他們返回給Node 2
6.Node 2將搜索結果交付給客戶端
節點處理,由誰分發,就由誰交付
若是您使用Elasticsearch主要用於搜索,或者若是搜索是面向客戶的功能。您應該監視查詢延遲和設定閾值。 監控關於查詢和提取的相關指標很重要,能夠幫助您肯定搜索隨時間的變化。 例如,您可能但願跟蹤查詢請求的尖峯和長期增加,以便您能夠作好準備。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Total number of queries | indices.search.query_total |
Work: Throughput |
Total time spent on queries | indices.search.query_time_in_millis |
Work: Performance |
Number of queries currently in progress | indices.search.query_current |
Work: Throughput |
Total number of fetches | indices.search.fetch_total |
Work: Throughput |
Total time spent on fetches | indices.search.fetch_time_in_millis |
Work: Performance |
Number of fetches currently in progress | indices.search.fetch_current |
Work: Throughput |
搜索性能指標的要點:
索引請求相似於傳統數據庫系統中的寫入請求,若是es的寫入工做量很重,那麼監控和分析您可以如何有效地使用新數據更新索引很是重要。在瞭解指標以前,讓咱們來探索Elasticsearch更新索引的過程,在新數據被添加進索引、更新或刪除已有數據,索引中的每一個shard都有兩個過程:refresh 和 flush
Index fresh
新索引的文檔不能立馬被搜索的。
首先,它們被寫入一個內存中的緩衝區(in-memory buffer),等待下一次索引刷新,默認狀況下每秒一次。刷新是以in-memory buffer爲基礎建立in-memory segment的過程(The refresh process creates a new in-memory segment from the contents of the in-memory buffer )。這樣索引進的文檔才能是可被搜索的,建立完segment後,清空buffer
以下圖:
A special segment on segments
索引由shards構成,shard又由不少segments組成,The core data structure from Lucene, a segment is essentially a change set for the index. 這些segments在每次刷新的時候被建立,隨後會在後臺進行合併,以確保資源的高效利用(每一個segment都要佔file handles、memory、CPU)
segments 是mini的倒排索引,這些倒排索引映射了terms到documents。每當搜索索引的時候,每一個主副shards都必須被遍歷。更深一步說shards上的每一個segment會被依次搜索。
segment是不可變的,所以updating a document 意味着以下:
當多個outdated segment合併後纔會被刪除。(意思是不單個刪除,合併後一塊兒刪)。
Index flush
在新索引的document添加到in-memory buffer的同時,它們也會被附加到分片的translog(a persistent, write-ahead transaction log of operations)中。
每隔30分鐘,或者每當translog達到最大大小(默認狀況下爲512MB)時,將觸發flush 。在flush 期間,在in-memory buffer上的documents會被refreshed(存到新的segments上),全部內存中的segments都提交到磁盤,而且translog被清空。
translog有助於防止節點發生故障時的數據丟失。 It is designed to help a shard recover operations that may otherwise have been lost between flushes. 這個translog每5秒將操做信息(索引,刪除,更新或批量請求(以先到者爲準))固化到磁盤上。
Elasticsearch提供了許多指標,可用於評估索引性能並優化更新索引的方式。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Total number of documents indexed | indices.indexing.index_total |
Work: Throughput |
Total time spent indexing documents | indices.indexing.index_time_in_millis |
Work: Performance |
Number of documents currently being indexed | indices.indexing.index_current |
Work: Throughput |
Total number of index refreshes | indices.refresh.total |
Work: Throughput |
Total time spent refreshing indices | indices.refresh.total_time_in_millis |
Work: Performance |
Total number of index flushes to disk | indices.flush.total |
Work: Throughput |
Total time spent on flushing indices to disk | indices.flush.total_time_in_millis |
Work: Performance |
索引性能指標的要點:
Indexing latency: Elasticsearch不會直接公開此特定指標,可是監控工具能夠幫助您從可用的index_total和index_time_in_millis指標計算平均索引延遲。 若是您注意到延遲增長,您可能會一次嘗試索引太多的文檔(Elasticsearch的文檔建議從5到15兆字節的批量索引大小開始,並緩慢增長)。
若是您計劃索引大量文檔,而且不須要當即可用於搜索。則能夠經過減小刷新頻率來優化。索引設置API使您可以暫時禁用刷新間隔:
curl -XPUT <nameofhost>:9200/<name_of_index>/_settings -d '{ "index" : { "refresh_interval" : "-1" } }'
完成索引後,您能夠恢復爲默認值「1s」
Flush latency: 在flush完成以前,數據不會被固化到磁盤中。所以追蹤flush latency頗有用。好比咱們看到這個指標穩步增加,代表磁盤性能很差。這個問題將最終致使沒法向索引添加新的數據。
能夠嘗試下降index.translog.flush_threshold_size。這個設置決定translog的最大值(在flush被觸發前)
在運行Elasticsearch時,內存是您要密切監控的關鍵資源之一。 Elasticsearch和Lucene以兩種方式利用節點上的全部可用RAM:JVM heap和文件系統緩存。 Elasticsearch運行在Java虛擬機(JVM)中,這意味着JVM垃圾回收的持續時間和頻率將成爲其餘重要的監控領域。
JVM heap: A Goldilocks tale
Elasticsearch強調了JVM堆大小的重要性,這是「正確的」 - 不要將其設置太大或過小,緣由以下所述。 通常來講,Elasticsearch的經驗法則是將少於50%的可用RAM分配給JVM堆,而不會超過32 GB。
您分配給Elasticsearch的堆內存越少,Lucene就可使用更多的RAM,這很大程度上依賴於文件系統緩存來快速提供請求。 可是,您也不想將堆大小設置得過小,由於應用程序面臨來自頻繁GC的不間斷暫停,可能會遇到內存不足錯誤或吞吐量下降的問題
Elasticsearch的默認安裝設置了1 GB的JVM heap大小,對於大多數用例來講,過小了。 您能夠將所需的heap大小導出爲環境變量並從新啓動Elasticsearch:
export ES_HEAP_SIZE=10g
如上咱們設置了es heap大小爲10G,經過以下命令進行校驗:
curl -XGET http://:9200/_cat/nodes?h=heap.max
Garbage collection
Elasticsearch依靠垃圾收集過程來釋放heap memory。由於垃圾收集使用資源(爲了釋放資源!),您應該注意其頻率和持續時間,以查看是否須要調整heap大小。設置過大的heap會致使GC時間過長,這些長時間的停頓會讓集羣錯誤的認爲該節點已經脫離。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Total count of young-generation garbage collections | jvm.gc.collectors.young.collection_count (jvm.gc.collectors.ParNew.collection_count prior to vers. 0.90.10) |
Other |
Total time spent on young-generation garbage collections | jvm.gc.collectors.young.collection_time_in_millis (jvm.gc.collectors.ParNew.collection_time_in_millis prior to vers. 0.90.10) |
Other |
Total count of old-generation garbage collections | jvm.gc.collectors.old.collection_count (jvm.gc.collectors.ConcurrentMarkSweep.collection_count prior to vers. 0.90.10) |
Other |
Total time spent on old-generation garbage collections | jvm.gc.collectors.old.collection_time_in_millis (jvm.gc.collectors.ConcurrentMarkSweep.collection_time_in_millis for versions prior to 0.90.10) |
Other |
Percent of JVM heap currently in use | jvm.mem.heap_used_percent |
Resource: Utilization |
Amount of JVM heap committed | jvm.mem.heap_committed_in_bytes |
Resource: Utilization |
JVM指標的要點:
JVM heap in use: 當JVM heap 使用率達到75%時,es啓動GC。如上圖所示,能夠監控node的JVM heap,而且設置一個警報,確認哪一個節點是否一直超過%85。若是一直超過,則代表垃圾的收集已經跟不上垃圾的產生。此時能夠經過增長heap(須要知足建議法則不超過32G),或者經過增長節點來擴展集羣,分散壓力。
JVM heap used vs. JVM heap committed: 與commit的內存(保證可用的數量)相比,瞭解當前正在使用多少JVM heap的狀況可能會有所幫助。heap memory的圖通常是個鋸齒圖,在垃圾收集的時候heap上升,當收集完成後heap降低。若是這個鋸齒圖向上偏移,說明垃圾的收集速度低於rate of object creation,這可能會致使GC時間放緩,最終OutOfMemoryErrors。
Garbage collection duration and frequency: Both young- and old-generation garbage collectors undergo 「stop the world」 phases, as the JVM halts execution of the program to collect dead objects。在此期間節點cannot complete any task。主節點每30秒會去檢查其餘節點的狀態,若是任何節點的垃圾回收時間超過30秒,則會致使主節點任務該節點脫離集羣。
Memory usage: 如上所述,es很是會利用除了分配給JVM heap的任何RAM。像Kafka同樣,es被設計爲依賴操做系統的文件系統緩存來快速可靠地提供請求。
許多變量決定了Elasticsearch是否成功讀取文件系統緩存,若是segment file最近由es寫入到磁盤,它已經in the cache。然而若是節點被關閉並從新啓動,首次查詢某個segment的時候,數據極可能是必須從磁盤中讀取,這是確保您的羣集保持穩定而且節點不會崩潰的重要緣由之一。
總的來講,監控節點上的內存使用狀況很是重要,而且儘量多給es分配RAM,so it can leverage the speed of the file system cache without running out of space。
Name | [Metric type][monitoring-101-blog] |
---|---|
Available disk space | Resource: Utilization |
I/O utilization | Resource: Utilization |
CPU usage | Resource: Utilization |
Network bytes sent/received | Resource: Utilization |
Open file descriptors | Resource: Utilization |
雖然Elasticsearch經過API提供了許多特定於應用程序的指標,但您也應該從每一個節點收集和監視幾個主機級別的指標。
Host指標要點:
Disk space: 若是數據不少,這個指標很關鍵。若是disk space 太小,講不能插入或更新任何內容,而且節點會掛掉。可使用Curator這樣的工具來刪除特定的索引以保持disk的可用性。
若是不讓刪除索引,另外的辦法是添加磁盤、添加節點。請記住analyzed field佔用磁盤的空間遠遠高於non-analyzed fields。
I/O utilization: 因爲建立,查詢和合並segment,Elasticsearch會對磁盤進行大量寫入和讀取,於具備不斷遇到大量I / O活動的節點的寫入繁重的集羣,Elasticsearch建議使用SSD來提高性能。
CPU utilization: 在每一個節點類型的熱圖(如上所示)中可視化CPU使用狀況可能會有所幫助。 例如,您能夠建立三個不一樣的圖表來表示集羣中的每組節點(例如,數據節點,主節點,客戶端節點), 若是看到CPU使用率的增長,這一般是因爲搜索量大或索引工做負載引發的。 若是須要,能夠添加更多節點來從新分配負載。
Network bytes sent/received: 節點之間的通信是集羣平衡的關鍵。所以須要監控network來確保集羣的health以及對集羣的需求(例如,segment在節點之間進行復制或從新平衡)。 Elasticsearch提供有關集羣通訊的指標,但也能夠查看發送和接收的字節數,以查看network接收的流量。
Open file descriptors: 文件描述符用於節點到節點的通訊,客戶端鏈接和文件操做。若是這個number達到了系統的最大值,則只有在舊的鏈接和文件操做關閉以後才能進行新的鏈接和文件操做。 若是超過80%的可用文件描述符被使用,您可能須要增長系統的最大文件描述符數量。大多數Linux系統每一個進程只容許1024個文件描述符。 在生產中使用Elasticsearch時,您應該將操做系統文件描述符計數從新設置爲更大,如64,000。
HTTP connections:
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Number of HTTP connections currently open | http.current_open |
Resource: Utilization |
Total number of HTTP connections opened over time | http.total_opened |
Resource: Utilization |
能夠用任何語言發送請求,但Java將使用RESTful API經過HTTP與Elasticsearch進行通訊。 若是打開的HTTP鏈接總數不斷增長,可能表示您的HTTP客戶端沒有正確創建持久鏈接。 從新創建鏈接會在您的請求響應時間內添加額外的毫秒甚至秒。 確保您的客戶端配置正確,以免對性能形成負面影響,或使用已正確配置HTTP鏈接的官方Elasticsearch客戶端。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Cluster status (green, yellow, red) | cluster.health.status |
Other |
Number of nodes | cluster.health.number_of_nodes |
Resource: Availability |
Number of initializing shards | cluster.health.initializing_shards |
Resource: Availability |
Number of unassigned shards | cluster.health.unassigned_shards |
Resource: Availability |
指標要點:
Cluster status: 若是集羣狀態爲黃色,則至少有一個副本分片未分配或丟失。 搜索結果仍將完成,但若是更多的分片消失,您可能會丟失數據。
紅色的羣集狀態表示至少有一個主分片丟失,而且您缺乏數據,這意味着搜索將返回部分結果。 您也將被阻止索引到該分片。 Consider setting up an alert to trigger if status has been yellow for more than 5 min or if the status has been red for the past minute.
Initializing and unassigned shards: 當首次建立索引或者重啓節點,其分片將在轉換到「started」或「unassigned」狀態以前暫時處於「initializing」狀態,此時主節點正在嘗試將分片分配到集羣中的數據節點。 若是您看到分片仍處於初始化或未分配狀態太長時間,則多是您的集羣不穩定的警告信號。
es節點使用線程池來管理線程如何消耗內存和CPU。 因爲線程池設置是根據處理器數量自動配置的,因此調整它們一般沒有意義。However, it’s a good idea to keep an eye on queues and rejections to find out if your nodes aren’t able to keep up; 若是沒法跟上,您可能須要添加更多節點來處理全部併發請求。Fielddata和過濾器緩存使用是另外一個要監視的地方,as evictions may point to inefficient queries or signs of memory pressure.
Thread pool queues and rejections
每一個節點維護許多類型的線程池; 您要監視的確切位置將取決於您對es的具體用途,通常來講,監控的最重要的是搜索,索引,merge和bulk,它們與請求類型(搜索,索引,合併和批量操做)相對應。
線程池隊列的大小反應了當前等待的請求數。 隊列容許節點跟蹤並最終服務這些請求,而不是丟棄它們。 一旦超過線程池的maximum queue size,Thread pool rejections就會發生。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Number of queued threads in a thread pool | thread_pool.bulk.queue thread_pool.index.queue thread_pool.search.queue thread_pool.merge.queue |
Resource: Saturation |
Number of rejected threads a thread pool | thread_pool.bulk.rejected thread_pool.index.rejected thread_pool.search.rejected thread_pool.merge.rejected |
Resource: Error |
指標要點:
Thread pool queues: 大隊列不理想,由於它們耗盡資源,而且若是節點關閉,還會增長丟失請求的風險。若是你看到線程池rejected穩步增長,你可能但願嘗試減慢請求速率(若是可能),增長節點上的處理器數量或增長羣集中的節點數量。 以下面的截圖所示,查詢負載峯值與搜索線程池隊列大小的峯值相關,as the node attempts to keep up with rate of query requests。
Bulk rejections and bulk queues: 批量操做是一次發送許多請求的更有效的方式。 一般,若是要執行許多操做(建立索引或添加,更新或刪除文檔),則應嘗試以批量操做發送請求,而不是發送許多單獨的請求。
bulk rejections 一般與在一個批量請求中嘗試索引太多文檔有關。根據Elasticsearch的文檔,批量rejections並非很須要擔憂的事。However, you should try implementing a linear or exponential backoff strategy to efficiently deal with bulk rejections。
Cache usage metrics: 每一個查詢請求都會發送到索引中的每一個分片的每一個segment中,Elasticsearch caches queries on a per-segment basis to speed up response time。另外一方面,若是您的緩存過多地堆積了這些heap,那麼它們可能會減慢速度,而不是加快速度!
在es中,文檔中的每一個字段能夠以兩種形式存儲:exact value 和 full text。
例如,假設你有一個索引,它包含一個名爲location的type。每一個type的文檔有個字段叫city。which is stored as an analyzed string。你索引了兩個文檔,一個的city字段爲「St. Louis」,另外一個的city字段爲「St. Paul」。在倒排索引中存儲時將變成小寫並忽略掉標點符號,以下表
Term | Doc1 | Doc2 |
---|---|---|
st | x | x |
louis | x | |
paul | x |
分詞的好處是你能夠搜索st。結果會搜到兩個。若是將city字段保存爲exact value,那隻能搜「St. Louis」, 或者 「St. Paul」。
Elasticsearch使用兩種主要類型的緩存來更快地響應搜索請求:fielddata和filter。
Fielddata cache: fielddata cache 在字段排序或者聚合時使用。 a process that basically has to uninvert the inverted index to create an array of every field value per field, in document order. For example, if we wanted to find a list of unique terms in any document that contained the term 「st」 from the example above, we would:
1.掃描倒排索引查看哪些文檔(documents)包含這個term(在本例中爲Doc1和Doc2)
2.對1中的每一個步驟,經過索引中的每一個term 從文檔中來收集tokens,建立以下結構:
Doc | Terms |
---|---|
Doc1 | st, louis |
Doc2 | st, paul |
3.如今反向索引被再反向,從doc中compile 獨立的tokens(st, louis, and paul)。compile這樣的fielddata可能會消耗大量堆內存。特別是大量的documents和terms的狀況下。 全部字段值都將加載到內存中。
對於1.3以前的版本,fielddata緩存大小是無限制的。 從1.3版開始,Elasticsearch添加了一個fielddata斷路器,若是查詢嘗試加載須要超過60%的堆的fielddata,則會觸發。
Filter cache: 過濾緩存也使用JVM堆。 在2.0以前的版本中,Elasticsearch自動緩存過濾的查詢,最大值爲堆的10%,而且將最近最少使用的數據逐出。 從版本2.0開始,Elasticsearch會根據頻率和段大小自動開始優化其過濾器緩存(緩存僅發生在索引中少於10,000個文檔的段或小於總文檔的3%)。 所以,過濾器緩存指標僅適用於使用2.0以前版本的Elasticsearch用戶。
例如,過濾器查詢能夠僅返回年份字段中的值在2000-2005範圍內的文檔。 在首次執行過濾器查詢時,Elasticsearch將建立一個與其相匹配的文檔的位組(若是文檔匹配則爲1,不然爲0)。 使用相同過濾器後續執行查詢將重用此信息。 不管什麼時候添加或更新新的文檔,也會更新bitset。 若是您在2.0以前使用的是Elasticsearch版本,那麼您應該關注過濾器緩存以及驅逐指標(更多關於如下內容)。
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Size of the fielddata cache (bytes) | indices.fielddata.memory_size_in_bytes |
Resource: Utilization |
Number of evictions from the fielddata cache | indices.fielddata.evictions |
Resource: Saturation |
Size of the filter cache (bytes) (only pre-version 2.x) | indices.filter_cache.memory_size_in_bytes |
Resource: Utilization |
Number of evictions from the filter cache (only pre-version 2.x) | indices.filter_cache.evictions |
Resource: Saturation |
Fielddata cache evictions: 理想狀況下,咱們須要限制fielddata evictions的數量,由於他們很吃I/O。若是你看到不少evictions而且你又不能增長內存。es建議限制fielddata cache的大小爲20%的heap size。這些是能夠在elasticsearch.yml中進行配置的。當fielddata cache達到20%的heap size時,es將驅逐最近最少使用的fielddata,而後容許您將新的fielddata加載到緩存中。
es還建議使用doc values,由於它們與fielddata的用途相同。因爲它們存儲在磁盤上,它們不依賴於JVM heap。儘管doc values不能被用來分析字符串, they do save fielddata usage when aggregating or sorting on other types of fields。在2.0版本後,doc values會在文檔被index的時候自動建立,which has reduced fielddata/heap usage for many users。
Filter cache evictions: 如前所述,filter cache eviction 指標只有在es2.0以前的版本可用。每一個segment都維護本身的filter cache eviction。由於eviction在大的segment上操做成本較高,沒有的明確的方法來評估eviction。可是若是你發現eviction很頻繁,代表你並無很好地利用filter,此時你須要從新建立filter,即便放棄原有的緩存,你也可能須要調整查詢方式(用bool query 而不是 and/or/not filter)。
Pending tasks:
Metric description | Name | [Metric type][monitoring-101-blog] |
---|---|---|
Number of pending tasks | pending_task_total |
Resource: Saturation |
Number of urgent pending tasks | pending_tasks_priority_urgent |
Resource: Saturation |
Number of high-priority pending tasks | pending_tasks_priority_high |
Resource: Saturation |
pending task只能由主節點來進行處理,這些任務包括建立索引並將shards分配給節點。任務分優先次序。若是任務的產生比處理速度更快,將會產生堆積。待處理任務的數量是您的羣集運行平穩的良好指標,若是您的主節點很是忙,而且未完成的任務數量不會減小,咱們須要仔細檢查緣由。
Unsuccessful GET requests: GET請求比正常的搜索請求更簡單 - 它根據其ID來檢索文檔。 get-by-ID請求不成功意味着找不到文檔ID