es原理

ES原理

原理

概念
  • index 邏輯命名空間,指向一個或者多個shards

  • shards index實際存儲的分片

集羣擴展時,會自動增加分片

shards分爲兩種: primary shards和replica shards。主分片和從分片

** 每一個文檔屬於一個主分片 **

從分片只是主分片的一個副本,它用於提供數據的冗餘副本,在硬件故障時提供數據保護,
同時服務於搜索和檢索這種*只讀*請求。

索引中的主分片的數量在索引創建後就固定下來了,但是從分片的數量可以隨時改變。

PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}

  • segments shards在磁盤實際存儲爲segments:以倒排索引的方式組織。

一個segments可以包含多個index的數據,它是磁盤緩衝區中的內容每秒刷到磁盤上形成的,後續還會對這些文件做一下合併。

數據從外部接收到寫入磁盤過程

segment、buffer和translog對實時性的影響
es中有一個commit文件管理物理系盤上的segments文件。新接收的數據首先到達內存,然後由內存到達磁盤緩衝區,再由磁盤緩衝區寫入磁盤segments,最後再更新commit文件。

由於寫到磁盤比較慢,這裏使用了磁盤緩衝到達準實時調試的目的,只要在磁盤緩衝區中,就可以檢索磁盤緩衝區中的segment文件

爲了防止由磁盤緩衝區寫到磁盤時候,由於一些異常引起數據丟失,es提供了translog機制來保證數據不丟失。

tanslog

保存了和內存buf一樣的內容,當內存buf中的數據在最終落盤前,translog始終存在,則當數據出現丟失的時候,從translog中恢復數據。
當數據在commit最終更新完成後,translog中的內容被刪除,即`flush`

對於 flush 操作,Elasticsearch 默認設置爲:每 30 分鐘主動進行一次 flush,或者當 translog 文件大小大於 512MB (老版本是 200MB)時,主動進行一次 flush。這兩個行爲,可以分別通過 index.translog.flush_threshold_period 和 index.translog.flush_threshold_size 參數修改。
如果對這兩種控制方式都不滿意,Elasticsearch 還可以通過 index.translog.flush_threshold_ops 參數,控制每收到多少條數據後 flush 一次。

translog可靠性保證

默認情況下,Elasticsearch 每 5 秒,或每次請求操作結束前,會強制刷新 translog 日誌到磁盤上。
後者是 Elasticsearch 2.0 新加入的特性。爲了保證不丟數據,每次 index、bulk、delete、update 完成的時候,一定觸發刷新 translog 到磁盤上,纔給請求返回 200 OK。這個改變在提高數據安全性的同時當然也降低了一點性能。

如果你不在意這點可能性,還是希望性能優先,可以在 index template 裏設置如下參數:
{
    "index.translog.durability": "async"
}

文件真正同步到磁盤上有個參數refresh_interval間隔可以設置,默認是1s,也可以設置多秒後再刷新到一次磁盤。

 curl -XPOST http://127.0.0.1:9200/logstash-2015.06.21/_settings -d'
{ "refresh_interval": "10s" }

如果是導入歷史數據的場合,那甚至可以先完全關閉掉:
 # curl -XPUT http://127.0.0.1:9200/logstash-2015.05.01 -d'
{
  "settings" : {
    "refresh_interval": "-1"
  }
}'
在導入完成以後,修改回來或者手動調用一次即可:
 # curl -XPOST http://127.0.0.1:9200/logstash-2015.05.01/_refresh
segment merge

es存入數據的本質就是”開新文件”segments

  • 帶來的問題
因爲默認每 1 秒,都會有一個新文件產生,每個文件都需要有文件句柄,內存,CPU 使用等各種資源。一天有 86400 秒,設想一下,每次請求要掃描一遍 86400 個文件,這個響應性能絕對好不了
  • 解決的方法
ES 會不斷在後臺運行任務,主動將這些零散的 segment 做數據歸併,儘量讓索引內只保有少量的,每個都比較大的,segment 文件。這個過程是有獨立的線程來進行的,並不影響新 segment 的產生。歸併過程中,尚未完成的較大的 segment 是被排除在檢索可見範圍之外的
  • 歸併程序帶來的問題
segment 歸併的過程,需要先讀取 segment,歸併計算,再寫一遍 segment,最後還要保證刷到磁盤,非常消耗磁盤IO和CPU
  • 解決方法
默認情況下,歸併線程的限速配置 indices.store.throttle.max_bytes_per_sec 是 20MB

磁盤轉速較高,甚至使用 SSD 盤的服務器來說,這個限速是明顯過低的,可以調到100m

 curl -XPUT http://127.0.0.1:9200/_cluster/settings -d'
{
    "persistent" : {
        "indices.store.throttle.max_bytes_per_sec" : "100mb"
    }
}'
  • 歸併策略
index.merge.policy.floor_segment 默認 2MB,小於這個大小的 segment,優先被歸併。
index.merge.policy.max_merge_at_once 默認一次最多歸併 10 個 segment
index.merge.policy.max_merge_at_once_explicit 默認 optimize 時一次最多歸併 30 個 segment。
index.merge.policy.max_merged_segment 默認 5 GB,大於這個大小的 segment,不用參與歸併。optimize 除外。

也加大 flush 間隔,儘量讓每次新生成的 segment 本身大小就比較大。

  • optimize 接口
默認的最大 segment 大小是 5GB,不建議增加index.merge.policy.max_merged_segment配置,這樣的結果會導致過多的index落到過大的segment文件裏,解析花費時間太多。爲了減小segment文件,還可以通過optimize選型來手動壓縮segments。 curl -XPOST http://127.0.0.1:9200/logstash-2015-06.10/_optimize?max_num_segments=1

如果一個index過大,則它必然存在於很多segments文件中,那麼檢索該index則會造成大量的資源浪費。
解決辦法,合理組織es的index方式,比如說按天索引。

寫請求如何確定數據的節點和分片

routing和replica的讀寫過程

  • 路由計算

作爲一個沒有額外依賴的簡單的分佈式方案,ES 在這個問題上同樣選擇了一個非常簡潔的處理方式,對任一條數據計算其對應分片的方式如下:
shard = hash(routing) % number_of_primary_shards

每個數據都有一個 routing 參數,默認情況下,就使用其 _id 值。將其 _id 值計算哈希後,對索引的主分片數取餘,就是數據實際應該存儲到的分片 ID。

由於取餘這個計算,完全依賴於分母,所以導致 ES 索引有一個限制,索引的主分片數,不可以隨意修改。因爲一旦主分片數不一樣,所以數據的存儲位置計算結果都會發生改變,索引數據就完全不可讀了。

  • 副本一致性

半同步機制: 當master收到寫入請求,根據hash計算出屬於的shard,找到該shard所在的主分片,主分片寫入完成後,同步給所有從分片,當一個從分片完成後,主分片所在的節點向master彙報寫入完成。

異步 replication 通過在客戶端發送請求的 URL 中加上 ?replication=async/one,該方式已經廢棄。
同步 all

timeout 如果集羣出現異常,有些分片當前不可用,ES 默認會等待 1 分鐘看分片能否恢復

shard 的 allocate 控制

某個 shard 分配在哪個節點上,一般來說,是由 ES 自動決定的。以下幾種情況會觸發分配動作

新索引生成
索引的刪除
新增副本分片
節點增減引發的數據均衡

* 節點增刪會引發數據平衡 *

es的分片控制邏輯

cluster.routing.allocation.enable   該參數用來控制允許分配哪種分片
默認是 all,包括primaries 和 new_primaries。none 則徹底拒絕分片

cluster.routing.allocation.allow_rebalance 該參數用來控制什麼時候允許數據均衡
默認是 indices_all_active,即要求所有分片都正常啓動成功以後,纔可以進行數據均衡操作,否則的話,在集羣重啓階段,會浪費太多流量了。

cluster.routing.allocation.cluster_concurrent_rebalance 該參數用來控制集羣內同時運行的數據均衡任務個數。

cluster.routing.allocation.node_initial_primaries_recoveries 該參數用來控制節點重啓時,允許同時恢復幾個主分片

cluster.routing.allocation.node_concurrent_recoveries 該參數用來控制節點除了主分片重啓恢復以外其他情況下,允許同時運行的數據恢復任務。

indices.recovery.concurrent_streams 該參數用來控制節點從網絡複製恢復副本分片時的數據流個數。

indices.recovery.max_bytes_per_sec 該參數用來控制節點恢復時的速率。
  • reroute 接口

es除了本身shard的自動選擇外,也可以手動完成對分片的分配選擇的控制,操作的方法是通過reroute接口

reroute 接口支持三種指令:allocate,move 和 cancel。常用的一般是 allocate 和 move

allocate 指令
因爲負載過高等原因,有時候個別分片可能長期處於 UNASSIGNED 狀態,我們就可以手動分配分片到指定節點上。默認情況下只允許手動分配副本分片,所以如果是主分片故障,需要單獨加一個 allow_primary 選項

 # curl -XPOST 127.0.0.1:9200/_cluster/reroute -d '{
  "commands" : [ {
        "allocate" :
            {
              "index" : "logstash-2015.05.27", "shard" : 61, "node" : "10.19.0.77", "allow_primary" : true
            }
        }
  ]
}'

注意,如果是歷史數據的話,請提前確認一下哪個節點上保留有這個分片的實際目錄,且目錄大小最大。然後手動分配到這個節點上。以此減少數據丟失。
move 指令
因爲負載過高,磁盤利用率過高,服務器下線,更換磁盤等原因,可以會需要從節點上移走部分分片
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"
            }
        }
  ]
}'
  • 節點下線

節點下線通過命令手動去m轉義每一個分片太過麻煩,這時候可以通過如下配置實現。

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 級別。

  • 冷熱數據的讀寫分離
實施方案

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"
         }
      }
  }
}
}'
這樣,寫操作集中在 N 臺熱數據節點上,大範圍的讀操作集中在 M 臺冷數據節點上。避免了堵塞影響
集羣自動發現

ES 是一個 P2P 類型(使用 gossip 協議)的分佈式系統

  • 同一個集羣配置

在無阻礙的網絡下,所有配置了相同 cluster.name 的節點都自動歸屬到一個集羣中。

  • multicast 方式

只配置 cluster.name 的集羣,其實就是採用了默認的自動發現協議,即組播(multicast)方式。
使用組播地址 224.2.2.4 ,以 54328 端口建立組播組發送 clustername 信息

Elasticsearch 2.0 開始,爲安全考慮,默認不分發 multicast 功能。依然希望使用 multicast 自動發現的用戶,需要單獨安裝:

bin/plugin install discovery-multicast

  • unicast 方式

配置裏提供幾臺節點的地址,ES 將其視作 gossip router 角色,藉以完成集羣的發現。由於這只是 ES 內一個很小的功能,所以 gossip router 角色並不需要單獨配置,每個 ES 節點都可以擔任。所以,採用單播方式的集羣,各節點都配置相同的幾個節點列表作爲 router 即可。

discovery.zen.minimum_master_nodes: 3
discovery.zen.ping.timeout: 100s
discovery.zen.fd.ping_timeout: 100s
discovery.zen.ping.multicast.enabled: false
discovery.zen.ping.unicast.hosts: ["10.19.0.97","10.19.0.98","10.19.0.99","10.19.0.100"]

配置數據查看

配置文件中,有對配置數據的描述

/usr/yupoo/app/elasticsearch/config/elasticsearch.yml

配置文件中的數據以json串的形式導入es中,通過kibana上的marvel插件,可以進行查看

集羣

  • 角色劃分

client

master

data

節點詳細介紹

  • 角色之間的差異

node.master: true/false

node.name: “1.7.5-192.168.60.13”

network.host: 192.168.60.13

node.data: true/false

discovery.zen.ping.unicast.hosts: [“192.168.60.14”, “192.168.60.15”, “192.168.60.16”, “192.168.60.17” ## 配置所有的master,如果已經是master,則排除自己

  • 節點擴容

只要第二個節點與第一個節點的 cluster.name 相同,它就能自動發現並加入到第一個節點的集羣中。如

集羣檢查

master節點執行命令

集羣普通health

GET /_cluster/health

[root@ES-ZJ-LNA-013 config]# curl 192.168.60.13:9200/_cluster/health\?pretty
{
  "cluster_name" : "elasticsearch-uplog",
  "status" : "green",
  "timed_out" : false,
  "number_of_nodes" : 25,
  "number_of_data_nodes" : 18,
  "active_primary_shards" : 8896,
  "active_shards" : 8899,
  "relocating_shards" : 0,
  "initializing_shards" : 0,
  "unassigned_shards" : 0,
  "delayed_unassigned_shards" : 0,
  "number_of_pending_tasks" : 0,
  "number_of_in_flight_fetch" : 0
}

字段解釋

status 最重要的字段,健康狀態

green 所有主分片和從分片都可用
yellow 所有主分片可用,但存在不可用的從分片
red 存在不可用的主要分片

其他字段解釋

number_of_nodes 集羣內的總節點數。
number_of_data_nodes 集羣內的總數據節點數。
active_primary_shards 集羣內所有索引的主分片總數。
active_shards 集羣內所有索引的分片總數。
relocating_shards 正在遷移中的分片數。
initializing_shards 正在初始化的分片數。
unassigned_shards 未分配到具體節點上的分片數。
level health

接口請求的時候,可以附加一個 level 參數,指定輸出信息以 indices 還是 shards 級別顯示。當然,一般來說,indices 級別就夠了。

 # curl -XGET http://127.0.0.1:9200/_cluster/health?level=indices
{
   "cluster_name": "es1003",
   "status": "red",
   "timed_out": false,
   "number_of_nodes": 38,
   "number_of_data_nodes": 27,
   "active_primary_shards": 1332,
   "active_shards": 2380,
   "relocating_shards": 0,
   "initializing_shards": 0,
   "unassigned_shards": 1
   "indices": {
      "logstash-2015.05.31": {
         "status": "green",
         "number_of_shards": 81,
         "number_of_replicas": 0,
         "active_primary_shards": 81,
         "active_shards": 81,
         "relocating_shards": 0,
         "initializing_shards": 0,
         "unassigned_shards": 0
      },
      "logstash-2015.05.30": {
         "status": "red",
         "number_of_shards": 81,
         "number_of_replicas": 0,
         "active_primary_shards": 80,
         "active_shards": 80,
         "relocating_shards": 0,
         "initializing_shards": 0,
         "unassigned_shards": 1
      },
      ...
   }
}

具體確定 unassign shard 的情況,更推薦使用 kopf 工具在頁面查看。

節點狀態監控接口

curl -XGET 127.0.0.1:9200/_nodes/stats

{
   "cluster_name": "elasticsearch_zach",
   "nodes": {
      "UNr6ZMf5Qk-YCPA_L18BOQ": {
         "timestamp": 1408474151742,
         "name": "Zach",
         "transport_address": "inet[zacharys-air/192.168.1.131:9300]",
         "host": "zacharys-air",
         "ip": [
            "inet[zacharys-air/192.168.1.131:9300]",
            "NONE"
         ],
...
索引狀態監控接口
發佈了46 篇原創文章 · 獲贊 2 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章