在我之前的文章 “Elasticsearch:我的 Elasticsearch 集群中应该有多少个分片?” , 它描述了在我们实际操作中的分片数量的准则。在文章 “Elasticsearch:如何部署 Elasticsearch 来满足自己的要求” 讲述了如何部署 Elasticsearch 来满足我们的搜索数据的需求。在实际的操作中,我们可能由于版本的变迁,会涉及到分片数据的变更。在今天的文章中,我们来描述一下具体的操作。
Elasticsearch 减少分片数量
当你的集群中有太多分片时并且有些分片的大小过小的时候,你可以采取一些步骤来减少分片的数量。 本文指南涵盖了删除或关闭索引以及重新索引到更大的索引中。 下面,我们将回顾如何减少新建索引的分片数量,如何减少现有索引的分片数量,如何减少主分片数量以及如何减少基于时间的索引的分片数量。
如何减少新建索引的分片数
在创建新索引时,你应该确保将新创建的分片数量配置为尽可能低的数量。
为了演示此选项,我们假设你正在运行旧版本的 Elasticsearch(v6.0 之前)并且你正在使用它来存储你的日志。 默认情况下,每个索引创建 5 个主分片。 这 5 个分片可以轻松容纳 100-250GB 的数据。 如果你知道你生成的数据量要少得多,你应该将集群的默认值调整为每个索引每 50GB 数据 1 个分片。
实现这一点的最简单方法是创建一个索引模板并将其存储在你的集群状态中。
此请求将创建一个名为 “template_1” 的索引模板。 它将应用于所有以 “log” 开头的新创建的索引名称,并将每个索引的分片数设置为 1。
PUT _index_template/template_1
{
"index_patterns": ["log*"],
"template": {
"settings": {
"index.number_of_shards": 1
}
}
}
确切的语法可能因你使用的 Elasticsearch 版本而异。 请检查这个文档。上面的 template 能够使得我们新创建的以 log 为开头的索引都具有一个分片,当然这个依赖于你具体的需求。
如何减少现有索引的分片数量
减少副本分片的数量
减少分片数量的一种简单方法是减少副本数量。 可以通过请求动态更改副本数量,只需几秒钟。
通常建议每个索引有 1 个副本分片,这样每个分片的一个副本将分配到另一个节点上(除非你有许多并行运行的搜索请求)。 副本用于故障安全,因此如果一个节点出现故障,你的数据仍然可用于搜索和存储。 它们增强集群弹性并更均匀地分配负载。
但是,如果你的集群完全过载,一个快速简单的解决方法是将副本设置为零。 如果这样做,请注意这并不理想,不应长时间保持这种状态。
此请求会将所有以 “log” 开头的索引名称的副本分片数设置为 0:
PUT log*/_settings
{
"index" : {
"number_of_replicas" : 0
}
}
减少主分片的数量
每个索引的主分片数量不能动态更改 — 它是不可变的。 用于在多个分片之间分发新文档的路由算法依赖于主分片的总数。 这就是为什么减少现有索引的主分片数量有点困难的原因。
你基本上需要创建一个新索引并将所有数据复制过来。 你可以使用 2 个 API:Shrink API 和 Reindex API。 当然,每个 API 都有自己的优点和缺点,但根据你的设置和要求,通常会有一个更理想。 Shrink API 更快,但它只能用于只读索引(不更新或插入任何文档的索引)。 Reindex API 可用于活动(active)索引。
使用 Shrink API 减少分片数量
你可以根据索引的大小将过度分片的索引缩小到 1 个或更多分片。 对于可以将索引缩小到的分片数量有非常严格的要求。 请阅读文档 “Elasticsearch:如何部署 Elasticsearch 来满足自己的要求” 以确保此选项适合您。
请记住,收缩索引时预计会有一些维护时间。 首先,一个索引的所有主分片需要分配到同一个节点。 请确保该节点上有足够的存储空间(如果没有,你可以考虑使用 Reindex API,如下所示)。 然后,需要将索引标记为只读。
此请求会将所有以 “log” 开头的索引名称的索引设置为只读,并将所有分片移动到同一节点。
PUT log*/_settings
{
"settings": {
"index.blocks.write": true,
"index.routing.allocation.require._name": "shrink_node_name"
}
}
你将需要使用此命令一个一个地缩小索引。 分片的分配将恢复为默认值,索引将再次可写。
POST log-1/_shrink/log-shrink-1
{
"settings": {
"index.routing.allocation.require._name": null,
"index.blocks.write": null
}
}
确切的语法可能因你使用的 Elasticsearch 版本而异。 请检查文档。
使用 Reindex API 减少分片数量
如果你尝试收缩的索引仍在积极写入,你可以改用 Reindex API。
Reindex API 可用于将文档从一个索引批量复制到另一个索引。 在这种情况下,所有需要在索引时间执行的工作都需要重复。 这使得使用 Reindex API 比复制整个分片要慢,但它仍然是一个相当快的过程。
Reindex API 创建索引当前状态的快照,然后复制所有这些文档。 在重建索引过程中新创建的文档将被忽略。 为了将这些新创建的文档复制到新索引,你需要使用一些确保你只创建新文档的设置来重复重建索引过程。
如果您的索引正在被积极写入并且您不能允许新索引中丢失任何文档,建议同时写入两个索引一段时间以确保没有增量。
此请求会将所有文档从名为 “log-1” 的索引复制到名为 “log-shrink-1” 的新索引。
确保应用第一部分中的索引模板。
POST _reindex
{
"source": {
"index": "log-1"
},
"dest": {
"index": "log-shrink-1",
"op_type" : "index"
}
}
第二次迭代仅添加在重建索引操作期间创建的文档:
POST _reindex
{
"source": {
"index": "log-1"
},
"dest": {
"index": "log-shrink-1",
"op_type" : "create"
}
}
减少基于时间的索引的分片数量
如果你使用基于时间的索引名称,例如用于日志记录的每日索引,并且你没有足够的数据,减少分片数量的一个好方法是切换到每周或每月模式。
你还可以按月、季度或年对旧的只读索引进行分组。 最简单的方法是使用 Reindex API。
减少多租户索引的分片数量
当你有一个多租户用例,每个客户都有一个索引时,减少分片似乎要困难得多。
在多租户情况下,你可能有几个大客户,每个索引有一个或多个分片,而且大小似乎合适。 同时,你还会有许多指数较小的客户。
如果你需要在此类设置中减少分片,同时仍需要为每个客户创建一个索引,则可以使用 Filtered Aliases。
使用 Filtered Aliases 减少分片数量
Filtered Aliases 不像普通索引别名那样广为人知,但它们允许你为一个索引创建多个视图。
你不是为每个租户或客户创建一个索引,而是为所有规模太小以至于不值得拥有自己的索引的较小租户创建一个索引。 然后添加关键字或数字字段来区分这些租户(客户名称或客户 ID)。
创建索引后,你现在可以简单地在该索引上存储过滤器并提供租户名称作为索引名称。
应用程序不会注意到你正在后台使用过滤器。 他们可以简单地使用索引名称。 但是你可以在一个索引中存储许多不同的租户并避免过度分片。
这一切都假设你正在为所有客户使用兼容的数据模型。
如何在索引上创建 Filtered Alias:
POST _aliases
{
"actions": [
{
"add": {
"index": "small-customers",
"alias": "customer-1",
"filter": {
"term": {
"customer-id": "1"
}
}
}
}
]
}
为了减少多租户环境中的分片数量,你可以为所有小租户创建一个新索引,并使用 Reindex API 简单地复制数据。 如果你需要添加一个新字段来区分租户,例如“customer-id”,你可以使用 ingest pipeline 来添加一个新字段,比如:
POST _reindex
{
"source": {
"index": "source"
},
"dest": {
"index": "dest",
"pipeline": "some_ingest_pipeline"
}
}
我们可以使用 set processor 来添加一个新的字段。