45

我问是因为我们的搜索在我们解决问题时处于不断变化的状态,但是每次我们对索引进行更改(更改标记器或过滤器,或分片/副本的数量)时,我们都必须删除整个索引并将我们所有的 Rails 模型重新索引到 Elasticsearch 中……这意味着我们必须考虑停机时间来重新索引所有记录。

有没有我不知道的更聪明的方法来做到这一点?

4

4 回答 4

71

我认为@karmi 是对的。但是,让我解释一下简单一点。我需要偶尔使用一些新属性或分析设置升级生产模式。我最近开始使用下面描述的场景来进行实时、恒定负载、零停机时间的索引迁移。您可以远程执行此操作。

以下是步骤:

假设:

  • 你有 indexreal1和 aliases real_writereal_read指向它,
  • 客户端只写入real_write和读取real_read
  • _source文档的属性可用。

1. 新索引

real2使用您选择的新映射和设置创建索引。

2. Writer别名切换

使用以下批量查询开关写入别名。

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_write" } },
        { "add" : { "index" : "real2", "alias" : "real_write" } }
    ]
}'

这是原子操作。从此时起real2,所有节点上的新客户端数据都将被填充。读者仍然使用旧的real1via real_read。这是最终的一致性。

3.旧数据迁移

数据必须从 迁移real1到,但是不能用旧条目覆盖其中的real2新文档。real2迁移脚本应使用bulk带有操作的 API create(不是indexupdate)。我使用具有良好 ETA 状态的简单 Ruby 脚本es-reindex :

$ ruby es-reindex.rb http://esserver:9200/real1 http://esserver:9200/real2

UPDATE 2017您可以考虑使用新的Reindex API而不是使用脚本。它具有许多有趣的功能,例如冲突报告等。

4.阅读器别名切换

现在real2是最新的,客户正在写入它,但他们仍在读取real1. 让我们更新阅读器别名:

curl -XPOST 'http://esserver:9200/_aliases' -d '
{
    "actions" : [
        { "remove" : { "index" : "real1", "alias" : "real_read" } },
        { "add" : { "index" : "real2", "alias" : "real_read" } }
    ]
}'

5.备份和删除旧索引

写入和读取转到real2real1您可以从 ES 集群中备份和删除索引。

完毕!

于 2013-07-03T11:15:23.460 回答
30

是的,有更聪明的方法可以在不停机的情况下重新索引数据。

首先,永远不要使用“最终”索引名称作为您的真实索引名称。因此,如果您想将索引命名为“articles”,请不要将该名称用作物理索引,而是创建一个索引,例如“articles-2012-12-12”或“articles-A”、“articles” -1”等。

其次,创建一个指向该索引的别名“alias”。然后,您的应用程序将使用此别名,因此您永远不需要手动更改索引名称、重新启动应用程序等。

第三,当您想要或需要重新索引数据时,将它们重新索引到不同的索引中,比如说“articles-B”——Tire 的索引工具链中的所有工具都支持您。

完成后,将别名指向新索引。这样,您不仅可以最大程度地减少停机时间(没有任何停机时间),而且还拥有一个安全的快照:如果您以某种方式将索引弄乱到新索引中,您可以切换回旧索引,直到您解决问题。

于 2012-12-13T09:21:29.297 回答
3

写了一篇关于我最近如何在没有停机的情况下处理重新索引的博客文章。需要一些时间来弄清楚需要到位的所有小事情。希望这可以帮助!

https://summera.github.io/infrastructure/2016/07/04/reindexing-elasticsearch.html

总结一下:

第 1 步:准备新索引

使用新映射创建新索引。这可以在同一个 Elasticsearch 实例上,也可以在一个全新的实例上。

第 2 步:使索引保持最新

在重新编制索引时,您希望使新旧索引都保持最新。对于写操作,这可以通过将写操作发送到新旧索引上的后台工作人员来完成。

删除有点棘手,因为在删除记录和将记录重新索引到新索引之间存在竞争条件。因此,您需要跟踪在重新索引期间需要删除的记录,并在完成后处理这些记录。如果您没有执行多次删除,另一种方法是在重新索引期间消除删除的可能性。

第 3 步:执行重新索引

您需要使用滚动搜索来读取数据并使用批量 API进行插入。由于在第 2 步之后,您将在后台将新的和更新的文档写入新索引,因此您要确保不会使用批量 API 请求更新新索引中的现有文档。

这意味着您希望批量 API 请求的操作是创建,而不是索引。来自文档:“如果已经存在具有相同索引和类型的文档,则创建将失败,而索引将根据需要添加或替换文档”。这里的要点是您不希望滚动搜索快照中的旧数据覆盖新索引中的新数据。

github 上有一个很棒的脚本可以帮助您完成这个过程:es-reindex

第 4 步:切换

完成重新索引后,就该将搜索切换到新索引了。您需要重新打开删除或处理新索引的排队删除作业。您可能会注意到搜索新索引一开始有点慢。这是因为 Elasticsearch 和 JVM 需要时间来预热。

执行您需要的任何代码更改,以便您的应用程序开始搜索新索引。如果遇到问题并需要回滚,您可以继续写入旧索引。如果您觉得这是不必要的,您可以停止写信给它。

第 5 步:清理

此时您应该完全过渡到新索引。如果一切顺利,请执行任何必要的清理工作,例如:

  • 如果旧索引主机与新索引主机不同,则删除它
  • 删除与旧索引相关的序列化代码
于 2016-07-07T15:30:59.527 回答
2

也许创建另一个索引,并将所有数据重新索引到该索引上,然后在重新索引完成后进行切换?

于 2012-12-13T00:26:41.290 回答