背景
最近在做訂單數據存儲到ElasticSearch,考慮到數據量比較大,采用冷熱架構來存儲,每月建立一個新索引,數據先寫入到熱索引,通過工具將3個月后的索引自動遷移到冷節點上。
ElasticSearch版本:6.2.4
冷熱架構
官方叫法:熱暖架構——“Hot-Warm” Architecture。
通俗解讀:熱節點存放用戶最關心的熱數據;溫節點或者冷節點存放用戶不太關心或者關心優先級低的冷數據或者暖數據。
1.1 官方解讀冷熱架構
為了保證Elasticsearch的讀寫性能,官方建議磁盤使用SSD固態硬盤。然而Elasticsearch要解決的是海量數據的存儲和檢索問題,海量的數據就意味需要大量的存儲空間,如果都使用SSD固態硬盤成本將成為一個很大的問題,這也是制約許多企業和個人使用Elasticsearch的因素之一。為了解決這個問題,Elasticsearch冷熱分離架構應運而生。
冷熱架構是一項十分強大的功能,能夠讓您將 Elasticsearch 部署划分為“熱”數據節點和“冷”數據節點。
- 熱數據節點處理所有新輸入的數據,並且存儲速度也較快,以便確保快速地采集和檢索數據。
- 冷節點的存儲密度則較大,如需在較長保留期限內保留日志數據,不失為一種具有成本效益的方法。
將這兩種類型的數據節點結合到一起后,您便能夠有效地處理輸入數據,並將其用於查詢,同時還能在節省成本的前提下在較長時間內保留數據。此架構對日志用例來說尤其大有幫助,因為在日志用例中,人們的大部分精力都會專注於近期的日志(例如最近兩周),而較早的日志(由於合規性或者其他原因仍需要保留)則可以接受較慢的查詢時間。
1.2 典型應用場景
一句話:在成本有限的前提下,讓客戶關注的實時數據和歷史數據硬件隔離,最大化解決客戶反應的響應時間慢
的問題。業務場景描述:
每日增量6TB日志數據,高峰時段寫入及查詢頻率都較高,集群壓力較大,查詢ES時,常出現查詢緩慢問題。
- ES集群的索引寫入及查詢速度主要依賴於磁盤的IO速度,冷熱數據分離的關鍵為使用SSD磁盤存儲熱數據,提升查詢效率。
- 若全部使用SSD,成本過高,且存放冷數據較為浪費,因而使用普通SATA磁盤與SSD磁盤混搭,可做到資源充分利用,性能大幅提升的目標。
實現原理
借助 Elasticsearch的分片分配策略,確切的說是:
- 第一:集群節點層面支持規划節點類型,這是划分熱暖節點的前提。
具體方式是在elasticsearch.yml文件中增加以下配置:
node.attr.{attribute}: {value}
其中attribute為用戶自定義的任意標簽名,value為該節點對應的該標簽的值,例如對於冷熱分離,可以使用如下設置
node.attr.temperature: hot //熱節點 node.attr.temperature: cold //冷節點
- 第二:索引層面支持將數據路由到給定節點,這為數據寫入冷、熱節點做了保障。
具體方式是在創建模板或索引時指定屬性:
index.routing.allocation.include.{attribute} //表示索引可以分配在包含多個值中其中一個的節點上。
index.routing.allocation.require.{attribute} //表示索引要分配在包含索引指定值的節點上(通常一般設置一個值)。
index.routing.allocation.exclude.{attribute} //表示索引只能分配在不包含所有指定值的節點上。
實現方案
1.1 集群設計:
節點名稱 | 服務器類型 | 存儲數據 |
es-master1 | 4C 16G 1T SATA | 元數據 |
es-master2 | ||
es-master3 | ||
es-hot1 | 16C 64G 1T SSD | Hot |
es-hot2 | ||
es-hot3 | ||
es-cold1 | 8C 32G 5T SATA | Cold |
es-cold2 |
2.1 配置Master節點
-
Master1節點配置(其他節點配置類似)
[root@es-master1 ~]# cd /etc/elasticsearch/ [root@es-master1 elasticsearch]# vim elasticsearch.yml cluster.name: linuxplus node.name: es-master1.linuxplus.com node.attr.rack: r6 node.master: true node.data: false path.data: /var/lib/elasticsearch path.logs: /var/log/elasticsearch network.host: 0.0.0.0 discovery.zen.ping.unicast.hosts: ["es-master1.linuxplus.com:9300","es-master2.linuxplus.com:9300","es-master3.linuxplus.com:9300","es-hot1.linuxplus.com:9300","es-hot2.linuxplus.com:9300","es-hot3.linuxplus.com:9300","es-stale1.linuxplus.com:9300","es-stale2.linuxplus.com:9300"] discovery.zen.minimum_master_nodes: 1 bootstrap.system_call_filter: false
2.2 配置Hot節點
-
Hot1節點配置(其他節點配置類似)
[root@es-hot1 elasticsearch]# vim elasticsearch.yml cluster.name: linuxplus node.name: es-hot1.linuxplus.com # 提示:自行修改其他節點的名稱 node.attr.rack: r1 node.master: false node.data: true path.data: /var/lib/elasticsearch path.logs: /var/log/elasticsearch network.host: 10.10.10.24 # 提示:自行修改其他節點的IP discovery.zen.ping.unicast.hosts: ["es-master1.linuxplus.com:9300","es-master2.linuxplus.com:9300","es-master3.linuxplus.com:9300"] discovery.zen.minimum_master_nodes: 1 bootstrap.system_call_filter: false node.attr.hotwarm_type: hot # 標識為熱數據節點 [root@es-hot1 elasticsearch]# /etc/init.d/elasticsearch start
2.3 配置Cold節點
-
Cold1節點配置(其他節點配置類似)
[root@es-stale1 elasticsearch]# vim elasticsearch.yml cluster.name: linuxplus node.name: es-stale1.linuxplus.com # 提示:自行修改其他節點的名稱 node.attr.rack: r1 node.master: false node.data: true path.data: /var/lib/elasticsearch path.logs: /var/log/elasticsearch network.host: 10.10.10.27 # 提示:自行修改其他節點的IP discovery.zen.ping.unicast.hosts: ["es-master1.linuxplus.com:9300","es-master2.linuxplus.com:9300","es-master3.linuxplus.com:9300"] discovery.zen.minimum_master_nodes: 1 bootstrap.system_call_filter: false node.attr.hotwarm_type: cold # 標識為冷數據節點 [root@es-stale1 elasticsearch]# /etc/init.d/elasticsearch start
3.1 數據寫入
- 方案一:通過模板指定冷熱數據節點
PUT _template/order_template
{ "index_patterns": "order_*", "settings": {
"index.routing.allocation.require.hotwarm_type": "hot", # 指定默認為熱數據節點
"index.number_of_replicas": "0"
} }
注:以【order_】開頭
索引命名的,都將其數據放到hot節點上
- 方案二:通過索引指定冷熱數據節點
PUT /order_2019-12 { "settings": { "index.routing.allocation.require.hotwarm_type": "hot", # 指定為熱數據節點 "number_of_replicas": 0 } }
- 熱節點效果圖:分別創建2個索引,包含3個分片1個副本
4.1 數據遷移至冷節點
- 方案一:手工修改索引路由為:cold
ES看到有新的標記就會將這個索引自動遷移到冷數據節點中
#在kibana里操作: PUT /order_stpprdinf_2019-12/_settings { "settings": { "index.routing.allocation.require.hotwarm_type": "cold" # 指定數據存放到冷數據節點 } }
- 方案二:通過shell腳本定期遷移數據
#!/bin/bash hot數據(保留7天)遷移到cold
Time=$(date -d "1 week ago" +"%Y.%m.%d") Hostname=$(hostname) arr=("order_stpprdinf" "order_stppayinf") for var in ${arr[@]} do curl -H "Content-Type: application/json" -XPUT http://$Hostname:9200/$var_$Time/_settings?pretty -d' { "settings": { "index.routing.allocation.require.hotwarm_type": "cold" # 指定數據存放到冷數據節點 } }' done
- 方案三:通過curator定期遷移數據
步驟1:創建config.yml,填寫Elasticsearch集群配置信息。
# Rmember, leave a key empty if there is no value. None will be a string, # not a Python "NoneType" client: hosts: ["10.0.101.100", "10.0.101.101", "10.0.101.102"] port: 9200 url_prefix: use_ssl: False certificate: client_cert: client_key: ssl_no_validate: False http_auth: timeout: 30 master_only: False logging: loglevel: INFO logfile: /opt/elasticsearch-curator/logs/run.log logformat: default blacklist: ['elasticsearch', 'urllib3']
步驟2:創建action.yml
# Remember, leave a key empty if there is no value. None will be a string, # not a Python "NoneType" # # Also remember that all examples have 'disable_action' set to True. If you # want to use this action as a template, be sure to set this to False after # copying it. actions: 1: action: allocation # 這里執行操作類型為刪除索引 description: >- Apply shard allocation routing to 'require' 'tag=cold' for hot/cold node setup for logstash- indices older than 3 days, based on index_creation date. options: key: hotwarm_type # 這是es節點中定義的屬性 value: cold # 這是要更新的值,變為冷節點 allocation_type: require # 這里alloction的類型 disable_action: false filters: - filtertype: pattern kind: prefix # 這里是指匹配前綴為 “order_” 的索引,還可以支持正則匹配等,詳見官方文檔 value: order_ - filtertype: age # 這里匹配時間 source: name # 這里根據索引name來匹配,還可以根據字段等,詳見官方文檔 direction: older timestring: "%Y-%m" # 用於匹配和提取索引或快照名稱中的時間戳 unit: months # 這里定義的是months,還有days,weeks等,總時間為unit * unit_count unit_count: 3
步驟3:運行curator
單次運行:
cd /opt/elasticsearch-curator
curator --config config.yml action.yml
cron定時任務運行:
crontab -e
#添加如下配置,每天0時運行一次
0 0 */1 * * curator --config /opt/elasticsearch-curator/config.yml /opt/elasticsearch-curator/action.yml
- 遷移冷節點效果圖:
應用
因為按時間分了多個索引,查詢的時候可以跨多個索引進行查詢,打分、排序、分頁和搜單個索引沒什么區別。
/** * 查詢. * * @param indexName 索引名稱 * @param type 索引類型 * @param conditionMap 查詢條件Map * @param orderByMap 排序Map * @param page 分頁page * @return 查詢結果 */ @Override public List<Map<String, Object>> query(final String[] indexName, final String type, final Map<String, Object> conditionMap, final Map<String, String> orderByMap, final Page page) { logger.info("查詢elasticSearch數據......"); logger.info("indexName={}", Arrays.toString(indexName)); logger.info("conditionMap={}", conditionMap.toString()); logger.info("orderByMap={}", orderByMap.toString()); final long currentTimeMillis = System.currentTimeMillis(); RestHighLevelClient client = null; List<Map<String, Object>> resultList = new ArrayList<>(); try { // 1、創建連接 client = createConnect(); // 2、創建search請求 SearchRequest searchRequest = new SearchRequest(indexName); searchRequest.types(type);
這里省略幾百行代碼................ }
參考:
銘毅天下:干貨 | Elasticsearch 冷熱集群架構實戰
https://blog.51cto.com/stuart/2335120