Elasticsearch 高可用集群GitChat

高可用 Elasticsearch 集群的索引设计

2019-06-10  本文已影响26人  大尚DS

Elasticsearch 开箱即用,上手十分容易。安装、启动、创建索引、索引数据、查询结果,整个过程,无需修改任何配置,无需了解 mapping,运作起来,一切都很容易。

这种容易是建立在 Elasticsearch 在幕后悄悄为你设置了很多默认值,但正是这种容易、这种默认的设置可能会给以后带来痛苦。

例如不但想对 field 做精确查询,还想对同一字段进行全文检索怎么办?shard 数不合理导致无法水平扩展怎么办?出现这些状况,大部分情况下需要通过修改默认的 mapping,然后 reindex 你的所有数据。

这是一个很重的操作,需要很多的资源。索引设计是否合理,会影响以后集群运行的效率和稳定性。

1 分析业务

当我们决定引入 Elasticsearch 技术到业务中时,根据其本身的技术特点和应用的经验,梳理出需要预先明确的需求,包括物理需求、性能需求。

在初期应用时,由于对这两方面的需求比较模糊,导致后期性能和扩展性方面无法满足业务需求,浪费了很多资源进行调整。

希望我总结的需求方面的经验能给将要使用 Elasticsearch 的同学提供一些帮助,少走一些弯路。下面分别详细描述。

1.1 物理需求

根据我们的经验,在设计 Elasticsearch 索引之前,首先要合理地估算自己的物理需求,物理需求指数据本身的物理特性,包括如下几方面。

业务所涉及的领域对象预期有多少条记录,对 Elasticsearch 来说就是有多少 documents 需要索引到集群中。

每条数据的各个属性的物理大小是多少,比如 1k 还是 10k。

明确数据集中是否有长文本,明确长文本是否需要检索,是否可以启用压缩。Elasticsearch 建索引的过程是极其消耗 CPU 的,尤其对长文本更是如此。

明确了长文本的用途并合理地进行相关设置可以提高 CPU、磁盘、内存利用率。我们曾遇见过不合理的长文本处理方式导致的问题,此处在 mapping 设计时会专门讨论。

根据上面估算的数据总量和单条数据大小,就可以估算出预期的存储空间大小。

这里主要明确数据是以何种方式纳入 Elasticsearch 的管理,比如平稳增加、定期全量索引、周期性批量导入。针对不同的数据增量方式,结合 Elasticsearch 提供的灵活设置,可以最大化地提高系统的性能。

数据生命周期指进入到系统的数据保留周期,是永久保留、还是随着时间推移进行老化处理?老化的周期是多久?既有数据是否会更新?更新率是多少?根据不同的生命周期,合理地组织索引,会达到更好的性能和资源利用率。

1.2 性能需求

使用任何一种技术,都要确保性能能够满足业务的需求,根据上面提到的业务场景,对于 Elasticssearch 来说,核心的两个性能指标就是索引性能和查询性能。

索引性能需求

Elasticsearch 索引过程需要对待索引数据进行文本分析,之后建立倒排索引,是个十分消耗 CPU 资源的过程。

对于索引性能来说,我们认为需要明确两个指标,一个是吞吐量,即单位时间内索引的数据记录数;另一个关键的指标是延时,即索引完的数据多久能够被检索到。

Elasticsearch 在索引过程中,数据是先写入 buffer 的,需要 refresh 操作后才能被检索到,所以从数据被索引到能被检索到之间有一个延迟时间,这个时间是可配置的,默认值是 1s。这两个指标互相影响:减少延迟,会降低索引的吞吐量;反之会增加索引的吞吐量。

查询性能需求

数据索引存储后的最终目的是查询,对于查询性能需求。Elasticsearch 支持几种类型的查询,包括:

结构查询主要是回答 yes/no,结构化查询不会对结果进行相关性排序。如 terms 查询、bool 查询、range 查询等。

全文检索查询主要回答数据与查询的相关程度。如 match 查询、query_string 查询。

无论结构化查询和全文检索查询,目的都是找到某些满足条件的结果,聚合查询则不然,主要是对满足条件的查询结果进行统计分析,例如平均年龄是多少、两个 IP 之间的通信情况是什么样的。

对不同的查询来说,底层的查询过程和对资源的消耗是不同的,我们建议根据不同的查询设定不同的性能需求。

2 索引设计

此处索引设计指宏观方面的索引组织方式,即怎样把数据组织到不同的索引,需要以什么粒度建立索引,不涉及如何设计索引的 mapping。(mapping 后文单独讲)

2.1 按照时间周期组织索引

如果查询中有大量的关于时间范围的查询,分析下自己的查询时间周期,尽量按照周期(小时、日、周、月)去组织索引,一般的日志系统和监控系统都符合此场景。

按照日期组织索引,不但可以减少查询时参与的 shard 数量,而且对于按照周期的数据老化备份删除的处理也很方便,基本上相当于文件级的操作性能。

这里有必要提一下 delete_by_query,这种数据老化方式性能慢,而且执行后,底层并不一定会释放磁盘空间,后期 merge 也会有很大的性能损耗,对正常业务影响巨大。

2.2 拆分索引

检查查询语句的 filter 情况,如果业务上有大量的查询是基于一个字段 filter,比如 protocol,而该字段的值是有限的几个值,比如 HTTP、DNS、TCP、UDP 等,最好把这个索引拆成多个索引。

这样每次查询语句中就可以去掉 filter 条件,只针对相对较小的索引,查询性能会有很大提高。同时,如果需要查询跨协议的数据,也可以在查询中指定多个索引来实现。

2.3 使用 routing

如果查询语句中有比较固定的 filter 字段,但是该字段的值又不是固定的,我们建议在创建索引时,启用 routing 功能。这样,数据就可以按照 filter 字段的值分布到集群中不同的 shard,使参与到查询中的 shard 数减少很多,极大提高 CPU 的利用率。

2.4 给索引设置别名

我们强烈建议在任何业务中都使用别名,绝不在业务中直接引用具体索引!

别名是什么

索引别名就像一个快捷方式,可以指向一个或者多个索引,我个人更愿意把别名理解成一个逻辑名称。

别名的好处

对于无法预估集群规模的场景,在初期可以创建单个分片的索引 index-1,用别名 alias 指向该索引,随着业务的发展,单个分片的性能无法满足业务的需求,可以很容易地创建一个两个分片的索引 index-2,在不停业务的情况下,用 alise 指向 index-2,扩展简单至极。

业务中难免会出现需要修改索引 mapping 的情况,修改 mapping 后历史数据只能进行 reindex 到不同名称的索引,如果业务直接使用具体索引,则不得不在 reindex 完成后修改业务索引的配置,并重启服务。业务端只使用别名,就可以在线无缝将 alias 切换到新的索引。

2.5 使用 Rollover index API 管理索引生命周期

对于像日志等滚动生成索引的数据,业务经常以天为单位创建和删除索引。在早期的版本中,由业务层自己管理索引的生命周期。

在 Rollover index API 出现之后,我们可以更方便更准确地进行管理:索引的创建和删除操作在 Elasticsearch 内部实现,业务层先定义好模板和别名,再定期调用一下 API 即可自动完成,索引的切分可以按时间、或者 DOC 数量来进行。

总结

在正式接入业务数据之前进行合理的索引设计是一个必要的环节,如果偷懒图方便用最简单的方式进行业务数据接入,问题就会在后期暴露出来,那时再想解决就困难许多。

下一节我们开始介绍索引层面之下的分片设计

点击了解《高可用 Elasticsearch 集群 21 讲》

8-banner.png
上一篇 下一篇

猜你喜欢

热点阅读