_seq_no和_primary_term这两个字段在Elasticsearch里的作用是什么?

它们用来实现基于乐观锁的版本控制。

Elasticsearch跟踪上次操作的序列号(sequence number)和主项(primary term),以更改它存储的每个文档。通过GET API响应信息中的_seq_no和_primary_term字段返回序列号和主项。

_primary_term

在故障转移期间,每当不同的分片成为主分片时,primary term的值就会增加。这有助于解决重新联机的旧的主分片上发生的更改,与新的主分片上发生的更改的冲突问题,一般新的主分片会获胜。

这里我们要先理解Elasticsearch的高性能和高可用机制:一个索引的数据可以存储到多个分片上,以均衡负载,提升读写性能;而每个分片(主分片)又可以有多个副本(副分片),在主分片脱机后Elasticsearch可以快速把其中一个副分片推举为新的主分片,保障Elasticsearch集群的高可用性。

副分片的primary term只是主分片更改次数的计数器。

这些primary term是递增的,并且在主分片升级时会发生变化。它们作为集群状态的一部分被持久化,因此代表了集群所在的主分片的一种“版本号”或“年代(generation)”。

为了确保文档的旧版本不会覆盖新版本,对文档执行的每个操作都由对应更改的主分片分配一个序列号。

假设你的索引由5个主分片组成(在Elasticsearch 7之前是默认的)。索引(新增文档)和更新的请求是针对主分片执行的。如果你有多个主分片,Elasticsearch能够将传入请求(例如,巨大的批量插入文档的请求)并行化/分发到多个分片,以提高性能。

因此,_primary_term字段提供了关于执行或协调更改主分片(本例中为#1、#2、#3、#4或#5)的信息。

_seq_no

序列号在Elasticsearch 6.0.0中引入。

一旦我们对primary term进行了保护,我们就添加了一个简单的计数器,并开始向每个操作发出该计数器的序列号。因此,这些序列号使我们能够理解发生在主分片上的对索引的操作。

_version字段存储了一个序列号,用于统计文档更新的次数。_seq_no字段也是一个序列号,用于统计索引上发生的操作次数。因此,如果你创建第二个文档,你将看到该文档的_seq_no和第一个文档的_seq_no有所不同。

实例

创建多个文档:

POST test/_doc/_bulk
{"index": {}}
{"test": 1}
{"index": {}}
{"test": 2}
{"index": {}}
{"test": 3}

返回响应信息:

{
  "took" : 166,
  "errors" : false,
  "items" : [
    {
      "index" : {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "d2zbSW4BJvP7VWZfYMwQ",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 0,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "eGzbSW4BJvP7VWZfYMwQ",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    },
    {
      "index" : {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "eWzbSW4BJvP7VWZfYMwQ",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 2,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

正如你所看到的:

  • 对于所有文档,版本号_version为1;
  • 对于文档1,_seq_no为0(第一次索引操作);
  • 对于文档2,_seq_no为1(第二次索引操作);
  • 对于文档3,_seq_no为2(第三次索引操作)。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注