Elasticsearch冷熱分離原理和實踐

性能與容量之間的矛盾由來已久,計算機的多級存儲體系就是其中一個經典的例子,同樣的問題在Elasticsearch中也存在。爲了保證Elasticsearch的讀寫性能,官方建議磁盤使用SSD固態硬盤。然而Elasticsearch要解決的是海量數據的存儲和檢索問題,海量的數據就意味需要大量的存儲空間,如果都使用SSD固態硬盤成本將成爲一個很大的問題,這也是制約許多企業和個人使用Elasticsearch的因素之一。爲了解決這個問題,Elasticsearch冷熱分離架構應運而生。

1. 實現原理

1.1 節點異構

傳統的Elasticsearch集羣中所有節點均採用相同的配置,然而Elasticsearch並沒有對節點的規格一致性做要求,換而言之就是每個節點可以是任意規格,當然這樣做會導致集羣各節點性能不一致,影響集羣穩定性。但是如果有規則的將集羣的節點分成不同類型,部分是高性能的節點用於存儲熱點數據,部分是性能相對差些的大容量節點用於存儲冷數據,卻可以一方面保證熱數據的性能,另一方面保證冷數據的存儲,降低存儲成本,這也是Elasticsearch冷熱分離架構的基本思想,如下圖爲一個3熱節點,2冷節點的冷熱分離Elasticsearch集羣:

其中熱節點爲16核64GB 1TB SSD盤,用於滿足對熱數據對讀寫性能的要求,冷節點爲8C32GB 5TB HDD在保證一定讀寫性能的基礎之上提供了成本較低的大存儲HDD盤來滿足冷節點對數據存儲的需求。

1.2 數據分佈

集羣節點異構後接着要考慮的是數據分佈問題,即用戶如何對冷熱數據進行標識,並將冷數據移動到冷節點,熱數據移動到熱節點。

節點指定冷熱屬性

僅僅將不同的節點設置爲不同的規格還不夠,爲了能明確區分出哪些節點是熱節點,哪些節點是冷節點,需要爲對應節點打標籤

Elasticsearch支持給節點打標籤,具體方式是在elasticsearch.yml文件中增加

node.attr.{attribute}: {value}

配置。其中attribute爲用戶自定義的任意標籤名,value爲該節點對應的該標籤的值,例如對於冷熱分離,可以使用如下設置

node.attr.temperature: hot //熱節點
node.attr.temperature: warm //冷節點

ps:中文通常叫冷熱,英文叫hot/warm

索引指定冷熱屬性

節點有了冷熱屬性後,接下來就是指定數據的冷熱屬性,來設置和調整數據分佈。冷熱分離方案中數據冷熱分佈的基本單位是索引,即指定某個索引爲熱索引,另一個索引爲冷索引。通過索引的分佈來實現控制數據分佈的目的。

Elasticsearch提供了index shard filtering功能(2.x開始),該功能在索引配置中提供瞭如下幾個配置

index.routing.allocation.include.{attribute}
Assign the index to a node whose {attribute} has at least one of the comma-separated values.

index.routing.allocation.require.{attribute}
Assign the index to a node whose {attribute} has all of the comma-separated values.

index.routing.allocation.exclude.{attribute}
Assign the index to a node whose {attribute} has none of the comma-separated values.

用戶可以在創建索引,或後續的任意時刻設置這些配置來控制索引在不同標籤節點上的分配動作。

index.routing.allocation.include.{attribute}表示索引可以分配在包含多個值中其中一個的節點上。

index.routing.allocation.require.{attribute}表示索引要分配在包含索引指定值的節點上(通常一般設置一個值)。

index.routing.allocation.exclude.{attribute}表示索引只能分配在不包含所有指定值的節點上。

數據分佈控制

Elasticsearch的索引分片分配由ShardAllocator決定,ShardAllocator通過在索引分片創建或rebalance時對每個節點調用一系列AllocationDecider來決定是否將節點分配到指定節點上,其中一個AllocationDecider是FilterAllocationDecider,該decider用於應用集羣,節點的一些基於attr的分配規則,涉及到節點級別配置的核心代碼如下

private Decision shouldIndexFilter(IndexMetaData indexMd, RoutingNode node, RoutingAllocation allocation) {
    if (indexMd.requireFilters() != null) {
        if (indexMd.requireFilters().match(node.node()) == false) {
            return allocation.decision(Decision.NO, NAME, "node does not match index setting [%s] filters [%s]",
                IndexMetaData.INDEX_ROUTING_REQUIRE_GROUP_PREFIX, indexMd.requireFilters());
        }
    }
    if (indexMd.includeFilters() != null) {
        if (indexMd.includeFilters().match(node.node()) == false) {
            return allocation.decision(Decision.NO, NAME, "node does not match index setting [%s] filters [%s]",
                IndexMetaData.INDEX_ROUTING_INCLUDE_GROUP_PREFIX, indexMd.includeFilters());
        }
    }
    if (indexMd.excludeFilters() != null) {
        if (indexMd.excludeFilters().match(node.node())) {
            return allocation.decision(Decision.NO, NAME, "node matches index setting [%s] filters [%s]",
                IndexMetaData.INDEX_ROUTING_EXCLUDE_GROUP_SETTING.getKey(), indexMd.excludeFilters());
        }
    }
    return null;
}

2 冷熱集羣搭建及使用實踐

2.1 集羣規格選型

根據業務數據量及讀寫性能要求選擇合適的冷熱節點規格

  • 存儲量計算:根據冷熱數據各自數據量及要求保留時間,計算出冷熱數據源數據量,然後使用如下公式計算出冷熱節點各自的磁盤需求量實際空間 = 源數據 * (1 + 副本數量) * (1 + 數據膨脹) / (1 - 內部任務開銷) / (1 - 操作系統預留)
    ≈ 源數據 * (1 + 副本數量) * 1.45
    ES建議存儲容量 = 源數據 * (1 + 副本數量) * 1.45 * (1 + 預留空間)
    ≈ 源數據 * (1 + 副本數量) * 2.2
  • 副本數量:副本有利於增加數據的可靠性,但同時會增加存儲成本。默認和建議的副本數量爲1,對於部分可以承受異常情況導致數據丟失的場景,可考慮設置副本數量爲0。
  • 數據膨脹:除原始數據外,ES 需要存儲索引、列存數據等,在應用編碼壓縮等技術後,一般膨脹10%。
  • 內部任務開銷:ES 佔用約20%的磁盤空間,用於 segment 合併、ES Translog、日誌等。
  • 操作系統預留:Linux 操作系統默認爲 root 用戶預留5%的磁盤空間,用於關鍵流程處理、系統恢復、防止磁盤碎片化問題等。
  • 預留空間:爲保證集羣的正常運行建議預留50%的存儲空間
  • 計算資源預估:

ES 的計算資源主要消耗在寫入和查詢過程,而不同業務場景在寫入和查詢方面的複雜度不同、比重不同,導致計算資源相比存儲資源較難評估

- 日誌場景:日誌屬於典型的寫多讀少類場景,計算資源主要消耗在寫入過程中。我們在日誌場景的經驗是:2核8GB內存的資源最大可支持0.5w/s的寫入能力,但注意不同業務場景可能有偏差。由於實例性能基本隨計算資源總量呈線性擴容,您可以按實例資源總量估算寫入能力。例如6核24GB內存的資源可支持1.5w/s的寫入能力,40核160GB內存的資源可支持10w/s的寫入能力。
- Metric 及 APM 等結構化數據場景:這也是寫多讀少類場景,但相比日誌場景計算資源消耗較小,2核8GB內存的資源一般可支持1w/s的寫入能力,您可參照日誌場景線性擴展的方式,評估不同規格實例的實際寫入能力。
- 站內搜索及應用搜索等搜索場景:此類爲讀多寫少類場景,計算資源主要消耗在查詢過程,由於查詢複雜度在不同使用場景差別非常大,計算資源也最難評估,建議您結合存儲資源初步選擇計算資源,然後在測試過程中驗證、調整。2.2 搭建集羣自建

按照選定冷熱節點規格部署服務器,搭建集羣,熱節點使用SSD盤,冷節點使用HDD盤,對熱節點elasticsearcy.yml增加如下配置

node.attr.temperature: hot 

對冷節點增加如下配置

node.attr.temperature: warm

啓動集羣,冷熱分離的Elasticsearch集羣即搭建完成

  • 購買雲ES服務

騰訊雲預計於12月中旬上線冷熱分離集羣,用戶只需要在創建頁面上根據需要即可分鐘級拉起一個冷熱分離架構的ES集羣,方便快速,擴展性好,運維成本低

  • 驗證

使用如下命令可以驗證節點冷熱屬性

GET _cat/nodeattrs?v&h=node,attr,value&s=attr:desc

node        attr        value
node1   temperature     hot
node2   temperature     hot
node3   temperature     warm
node4   temperature     hot
node5   temperature     warm
...

可以看到該集羣爲三熱二冷的冷熱分離集羣(當然要注意如果其中有專用主節點或專用協調節點這類無法分配shard的節點,即使設置了冷熱屬性也不會有分片可以分配到其上)

3. 爲索引設置冷熱屬性

業務方可以根據實際情況決定索引的冷熱屬性

  • 對於熱數據,索引設置如下
PUT hot_data_index/_settings
{
    "index.routing.allocation.require.temperature": "hot"
}
  • 對於冷數據,索引設置
PUT hot_data_index/_settings
{
    "index.routing.allocation.require.temperature": "warm"
}
  • 驗證

創建索引

PUT hot_warm_test_index
{
    "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3
    }
}

查看分片分配,可以看到分片均勻分配在五個節點上

GET _cat/shards/hot_warm_test_index?v&h=index,shard,prirep,node&s=node

index          shard prirep node
hot_data_index 1     p      node1
hot_data_index 0     r      node1
hot_data_index 2     r      node2
hot_data_index 2     p      node3
hot_data_index 1     r      node4
hot_data_index 0     p      node5

設置索引爲熱索引

PUT hot_warm_test_index/_settings
{
    "index.routing.allocation.require.temperature": "hot"
}

查看分片分配,發現分片均分配在熱節點上

GET _cat/shards/hot_warm_test_index?v&h=index,shard,prirep,node&s=node

index          shard prirep node
hot_data_index 1     p      node1
hot_data_index 0     r      node1
hot_data_index 0     p      node2
hot_data_index 2     r      node2
hot_data_index 2     p      node4
hot_data_index 1     r      node4

設置索引爲冷索引

PUT hot_warm_test_index/_settings
{
    "index.routing.allocation.require.temperature": "warm"
}

查看分片分配,發現分片均分配到冷節點上

GET _cat/shards/hot_warm_test_index?v&h=index,shard,prirep,node&s=node

index          shard prirep node
hot_data_index 1     p      node3
hot_data_index 0     r      node3
hot_data_index 2     r      node3
hot_data_index 0     p      node5
hot_data_index 2     p      node5
hot_data_index 1     r      node5

4. 索引生命週期管理

從ES6.6開始,Elasticsearch提供索引生命週期管理功能,索引生命週期管理可以通過API或者kibana界面配置,詳情參考[index-lifecycle-management], 本文僅通過kibana界面演示如何使用索引生命週期管理結合冷熱分離架構實現索引數據的動態管理。

kibana中的索引生命週期管理位置如下圖(版本6.8.2):

點擊創建create policy,進入配置界面,可以看到索引的生命週期被分爲:Hot phrase,Warm phase, Cold phase,Delete phrase四個階段

  • Hot phrase: 該階段可以根據索引的文檔數,大小,時長決定是否調用rollover API來滾動索引,詳情可以參考[indices-rollover-index],因與本文關係不大不再詳細贅述。
  • Warm phrase: 當一個索引在Hot phrase被roll over後便會進入Warm phrase,進入該階段的索引會被設置爲read-only, 用戶可以爲這個索引設置要使用的attribute, 如對於冷熱分離策略,這裏可以選擇temperature: warm屬性。另外還可以對索引進行forceMerge, shrink等操作,這兩個操作具體可以參考官方文檔。

  • Cold phrase: 可以設置當索引rollover一段時間後進入cold階段,這個階段也可以設置一個屬性。從冷熱分離架構可以看出冷熱屬性是具備擴展性的,不僅可以指定hot, warm, 也可以擴展增加hot, warm, cold, freeze等多個冷熱屬性。如果想使用三層的冷熱分離的話這裏可以指定爲temperature: cold, 此處還支持對索引的freeze操作,詳情參考官方文檔。
  • Delete phrase: 可以設置索引rollover一段時間後進入delete階段,進入該階段的索引會自動被刪除。

冷熱分離架構是Elasticsearch的經典架構之一,使用該架構用戶可以在保證熱數據良好讀寫性能的同時,仍可以存儲海量的數據,極大地豐富了ES的應用場景,解決了用戶的成本問題。再結合ES在6.6推出的索引生命週期管理,使得ES集羣在使用性和自動化方面表現出色,真正地解決了用戶在性能,存儲成本,自動化數據管理等方面的問題。

歡迎關注公衆號Elastic慕容,和我一起進入Elastic的奇妙世界吧

發佈了10 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章