vlambda博客
学习文章列表

读书笔记《elasticsearch-server-third-edition》ElasticSearch集群详细介绍

Chapter 9. Elasticsearch Cluster in Detail

上一章完全专注于搜索功能,而不仅仅是全文搜索。我们学习了如何使用 percolator——一种反向搜索,它允许我们在 Elasticsearch 之上构建改变功能。我们学会了使用 Elasticsearch 的空间功能,并使用了建议 API,它允许我们纠正用户的拼写错误并构建非常高效的自动完成功能。但现在让我们专注于运行和管理 Elasticsearch。在本章结束时,您将学习以下主题:

  • Elasticsearch 如何找到应该加入集群的新节点

  • 什么是网关和恢复模块

  • 模板如何工作

  • 如何使用动态模板

  • 如何使用 Elasticsearch 插件机制

  • Elasticsearch 中有哪些缓存以及如何调整它们

  • 如何使用更新设置 API 更新正在运行的集群上的 Elasticsearch 设置

Understanding node discovery


启动 Elasticsearch 节点时,首先发生的事情之一是寻找一个 具有相同集群名称且可见的主节点。如果找到主节点,则该节点将加入到已经形成的集群中。如果没有找到主节点,则选择节点本身作为主节点(当然,如果配置允许这种行为)。 形成集群并找到节点的过程称为发现。负责发现的模块有两个主要目的:选举主节点和发现集群中的新节点。在本节中,我们将讨论如何配置和调整发现模块。

Discovery types

默认情况下,无需安装额外的插件,Elasticsearch 允许我们使用 Zen 发现,它为我们提供 单播 发现。单播(http://en.wikipedia.org/wiki/Unicast)允许通过网络一次将单个消息传输到单个主机。 Elasticsearch 节点将消息发送到配置中定义的节点并等待响应。当节点被接受到集群中时,恢复模块将启动并在需要时启动恢复过程,如果仍然没有选举主节点,则启动主节点选举过程。

Note

在 Elasticsearch 2.0 之前,Zen 发现模块允许我们使用多播发现。在支持多播的网络上,Elasticsearch 能够自动发现节点,而无需指定共享相同集群名称的其他 Elasticsearch 服务器的任何 IP 地址。这很容易出错,不建议用于生产,因此它已被弃用并删除到插件中。

Elasticsearch 架构设计为点对点的。在进行索引或搜索等操作时,主节点不参与通信,相关节点之间直接通信。

Node roles

Elasticsearch 节点可以配置为以下角色之一:

  • Master:节点负责维护全局集群状态,改变它根据需要,处理节点的添加和 删除。单个集群中只能有一个主节点处于活动状态。

  • Data:节点 负责保存数据并执行相关数据<对节点本地存在的分片的 id="id1210" class="indexterm"> 操作(索引和搜索)。

  • Client:负责处理请求的节点。对于索引请求,客户端节点将请求转发到适当的主分片,对于< /a> 搜索请求,它将它发送到所有相关的分片并聚合结果。

默认情况下,每个节点都可以作为主节点、数据节点或客户端。例如,它可以同时是数据和客户端。在大型和高负载的集群上,划分集群中节点的角色并让节点一次只扮演一个角色是非常重要的。在处理此类集群时,您通常会看到至少三个主节点、多个数据节点和一些仅客户端节点作为整个集群的一部分。

Master node

从 Elasticsearch 集群的角度来看,它是最重要的节点类型。它处理集群状态,更改它,管理加入和离开集群的节点,检查集群中其他节点的健康状况(通过运行 ping 请求),并管理分片重定位操作。如果 master 以某种方式与集群断开连接,其余节点 将相互选择一个新的 master。所有这些过程都是根据我们提供的配置值自动完成的。您通常希望主节点仅与其他 Elasticsearch 节点通信,使用 内部 Java 通信。为避免误击主节点,建议在配置中为它们关闭 HTTP 模块。

Data node

数据节点负责保存索引中的数据。数据节点是需要最多磁盘空间的节点,因为加载了数据索引请求并在本地拥有的数据上运行搜索。类似于主节点的数据节点可以禁用 HTTP 模块。

Client node

客户端节点在大多数情况下是没有任何数据且不是主节点的节点。客户端节点是与外部世界和集群中所有节点通信的节点。他们将数据转发到适当的分片并聚合来自所有其他节点的搜索和聚合结果。

请记住, 客户端节点也可以拥有数据,但在这种情况下,它们 a> 将运行本地数据的索引请求和搜索请求,并将聚合来自其他节点的数据,这在大型集群中可能对单个节点来说工作量太大。

Configuring node roles

默认情况下,Elasticsearch 允许每个节点成为主节点、数据节点或客户端节点。但是,正如我们已经提到的,在某些情况下,您可能希望拥有仅保存数据的节点、仅用于处理请求的客户端节点以及用于 管理集群。一种这样的情况是当需要处理大量数据时,数据节点应该尽可能地高性能。为了告诉 Elasticsearch 它应该扮演什么角色,我们使用 elasticsearch.yml 配置文件中设置的三个布尔属性:

  • node.master:当设置为 true, 我们告诉 Elasticsearch 该节点是主节点,这 表示可以担任master的角色。但是,请注意,一旦为其分配了客户端角色,master 将被自动标记为不符合 master 资格。

  • node.data:当设置为true时,我们告诉 Elasticsearch 该节点可用于保存数据。

  • node.client:当设置为true时,我们告诉 Elasticsearch 该节点应该用作客户端。

因此,要将节点设置为 只保存数据,我们应该将以下属性添加到 elasticsearch.yml 配置文件:

node.master: false
node.data: true
node.client: false

要将节点设置为不保存数据而仅作为主节点,我们需要指示 Elasticsearch 我们不希望节点保存数据。为此,我们将以下属性添加到 elasticsearch.yml 配置文件中:

node.master: true
node.data: false
node.client: false

Setting the cluster's name

如果我们没有在 elasticsearch.yml 文件中设置 cluster.name 属性,Elasticsearch 使用 elasticsearch 默认值。这不是一件好事,因为每个新的 Elasticsearch 节点都将具有相同的集群名称,并且您可能希望在同一网络中拥有多个集群。在这种情况下,将错误的节点连接在一起只是时间问题。因此,我们建议将 cluster.name 属性设置为您选择的其他值。通常,根据集群职责调整集群名称是一个好主意。

Zen discovery

Elasticsearch 使用的默认发现 方法以及在 Elasticsearch 世界中常用的一种方法称为 Zen 发现。它支持单播发现并允许调整其配置的各个部分。

Note

请注意,还有其他可用作插件的发现类型,例如 Amazon EC2 发现、Microsoft Azure 发现和 Google Compute Engine 发现。

Master election configuration

假设您有一个由 10 个节点构建的集群。一切正常,直到有一天您的网络出现故障并且您的 3 个节点与集群断开连接,但它们仍然可以看到彼此。由于 Zen 发现和主节点选举过程,断开 的节点会选举一个新的主节点,您最终会得到两个同名的集群,其中两个主节点。这种情况称为脑裂,您必须尽可能避免这种情况。当发生脑裂时,您最终会得到两个(或更多)集群,这些集群在网络(或任何其他)问题得到解决之前不会相互连接。要记住的是,脑裂可能会导致不可恢复的错误,例如数据冲突,最终导致数据损坏或部分数据丢失。这就是为什么不惜一切代价避免这种情况很重要的原因。

为了防止出现脑裂情况,Elasticsearch 提供了一个 discovery.zen.minimum_master_nodes 属性。此属性定义了应相互连接以形成集群的主合格节点的最小数量。现在让我们回到我们的集群;如果我们将 discovery.zen.minimum_master_nodes 属性设置为可用节点总数的 50% + 1(在我们的例子中为 6),我们最终将得到一个集群。这是为什么?在网络故障之前,我们有10个节点,也就是6个以上的节点,这些节点组成了一个集群。在三个节点断开连接后,我们仍然可以让第一个集群启动并运行。但是,由于只有三个节点断开连接,并且三个小于六个,这三个节点将无法选举新的主节点,它们将等待与原始集群重新连接。

当然,这也不是一个完美的场景。建议只有一个专用的主合格节点,它们不能用作数据或客户端节点。在这种情况下,要获得法定人数,我们至少需要三个符合条件的专用主节点,因为这将允许我们让一个主节点离线并仍然保持法定人数。这通常足以使集群在掌握相关功能和防裂脑时保持良好状态。当然,在这种情况下, discovery.zen.minimum_master_nodes 属性应该设置为 2 我们应该有这三个主节点启动并运行。

此外,Elasticsearch 允许我们额外指定两个额外的布尔属性:discover.zen.master_election.filter_clientdiscover.zen.master_election.filter_data 。它们允许我们告诉 Elasticsearch 在主选举期间忽略来自客户端和数据节点的 ping 请求。默认情况下,第一个属性设置为 true,第二个属性设置为 false。这允许 Elasticsearch 专注于主节点选举,而不会因来自不符合主节点资格的节点的 ping 请求而过载。

除了提到的属性之外,Elasticsearch 还允许配置与主选举过程相关的超时。 discovery.zen.ping_timeout,默认为3s(三秒),允许为慢速网络配置超时——值越高,失败的机会越小,但选举过程可能需要更长的时间。第二个属性称为 discover.zen.join_timeout 并指定加入 master 请求的超时时间.它默认为 discovery.zen.ping_timeout 属性的 20 倍。

Configuring unicast

由于单播工作的 方式,我们至少需要指定单播消息应该发送到的主机。为此,我们应该将 discovery.zen.ping.unicast.hosts 属性添加到我们的 elasticsearch.yml 配置文件中。基本上,我们应该在 discovery.zen.ping.unicast.hosts 属性中指定构成集群的所有主机(我们不必指定所有主机,只需需要提供足够的东西,以便我们确定一个可以工作)。例如,如果我们想要主机 192.168.2.1192.168.2.2192.168。 2.3 对于我们的主机,我们应该通过以下方式指定前面的属性:

discovery.zen.ping.unicast.hosts: 192.168.2.1:9300, 192.168.2.2:9300, 192.168.2.3:9300

还可以定义 Elasticsearch 可以使用的端口范围。例如,要说可以使用从 93009399 的端口,我们指定以下内容:

discovery.zen.ping.unicast.hosts: 192.168.2.1:[9300-9399], 192.168.2.2:[9300-9399], 192.168.2.3:[9300-9399]

请注意,主机用逗号分隔,我们已经指定了我们期望单播消息的端口。

Fault detection ping settings

除了前面讨论的设置,我们还可以控制或更改默认 ping 配置。 Ping 是节点之间发送的信号,用于检查它们是否正在运行和响应。主节点 ping 集群中的所有其他节点, 集群中的每个其他节点都 ping 主节点。可以设置以下属性:

  • discovery.zen.fd.ping_interval:默认为 1s(一秒)并指定 节点经常互相ping通

  • discovery.zen.fd.ping_timeout:默认为 30s(30 秒)并定义节点等待在将节点 视为无响应之前响应其 ping 消息

  • discovery.zen.fd.ping_retries:默认为 3 并指定应该重试多少次 在考虑节点不工作之前采取

如果您的网络遇到一些问题,或者您知道您的节点需要更多时间才能看到 ping 响应,您可以将前面的值调整为适合您的 部署。

Cluster state updates control

正如我们已经讨论过的,主节点负责处理集群状态的变化,而 Elasticsearch 允许我们控制该过程。对于大多数用例,默认设置就足够了,但您可能会遇到需要更改设置的情况。

主节点一次处理一个集群状态命令。首先主节点将更改传播到其他节点,然后等待响应。直到有足够多的节点向主节点响应并确认后,才认为每个集群状态更改都已完成。需要响应的节点数量由我们已经知道的 discovery.zen.minimum_master_nodes, 指定。 Elasticsearch 节点等待节点响应的最长时间默认为 30s,由 discovery.zen.commit_timeout 指定财产。如果没有足够的节点响应主节点,则拒绝集群状态更改。

一旦有足够多的节点响应主发布消息,主节点上就会接受集群状态更改并更改集群状态。一旦完成,主节点会向所有节点发送一条消息,说明可以应用更改。此消息的超时再次设置为 30 秒,并使用 discovery.zen.publish_timeout 属性进行控制。

Dealing with master unavailability

如果集群没有主节点,无论是什么原因,它都不能完全运行。默认情况下,我们无法更改元数据,集群范围的命令将不起作用,等等。 Elasticsearch allows us to configure the behavior of the nodes when the master node is not elected.为此,我们可以使用 discovery.zen.no_master_block 属性来设置 all。将此属性设置为 all 表示该节点上的所有操作都将被拒绝,即搜索操作、写相关操作以及集群范围的操作,如健康或映射检索。将此属性设置为 write 意味着只有写操作会被拒绝——这是 Elasticsearch 的默认行为。

Adjusting HTTP transport settings

在讨论 节点发现模块和流程时,我们提到了一些HTTP模块次。我们现在想回到那个话题,讨论一些在讨论和使用 Elasticsearch 时有用的属性。

Disabling HTTP

首先是完全禁用 HTTP。这有助于确保主节点和数据节点一般不会接受任何 查询或来自用户的请求。要完全禁用 HTTP 传输,我们只需在 elasticsearch.ymlhttp.enabled 属性并将其设置为 false > 文件。

HTTP port

Elasticsearch 允许我们 定义它将监听 HTTP 请求的端口。这是通过使用 http.port 属性来完成的。默认为 9200-9300,这意味着 Elasticsearch 将从 9200 端口开始,如果端口不可用则增加(因此下一个实例将使用 9201 端口等)。还有 http.publish_port, 在防火墙后面运行 Elasticsearch 和 HTTP 端口不可直接访问时非常有用。它定义连接到 Elasticsearch 的客户端应该使用哪个端口,并默认为与 http.port 属性相同的值。

HTTP host

我们还可以定义 Elasticsearch 将绑定到的主机。要指定它,我们需要定义 http.host 属性。默认值为网络模块设置的值。如果需要,我们可以分别设置发布主机和使用http.publish_host和<代码类="literal">http.bind_host 属性。您通常不必指定这些属性,除非您的节点具有非标准主机名或多个名称,并且您希望 Elasticsearch 仅绑定到一个。

您可以在 https://www.elastic.co/guide/en/elasticsearch/reference/2.2/modules- http.html

The gateway and recovery modules


除了我们的 索引和其中索引的数据之外,Elasticsearch 需要保存元数据,例如类型映射、索引级别设置等。此信息需要保存在某个地方,以便在集群恢复期间可以读取。当然,它可以存储在 内存中,但是完全集群重启或致命故障会< /a> 导致此信息丢失,这不是我们想要的。这就是 Elasticsearch 引入网关模块的原因。您可以将其视为集群数据和元数据的安全天堂。每次启动集群时,都会从网关读取所有需要的数据,当您对集群进行更改时,它会使用网关模块进行持久化。

The gateway

为了设置我们要使用的网关的类型,我们需要添加gateway.type elasticsearch.yml 配置文件的属性并将其设置为本地值。目前,Elasticsearch 推荐使用本地网关类型(gateway.type 设置为 local),这是默认的,也是唯一的一种无需额外插件即可使用。

默认本地网关类型将索引及其元数据存储在本地文件系统中。与其他网关相比,这个网关的写操作不是异步执行的,所以只要写成功,就可以确定数据已经写入网关(所以基本上是索引或存储在事务日志中) .

Recovery control

除了选择网关类型之外,Elasticsearch 还允许我们配置何时开始初始恢复过程。恢复是初始化所有分片和副本的过程,从事务日志中读取所有数据,并将它们应用到分片上。基本上,这是启动 Elasticsearch 所需的一个过程。

例如,假设我们有一个由 10 个 Elasticsearch 节点组成的集群。我们应该通过将 gateway.expected_nodes 设置为那个值来通知 Elasticsearch 节点的数量,在我们的例子中是 10。我们通知 Elasticsearch 有资格保存数据并有资格被选为主节点的预期节点数量。如果集群中的节点数等于该属性,Elasticsearch 将立即启动恢复过程。

我们还想在六个节点在一起后开始恢复。为此,我们应该将 gateway.recover_after_nodes 属性设置为 6。此属性应设置为确保最新版本的集群状态快照可用的值,这通常意味着您应该在大多数节点可用时开始恢复。

还有一件事。我们希望网关恢复过程在 gateway.recover_after_nodes 条件满足 5 分钟后开始。为此,我们将 gateway.recover_after_time 属性设置为 5m。此属性告诉网关模块在节点数达到 gateway.recovery_after_nodes 属性指定的最小值后等待恢复过程的时间。我们可能想要这样做,因为我们知道我们的网络非常慢并且我们希望节点通信稳定。请注意,如果构成集群的主节点和数据合格节点的数量等于 gateway.expected_nodes 属性的值,则 Elasticsearch 不会延迟恢复。

上述属性值应在 elasticsearch.yml 配置文件中设置。例如:如果我们希望 在提到的文件中具有前面讨论的值,我们将在文件中得到以下部分:

gateway.recover_after_nodes: 6
gateway.recover_after_time: 5m
gateway.expected_nodes: 10

Additional gateway recovery options

除了上述选项之外,Elasticsearch 还允许我们进行一定程度的额外控制。这些额外的 选项是:

  • gateway.recover_after_master_nodes:这类似于 gateway_recover_after_nodes 属性,但没有考虑所有 nodes,它允许我们指定在恢复开始之前集群中应该存在多少主合格节点

  • gateway.recover_after_data_nodes:这也类似于 gateway_recover_after_nodes 属性,但它允许指定多少个数据节点 应该在恢复开始之前存在于集群中

  • gateway.expected_master_nodes:这类似于 gateway.expected_nodes 属性,但不是指定我们需要的所有节点的数量期望在集群中,它允许指定我们期望存在多少个符合条件的主节点

  • gateway.expected_master_nodes:这类似于 gateway.expected_nodes 属性,但允许指定我们 预计会出现

  • gateway.expected_data_nodes:这个也类似于gateway.expected_nodes 属性,但允许指定我们期望存在多少数据节点

Indices recovery API

在恢复过程中还有另外一个——索引恢复API。它使我们能够看到索引或索引恢复的过程。要使用它,我们只需要指定索引并使用 _recovery 端点。例如,要检查 library 索引的恢复过程,我们将运行以下命令:

curl -XGET 'localhost:9200/library/_recovery?pretty'

前面命令的响应可能很大,并且取决于索引中的分片数量,当然还有我们想要获取信息的索引数量。在我们的例子中,响应如下所示(我们留下了有关单个分片的信息以使其不那么广泛):

{
  "library" : {
    "shards" : [ {
      "id" : 0,
      "type" : "STORE",
      "stage" : "DONE",
      "primary" : true,
      "start_time_in_millis" : 1444030695956,
      "stop_time_in_millis" : 1444030695962,
      "total_time_in_millis" : 5,
      "source" : {
        "id" : "Brt5ejEVSVCkIfvY9iDMRQ",
        "host" : "127.0.0.1",
        "transport_address" : "127.0.0.1:9300",
        "ip" : "127.0.0.1",
        "name" : "Puff Adder"
      },
      "target" : {
        "id" : "Brt5ejEVSVCkIfvY9iDMRQ",
        "host" : "127.0.0.1",
        "transport_address" : "127.0.0.1:9300",
        "ip" : "127.0.0.1",
        "name" : "Puff Adder"
      },
      "index" : {
        "size" : {
          "total_in_bytes" : 157,
          "reused_in_bytes" : 157,
          "recovered_in_bytes" : 0,
          "percent" : "100.0%"
        },
        "files" : {
          "total" : 1,
          "reused" : 1,
          "recovered" : 0,
          "percent" : "100.0%"
        },
        "total_time_in_millis" : 1,
        "source_throttle_time_in_millis" : 0,
        "target_throttle_time_in_millis" : 0
      },
      "translog" : {
        "recovered" : 0,
        "total" : -1,
        "percent" : "-1.0%",
        "total_on_start" : -1,
        "total_time_in_millis" : 4
      },
      "verify_index" : {
        "check_index_time_in_millis" : 0,
        "total_time_in_millis" : 0
      }
    },
    ...
    ]
  }
}

正如您在响应中看到的,我们看到了有关每个分片的信息。对于每个分片,我们可以看到操作的类型(type 属性)、描述什么的阶段(stage 属性) 部分恢复过程正在进行中,以及是否是主分片(primary 属性) .除此之外,我们还会看到有关源分片、目标分片、分片所属索引、事务日志信息以及索引验证信息的部分。所有这些都让我们看到了我们的指数恢复的状态。

Delayed allocation

我们已经讨论过,默认情况下,Elasticsearch 会尝试根据集群中的节点数量来平衡集群中的分片。因此,当一个节点从 集群(或多个节点退出)或当节点加入集群时,Elasticsearch 开始重新平衡集群,移动分片和周围的复制品。这通常是非常昂贵的——新的主分片可能会从可用的副本中提升出来,大量的数据可能会在新的主分片和它的副本之间复制,等等。这可能是因为单个节点刚刚重新启动进行了 30 秒的维护。

为了避免这种情况,Elasticsearch 为我们提供了控制在开始分配处于未分配状态的分片之前等待多长时间的可能性。我们可以通过使用 index.unassigned.node_left.delayed_timeout 属性并根据每个索引设置它来控制延迟。例如,要将 library 索引的分配超时时间配置为 10 分钟,我们运行以下命令:

curl -XPUT 'localhost:9200/library/_settings' -d '{
 "settings": {
  "index.unassigned.node_left.delayed_timeout": "10m"
 }
}'

我们还可以通过运行以下命令为所有索引配置分配超时:

curl -XPUT 'localhost:9200/_all/_settings' -d '{
 "settings": {
  "index.unassigned.node_left.delayed_timeout": "10m"
 }
}'

Index recovery prioritization

在索引恢复过程中,Elasticsearch 2.2 公开了 一项新功能,允许我们定义在恢复时应优先考虑哪些索引。通过在索引设置中指定 index.priority 属性并为其分配一个正整数值,我们定义了 Elasticsearch 恢复索引的顺序; index.priority 属性较高的将首先启动。

例如,假设我们有两个索引,librarymap, 我们想要 library 索引要在 map 索引之前恢复。为此,我们将运行以下命令:

curl -XPUT 'localhost:9200/library/_settings' -d '{
 "settings": {
  "index.priority": 10
 }
}'
curl -XPUT 'localhost:9200/map/_settings' -d '{
 "settings": {
  "index.priority": 1
 }
}'

我们为 library 索引分配了更高的优先级,因此,它将更快地恢复。

Templates and dynamic templates


在第 2 章的映射配置部分,索引您的数据, 我们讨论了映射、它们是如何创建的以及类型确定机制是如何工作的。现在我们将进入更高级的主题。我们将向您展示如何为新索引动态创建映射以及如何将一些逻辑应用于模板,以便已经使用预定义的映射创建新索引。

Templates

在本书的各个部分 中,当讨论索引配置及其结构时,我们已经看到这会变得很复杂,尤其是当我们拥有复杂的数据结构时我们想要索引、搜索和聚合。尤其是如果你有很多相似的索引,处理每个索引中的映射可能是一个非常痛苦的过程——每个新索引都必须使用适当的映射来创建。 Elasticsearch 的创建者预测到了这一点,并实现了一项称为索引模板的功能。每个模板都定义了一个模式,该模式与新创建的索引名称进行比较。当它们都匹配时,模板中定义的值被复制到索引结构定义中。当多个模板与新创建的索引的名称匹配时,它们都将被应用,并且稍后应用的模板中的值将覆盖先前应用的模板中定义的值。这非常方便,因为我们可以在通用模板中定义一些常用设置,并在更专业的模板中更改它们。此外,还有一个 order 参数可以让我们强制执行所需的模板排序。您可以将模板视为动态映射,它不能应用于文档中的类型,而是应用于索引。

An example of a template

让我们看一个真实的 模板示例。想象一下,我们想要创建许多索引,我们不想在其中存储文档的来源,以便我们的索引更小。我们也不需要任何副本。我们可以使用 Elasticsearch REST API 和 /_template 端点创建符合我们需要的模板,方法是发送以下命令:

curl -XPUT http://localhost:9200/_template/main_template?pretty -d '{
  "template" : "*",
    "order" : 1,
    "settings" : {
    "index.number_of_replicas" : 0
  },
  "mappings" : {
    "_default_" : {
      "_source" : {
        "enabled" : false
      }
    }
  }
}'

从现在开始,所有创建的索引都没有副本,也没有存储源。这是因为模板参数值设置为 *,它匹配所有索引的名称。请注意我们示例中的 _default_ type 名称。这是一个特殊的类型名称,表示当前规则应该应用于每个文档类型。第二个有趣的事情是 order 参数。让我们使用以下命令定义第二个模板:

curl -XPUT http://localhost:9200/_template/ha_template?pretty -d '{
  "template" : "ha_*",
  "order" : 10,
  "settings" : {
    "index.number_of_replicas" : 5
  }
}'

运行前面的 命令后,除了名称以ha_。在这些索引的情况下,两个模板都被应用。首先,使用具有较低 order 值的模板,然后下一个模板覆盖副本的设置。因此,名称以 ha_ 开头的索引将存储五个副本和禁用的源。

Note

在 2.0 版本之前,Elasticsearch 模板也可以存储在文件中。从 Elasticsearch 2.0 开始,此功能不再可用。

Dynamic templates

有时 我们希望有可能定义依赖于字段名称和类型的类型。这就是动态模板可以提供帮助的地方。动态模板类似于通常的映射,但每个模板都定义了其模式,该模式应用于文档的字段名称。如果字段名称与模式匹配,则使用模板。

让我们看一下下面的例子:

curl -XPOST 'localhost:9200/news' -d '{
  "mappings" : {
    "article" : {
      "dynamic_templates" : [
        {
          "template_test": {
            "match" : "*",
            "mapping" : {
              "index" : "analyzed",
              "fields" : {
                "str": {
                  "type": "{dynamic_type}",
                  "index": "not_analyzed"
                }
              }
            }
          }
        }
      ]
    }
  }
}'

在前面的示例中,我们定义了文章类型的映射。在这个映射中,我们只有一个名为 template_test 的动态模板。由于 match 属性中的单个星号模式,此模板适用于输入文档中的每个字段。每个字段将被视为一个多字段,由一个名为原始字段的字段组成(对于 示例,title )和名称以 str 为后缀的第二个字段(例如,title.str)。第一个字段的类型由 Elasticsearch 确定(使用 {dynamic_type} 类型),第二个字段将是一个字符串(因为 string 类型)。

The matching pattern

我们有两种定义匹配模式的方法。它们如下:

  • match:如果使用此模板indexterm"> 字段匹配模式(在我们的示例中使用了此模式类型)

  • unmatch:如果字段名称与模式不匹配,则使用此模板

默认情况下,该模式非常简单并使用 glob 模式。这可以通过使用 match_pattern=regexp 进行更改。添加此属性后,我们可以使用正则表达式提供的所有魔法来匹配和unmatch模式。 path_matchpath_unmatch 等变体可用于匹配嵌套文档中的名称(通过提供路径,类似于查询)。

Field definitions

在编写 target 字段定义时,可以使用以下变量:

  • {name}:输入文档中原始字段的名称

  • {dynamic_type}:从原始文档中确定的类型

    Note

    请注意,Elasticsearch 按定义顺序检查模板,并应用第一个匹配的模板。这意味着最通用的模板(对于 示例,带有 "match": "*")必须最后定义。

Elasticsearch plugins


在本书的各个地方,我们使用了不同的插件来扩展 Elasticsearch 的核心功能。您可能还记得 Scripting 中描述的脚本中使用的其他编程语言 Elasticsearch 的功能 第 6 章让您的搜索更好。在本节中,我们将了解插件如何工作以及如何安装它们。

The basics

默认情况下,Elasticsearch 插件位于搜索引擎主目录的 plugins 子目录中自己的子目录中。如果你手动下载了一个新插件,你可以用插件名称创建一个新目录,然后将插件存档解压到这个目录。还有一种更方便的方式来安装插件:使用 plugin 脚本。我们已经在本书中多次使用它,但没有讨论它,所以这次让我们花点时间来描述一下这个工具。

Elasticsearch 有两种主要类型的插件。这两种类型可以根据plugin-descriptor.properties文件的内容进行分类:Java插件和站点插件。让我们从站点插件开始。它们通常包含 HTML、CSS 和 JavaScript 文件集,并向 Elasticsearch 添加额外的 UI 组件。 Elasticsearch 将站点插件视为一个文件集,应该由 /_plugin/plugin_name/ URL 下的内置 HTTP 服务器提供服务(例如,/_plugin/bigdesk/)。这种类型的插件不会改变核心 Elasticsearch 功能中的任何内容。

Java 插件是添加或修改核心 Elasticsearch 功能的插件。它们通常包含 JAR 文件。 plugin-descriptor.properties 文件包含有关 Elasticsearch 应用作配置插件的入口点的主类的信息 并允许他们扩展 Elasticsearch 功能。 Java 插件的好处是它们也可以包含站点部分。如果我们手动解包插件,插件的站点部分需要放在 _site 目录中。

Installing plugins

可以从三种源类型下载插件。第一个是位于 https://download.elastic.co 的官方存储库。此来源的所有插件都可以通过 引用插件名称来安装。例如:

bin/plugin install lang-javascript

前面的 命令会导致安装插件,允许我们使用额外的脚本语言 JavaScript。 Elasticsearch 会自动尝试查找与我们正在使用的 Elasticsearch 版本相同的插件版本。有时,如下例所示,插件可能会在安装过程中要求额外的权限。

为了让我们知道会发生什么,这是运行上述命令的示例结果:

-> Installing lang-javascript...
Trying https://download.elastic.co/elasticsearch/release/org/elasticsearch/plugin/lang-javascript/2.2.0/lang-javascript-2.2.0.zip ...
Downloading ...........................................................................DONE
Verifying https://download.elastic.co/elasticsearch/release/org/elasticsearch/plugin/lang-javascript/2.2.0/lang-javascript-2.2.0.zip checksums if available ...
Downloading .DONE
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@     WARNING: plugin requires additional permissions     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
* java.lang.RuntimePermission createClassLoader
* org.elasticsearch.script.ClassPermission <<STANDARD>>
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.ContextFactory
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.Callable
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.NativeFunction
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.Script
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.ScriptRuntime
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.Undefined
* org.elasticsearch.script.ClassPermission org.mozilla.javascript.optimizer.OptRuntime
See http://docs.oracle.com/javase/8/docs/technotes/guides/security/permissions.html
for descriptions of what these permissions allow and the associated risks.

Continue with installation? [y/N]y
Installed lang-javascript into /Users/someplace/elasticsearch-2.2.0/plugins/lang-javascript
Installed lang-javascript into /Users/negativ/Developer/Elastic/elasticsearch-2.2.0/plugins/lang-javascript

如果插件在第一个位置没有可用,则可以将其放置在以下 Apache Maven 存储库中:Maven 中央 (https://search.maven.org/) 或 Maven Sonatype ( https://oss.sonatype.org/)。在这种情况下,安装的 plugin 名称应该等于 groupId/artifactId/version,就像 Maven 的每个库 ( http://maven.apache.org/)。对于 示例:

bin/plugin install org.elasticsearch/elasticsearch-mapper-attachments/3.0.1

第三个来源是 GitHub (https ://github.com/) 存储库。插件工具假定给定的插件地址包含组织名称,后跟插件名称,以及可选的版本号。让我们看下面的命令示例:

bin/plugin install mobz/elasticsearch-head

如果您编写自己的插件并且无法访问前面提到的站点,则没有问题。 plugin 工具接受 url 属性,应该从该属性下载 plugin (而不是指定 plugin 的名称)。此选项允许我们为插件设置任何位置,包括本地文件系统(使用 file:// 前缀)或远程文件(使用 http:// 前缀)。例如,以下命令将导致安装一个插件,该插件存档在 /tmp/elasticsearch-lang-javascript-3.0.0.RC1.zip 中的本地文件系统中目录:

bin/plugin install file:///tmp/elasticsearch-lang-javascript-3.0.0.RC1.zip

Removing plugins

删除一个 插件就像删除它的目录一样简单。您也可以使用 plugin 工具来做到这一点。例如,要删除之前安装的 JavaScript 插件,我们运行如下命令:

bin/plugin remove lang-javascript

该命令的输出只是确认插件已被删除:

-> Removing lang-javascript...
Removed lang-javascript

Note

您需要重启 Elasticsearch 节点才能使插件安装或移除生效。

Elasticsearch caches


到目前为止,我们还没有在书中过多地提及 Elasticsearch 缓存。然而,作为最常见的系统,Elasticsearch 使用各种缓存来执行更复杂的操作或加快从基于磁盘的 Lucene 索引中检索大量数据的性能。在本节中,我们将看看 Elasticsearch 中最常见的缓存 什么它们的用途,使用它们的性能影响是什么,以及如何配置它们。

Fielddata cache

在本书的开头,我们讨论了 Elasticsearch 使用所谓的倒排索引数据结构来快速高效地搜索文档。这在搜索 和过滤数据时非常好,但是对于聚合、排序或脚本使用等功能,Elasticsearch 需要一个未倒置的数据结构,因为这些功能依赖于每个文档的数据信息。

由于需要 未反转数据,当 Elasticsearch 首次发布时,它包含并且仍然包含称为 fielddata 的内存数据结构。 Fielddata 用于将给定字段的所有值存储到内存中,以提供非常快速的基于文档的查找。但是,使用 fielddata 的成本是内存和增加的垃圾收集。由于内存和性能成本,从 Elasticsearch 2.0 开始,每个索引的、未分析的字段默认使用 doc 值。其他字段,例如分析的文本字段,仍然使用 fielddata,因此最好知道如何处理 fielddata。

Fielddata size

Elasticsearch 允许我们控制 fielddata 缓存使用多少内存。默认情况下,缓存是无界的,非常危险。如果您有大索引,您可能会遇到内存问题,其中 fielddata 缓存将占用 Elasticsearch 的大部分内存并导致节点故障。我们可以通过使用设置为显式值的静态 indices.fielddata.cache.size 属性(如 10GB)或分配给 Elasticsearch 的整个内存的百分比(如 20%)。

请记住,构建字段数据缓存非常昂贵,因为它需要将给定字段的所有值加载到内存中。这可能会花费大量时间,从而导致查询性能下降。因此,建议有足够的内存将所需的缓存永久保存在 Elasticsearch 内存中。但是,我们知道由于硬件成本,这并不总是可行的。

Circuit breakers

Elasticsearch 的好处是它允许我们以多种方式实现类似的事情, 在字段数据和限制内存方面我们也有同样的情况用法。 Elasticsearch 允许我们使用一个称为断路器的功能,它可以估计请求或查询将使用多少内存,如果超过定义的阈值,则根本不会执行,导致没有内存使用和抛出异常。当我们不想限制字段数据缓存的大小但我们也不希望单个查询导致内存问题并使集群不稳定时,这非常好。有两个主要的断路器:现场数据断路器和请求断路器。

第一个断路器,字段数据,估计将需要用于将数据加载到给定查询的 fielddata 缓存的内存量。我们可以使用 indices.breaker.fielddata.limit 属性来配置限制,默认设置为 60%,这意味着单个查询的字段数据缓存使用的内存不能超过 Elasticsearch 的 60%。

第二个断路器,请求一,估计每个请求数据结构使用的内存,并防止它们使用超过 indices.breaker.request.limit 属性指定的数量.默认情况下,上述属性设置为 40%,这意味着单个请求数据结构,例如用于聚合计算的数据结构,不能使用超过 40%分配给 Elasticsearch 的内存。

最后,还有一个由 indices.breaker.limit.total 属性定义的断路器(默认设置为 70% )。这个断路器定义了每个请求数据结构和字段数据都可以使用的内存总量。

请记住,断路器的设置是动态的,可以使用集群更新设置进行更新。

Fielddata and doc values

正如我们已经讨论过的,可以使用 doc 值代替 fielddata 缓存。当然,这仅适用于未 分析的字段以及使用数字数据类型而非多值数据类型的字段。这将节省内存,并且在查询期间应该比 fielddata 缓存更快,但代价是索引速度略有下降(非常小)和索引稍大。如果您可以使用 doc 值,那就这样做吧——它将帮助您的 Elasticsearch 集群保持稳定性并快速响应查询。

Shard request cache

对查询进行操作的第一个缓存。分片请求缓存缓存查询结果的聚合和建议,但是,在编写本书时,它并没有缓存查询命中。当 Elasticsearch 执行查询时,这个缓存可以保存查询消耗的资源,并通过从内存中检索聚合或建议来加速后续查询。

Note

在本书的编写过程中,分片请求缓存仅在查询设置了size=0参数时使用。这意味着只有命中总数、聚合结果和建议将被缓存。请记住,当运行带有日期的查询并使用 now 常量时,分片查询缓存也不会被使用。

分片请求缓存,顾名思义,缓存每个分片上的查询结果,然后将它们返回到聚合结果的节点。当您的聚合很重时,这可能非常好,例如对查询返回的数据进行大量计算的聚合。如果您对查询运行大量聚合并且可以重复查询,请考虑使用分片请求缓存,因为它应该可以帮助您减少查询延迟。

Enabling and configuring the shard request cache

分片请求 缓存默认是禁用的,但可以很容易地启用。要启用它,我们应该在 index.requests.cache.enable 属性设置为 true class="indexterm">创建索引。例如,要为名为 new_library, 的索引启用分片请求缓存,我们使用以下命令:

curl -XPUT 'localhost:9200/new_library' -d '{
 "settings": {
  "index.requests.cache.enable": true
 }
}'

要记住的一件事是,上述设置不可动态更新。我们需要将它包含在索引创建命令中,或者我们可以在索引关闭时更新它。

缓存的最大大小使用 indices.requests.cache.size 属性指定,默认设置为 1% (这意味着分配给 Elasticsearch 的总内存的 1%)。我们还可以使用 indices.requests.cache.expire 属性指定每个条目应保留多长时间,但默认情况下未设置。此外,一旦刷新索引(在索引搜索器重新打开期间),缓存就会失效,这< /a> 在大多数情况下使设置无用。

Note

请注意,在早期版本的 Elasticsearch 中,例如在 1.x 分支中,为了启用或禁用此缓存,使用了 index.cache.query.enable 属性。从旧版 Elasticsearch 迁移时,这可能很重要。

Per request shard request cache disabling

Elasticsearch 允许 我们控制基于每个请求使用的请求分片缓存。如果我们启用了上述缓存,我们仍然可以强制搜索引擎忽略此类请求的缓存。这是通过使用 request_cache 参数来完成的。如果设置为 true, 请求将被缓存,如果设置为 false, 请求将不会被缓存。当我们想要缓存我们的请求但忽略对一些罕见且不经常使用的查询的缓存时,这尤其有用。不缓存使用非确定性脚本和时间范围的请求也是明智之举。

Shard request cache usage monitoring

如果我们不使用任何 监控软件来监控缓存使用情况,我们可以使用 Elasticsearch API 来检查分片请求缓存周围的指标。这可以在索引级别或节点级别完成。

要检查所有索引的分片请求缓存的指标,我们应该使用索引统计 API 并运行以下命令:

curl 'localhost:9200/_stats/request_cache?pretty'

要检查请求缓存指标,但在每个节点视图中,我们运行以下命令:

curl 'localhost:9200/_nodes/stats/indices/request_cache?pretty'

Node query cache

节点查询缓存负责保存整个节点的查询结果。它的大小由使用indices.queries.cache.size定义,默认为10%,并且是可共享的跨节点上存在的所有分片。我们可以将其设置为 Elasticsearch 的堆内存百分比,如默认值,或显式值,如 1024mb。关于缓存要记住的一件事是它的配置是静态的,它不能动态更新,应该在 elasticsearch.yml 文件中设置。节点查询缓存使用最近最少使用的驱逐策略,这意味着,当已满时,它会删除最少使用的数据。

当您运行重复且繁重的查询时,此缓存非常有用,例如用于生成类别页面或电子商务应用程序中的主页的查询。

Indexing buffers

我们要讨论的最后一个缓存是 索引缓冲区,它允许我们提高索引吞吐量。索引缓冲区在节点上的所有分片之间划分,用于存储新索引的文档。一旦缓存填满,Elasticsearch 会将缓存中的数据刷新到磁盘,在索引中创建一个新的 Lucene 段。

有四个静态属性允许我们配置索引缓冲区大小。它们需要在 elasticsearch.yml 文件中设置,并且不能使用 Settings API 动态更改。这些属性是:

  • indices.memory.index_buffer_size:此属性定义索引缓冲区的 节点使用的内存量.它接受百分比值以及以字节为单位的显式值。默认为 10%,这意味着分配给节点的堆内存的 10% 将用作索引缓冲区.

  • indices.memory.min_index_buffer_size:此属性默认为 48mb 并指定索引缓冲区将使用的最小内存。 indices.memory.index_buffer_size 定义为百分比值时很有用,以便索引缓冲区永远不会小于此属性定义的值。

  • indices.memory.max_index_buffer_size:此属性指定索引缓冲区将使用的最大内存 .当 indices.memory.index_buffer_size 定义为百分比值时很有用,这样索引缓冲区永远不会超过一定的内存使用量。

  • indices.memory.min_shard_index_buffer_size:该属性默认为4mb< /a> 设置分配给节点上每个分片的索引缓冲区的硬性最小限制。每个分片的索引缓冲区不会低于此属性设置的值。

在索引性能方面,如果您需要更高的索引吞吐量,请考虑将索引缓冲区大小设置为高于默认大小的值。它将允许 Elasticsearch 减少将数据刷新到磁盘的频率并创建更少的段。这将导致更少的合并,从而减少 I/O 和 CPU 密集型操作。因此,Elasticsearch 将能够将更多资源用于索引目的。

When caches should be avoided

用户可能会问的常见问题 是他们是否真的应该缓存所有请求。答案很明显——当然,缓存并不是适合所有人的工具。使用缓存并不是免费的——它需要内存和额外的操作来将数据放入缓存或从中取出数据。

此外,您应该记住,主分片之间的 Elasticsearch 循环查询是副本,因此,如果您有副本,则不是第一个请求之后的每个请求都会使用缓存。想象一下,你有一个索引,它有一个主分片和两个副本。当第一个请求到来时,它会命中一个随机分片,但下一个请求,即使使用相同的查询,也会命中另一个分片,而不是同一个分片(除非使用路由)。使用缓存时应该考虑到这一点,因为如果您的查询不重复,您可能会因为使用缓存而使它们运行更长时间。

因此,要回答您是否应该使用缓存的问题,我们建议您获取数据、查询并 使用 JMeter 等工具运行性能测试(http://jmeter.apache.org)。这将让您了解您的集群在测试负载下如何处理真实数据,并查看在有或没有缓存的情况下查询是否实际上更快。

The update settings API


Elasticsearch 让 我们通过在 elasticsearch.yml 文件中指定各种参数来调整自身。但是您应该将此文件视为可以在运行时使用 Elasticsearch REST API 更改的一组默认值。我们可以更改每个索引设置和集群范围设置。但是,您应该记住,并非所有属性都可以动态更改。如果您尝试更改这些参数,Elasticsearch 会以适当的错误响应。

The cluster settings API

为了设置 集群属性之一,我们需要使用 HTTP PUT 方法并发送一个对 _cluster/settings URI 的正确请求。但是,我们有两个选择:将更改添加为瞬态或 永久。

第一个是瞬态的,只会在第一次重新启动之前设置属性。为此,我们发送以下命令:

curl -XPUT 'localhost:9200/_cluster/settings' -d '{
  "transient" : {
    "PROPERTY_NAME" : "PROPERTY_VALUE"
  }
}'

如您所见,在前面的命令中,我们使用了名为 transient 的对象,并在那里添加了我们的属性定义。这意味着该属性仅在重新启动之前有效。如果我们希望我们的属性设置在重启之间保持不变,而不是使用名为 transient 的对象,我们使用名为 persistent 的对象。

您可以随时使用以下命令获取这些设置:

curl -XGET localhost:9200/_cluster/settings

The indices settings API

为了更改与索引相关的设置,Elasticsearch 提供了 /_settings 端点来更改 所有索引的参数和 /index_name/_settings 端点,用于修改单个索引的设置。与集群范围的设置相比,使用 API 对索引所做的所有更改在 Elasticsearch 重新启动后始终保持有效。要更改所有索引的设置,我们发送以下命令:

curl -XPUT 'localhost:9200/_settings' -d '{
  "index" : {
    "PROPERTY_NAME" : "PROPERTY_VALUE"
  }
}'

可以使用以下命令列出所有索引的当前设置:

curl -XGET localhost:9200/_settings

要为单个索引设置属性,我们运行以下命令:

curl -XPUT 'localhost:9200/index_name/_settings' -d '{
  "index" : {
    "PROPERTY_NAME" : "PROPERTY_VALUE"
  }
}'

获取 library 索引的设置,我们运行 以下命令:

curl -XGET localhost:9200/library/_settings

Summary


在我们刚刚完成的那一章中,我们学到了一些关于 Elasticsearch 的非常重要的东西。首先,我们了解了如何配置节点发现机制。除此之外,我们还学会了使用恢复和网关模块来控制集群最初形成后发生的情况。我们使用动态和非动态模板来更轻松地处理我们的索引,并且我们了解了 Elasticsearch 有哪些类型的缓存以及如何控制它们。最后,我们使用更新设置 API 来更新已经存在的集群上的各种 Elasticsearch 配置变量。

在下一章中,我们将重点介绍集群管理。我们将从学习如何备份我们的数据以及如何监控关键集群指标开始。我们将看到控制集群重新平衡和分片分配的方法,我们将使用对人类友好的 Cat API,它允许我们获取有关集群的各种信息。最后,我们将学习如何预热我们的索引和混叠。