【问题标题】:Is there any way to guarantee that an ElasticSearch index has been deleted有什么方法可以保证 ElasticSearch 索引已被删除
【发布时间】:2019-06-13 12:01:58
【问题描述】:

在一些自动化测试中,我尝试在每次测试开始时删除并立即重新创建一个索引,使用 ElasticSearch 的高级休息客户端(版本 6.4),如下所示:

DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName);
deleteIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen());
client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);

CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName);
request.mapping("_doc", "{...}", XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);

我遇到的问题是,我的测试间歇性地在创建索引时失败,并出现错误:

{"error": {"root_cause":[{"type":"resource_already_exists_exception","reason":"index [(index-name)/(UUID)] already exists, ...,}] "status":400}

我运行的测试越多,我就越有可能看到错误,这似乎是一个强有力的指标,表明这是一个竞争条件 - 大概当我尝试重新创建索引时,之前的删除操作并不总是完成.

如果我在删除操作后立即设置断点并手动运行curl 请求以查看我试图删除的索引,我发现它仍然存在一些时间;在这些情况下,如果我继续测试,就会出现上述错误。

我尝试过断言对删除操作的响应的isAcknowledged() 方法,但它总是返回true,即使在发生错误的情况下也是如此。

我还尝试在创建操作之前进行exists() 检查。有趣的是,如果我在没有断点的情况下运行测试,exists() 检查总是返回false(即索引不存在),即使在随后会发生错误的情况下,但是如果我在创建操作之前放置了一个断点,那么exists() 检查会在发生错误的情况下返回true

我有点不知所措。据我了解,我的请求应该是同步的,从对this question 的评论来看,这应该意味着delete() 操作只有在索引确实被删除时才会返回。

我怀疑问题的关键部分可能是这些测试是在 3 个节点的集群上运行的。在设置客户端时,我只处理其中一个节点:

client = new RestHighLevelClient(RestClient.builder(new HttpHost("example.com", 9200, "https")));

但我可以看到每个操作都被复制到其他两个节点。

当我在创建操作之前停止断点时,如果索引没有被删除,我可以看到它没有在任何节点上被删除,而且似乎不管我等待多长时间,它永远不会得到已删除。

有没有什么方法可以在创建索引之前可靠地确定索引是否已被删除?或者也许我需要在尝试删除操作之前做一些事情,以保证它会成功?

【问题讨论】:

    标签: java elasticsearch automated-tests race-condition


    【解决方案1】:

    嘿,我认为有很多事情要考虑。首先,我会用 curl 或某种 rest 客户端测试所有内容,直到我开始在代码中做任何事情。可能只是在概念上对您有所帮助,但这只是我的意见。

    这是您应该考虑的一件事: “如果使用了外部版本控制变体,如果之前没有创建过索引,删除操作会自动创建索引(查看手动创建索引的创建索引 API)。” https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete.html 哪种可以解释为什么 exists() 会返回 false。因此,如果使用外部版本控制变体,则删除选项实际上会在删除之前创建一个具有相同名称的索引。

    您提到您正在使用三节点集群这一事实。你可以尝试的是: “在发出删除请求时,您可以设置 wait_for_active_shards 参数以要求在开始处理删除请求之前激活最少数量的分片副本。”这是一个超级详细的解释,当然值得一读:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards

    我建议你试试:

    curl -X DELETE 127.0.0.1:9200/fooindex?wait_for_active_shards=3
    

    您说您的集群中有 3 个节点,所以这意味着:“...索引操作将需要 3 个活动分片副本才能继续,因为集群中有 3 个活动节点,所以应该满足这一要求,每个一个持有碎片副本的人。” 根据此处的文档,此检查可能不是 100% 防水的:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html#index-wait-for-active-shards “需要注意的是,这个设置大大降低了写操作没有写入必要数量的分片副本的机会,但它并不能完全消除这种可能性,因为这个检查发生在写操作开始之前。一旦写操作正在进行中,仍有可能复制在任意数量的分片副本上失败,但在主分片上仍然成功。写操作响应的 _shards 部分显示复制成功/失败的分片副本数。所以也许可以使用这个参数,但是让你的代码检查响应以查看是否有任何操作失败。

    您还可以尝试以下方法: (我似乎找不到好的文档来支持此信息) 这应该能够告诉您集群是否尚未准备好接受删除。

    curl -X DELETE 127.0.0.1:9200/index?wait_for_completion=true
    

    【讨论】:

    • 关于外部版本控制,我对此了解不多,但我提到的exists() 检查是我在创建操作之前(在删除操作之后)放入的东西,所以我认为如果它是在测试运行之前创建或作为删除操作的一部分创建的,它不会有很大的不同。 FWIW,在这些情况下,我确信索引在删除之前就存在,所以我认为这与我的具体情况无关。
    • 我没有使用任何别名,所以我认为这不是问题,但还是个好主意 - 谢谢!
    • 最后,我喜欢您对 wait_for_active_shards 参数的建议 - 您说“请参阅此处了解更多详细信息”,但没有链接 - 您可以编辑答案以包含该参数吗?
    • 肯定会更新我对 wait_for_active_shards 选项的回答。很久以前写了一篇关于这个的文章,我想链接到但找不到。顺便说一句,很好的问题。我认为您尝试测试比赛条件很酷。基于 nosql 的应用程序存在一些有趣的竞争条件,尤其是从安全的角度来看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多