2024-03-13
原文作者:吴声子夜歌 原文地址: https://blog.csdn.net/cold___play/article/details/133873358

1、乐观并发控制

Elasticsearch是分布式的,创建、更新或删除文档时,必须将 文档的新版本复制到集群中的其他节点。Elasticsearch也是异步和并发的,这意味着这些复制请求是并行发送的,并且可能不按顺序到 达目的地。Elasticsearch需要一种方法来确保旧版本的文档永远不 会覆盖新版本的文档。

为了确保旧版本的文档不会覆盖新版本文档,对文档执行的每个 操作都由主分片分配一个序列号,序列号随着每个操作的增加而增 加,因此新操作的序列号肯定比旧操作的序列号更高。然后, Elasticsearch可以使用这个序列号来确保新的文档版本不会被分配 了较小序列号的更改覆盖。

例如,以下索引命令将创建一个文档并为其分配初始序列号 _seq_no_primary_term ( _primary_term 和 _seq_no 都是整 数),每当主分片发生重新分配时,比如重启、Primary选举等, _primary_term会递增1:

    PUT products/_doc/1
    {
      "product":"r2d2",
      "details":"A resourceful astromech droid"
    }

在响应中包括分配的_seq_no和_primary_term:

    {
      "_index" : "products",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "result" : "created",
      "_shards" : {
        "total" : 2,
        "successful" : 1,
        "failed" : 0
      },
      "_seq_no" : 0,
      "_primary_term" : 1
    }

Elasticsearch 跟 踪 上 次 操 作 的_seq_no_primary_term, 以 更改其存储的每个文档。在GET API的响应中,会在_seq_no和 _primary_term字段中返回:

    GET products/_doc/1
    {
      "_index" : "products",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 1,
      "_seq_no" : 0,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "product" : "r2d2",
        "details" : "A resourceful astromech droid"
      }
    }

搜索API可以通过设置seq_no_primary_term参数返回每个命中 文档的_seq_no和_primary_term:

    GET products/_search
    {
      "seq_no_primary_term":true,
      "query": {
        "match": {
          "details": "droid"
        }
      }
    }
    {
      "took" : 5,
      "timed_out" : false,
      "_shards" : {
        "total" : 1,
        "successful" : 1,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : {
          "value" : 1,
          "relation" : "eq"
        },
        "max_score" : 0.2876821,
        "hits" : [
          {
            "_index" : "products",
            "_type" : "_doc",
            "_id" : "1",
            "_seq_no" : 0,
            "_primary_term" : 1,
            "_score" : 0.2876821,
            "_source" : {
              "product" : "r2d2",
              "details" : "A resourceful astromech droid"
            }
          }
        ]
      }
    }

_seq_no和_primary_term唯一地标识一个变更。通过记下返回 的这两个值,可以确保仅在检索文档后没有对其进行其他更改的情况 下更改文档。这是通过设置索引API或删除API的if_seq_no和 if_primary_term参数来完成的。

例如,以下调用将确保向文档中添加标记tag,而不会丢失对描述 的任何潜在更改或由其他API添加其他标记:

    POST products/_update/1?if_seq_no=0&if_primary_term=1
    {
      "doc": {
        "tags": ["droid"]
      }
    }
    {
      "_index" : "products",
      "_type" : "_doc",
      "_id" : "1",
      "_version" : 2,
      "_seq_no" : 1,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
        "product" : "r2d2",
        "details" : "A resourceful astromech droid",
        "tags" : [
          "droid"
        ]
      }
    }

2、refresh参数

索引、更新、删除和批量API支持用refresh参数来控制请求所做 的更改何时对搜索可见。

允许的值如下:

  • 空或true :操作发生后立即刷新相关的主分片和副本分片(不是整个索引),以便更新的文档立即显示在搜索结果中。这个设置需要仔细考虑和验证,因为会导致性能下降(从索引和搜索的角度来看)。
  • wait_for :在返回结果之前,将等待刷新使请求所做的更改可见,这不会强 制立即刷新,而是等待刷新发生。Elasticsearch自动刷新,刷新频 率是index.refresh_interval,默认是1s。这个设置是动态的。调用 refresh API,或在响应的API上设置refresh为true都将导致刷新,请 求将返回。
  • false(默认值) :不执行与刷新相关的操作。此请求所做的更改将在请求返回后的 某个时间点可见。

2.1、如何选择refresh的值

除非有充分的理由等待更改变为可见,否则始终使用 refresh=false。

如果必须使请求所做的更改与请求同步可见,当设置refresh为 true时,Elasticsearch将增加更多负载,设置为wait_for;将等待更 长时间,这需要结合实际情况决定。

2.2、强制刷新

如果当已经有index.max_refresh_listeners值定义数量(默认 为1000个)的请求在该分片上等待刷新时,该请求的行为将如同 refresh设置为true一样:它将强制刷新。这保证了当该请求返回时,其更改对搜索可见,同时防止对被阻塞的请求使用未经检查的资源。 如果请求由于监听器槽用完而强制刷新,则其 响应将包含"forced_refresh":true信息。

批量请求只占用它们接触的每个分片上的一个槽,不管它们修改 分片多少次。

例如,如下将请求创建文档并立即刷新索引,使其可见:

    PUT /test/_doc/1?refresh
    {"test":"test"}
    PUT /test/_doc/2?refresh=true
    {"test":"test"}

如下操作都将创建一个文档,但文档不会立即可见,请求立即返 回不会等待文档可见:

    PUT /test/_doc/3
    {"test":"test"}
    PUT /test/_doc/4?refresh=fase
    {"test":"test"}

如下操作将创建一个文档,并等待其在搜索时变为可见:

    PUT /test/_doc/5?refresh=wait_for
    {"test":"test"}
阅读全文