ES索引规划方案
1.引言
《ES索引规划方案》是研发部门针对审计系统需求,对海量日志数据进行实时存储和查询的解决方案,经过不断完善整理成册,以供后续相关开发人员学习使用
1.1.术语
序号 | 用语 | 说明 |
---|---|---|
1 | 时序索引 | 以时间为轴,数据只有增加,没有变更,并且必须包含time stamp(日期时间,名称随意)字段。即按时间拆分的索引 |
2 | 索引HOT | 存放于ES中HOT数据节点的索引,最佳采用SSD磁盘,有一定分片,主要处理时序数据的实时写入 |
3 | 索引WARM | 存放于ES中WARM数据节点的索引,没有分片,常规大容量磁盘即可满足,可以用来查询,但是不再写入 |
4 | 索引DELETE | 于ES中索引的删除,即数据将被删除 |
1.2.缩略语
序号 | 原词 | 缩写 | 说明 |
---|---|---|---|
1 | Elasticsearch | ES | Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎;基于Lucene开发; |
2.规划目标
由于日志系统会产生大量的日志,特别是集群部署的情况下,更是会产生海量的日志,面对这样一个数据量级的需求,我们的数据如何存储和实现实时查询将面临一个严峻的挑战,经过对ES多方调研和超过几百亿条数据的插入和聚合查询的验证之后,总结出以下几种能够有效提升性能和解决这一问题的方案,包括从集群规划、存储策略、索引拆分、冷热分区等几个维度的优化方案,在本文中逐一介绍。
3.索引整体规划
4.索引命名规则
4.1.命名规范
索引受文件系统的限制,仅可能为小写字母,不能以下划线开头,同时还遵守以下规则:
- 不能包括 , /, *, ?, ", \<, \>, |, 空格, 逗号, #
- 7.0版本之前可以使用冒号:,但不建议使用并在7.0版本之后不再支持
- 不能以这些字符 -, \_, + 开头
- 不能包括 . 或 …
- 长度不能超过 255 个字符
这些命名限制是因为当Elasticsearch使用索引名称作为磁盘上的目录名称,这些名称必须符合不同操作系统的约定。
4.2.命名规则
系统:csbit\_logs\_audit\_tradition\_20210104\_000001
索引以:csbit\_logs\_audit\_tradition\_ 开头 当天的年.月.日即:yyyymmdd\_000001 结尾
5.索引拆分规划
Index通过横向扩展shards实现分布式存储,这样可以解决index大数据存储的问题,但在一个index变的越来越大,单个shard也越来越大,查询和存储的速度也越来越慢,更重要的是一个index其实是有存储上限的(除非你设置足够多的shards和机器),如官方声明单个shard的文档数不能超过20亿(受限于Lucene index,每个shard是一个Lucene index),考虑到I、O,面对这样一个庞大的index,我们是采用更多的shards,还是更多的index我们如何选择,index的shards总量也不宜太多,更多的shards会带来更多的I、O开销,其实答案就已经很明确,除非你能接受长时间的查询等待。为避免超大索引,提高ES查询效率,我们需要进行索引拆分
5.1.规划
Index拆分的思路很简单,时序索引有一个好处就是只有增加,没有变更,按时间累积,天然对索引的拆分友好支持,可以按照时间和数据量做任意时间段的拆分,ES提供的Rollover Api + Index Template可以非常便捷和友好的实现index的拆分工作,把单个index docs数量控制在百亿内,也就是一个index默认5个shards左右即可,保证查询的即时响应,但是因为审计日志有滞后性,我们这里不采用Rollover实现,而是利用Index Template的特性,只要索引名称符合模板匹配规则,就会套用此模板创建新的时序索引。
5.2.模板
1) 添加 es\_time 使每次写入 ES的时候会自动添加时间信息:
PUT _ingest/pipeline/add_es_time
{
"description": "add field es_time to doc",
"processors": [
{
"set": {
"field": "_source.es_time",
"value": "{{_ingest.timestamp}}"
}
}
]
}
2) 添加模板,添加模板前先确保步骤 1) 中 es\_time 已经设置
PUT _template/csbit_logs_audit_tradition_template
{
"order": 0,
"index_patterns": [
"csbit_logs_audit_tradition_*"
],
"settings": {
"index": {
"default_pipeline": "add_es_time",
"number_of_replicas": 0,
"number_of_shards": 5,
"queries": {
"cache": {
"enabled": false
}
},
"requests": {
"cache": {
"enable": false
}
}
}
},
"mappings": {
"_source": {
"enabled": true
},
"dynamic": "strict",
"properties": {
"action": {
"type": "integer"
},
"desc": {
"type": "keyword"
},
"es_time": {
"type": "date"
},
"level": {
"type": "integer"
},
"server": {
"properties": {
"ip": {
"type": "ip"
},
"port": {
"index": false,
"type": "integer"
}
}
},
"tm": {
"type": "date"
},
"web": {
"properties": {
"ip": {
"type": "ip"
},
"param": {
"type": "text"
},
"url": {
"type": "keyword"
},
"user": {
"type": "keyword"
}
}
}
}
}
}
- 根据实际需求,进行settings配置,可参考文档生命周期,部分配置,指定mapping和setting
- 索引名称必须如同 csbit\_logs\_audit\_tradition\_yyyymmdd\_000001
5.3.切分
- 索引的切分按照索引名称规范即可,因为没有使用Rollover
5.4.使用
- 因为按时间分了多个索引,查询的时候可以跨多个索引进行查询,打分、排序、分页和搜单个索引没什么区别。
6.索引生命周期
由于我们的索引是用来存储各项日志数据,日志存储是存在一定时效性(等保要求至少存储180天);因此我们将根据这一特点,自动删除日志数据,从而保证索引文件不会过多过大,同时提高日志数据查询时效性也能得到保证;
6.1.规划
索引的生命周期分为四各阶段:HOT\>WARM\>COLD\>DELETE,除HOT为必须的阶段外,其他为非必须阶段,可任意选择配置。因为日志索引只需要满足自动删除功能,所以我们只需规划日志索引的HOT、Warm和DELETE三个阶段;
- HOT阶段
HOT阶段用来写入日志数据和查询日志数据,该阶段规划将不采用ES自带的策略规则实现。因为采用ES自带策略索引名称将自动进行Rollover动作,Rollover会将关联别名的其他索引标记为不可写入动作;但实际运用中由于数据延期,很有可能写入前一天数据到上一个切分索引中。
- WARM阶段
WARM阶段用来存储相对的历史日志数据和查询日志数据,可使用手动迁移,或者自动迁移的方式: shell脚本或者curator 定期进行hot转warm动作
- DELETE阶段
DELETE阶段是用来对日志数据的删除,日志数据满足DELETE阶段的删除条件(如:超过180天的索引数据),即可配置相关策略,手动或者脚本自动进行删除索引数据
6.2.实现
操作ES 节点配置的YML文件,加入以下配置,即可指定node为冷暖阶段
- node.attr.hotwarm\_type: hot # 标识为热数据节点Hot
- node.attr.hotwarm\_type: warm # 标识为暖数据节点 Warm
- 例:
热节点
暖节点
6.3.数据写入
建立模板,或者索引时候,指定设置index.routing.allocation.require.hotwarm\_type为hot类型即可实现,数据写入到热节点中
6.3.1.方案一:通过模板指定冷热数据节点(默认采用)
- 注:以【order\_】开头索引命名的,都将其数据放到hot节点上
6.3.2.方案二:通过索引指定冷热数据节点
6.4.数据迁移至冷节点
6.4.1.手动迁移
- 在kibana里操作:
6.4.2.自动迁移
- 亦可通过shell脚本或curator定期迁移,因本项目的写入数据的实时性偏低,可根据实际情况使用
- 这里提供shell脚本方案:
7.es配置分布分片规则
- cluster.routing.allocation.awareness.attributes
根据某个属性作为分片分布规则。
设置节点属性rack\_id及属性值rack\_one
node.rack\_id: rack\_one
设置rack\_id属性作为分片分布规则
cluster.routing.allocation.awareness.attributes: rack\_id
- 可以为分片分布规则设置多个属性,例如:
cluster.routing.allocation.awareness.attributes: rack\_id,zone
- 注意:当设置了分片分布属性时,如果集群中的节点没有设置其中任何一个属性,那么分片就不会分布到这个节点中。