1. 何为ES索引设计
ElasticSearch(以下简称:ES )是一个分布式、RESTful 风格的搜索和数据分析引擎。区别于传统关系型数据库(比如:MySQL、Oracle 等),ES 在定义数据模型和搜索方式上非常灵活,数据模型可以采用静态数据映射与动态数据映射,搜索方式也支持多维度类型的搜索(结构化数据、非结构化数据、地理位置、指标参数等)。如果对事务性要求不高或者事务性操作在 RDMS 端,可以考虑使用 ES 作为海量数据存储与检索分析的平台。用户在创建新索引时,可以直接写数据,所有配置走默认,收缩自如、十分灵活;也可以精细化评估,按照自己的业务需求,提前做好索引的 settings 和 mappings 的设置,未雨绸缪、尽在掌握。
针对 ES 索引设计还是有一些问题困扰着我们:
-
那么何为 ES 索引设计?
-
为什么需要提前规划,做不好索引设计又会出现什么问题?
-
如何做好 ES 索引设计,有什么需要注意的要点?
-
索引应该如何设置分片数,副本数?
-
索引大小不可预估,如何做动态拆分?
-
mapping 如何设置,有什么需要注意的?
-
以下会逐点展开,抽丝剥茧,让大家基于上述问题的解析对 ES 索引设计有一个全新的认知。
1.1 ES 索引设计
ES 索引设计主要是根据在新索引数据写入前,提前手动创建索引的配置与数据结构,以达到极致的稳定性和资源利用的最大化。一个完备的 ES 索引设计,通常会涉及以下几个点:
-
索引的存储量评估与分片数大小
-
索引的读写情况
-
索引的副本数量
-
索引的字段类型与是否可扩展
-
性能优化需要调整哪些参数
-
以上几点包含了索引层面、分片层面、字段层面的考量,后续的几个章节主要也是围绕这几点进行展开分析。
1.2 ES 索引设计可能遇到的问题
如果采用的是索引动态创建,使用的将是默认的配置。对于数据量大,业务复杂的系统,可能会出现如下问题:
分片数无法修改,数据膨胀后,导致无法使用:ES 7.x 后默认分片数为 1 ,而单个分片的存储 doc 数为 2,147,483,519 。超过则无法写入。而分片数设置后,无法修改,只能通过 reindex 进行调整,但是会有很大的性能隐患和时间成本。
影响写入性能:对于日志类的写多读少的业务类型,没必要按照默认的每秒进行 refresh 刷新,可以根据业务情况,调整为 60s 甚至 120s ,这样可以大大提升写入性能。
影响恢复性能:当集群有节点 left 集群的时候,集群需要对 unassigned shards 进行恢复,如果是默认的配置,则会在1min 后进行恢复(将宕机节点的 shards 在集群的副本进行恢复),这样会大大提升集群节点之间的 IO 操作,当本节点加入进来后,还会继续进行大量的节点间 shards 同步,会大大影响恢复进度,继而影响集群性能。如果是调高"index.unassigned.node_left.delayed_timeout"这个参数,集群则会在一段时间内不做分配,在宕机节点重启后,由宕机节点本机磁盘数据进行恢复,在大型集群调优中,能提到数倍的恢复差异。
数据结构无法更改: ES 的字段类型一旦创建无法更改,当动态映射的类型不满足业务需求时,则会出现隐患。
举例,下图是动态创建写入数据:
以上数据对应的动态映射的 settings 如下:
可以看到如果直接动态映射,很多索引级别和 mapping 级别的设置都不可控。
而静态映射,在设置的时候就能把握很多属性细节:
2. 索引Settings设计
索引的 Settings 部分主要针对的是索引和分片层面的设置,重点讨论的是索引的分片大小与分片数的评估(涉及到存储评估设置)、索引恢复设置与性能优化设置。相信了解了这些可以对索引的 Settings 设置更加游刃有余。
要点:索引大小预估、分片大小设计、shards_per_nodes、refresh、flush设置、node_left(delayed_timeout)、replicas
2.1 存储评估设置
在创建索引前,应该做一个短暂的评估,重点在于索引的业务类型、存储周期、分片配置这几块。
2.1.1 业务类型
-
写多读少
一般日志类的数据是写多读少,压力主要在写入端,且数据量很大。索引通常以日期为单位(常见的有按天、也有按周的),比如log_appcode-yyyy.mm.dd或者log_appcode-yyyy.ww。
对于写入量特别大的索引,建议使用 rollover 进行索引滚动创建管理。这样能保证单个索引存储量可控,单个分片存储也可控。动态索引的使用效果如下:
log_appcode-2021-10-01-000001
log_appcode-2021-10-01-000002
log_appcode-2021-10-01-000003
-
写少读多
除日志类外,很多业务类的数据是写少读多,也即数据产生并不是周期性的,可以根据业务和压测进行数据量来进行评估。
对于查询量大的索引,应保证查询性能优先,可以设置尽可能多的分片数,以保证请求平摊提升性能。
2.1.1.1 rollover 操作实践
a. 创建需要 rollover 的索引,并设置对应的别名 alias
PUT log_xxx-20211020-000001
{
"aliases": {
"log_xxx-alias": {
"is_write_index": true
}
}
}
b. 向别名批量插入若干数据
PUT log_xxx-alias/_bulk
{"index":{"_id":1}}
{"name":"zhangsan"}
{"index":{"_id":2}}
{"name":"lisi"}
{"index":{"_id":3}}
{"name":"wangwu"}
{"index":{"_id":4}}
{"name":"zhaoliu"}
{"index":{"_id":5}}
{"name":"qinqi"