elasticsearch 基礎知識彙總

 

 


索引分片: 從策略層面,控制分片分配的選擇

  • 磁盤限額 爲了保護節點數據安全,ES 會定時(cluster.info.update.interval,默認 30 秒)檢查一下各節點的數據目錄磁盤使用狀況。在達到 cluster.routing.allocation.disk.watermark.low (默認 85%)的時候,新索引分片就不會再分配到這個節點上了。在達到 cluster.routing.allocation.disk.watermark.high (默認 90%)的時候,就會觸發該節點現存分片的數據均衡,把數據挪到其餘節點上去。這兩個值不但能夠寫百分比,還能夠寫具體的字節數。有些公司可能出於成本考慮,對磁盤使用率有必定的要求,須要適當擡高這個配置:
# curl -XPUT localhost:9200/_cluster/settings -d '{ "transient" : { "cluster.routing.allocation.disk.watermark.low" : "85%", "cluster.routing.allocation.disk.watermark.high" : "10gb", "cluster.info.update.interval" : "1m" } }'

 

  • 熱索引分片不均 默認狀況下,ES 集羣的數據均衡策略是以各節點的分片總數(indices_all_active)做爲基準的。這對於搜索服務來講無疑是均衡搜索壓力提升性能的好辦法。可是對於 Elastic Stack 場景,通常壓力集中在新索引的數據寫入方面。正常運行的時候,也沒有問題。可是當集羣擴容時,新加入集羣的節點,分片總數遠遠低於其餘節點。這時候若是有新索引建立,ES 的默認策略會致使新索引的全部主分片幾乎全分配在這臺新節點上。整個集羣的寫入壓力,壓在一個節點上,結果極可能是這個節點直接被壓死,集羣出現異常。 因此,對於 Elastic Stack 場景,強烈建議你們預先計算好索引的分片數後,配置好單節點分片的限額。好比,一個 5 節點的集羣,索引主分片 10 個,副本 1 份。則平均下來每一個節點應該有 4 個分片,那麼就配置:
# curl -s -XPUT http://127.0.0.1:9200/logstash-2015.05.08/_settings -d '{ "index": { "routing.allocation.total_shards_per_node" : "5" } }'

注意,這裏配置的是 5 而不是 4。由於咱們須要預防有機器故障,分片發生遷移的狀況。若是寫的是 4,那麼分片遷移會失敗。 
此外,另外一種方式則更加玄妙,Elasticsearch 中有一系列參數,相互影響,最終聯合決定分片分配: 
cluster.routing.allocation.balance.shard 節點上分配分片的權重,默認爲 0.45。數值越大越傾向於在節點層面均衡分片。 
cluster.routing.allocation.balance.index 每一個索引往單個節點上分配分片的權重,默認爲 0.55。數值越大越傾向於在索引層面均衡分片。 
cluster.routing.allocation.balance.threshold 大於閾值則觸發均衡操做。默認爲1。html


reroute 接口

  • reroute 接口支持五種指令:allocate_replica, allocate_stale_primary, allocate_empty_primary,move 和 cancel。
  • 經常使用的通常是 allocate 和 move: 
    allocate_* 指令
  • 由於負載太高等緣由,有時候個別分片可能長期處於 UNASSIGNED 狀態,咱們就能夠手動分配分片到指定節點上。默認狀況下只容許手動分配副本分片(即便用 allocate_replica),因此若是要分配主分片,須要單獨加一個 accept_data_loss 選項:
# curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{ "commands" : [ { "allocate_stale_primary" : { "index" : "logstash-2015.05.27", "shard" : 61, "node" : "10.19.0.77", "accept_data_loss" : true } } ] }'

 

  • 由於負載太高,磁盤利用率太高,服務器下線,更換磁盤等緣由,能夠會須要從節點上移走部分分片:
curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{ "commands" : [ { "move" : { "index" : "logstash-2015.05.22", "shard" : 0, "from_node" : "10.19.0.81", "to_node" : "10.19.0.104" } } ] }'

 


節點下線

  • 集羣中個別節點出現故障預警等狀況,須要下線,也是 Elasticsearch 運維工做中常見的狀況。若是已經穩定運行過一段時間的集羣,每一個節點上都會保存有數量很多的分片。這種時候經過 reroute 接口手動轉移,就顯得太過麻煩了。這個時候,有另外一種方式:
curl -XPUT 127.0.0.1:9200/_cluster/settings -d '{ "transient" :{ "cluster.routing.allocation.exclude._ip" : "10.0.0.1" } }'

 

Elasticsearch 集羣就會自動把這個 IP 上的全部分片,都自動轉移到其餘節點上。等到轉移完成,這個空節點就能夠毫無影響的下線了。和 _ip 相似的參數還有 _host, _name 等。此外,這類參數不單是 cluster 級別,也能夠是 index 級別。下一小節就是 index 級別的用例。node


冷熱數據的讀寫分離

Elasticsearch 集羣一個比較突出的問題是: 用戶作一次大的查詢的時候, 很是大量的讀 IO 以及聚合計算致使機器 Load 升高, CPU 使用率上升, 會影響阻塞到新數據的寫入, 這個過程甚至會持續幾分鐘。因此,可能須要仿照 MySQL 集羣同樣,作讀寫分離。1算法

實施方案apache

N 臺機器作熱數據的存儲, 上面只放當天的數據。這 N 臺熱數據節點上面的 elasticsearc.yml 中配置 node.tag: hot 
以前的數據放在另外的 M 臺機器上。這 M 臺冷數據節點中配置 node.tag: stale 
模板中控制對新建索引添加 hot 標籤: 

「order」 : 0, 
「template」 : 「*」, 
「settings」 : { 
「index.routing.allocation.require.tag」 : 「hot」 


天天計劃任務更新索引的配置, 將 tag 更改成 stale, 索引會自動遷移到 M 臺冷數據節點編程

# curl -XPUT http://127.0.0.1:9200/indexname/_settings -d' { "index": { "routing": { "allocation": { "require": { "tag": "stale" } } } } }'

 


集羣自動發現

  • fd 是 fault detection
  • 考慮到節點有時候由於高負載,慢 GC [垃圾回收] 等緣由會偶爾沒及時響應 ping ,通常建議稍加大 Fault Detection 的超時時間。
  • discovery.zen.ping_timeout 僅在加入或者選舉 master 主節點的時候才起做用;
  • discovery.zen.fd.ping_timeout 在穩定運行的集羣中,master檢測全部節點,以及節點檢測 master是否暢通時長期有用
discovery.zen.ping.unicast.hosts: ["es0","es1", "es2","es3","es4"] # 集羣自動發現 discovery.zen.fd.ping_timeout: 120s # 超時時間(根據實際狀況調整) discovery.zen.fd.ping_retries: 6 # 重試次數,防止GC[Garbage collection]節點不響應被剔除 discovery.zen.fd.ping_interval: 30s # 運行間隔

 


API 接口

數據寫入

# curl -XPOST http://127.0.0.1:9200/logstash-2015.06.21/testlog -d '{ "date" : "1434966686000", "user" : "chenlin7", "mesg" : "first message into Elasticsearch" }'

命令返回響應結果爲:api

{"_index":"logstash-2015.06.21","_type":"testlog","_id":"AU4ew3h2nBE6n0qcyVJK","_version":1,"created":true}

 

數據讀取

# curl -XGET http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK # curl -XGET http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK/_source GET apache-2016.12.30/testlog/AVlPEWLkYdfL4HTWelef/_source GET apache-2016.12.30/testlog/AVlPEWLkYdfL4HTWelef?fields=user # 指定字段

數據刪除

# curl -XDELETE http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK 刪除不單針對單條數據,還能夠刪除整個整個索引。甚至能夠用通配符。 # curl -XDELETE http://127.0.0.1:9200/logstash-2015.06.0* 在 Elasticsearch 2.x 以前,能夠經過查詢語句刪除,也能夠刪除某個 _type 內的數據。如今都已經再也不內置支持,改成 Delete by Query 插件。由於這種方式自己對性能影響較大!

數據更新

已經寫過的數據,一樣仍是能夠修改的。有兩種辦法,一種是全量提交,即指明 _id 再發送一次寫入請求。
# curl -XPOST http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK -d '{ "date" : "1434966686000", "user" : "chenlin7", "mesg" " "first message into Elasticsearch but version 2" }' 另外一種是局部更新,使用 /_update 接口: # curl -XPOST 'http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK/_update' -d '{ "doc" : { "user" : "someone" } }' 或者 # curl -XPOST 'http://127.0.0.1:9200/logstash-2015.06.21/testlog/AU4ew3h2nBE6n0qcyVJK/_update' -d '{ "script" : "ctx._source.user = \"someone\"" }'

 

分片存儲設置

PUT /_cluster/settings{
  "transient": { "cluster.routing.allocation.disk.watermark.low": "80%", "cluster.routing.allocation.disk.watermark.high": "5gb", "cluster.info.update.interval": "1m" } }

 

搜索請求

全文搜索
# curl -XGET http://127.0.0.1:9200/logstash-2015.06.21/testlog/_search?q=first # curl -XGET http://127.0.0.1:9200/logstash-2015.06.21/testlog/_search?q=user:"chenlin7" { "took": 2, Elasticsearch 執行這個搜索的耗時,以毫秒爲單位 "timed_out": false, 搜索是否超時 "_shards": { 指出多少個分片被搜索了,同時也指出了成功/失敗的被搜索的shards 的數量 "total": 5, "successful": 5, "failed": 0 }, "hits" : { 搜索結果 "total" : 579, 匹配查詢條件的文檔的總數目 "max_score" : 0.12633952, "hits" : [ 真正的搜索結果數組(默認是前10個文檔) { "_index" : "logstash-2015.06.21", "_type" : "logs", "_id" : "AVmvfgGaSF0Iy2LFN0EH", "_score" : 0.12633952, "_source" : { "user" : "chenlin7" } } ...... 

 

querystring 語法

  • 上例中,?q=後面寫的,就是 querystring 語法。鑑於這部份內容會在 Kibana 上常用,這裏詳細解析一下語法:
  • 全文檢索:直接寫搜索的單詞,如上例中的 first;
  • 單字段的全文檢索:在搜索單詞以前加上字段名和冒號,好比若是知道單詞 first 確定出如今 mesg 字段,能夠寫做 mesg:first;
  • 單字段的精確檢索:在搜索單詞先後加雙引號,好比 user:」chenlin7」;
  • 多個檢索條件的組合:可使用 NOT, AND 和 OR 來組合檢索,注意必須是大寫。好比 user:(「chenlin7」 OR 「chenlin」) AND NOT mesg:first;
  • 字段是否存在:exists:user 表示要求 user 字段存在,missing:user 表示要求 user 字段不存在;
  • 通配符:用 ? 表示單字母,* 表示任意個字母。好比 fir?t mess*;
  • 正則:須要比通配符更復雜一點的表達式,可使用正則。好比 mesg:/mes{2}ages?/。注意 ES 中正則性能不好,並且支持的功能也不是特別強大,儘可能不要使用。ES 支持的正則語法見:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax
  • 近似搜索:用 ~ 表示搜索單詞可能有一兩個字母寫的不對,請 ES 按照類似度返回結果。好比 frist~;
  • 範圍搜索:對數值和時間,ES 均可以使用範圍搜索,好比:rtt:>300,date:[「now-6h」 TO 「now」} 等。其中,[] 表示端點數值包含在範圍內,{} 表示端點數值不包含在範圍內;
  • 完整語法: 
    https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-queries.html

term query 的寫法數組

# curl -XGET http://127.0.0.1:9200/_search -d ' { "query": { "term": { "user": "chenlin7" } } }' 

 

集羣健康狀態

$ curl -XGET 127.0.0.1:9200/_cluster/health?pretty安全

  • green 綠燈,全部分片都正確運行,集羣很是健康。
  • yellow 黃燈,全部主分片都正確運行,可是有副本分片缺失。這種狀況意味着 ES 當前仍是正常運行的,可是有必定風險。注意,在 Kibana4 的 server 端啓動邏輯中,即便是黃燈狀態,Kibana 4 也會拒絕啓動,死循環等待集羣狀態變成綠燈後才能繼續運行。
  • red 紅燈,有主分片缺失。這部分數據徹底不可用。而考慮到 ES 在寫入端是簡單的取餘算法,輪到這個分片上的數據也會持續寫入報錯。

level 請求參數

接口請求的時候,能夠附加一個 level 參數,指定輸出信息以 indices 仍是 shards 級別顯示。固然,通常來講,indices 級別就夠了。bash

節點狀態監控接口

GC(垃圾回收)

對不瞭解 JVM 的 GC 的讀者,這裏先介紹一下 GC(垃圾收集)以及 GC 對 Elasticsearch 的影響。 
Java is a garbage-collected language, which means that the programmer does not manually manage memory allocation and deallocation. The programmer simply writes code, and the Java Virtual Machine (JVM) manages the process of allocating memory as needed, and then later cleaning up that memory when no longer needed. Java 是一個自動垃圾收集的編程語言,啓動 JVM 虛擬機的時候,會分配到固定大小的內存塊,這個塊叫作 heap(堆)。JVM 會把 heap 分紅兩個組: 
Young 新實例化的對象所分配的空間。這個空間通常來講只有 100MB 到 500MB 大小。Young 空間又分爲兩個 survivor(倖存)空間。當 Young 空間滿,就會發生一次 young gc,還存活的對象,就被移入倖存空間裏,已失效的對象則被移除。 
Old 老對象存儲的空間。這些對象應該是長期存活並且在較長一段時間內不會變化的內容。這個空間會大不少,在 ES 來講,一節點上可能就有 30GB 內存是這個空間。前面提到的 young gc 中,若是某個對象連續屢次倖存下來,就會被移進 Old 空間內。而等到 Old 空間滿,就會發生一次 old gc,把失效對象移除。 
聽起來很美好的樣子,可是這些都是有代價的!在 GC 發生的時候,JVM 須要暫停程序運行,以便本身追蹤對象圖收集所有失效對象。在這期間,其餘一切都不會繼續運行。請求沒有響應,ping 沒有應答,分片不會分配…… 
固然,young gc 通常來講執行極快,沒太大影響。可是 old 空間那麼大,稍慢一點的 gc 就意味着程序幾秒乃至十幾秒的不可用,這太危險了。 
JVM 自己對 gc 算法一直在努力優化,Elasticsearch 也儘可能複用內部對象,複用網絡緩衝,而後還提供像 Doc Values 這樣的特性。但無論怎麼說,gc 性能老是咱們須要密切關注的數據,由於它是集羣穩定性最大的影響因子。 
若是你的 ES 集羣監控裏發現常常有很耗時的 GC,說明集羣負載很重,內存不足。嚴重狀況下,這些 GC 致使節點沒法正確響應集羣之間的 ping ,可能就直接從集羣裏退出了。而後數據分片也隨之在集羣中從新遷移,引起更大的網絡和磁盤 IO,正常的寫入和搜索也會受到影響。服務器

集羣更新節點配置

  • 剛上線的服務,最近一再的更新基礎配置(硬盤)
1. 關閉分片自動均衡 PUT /_cluster/settings { "transient" : { "cluster.routing.allocation.enable" : "none" } } 2). 升級重啓該節點,並確認該節點從新加入到了集羣中 3). 其餘節點重複第2步,升級重啓。 4. 最後全部節點配置更新完成後,重啓集羣的shard均衡 curl -XPUT http://192.168.1.2/_cluster/settings -d' { "transient" : { "cluster.routing.allocation.enable" : "all" } }' 

 

Grafana 監控ES

Kibana 2.x

  • Sence
  • Marvel
  • 5.x 版本( x-pack )
相關文章
相關標籤/搜索