Elasticsearch集群 管理
第7章 深入Elasticsearch集群
启动一个Elasticsearch节点时,该节点会开始寻找具有相同集群名字并且可见的主节点。如 果找到主节点,该节点加入一个已经组成了的集群;如果没有找到,该节点成为主节点(如果配 置允许)。形成集群和寻找节点的过程称为发现。负责发现的模块有两个主要目的:选出一个主 节点和发现集群中的新节点。本节将讨论如何配置和优化发现模块。
7.1节点发现
7.1.1 发现的类型
默认在没有安装额外插件的情况下,Elasticsearch允许使用zen发现,它提供了多播和单播发 现。在计算机网络术语中,多播(http://en.wikipedia.org/wiki/Multicast)是指在单个传输中将消 息传递到一组计算机中。单播(http://en.wikipedia.org/wiki/Unicast)指的是一次只通过网络传输 单条消息到单个主机上。
选择多播还是单播,首先你应该知道你的网络能否处理多播消息。如果它可以,使用多播将 更简单。如果你的网络不能处理多播,请使用单播发现。另一个使用单播发现的原因是安全:不 想任何节点误加入你的集群中。所以,如果要运行多个集群,或者开发人员的计算机和集群在同 一个网络中,使用单播是更好的选择。
7.1.2主节点
我们已经看到,发现的主要目的之一就是要选择一个主节点,它将查看整个集群。主节点会 检查所有其他节点,看它们是否有响应(其他节点也ping主节点)。主节点还将接受想加入群集 的新节点。如果不知什么缘故,主节点跟集群断开连接了,其余节点将从中选择一个新的主节点。 所有这些过程都基于我们提供的配置自动完成。
1. 配置主节点和数据节点
默认情况下,Elasticsearch允许节点同时成为主节点和数据节点。但在特定情况下,你可能 希望有只保存数据的工作节点,以及只处理请求和管理集群的主节点。一种情形是当你需要处理 大量的数据,这时数据节点应该尽可能地高性能。为了把节点设置成只保存数据,需要告诉 Elasticsearch,不希望这些节点成为主节点。为此,在elasticsearch.yml配置文件中添加如下属性:
node.master: false
node.data: true
为设置节点不保存数据,而只做主节点,我们希望通知Elasticsearch不希望这些节点保存数 据。为此,在elasticsearch.yml配置文件中添加如下属性:
node.master: true
node.data: false
请注意,如果不设置的话,node.master和node.data默认都为true。但我们倾向于在配 置中包含它,这样更清晰。
2. 主节点选取的配置
【脑裂发生】
想象一下你创建了一个包含10个节点的集群。一切工作正常,直到有一天你的网络出现故障, 有三个节点从集群中断开连接,但它们仍然能互相看见对方。由于zen发现机制和主节点选取的 过程,断开的三个节点中选出了一个新的主节点,你最终有了两个名字相同的集群,各自都有一 个主节点。这样的情况称为脑裂(split-brain),你必须尽可能避免。当脑裂发生时,你有两个(或 更多)不会互相连接的集群,直到网络(或其他任何)问题得到修复。
【避免脑裂】
为了防止脑裂发生,Elasticsearch提供了discovery.zen.minimum_master_nodes属性。 该属性定义的是为了形成一个集群,有主节点资格并互相连接的节点的最小数目。现在回到我们 的集群,如果把discovery.zen.minimum_master_nodes属性设置为所有可用节点个数加1的 50%(在我们的例子中即是6),将只会有一个集群。为什么呢?因为如果网络正常,我们将有10 个节点,多于6个,这些节点将成为一个集群。3个节点断开连接后,第一个集群仍然在运行。然 而,因为只有3个断开连接,小于6个,它们将无法选出一个新的主节点,只能等待重新连回原来 的集群。
7.1.3设置集群名
如果我们不在elasticsearch.yml文件设置cluster.name属性,Elasticsearch将使用默认值: elasticsearch。这不见得很好,因此建议你设置cluster.name属性为你想要的名字。如果 你想在一个网络中运行多个集群,也必须设置cluster.name属性,否则,将导致不同集群的所 有节点都连接在一起。
1.配置多播
多播是zen发现的默认方法。除了常见的设置(很快就会讨论到)外,我们还可以控制以下 四个属性。
discovery.zen.ping.multicast.group :用于多播请求的群组地址,默认为
224.2.2.4。
discovery.zen.ping.multicast.port:用于多播通信的端口号,默认为54328。
discovery.zen.ping.multicast.ttl:多播请求被认为有效的时间,默认为3秒。
discovery.zen.ping.multicast.address:Elasticsearch应该绑定的地址。默认为
null,意味着Elasticsearch将尝试绑定到操作系统可见的所有网络接口。
要禁用多播,应在 elasticsearch.yml 文件中添加 discovery.zen.ping.multicast. enabled属性,并且把值设为false。
2.配置单播
因为单播的工作方式,我们需要指定至少一个接收单播消息的主机。为此,在elasticsearch.yml 文件中添加discovery.zen.ping.unicast.hosts属性。基本上,我们应该在discovery.zen. ping.unicast.hosts属性中指定所有形成集群的主机。指定所有主机不是必须的,只需要提 供足够多的主机以保证最少有一个能工作。如果希望指定192.168.2.1、192.168.2.2和192.168.2.3 主机,可以用下面的方法来设置上述属性:
discovery.zen.ping.unicast.hosts: 192.168.2.1:9300, 192.168.2.2:9300, 192.168.2.3:9300
你也可以定义一个Elasticsearch可以使用的端口范围,例如,从9300到9399端口,指定以下 命令行:
discovery.zen.ping.unicast.hosts: 192.168.2.1:[9300-9399], 192.168.2.2:[9300-9399], 192.168.2.3:[9300-9399]
请注意,主机之间用逗号隔开,并指定了预计用于单播消息的端口。
使用单播时,总是设置discovery.zen.ping.multicast.enabled为 false。
7.1.4节点的ping设置
除了刚刚讨论的设置,还可以控制或改变默认的ping设置。ping是一个节点间发送的信号, 用来检测它们是否还在运行以及可以响应。主节点会ping集群中的其他节点,其他节点也会ping 主节点。可以设置下面的属性。
discovery.zen.fd.ping_interval:该属性默认为1s(1秒钟),指定了节点互相ping
的时间间隔。
discovery.zen.fd.ping_timeout:该属性默认为30s(30秒钟),指定了节点发送ping
信息后等待响应的时间,超过此时间则认为对方节点无响应。
discovery.zen.fd.ping_retries:该属性默认为3,指定了重试次数,超过此次数
则认为对方节点已停止工作。
如果你遇到网络问题,或者知道你的节点需要更多的时间来等待ping响应,可以把上面那些 参数调整为对你的部署有利的值。
7.2时光之门与恢复模块
除了我们的索引和索引里面的数据,Elasticsearch还需要保存类型映射和索引级别的设置等 元数据。此信息需要被持久化到别的地方,这样就可以在群集恢复时读取。这就是为什么 Elasticsearch引入了时光之门模块。你可以把它当做一个集群数据和元数据的安全的避风港。你 每次启动群集,所有所需数据都从时光之门读取,当你更改你的集群,它使用时光之门模块保存。
7.2.1时光之门
为了设置我们希望使用的时光之门类型,需要在elasticsearch.yml配置文件中添加gateway. type属性,并设置为local。目前,Elasticsearch推荐使用本地时光之门类型(gateway.type 设为local),这也是默认值。过去有其他时光之门类型(比如fs、hdfs和s3),但已被弃用,
将在未来的版本中删除。因此跳过对它们的讨论。默认的本地时光之门类型在本地文件系统中存 储索引和它们的元数据。跟其他时光之门类型相比,这种的写操作不是异步的。所以,每当 写操作成功,都可以确保数据已经被写入了gateway(也就是说,它被索引或存储在事务日 志中)。
7.2.2恢复控制
【恢复是初始化所有分片和副本的过程,从事务日志中读取所有数据,并应用到分片上。】
除了选择时光之门类型以外,Elasticsearch允许配置何时启动最初的恢复过程。恢复是初始
化所有分片和副本的过程,从事务日志中读取所有数据,并应用到分片上。基本上,这是启动
Elasticsearch所需的一个过程。
假设有一个由10个Elasticsearch节点组成的集群。应该通知Elasticsearch我们的节点数目,设
置gateway.expected_nodes属性为10。我们告知Elasticsearch有资格来保存数据且可以被选为
主节点的期望节点数目。集群中节点的数目等于gateway.expected_nodes属性值时,
Elasticsearch将立即开始恢复过程。
【恢复开始的条件】
也可以在8个节点之后开始恢复,设置gateway.recover_after_nodes属性为8。可以将
它设置为任何我们想要的值,但应该把它设置为一个值以确保集群状态快照的最新版本可用,一
般在大多数节点可用时开始恢复。
然而,还有一件事:我们希望gateway在集群形成后的10分钟以后开始恢复,因此设置
gateway.recover_after_time属性为10m。这个属性告诉gateway模块,在gateway.
recover_after_nodes属性指定数目的节点形成集群之后,需要等待多长时间再开始恢复。如
果我们知道网络很慢,想让节点之间的通信变得稳定时,可能需要这样做。
上述属性值都应该设置在elasticsearch.yml配置文件中,如果想设置上面的值,则最终在文件
中得到下面的片段:
gateway.recover_after_nodes: 8
gateway.recover_after_time: 10m
gateway.expected_nodes: 10
额外的gateway恢复选项
除了提到的选项,Elasticsearch还允许做一些控制。额外的选项如下。
gateway.recover_after_master_nodes:这个属性跟gateway_recover_after_
nodes属性类似。它指定了多少个有资格成为主节点的节点在集群中出现时才开始启动恢
复,而不是指定所有节点。
gateway.recover_after_data_nodes:这个属性也跟gateway_recover_after_
nodes属性类似。它指定了多少个数据节点在集群中出现时才开始启动恢复。
gateway.expected_master_nodes:这个属性跟gateway.expected_nodes属性类
似,它指定了希望多少个有资格成为主节点的节点出现,而不是所有的节点。
gateway.expected_data_nodes:这个属性也跟gateway.expected_nodes属性类
似,它指定了你期望出现在集群中的数据节点的个数
7.3为高效查询和高索引吞吐量准备Elasticsearch集群
直到现在,我们谈的主要是Elasticsearch在处理查询和索引数据方面不同的功能。在这里, 我们想简要谈谈为高查询和高索引吞吐量准备Elasticsearch集群。本节的开头先提到一些还没谈 到的Elasticsearch功能,它们对优化集群很重要。我们知道,这是一个非常简要的介绍,但我们 会试着只介绍那些我们认为重要的内容。之后,会就如何调整这些功能给出一般性建议,以及注 意事项。希望通过阅读这一节,你能够在调优集群时知道要注意的事项。
7.3.1过滤器缓存
过滤器缓存负责缓存查询中使用到的过滤器。你可以从缓存中飞快地获取信息。如果设置得 当,它将有效地提高查询速度,尤其是那些包含已经执行过的过滤器的查询。
Elasticsearch包含两种类型的过滤器缓存:节点过滤器缓存(默认)和索引过滤器缓存。节 点过滤器缓存被分配在节点上的所有索引共享,可以配置成使用特定大小的内存,或分配给 Elasticsearch总内存的百分比。为了设置这个值,应该包含indices.cache.filter.size这个 节点属性值,并设置成需要的大小或百分比。
第二种过滤器缓存基于索引级别。一般来说,你应该使用节点级别的过滤器缓存,因为很难 预测每个索引的最终缓存大小,通常也不知道最终节点上会有多少索引。我们将省略对索引级别 过滤器缓存的进一步解释,关于它的更多信息可以在官方文档找到,或者我们的书Mastering ElasticSearch。
7.3.2字段数据缓存和断路器
字段数据缓存是Elasticsearch缓存的一部分,主要用于当查询对字段执行排序或切面时。 Elasticsearch把用于该字段的数据加载到内存,以便基于每个文档快速访问这些值。构建这些字 段数据缓存是昂贵的,所以最好有足够的内存,以便缓存中的数据一旦加载就留在缓存中。
你也可以把字段配置成使用doc值,而不是字段数据缓存。doc值在2.2节中 讨论过。
允许用于字段数据缓存的内存大小可以用indices.fielddata.cache.size属性来控制。 可以把它设置为绝对值(例如2 GB)或者分配给Elasticsearch实例的内存百分比(例如40%)。请 注意,这些值是节点级别,而不是索引级别的。为其他条目丢弃部分缓存会导致查询性能变差, 所以建议要有足够的物理内存。此外请记住,默认情况下,字段数据缓存的大小是无限的,所以 如果我们不小心,会导致集群的内存爆炸。
我们还可以控制字段数据缓存的过期时间,同样,默认情况下字段数据缓存永远不过期。可 以使用indices.fielddata.cache.expire属性来控制,将其设置为最大的不活动时间。例如, 将它设置为10m将导致缓存不活动10分钟后过期。记住重建字段数据缓存是非常昂贵的,一般情 况下,你不应该设置过期时间。
断路器
字段数据断路器(field data circuit breaker)允许估计一个字段加载到缓存所需的内存。利用 它,可以通过抛出异常来防止一些字段加载到内存中。Elasticsearch有两个属性来控制断路器的 行为。第一个是indices.fielddata.breaker.limit属性,默认值为80%,可以使用集群的 更新设置API来动态地修改它。这意味着,当查询导致加载字段的值所需的内存超过了 Elasticsearch进程中可用堆内存的80%时,将引发一个异常。第二个属性是indices.fielddata. breaker.overhead,默认为1.03,它定义了用来与原始估计相乘的一个常量。
7.3.3存储模块
Elasticsearch中的存储模块负责控制如何写入索引数据。我们的索引可以完全存储在内存或 者一个持久化磁盘中。纯内存的索引极快但不稳定,而基于磁盘的索引慢一些,但可容忍故障。
利用index.store.type属性,可以指定使用哪种存储类型,可用的选项包括下面这些。
simplefs:这是基于磁盘的存储,使用随机文件来访问索引文件。它对并发访问的性能
不够好,因此不建议在生产环境使用。
niofs:这是第二个基于磁盘的索引存储,使用Java NIO类来访问索引文件。它在高并发环
境提供了非常好的性能,但不建议在Windows平台使用,因为Java在这个平台的实现有bug。
mmapfs:这是另一个基于磁盘的存储,它在内存中映射索引文件(对于mmap,请参阅
http://en.wikipedia.org/wiki/Mmap)。这是64位系统下的默认存储,因为为索引文件提供了
操作系统级别的缓存,因此它的读操作更快。你需要确保有足够数量的虚拟地址空间,
但在64位系统下,这不是问题。
memory:这将把索引存在内存中。请记住你需要足够的物理内存来存储所有的文档,否
则Elasticsearch将失败。
7.3.4索引缓冲和刷新率
当说到索引时, Elasticsearch允许你为索引设置最大的内存数。 indices.memory. index_buffer_size属性可以控制在一个节点上,所有索引的分片共拥有的最大内存大小(或 者最大堆内存的百分比)。例如,把该属性设置为20%,将告诉Elasticsearch提供最大堆大小20% 的内存给索引缓冲。
此外,还有个indices.memory.min_shard_index_buffer_size属性,默认为4mb,允 许为每个分片设置最小索引缓冲。
索引刷新率
有关索引的最后一件事是index.refresh_interval属性,它指定在索引上,默认为1s(1 秒钟),指定了索引搜索器对象刷新的频率,基本上意味着数据视图刷新的频率。刷新率越低, 文档对搜索操作可视的时间越短,也意味着Elasticsearch将需要利用更多资源来刷新索引视图, 因此索引和搜索操作将会变慢。
对庞大的批量索引,例如,当对数据重建索引时,建议在索引阶段把 index.refresh_interval属性设为-1。
7.3.5线程池的配置
Elasticsearch使用多个池来控制线程的处理,以及控制用户请求占用多少内存消耗。
我们尤其感兴趣的是Elasticsearch公开的如下线程池类型。
cache:这是无限制的线程池,为每个传入的请求创建一个线程。
fixed:这是一个有着固定大小的线程池,大小由size属性指定,允许你指定一个队列
(使用queue_size属性指定)用来保存请求,直到有一个空闲的线程来执行请求。如果
Elasticsearch无法把请求放到队列中(队列满了),该请求将被拒绝。
有很多线程池(可以使用type属性指定要配置的线程类型),然而,对于性能来说,最重要 的是下面几个
index:此线程池用于索引和删除操作。它的类型默认为fixed,size默认为可用处理
器的数量,队列的size默认为300。
search:此线程池用于搜索和计数请求。它的类型默认为fixed,size默认为可用处理
器的数量乘以3,队列的size默认为1000。
suggest:此线程池用于建议器请求。它的类型默认为fixed,size默认为可用处理器
的数量,队列的size默认为1000。
get:此线程池用于实时的GET请求。它的类型默认为fixed,size默认为可用处理器的
数量,队列的size默认为1000。
bulk:你可以猜到,此线程池用于批量操作。它的类型默认为fixed,size默认为可用
处理器的数量,队列的size默认为50。
percolate:此线程池用于预匹配器操作。它的类型默认为fixed,size默认为可用处
理器的数量,队列的size默认为1000。
举个例子,把用于索引操作的线程池配置成fixed类型,大小为100,队列大小为500,我们 将在elasticsearch.yml配置文件中设置如下属性:
threadpool.index.type: fixed
threadpool.index.size: 100
threadpool.index.queue_size: 500
记住,线程池的配置可以使用集群的更新API来更新,如下所示:
curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient" : { "threadpool.index.type" : "fixed", "threadpool.index.size" : 100, "threadpool.index.queue_size" : 500 } }'
7.3.6通用建议
现在,我们知道了Elasticsearch所公开的缓存和缓冲区,可以尝试结合这些知识来配置一个
高索引和查询吞吐量的集群。接下来的两个小节将讨论在设置集群时,什么可以在默认配置中更
改,什么是要注意的。
在讨论Elasticsearch特定配置相关的所有事情之前,应该记住,必须给予Elasticsearch足够的
内存,而且是物理内存。一般来说,运行Elasticsearch的JVM进程不应该超过可用内存的50%或
60%,这样做是因为要留一些可用内存给操作系统以及操作系统的I/O缓存。
然而,需要记住,50%到60%不一定总是对的。你可以想象一个有256 GB内存的节点,在节
点上有个总共30 GB的索引,在这种情况下,即使分配多于60%的物理内存给Elasticsearch,也会
给操作系统留下足够的内存。另外,把Xmx和Xms参数设置为相同的值以避免JVM堆的大小调整,
也是个好主意。
当优化你的系统时,记得有一个在相同环境可以反复跑的性能测试。一旦你做出更改,你
需要看到它是如何影响整体性能的。此外,Elasticsearch可扩展,正因为此,有时最好在单机上
做一个简单的性能测试,看看性能如何,可以从中得到什么。这样的一些观察是进一步调优的
好起点。
在继续之前,注意我们不能给你高索引高查询吞吐量的秘方,因为每个部署都是不同的。因
此,我们将只讨论你在调优时应该注意什么。如果你对这样的用例感兴趣,可以访问博客
http://blog.sematext.com,有些作者会写一些关于性能测试的文章。
1、选择正确的存储
当然,除了已经谈过的物理内存外,应该选择正确的存储实现。一般来说,如果运行的是64 位操作系统,你应该选择mmapfs。如果没有运行64位操作系统,为UNIX系统选择niofs,为 Windows系统选择simplefs。如果你可以容忍一个易失的存储,但希望它非常快,可以看看 memory存储,它会给你最好的索引访问性能,但需要足够的内存来处理所有索引文件、索引和 查询。
2、索引刷新率
应该注意的第二件事是索引刷新率。我们知道刷新率指定文档多快可以对搜索操作可见。等 式非常简单:刷新率越快,查询越慢,索引吞吐量越低。如果我们允许有一个较慢的刷新率,如 10s或30s,设置它是不错的。这使得Elasticsearch承受的压力更少,因为内部对象重新打开的频率 更低,因此,将有更多的资源用于索引和查询。
3、优化线程池
强烈建议调整默认线程池,尤其是查询操作。在性能测试之后,你通常看到集群上的查询不 堪重负,这时应该开始拒绝请求。我们认为在大多数情况下,最好是立刻拒绝该请求,而不是把 它放到队列并强制应用程序等待很长时间请求处理。我们真的很想给你一个准确的数字,但这仍 然在很大程度上取决于你的部署,给不了通用的建议。
4、优化合并过程
合并过程同样在很大程度上取决于你的用例,以及若干因素,例如是否正在索引、你添加了 多少数据以及做这些操作的频率。一般来说,记住查询多个段跟查询数量更少的段相比更慢。但 是,想要段的数目更少,你需要付出更多的合并代价。
2.5节讨论过段合并。我们还提到了调节,它允许限制I/O操作。
通常来说,如果你想查询更快,应该以索引中更少的段为目标。如果想索引更快,应该有更 多的段。如果你想兼具两者,就要找到两者之间的黄金点,让合并不会太频繁但又不会导致大量 的段。使用并行合并调度器并调整默认调节值,使I/O子系统不会被合并淹没。
5、字段数据缓存和断路器
默认情况下,Elasticsearch中的字段数据缓存是无限的。这很危险,尤其在很多字段上使用 切面或排序时。如果字段基数很高,你可能会遇到更多的麻烦,麻烦的意思是说你可能会内存 不足。
我们有两个不同因子可以调节,来确保不会遇到内存不足错误。首先,可以限制字段数据缓 存的大小。其次是断路器,通过它可以很容易地配置成在加载过多数据时抛出一个异常。两者结 合可以确保我们不会遇到内存问题。
然而,也应该记住,当数据字段缓存的大小不足以处理切面或排序请求时,Elasticsearch将 从中移除数据。这将影响查询性能,因为加载字段数据信息是低效的。不过,我们认为宁愿让查 询慢,也不能由于内存不足错误而导致集群不工作。
6、索引的内存缓冲区
请记住,用于索引缓冲区的可用内存越多(indices.memory.index_buffer_size属性), Elasticsearch可以在内存中保存的文档也越多。但是,我们当然不想Elasticsearch占用100%的可用 内存。默认情况下,该属性被设置为10%,但如果真的需要更高的索引比例,你可以提高这个百 分比。我们见过一些关注数据索引的集群,把该属性设为30%,确实是有帮助的。
7、优化事务日志
我们还没讨论到,但Elasticsearch有个内部模块称为translog(http://www.elasticsearch.org/ guide/en/elasticsearch/reference/current/index-modules-translog.html)。它是分片上的结构,为预写 日志(http://en.wikipedia.org/wiki/Write-ahead_logging)服务。
基本上,它允许Elasticsearch为GET操作公开最新的更新,确保数据持久性,并优化对Lucene 索引的写入。
默认情况下,Elasticsearch在事务日志中保存最多5000次操作,同时最大不超过200 mb。但如 果想要更高的索引吞吐量,又可以承担数据对搜索操作不可见的时间更长,就可以提高这个默认值。 通 过 index.translog.flush_threshold_ops 和 index.translog.flush_threshold_size 属性(两者都是索引上的设置,可以用Elasticsearch API实时更新),可以设置保存在事务日志中的 最大操作数和最大的大小。我们见过一些部署把这个属性值设成默认值的10倍。
要记住一件事,如果发生故障,对于有更大事务日志的分片,其初始化当然也更慢,因为 Elasticsearch需要在分片可用之前处理事务日志中的所有信息。
8、牢记于心
当然,前面提到的因素并非全部。你应该监视Elasticsearch集群并作出相应的反应。如果你
看到索引中的段开始增长,而你不想这样,请调整合并政策。当你看到合并使用过多的I/O资源, 并影响了整体性能,请调整你的调节。只是要记住,调整不是一次性的;数据会增加,查询数目 也会增加,你要不断适配它。
7.4模板和动态模板
在2.2节中,我们学过映射、如何创建它们以及类型确定机制是如何工作的。现在将进入更 高级的主题,如何为新的索引动态地创建映射以及如何在模板中应用一些逻辑。
7.4.1模板
7.4.2动态模板
7.5小结
第8章 集群管理
8.1Elasticsearch时光机
8.1.1创建快照存储库
快照保存它创建的时间点上所有跟集群相关的数据,包括集群状态和索引的信息。至少在创 建第一个快照之前,必须创建一个快照存储库。
每个存储库由名称区分,应该定义如下几个方面。
name:这是存储库的唯一名称,后面会用到它。
type:这是存储库的类型,可能的值包括fs(共享文件系统中的存储库)、url(一个通 过URL访问的只读存储库)。
settings:这是不同存储库类型需要的额外信息。
现在,创建一个文件系统存储库。请注意,集群中的每个节点都应该能访问这个目录。为创 建一个新的文件系统存储库,可以执行下列命令:
curl -XPUT localhost:9200/_snapshot/backup -d '{ "type": "fs", "settings": { "location": "/tmp/es_backup_folder/cluster1" } }'
前面的命令创建一个名为backup的库,将备份文件存储在由location属性指定的目录中。 Elasticsearch返回下列信息:
{"acknowledged":true}
我们说过,第二种存储库类型是url。它需要一个url参数,而不是 location,该参数指向存储库所在的地址,例如,HTTP地址。你还可以把快 照存储在Amazon S3或HDFS中,使用额外的可用插件(参见https://github. com/elasticsearch/elasticsearch-cloud-aws#s3-repository 和 https://github.com/elastic search/elasticsearch-hadoop/tree/master/repository-hdfs)。
现在,我们有了第一个存储库,可以使用以下命令看到它的定义:
curl -XGET localhost:9200/_snapshot/backup?pretty
还可以运行以下命令检查所有存储库:
curl -XGET localhost:9200/_snapshot/_all?pretty
如果你想删除一个快照存储库,标准的DELETE命令可以帮忙:
curl -XDELETE localhost:9200/_snapshot/backup?pretty
8.1.2创建快照
默认情况下,创建快照时,Elasticsearch取得所有的索引和集群设置(除了瞬时的那些)。你 可以创建任意数量的快照,每个快照将持有从创建的时间点开始的所有信息。快照的创建用了一 种巧妙的方式:仅复制新的信息。这意味着Elasticsearch知道哪些段已经存储在存储库中,不会再保存它们。
为了创建新的快照,需要选择一个唯一的名称,并使用下面的命令:
curl -XPUT 'localhost:9200/_snapshot/backup/bckp1'
上面的命令定义了一个名为bckp1的新快照(给定名称只能有一个快照,Elasticsearch会检查 它的唯一性),数据将保存在之前定义的backup库中。该命令立即返回一个响应,如下所示:
{"accepted":true}
上述响应意味着,快照的进程已经在后台开始并继续。如果你想在实际的快照被创建后才得 到响应,可以添加wait_for_completion参数,如下面的例子所示:
curl -XPUT 'localhost:9200/_snapshot/backup/bckp2?wait_for_completion= true&pretty'
上述命令的响应展现了新创建快照的状态:
{
"snapshot": {
"snapshot": "bckp2",
"indices": [
"art"
],
"state": "SUCCESS",
"start_time": "2014-02-22T13:04:40.770Z",
"start_time_in_millis": 1393074280770,
"end_time": "2014-02-22T13:04:40.781Z",
"end_time_in_millis": 1393074280781,
"duration_in_millis": 11,
"failures": [],
"shards": {
"total": 5,
"failed": 0,
"successful": 5
}
}
}
可以看到,Elasticsearch给出了快照过程消耗的时间、它的状态和影响到的索引等信息。
额外参数
快照命令还可以接受以下额外参数。
indices:想拍下快照的索引名称。
ignore_unavailable:默认为true。设置为false时,意味着如果indices参数指向
了不存在的索引,命令将失败。
include_global_state:默认值为true,指集群的状态也被写入快照中(除了那些瞬
时的设置)。
partial:快照的成功与否取决于所有分片的可用性。任何一个分片不可用,快照都将
失败。设置partial为true时,Elasticsearch值保存可用分片的信息,省略丢失的分片。
使用额外参数的一个示例如下:
curl -XPUT 'localhost:9200/_snapshot/backup/bckp?wait_for_ completion=true&pretty' -d '{ "indices": "b*", "include_global_state": "false" }'
8.1.3 还原快照
我们已经完成了快照,接下来学习如何从给定的快照中恢复数据。前面说过,可以通过名称 指向一个快照。可以使用下面的命令列出所有快照:
curl -XGET 'localhost:9200/_snapshot/backup/_all?pretty'
先前创建的存储库名称为backup。为了从库中还原一个名为bckp1的快照,执行下面的 命令:
curl -XPOST 'localhost:9200/_snapshot/backup/bckp1/_restore'
执行这个命令的过程中,Elasticsearch取得定义在此快照中的索引,并用快照中的数据创建 它们。如果索引已经存在而且未关闭,该命令将失败。这种情况下,你可能会发现只还原某些索 引是很方便的,例如:
curl -XPOST 'localhost:9200/_snapshot/backup/bck1/_restore?pretty' -d '{ "indices": "c*"}'
上述命令只还原以字母c开头的索引,还有以下可用参数。
ignore_unavailable:与创建快照时相同。
include_global_state:与创建快照时相同。
rename_pattern:允许你改变存储在快照中的索引的名称。归功于此,还原的索引将
有一个不同的名称。此参数的值是一个正则表达式,定义了源索引的名字,如果模式与
索引名字匹配,将发生名称替换。在该模式中,应当使用以rename_replacement参数
中所用括号分隔的分组。
rename_replacement:该参数和rename_pattern一起定义了目标索引名称。使用美
元符号和数字可以指向rename_pattern中合适的组。
例如,由于rename_pattern=products_(.*),只有名称以products_开头的索引将被还 原。索引名字的其他部分将使用在替换部分。配合rename_replacement=items_$1,将让 products_cars索引被还原成名为items_cars的索引。
8.1.4 清理:删除旧的快照
curl -XDELETE 'localhost:9200/_snapshot/backup/bckp1?pretty'
8.2监控集群的状态和健康度
Elasticsearch提供了非常详细的信息,使你能够检查和监控单个节点或作为一个整体的集群。 这包括统计数字、有关服务器的信息、节点、索引和分片。当然,也能够获得整个集群状态的有 关信息。在深入提到的API细节之前,请记住,API是复杂的,我们只是描述基本的东西。我们 会试着展现什么时候开始,让你在需要非常详细的信息时能知道要找什么。
8.2.1 集群健康度API
一个最基本的API是集群健康度API,它允许使用单个HTTP命令得到整个集群的状态信息。 例如,执行以下命令:
curl 'localhost:9200/_cluster/health?pretty'
上述命令返回的响应示例如下所示:
{
"cluster_name": "es-book",
"status": "green",
"timed_out": false,
"number_of_nodes": 1,
"number_of_data_nodes": 1,
"active_primary_shards": 4,
"active_shards": 4,
"relocating_shards": 0,
"initializing_shards": 0,
"unassigned_shards": 0
}
最重要的一个信息是关于集群的状态。在例子中,我们看到集群是green状态。这意味着所 有分片已妥善分配,没有错误。
暂停一下,先谈谈作为一个整体的集群什么时候会完全运作。当Elasticsearch能够根据配置
分配所有分片和副本时,集群才全面运作。在这种情况下,集群在green状态。yellow状态意 味着我们已经准备好处理请求,因为主分片已经分配,但部分或所有副本还没有。最后一个状态 是red,这意味着至少一个主分片没有分配,因此集群还没有准备好。这意味着查询可能返回错 误或不完整的结果。
前面的命令也可以用来检查某索引的健康状况。如果想要检查library和map索引的健康 度,运行以下命令:
curl 'localhost:9200/_cluster/health/library,map/?pretty'
1. 控制信息细节
Elasticsearch允许指定一个特殊的level参数,把它指定为cluster(默认)、indices或 shards。这样就能够控制由健康度API返回信息的细节。我们已经看过默认的行为。当设置level 为indices时,除集群信息外,还将获得每个索引的健康度。参数设置为shards告诉Elasticsearch 除了返回我们在示例中看到内容,还要返回每个分片的信息。
2. 额外的参数
除了level参数,还有一些额外参数用来控制健康度API的行为。
第一个参数是timeout。它允许控制命令执行的最长时间。默认值为30s,意味着健康度命
令将最长等待30秒钟,然后返回。
wait_for_status参数告诉Elasticsearch返回响应时,集群应该处于什么状态。可以把它设
置为green、yellow和red。例如,设置为green时,健康度API调用将返回绿色状态,或者达
到timeout时间。
wait_for_nodes参数允许设置返回响应时需要多少节点可用(或者达到timeout时间)。
可以设置该参数为整数值,比如3,或者一个简单等式,比如>=3(大于或等于3个节点),<=3(小
于或等于3个节点)。
最后一个参数是wait_for_relocating_shard,默认不指定。它告诉Elasticsearch应该重
定位多少分片(或者等待timeout时间)。设置该参数为0意味着Elasticsearch应该等待所有重定
位分片。
使用以上参数的健康度命令的一个例子如下所示:
curl 'localhost:9200/_cluster/health?wait_for_status=green&wait_for_ nodes=>=3&timeout=100s'
8.2.2索引统计API
Elasticsearch索引是保存数据的地方,它对大多数部署来说是非常重要的部分。使用_stats
端点上的索引统计API,可以得到关于集群中索引的各种信息。当然,和Elasticsearch大多数API 一样,可以发送命令得到所有索引的信息(使用纯_stats端点),或得到某特定索引的信息(例 如,library/_stats),或者一次得到几个索引的信息(例如,library,map/_stats)。例 如,为了检查本书中使用的map和library索引的统计信息,可以执行如下命令:
curl localhost:9200/library,map/_stats?pretty
上面的命令将返回超过500行的响应,所以省略它,只描述一下它的结构。除了响应状态和 响应时间等信息之外,还可以看到三个对象,分别是primaries、total和indices。indices 对象包含library和map索引的信息。primaries对象包含分配在当前节点的主分片信息, total对象包含所有分片(包括副本分片)的所有信息。所有这些对象都包含描述特殊统计的对 象,比如docs、store、indexing、get、search、merges、refresh、flush、warmer、 filter_cache、id_cache、fielddata、percolate、completion、segments和translog。 来讨论存储在这些对象中的信息。
1. docs
响应中的docs节点显示索引文档的信息。它看上去可能如下所示:
"docs" : { "count" : 4, "deleted" : 0 }
主要信息是count,指文档的数目。从索引中删除文档时,Elasticsearch并不会立即移除这些 文档,只把它们标记为删除。这些文档将在段合并过程中被删除。被标记成删除的文档数目将出 现在deleted属性中,在合并结束时应该为0。
2. store
下一个统计组是store,提供了关于存储的信息。例如,该节点看上去可能如下所示:
"store" : { "size_in_bytes" : 6003, "throttle_time_in_millis" : 0 }
主要的信息是关于这个索引(或多个索引)的大小。我们还看到了调节统计值。在系统有I/O 性能问题,并且设置了段合并过程中内部操作的限制时,这个信息很有用。
3. indexing、get和search
响应中的indexing、get和search节点提供了数据操纵的相关信息:索引删除操作、实时 的get和搜索。来看看Elasticsearch返回的下列例子:
"indexing" : {
"index_total" : 11501,
"index_time_in_millis" : 4574,
"index_current" : 0,
"delete_total" : 0,
"delete_time_in_millis" : 0,
"delete_current" : 0
},
"get" : {
"total" : 3,
"time_in_millis" : 0,
"exists_total" : 2,
"exists_time_in_millis" : 0,
"missing_total" : 1,
"missing_time_in_millis" : 0,
"current" : 0
},
"search" : {
"query_total" : 0,
"query_time_in_millis" : 0,
"query_current" : 0,
"fetch_total" : 0,
"fetch_time_in_millis" : 0,
"fetch_current" : 0
}
可以看到,所有这些统计具有类似结构。可以看到各种类型的请求花费的总时间(以毫秒为 单位)以及请求数,可以用总时间计算单个查询的平均时间。在实时的情况下,get请求中有价 值的信息是不成功读取的次数(因为文档缺失)。
4. 额外信息
此外,Elasticsearch提供了下列信息。
merges:该节点包含Lucene段合并的信息。
refresh:该节点包含刷新操作的信息。
flush:该节点包含清理信息。
warmer:该节点包含预热器的信息,以及它们执行了多久。
filter_cache:这些是过滤器缓存统计信息。
id_cache:这些是标识符缓存统计信息。
fielddata:这些是字段数据缓存统计信息。
percolate:该节点包含预匹配器使用情况的信息。
completion:该节点包含自动完成建议器的信息。
segments:该节点包含Lucene段的信息。
translog:该节点包含事务日志计数和大小的信息。
8.2.3 状态API
另一个得到关于索引信息的方法,是使用_status端点的状态API。返回的信息描述了可用 的分片,包含的信息有:哪个分片被认为是主分片,它被分配到了哪个节点,被重分配到了哪个 节点(如果是的话),分片的状态(活跃与否),事务日志,合并过程以及刷新和清理统计。
8.2.4 节点信息API
节点信息API提供了关于集群中节点的信息,为从该API得到信息,需要发送请求到_nodes 端点。
这个API可以使用如下特性获取单个或特定几个节点的信息。
Node名:如果想得到名为Pulse的节点的信息,可以在_nodes/Pulse REST端点上执行
命令。
Node标识符:如果想得到标识符为ny4hftjNQtuKMyEvpUdQWg的节点的信息,可以在
_nodes/ny4hftjNQtuKMyEvpUdQWg端点上执行命令。
IP地址:如果想得到IP地址为192.168.1.103的节点的信息,可以在_nodes/192.168.1.
103 REST端点上执行命令。
Elasticsearch配置参数:如果想得到node.rack属性等于2的所有节点的信息,可以在
_nodes/rack:2 REST端点上执行命令。
该API还允许使用如下方式一次性得到几个节点的信息:
模式,例如,_nodes/192.168.1.*或者_nodes/P*;
节点枚举,例如,_nodes/Pulse,Slab;
模式与节点枚举,例如,/_nodes/P*,S*。
默认情况下,对节点API的请求将返回关于节点的基本信息,比如名称、标识符、地址。通 过添加额外参数,可以获得其他信息。可用的参数如下所示。
settings:此参数用来获取Elasticsearch配置信息。
os:此参数用来获取服务器的信息,诸如处理器、内存和交换区等。
process:此参数用来获取进程标识符和可用的文件描述符等信息。
jvm:此参数用来获取关于Java虚拟机(JVM)的信息,比如内存限制。
thread_pool:此参数用来获取各种操作的线程池配置。
network:此参数用来获取网络接口的名称和地址。
transport:此参数用来获取传输的侦听接口地址。
http:此参数用来获取HTTP侦听地址。
plugins:此参数用来获取安装的插件信息。
使用先前描述的API示例如下:
curl 'localhost:9200/_nodes/Pulse/os,jvm,plugins?pretty'
上述命令除了返回基本信息外,还有操作系统、Java虚拟机和插件的相关信息。当然,所有 信息都是针对Pulse节点。
8.2.5节点统计API
节点统计API跟前面描述的节点信息API类似。主要的区别是,节点信息API提供环境信息, 而节点统计API告诉我们集群工作时发生过什么。为使用节点统计API,你应该发送命令到 /_nodes/stats REST端点。跟节点信息API类似,我们同样可以获取特定节点的信息(比如, _nodes/Pulse/stats)。
默认情况下,Elasticsearch返回所有可用的统计,但可以限制为我们感兴趣的那些。可用的 选项如下。
indices:提供了关于索引的信息,包括大小、文档个数、索引相关的统计、搜索和获
取时间、缓存、段合并,等等。
os:提供了操作系统相关的信息,比如可用磁盘空间、内存、交换分区的使用。
process:提供了跟Elasticsearch进程相关的包括内存、CPU和文件句柄等的使用情况。
jvm:提供了关于Java虚拟机内存和垃圾回收统计的信息。
network:提供了TCP级别的信息。
transport:提供了传输模块发送和接收数据的信息。
http:提供了HTTP连接的信息。
fs:提供了可用磁盘空间和I/O操作统计的信息。
thread_pool:提供了分配给各种操作线程的状态信息。
breaker:提供了字段数据缓存断路器的信息。
一个使用该API的示例代码如下所示:
curl 'localhost:9200/_nodes/Pulse/stats/os,jvm,breaker?pretty'
8.2.6 集群状态API
Elasticsearch提供的另一个API是集群状态API。顾名思义,它允许获取关于整个集群的信息 (也可以通过在请求中添加local=true,限制只返回本地节点的信息)。用于获取所有信息的基 本命令如下所示:
curl 'localhost:9200/_cluster/state?pretty'
不过,也可以把提供信息限定为特定的度量(用逗号分隔,在REST调用的_cluster/state 部分之后指定),以及特定的索引(同样用逗号分隔,在REST调用的_cluster/state/metrics 部分之后指定)。下面是一个示例调用,它只返回关于map和library索引的节点相关信息:
curl 'localhost:9200/_cluster/state/nodes/map,library?pretty'
可使用下面这些度量。
version:返回关于集群状态版本的信息。
master_node:返回关于所选主节点的信息。
nodes:返回节点上的信息。
routing_table:返回路由相关的信息。
metadata:返回元数据相关的信息。当指定要获取元数据度量,还可以包含一个额外的
参数index_templates=true,将在结果中包含定义的索引模板。
blocks:返回关于块的信息。
8.2.7 挂起任务API
Elasticsearch 1.0中引入的一个API是挂起任务API(pending tasks API),它允许我们坚持哪些 任务在等待执行。为获取这个信息,需要发送请求到/_cluster/pending_tasks REST端点。 在响应中,我们将看到一组任务,包含任务优先级、队列等待时间等信息。
8.2.8 索引段API
我们想提的最后一个API是通过使用/_segments端点的Lucene段API。可以为整个集群或单 独的索引执行它。该API提供的信息包括分片、分片的布局,以及Lucene库管理的跟物理索引相 连的段。
8.2.9 cat API
当然,可以说我们需要的用来诊断和观察集群的所有信息都可以通过提供的API获取。然而, API返回的响应是JSON格式,它很好,但至少对于人类来说,不是特别方便使用。这就是为什么 Elasticsearch允许使用一个友好的API:cat API。为使用cat API,需要向_cat REST端点发送一个 请求,紧跟着下面的其中一个选项。
aliases:返回有关别名的信息(8.6节中将介绍别名)。
allocation:返回分片分配和磁盘使用的信息。
count:为所有索引或单个索引返回文档个数的信息。
health:返回集群健康度的信息。
indices:返回所有索引或单个索引的信息。
master:返回当选主节点的信息。
nodes:返回集群拓扑相关信息。
pending_tasks:返回正在等待执行的任务信息。
recovery:返回还原过程的视图。
thread_pool:返回集群范围内的线程池的统计信息。
shards:返回关于分片的信息。
这可能有点混乱,来看一个返回分片信息的示例命令,如下所示:
curl -XGET 'localhost:9200/_cat/shards?v'
注意,在请求中包括v参数。这意味着我们希望更详细的信息,例如,包括 头部信息。除v参数外,也可以使用help参数,它将返回给定命令的头部描述; 还有h参数,它接受一个逗号分隔的列表,指定要包含在响应中的列。
上述命令的响应如下所示:
index shard prirep state docs store ip node
map 0 p STARTED 4 5.9kb 192.168.1.40 es_node_1
library 0 p STARTED 9 11.8kb 192.168.56.1 es_node_2
可以看到,我们有两个索引,每个都有一个分片。还看到分片的ID,也就是说,它是不是主
分片,以及它的状态、文档数、大小、节点的IP地址、节点名称等。
可以看到,我们有两个索引,每个都有一个分片。还看到分片的ID,也就是说,它是不是主 分片,以及它的状态、文档数、大小、节点的IP地址、节点名称等。
限制返回信息
一些cat API命令允许限制它们返回的信息。例如,别名调用允许我们通过添加别名来得到特 定别名的信息,就像下面的命令:
curl -XGET 'localhost:9200/_cat/aliases/current_index'
我们总结一下允许限制信息的命令。
aliases:通过在请求中添加别名,来限定获取特定别名的信息。
count:通过在请求中添加我们感兴趣的索引名字,来限定获取特定索引的信息。
indices:同count一样,限定只获取特定索引的信息。
shards:通过在请求中添加我们感兴趣的索引名字,来限定获取特定索引的信息。
8.3控制集群的再平衡
默认情况下,Elasticsearch试图把分片和其副本在集群中均衡分布。在大多数情况下这种行 为是好的,但有时我们想控制此行为。本节将深入介绍如何避免集群再平衡(rebalancing),以及 如何控制这一过程的行为。
假设你的网络可以处理很高的流量,或者相反,网络被大量使用,你希望可以避免太多压力。 另一个例子是,你可能想在整个集群重启后,减少I/O子系统的压力,并且同时你要减少分片和 副本的初始化。这只是两个再平衡控制可能很方便的例子。
8.3.1 再平衡
再平衡是在集群的不同节点之间移动分片的过程。我们已经提到,在大多数情况下它是好 的,但有时你可能想完全避免这种情况。如果我们定义且希望保持分片放置,就要避免再平衡。 然而,默认情况下,当集群状态变化,或者Elasticsearch认为需要再平衡时,它会尽量对集群进 行再平衡。
8.3.2 集群的就绪
我们已经知道,索引可以由分片和副本构成。主分片(或者简称分片)用于新文档被编入索 引以及更新或删除,或者只是索引发生任何变化时。我们的副本从主分片获取数据。
你可以认为,当所有主分片都被分配在集群中的节点上,也就是一旦达到黄色的健康状态 时,集群就已经就绪了。然而,此时Elasticsearch还可能在初始化其他分片:副本。但是,你已 经可以使用集群,并确保可以搜索整个数据集,也可以发送索引更改命令。之后,这些都将被 正确处理。
8.3.3 集群再平衡设置
Elasticsearch允许控制再平衡过程,通过设置elasticsearch.yml文件中的几个属性,或使用 Elasticsearch REST API(在8.8节中描述)。
1. 控制再平衡何时开始
可以通过设置cluster.routing.allocation.allow_rebalance属性来指定再平衡何 时开始。该属性可以设置为如下几个值。
always:该值表明再平衡可以在需要时随时开始。
indices_primaries_active:该值表明当所有的主分片都初始化后,再平衡才会开始。
indices_all_active:该值是默认设置,意味着所有分片和副本都初始化后,再平衡 才会开始。
2.控制同时在节点中移动的分片数量
可以设置cluster.routing.allocation.cluster_concurrent_rebalance属性来指 定整个集群中同时可以在节点间移动的分片数量。如果你的集群由很多节点组成,可以提高这个 值,默认值为2。
3. 控制单个节点上同时初始化的分片数量
cluster.routing.allocation.node_concurrent_recoveries 属性可以用来设置 Elasticsearch在单个节点上一次可以初始化多少分片。请注意分片的还原过程是非常耗I/O的,所 以你可能要避免太多的分片同时被还原。该属性值默认跟上一个属性一样,为2。
4. 控制单个节点上同时初始化的主分片数
可以设置cluster.routing.allocation.node_initial_primaries_recoveries属 性来控制单个节点上一次可以初始化多少主分片。
5. 控制分配的分片类型
使用cluster.routing.allocation.enable属性,可以控制允许分配哪种类型的分片。 该属性可以使用如下值。
all:这是默认值,告诉Elasticsearch所有类型的分片都可以被分配。
primaries:告诉Elasticsearch它应该只分配主分片,而不要分配副本。
new_primaries:告诉Elasticsearch只分配新创建的主分片。
none:这完全禁用了分片的分配。
6. 控制单个节点上的并发流数目
indices.recovery.concurrent_streams属性允许控制在一个节点上一次可以打开多 少流,以便从目标分片中恢复一个分片。它的默认值为3。如果你的网络和节点可以处理更多, 就可以提高这个值。
8.4控制分片和副本的分配
Elasticsearch集群内部的索引,可以由许多分片建成,每个分片可以有多个副本。因为单一 的索引可以有多个分片,可以处理索引大到无法存入到单台机器的情况。可能有其他原因,比如 与存储相关的内存和CPU等。因为每个分片可以有多个副本,可以通过把副本散布到多台服务器
上,来处理更高的查询。可以说通过使用分片和副本,可以横向扩展Elasticsearch。然而, Elasticsearch必须找出在集群的什么地方放置分片和副本,即每个分片或副本应放在哪些服务器 或节点上。
8.4.1 显式控制分配
假设希望把索引放置在不同的集群节点上。例如,把一个叫shop的索引放置在某些节点上, 第二个叫users的索引放置在其他节点上。把最后一个名为promotions的索引放置在users和 shop索引放置的所有节点上。需要这样做可能是由于性能原因。我们知道安装过Elasticsearch的 一些服务器比其他服务器更强大。使用默认Elasticsearch行为,我们不知道分片和副本将放置在 哪,但幸好,Elasticsearch允许我们控制它。
1. 指定节点参数
所以让我们把集群分为两个区域。我们说“区”,但它可以是任何你喜欢的名称,我们只是 喜欢用“区”。假设有四个节点,希望把更强大的编号为1和2的节点放置在一个叫zone_one的区; 编号3和4的节点资源较少,放在叫zone_two的区域。
2. 配置
为了实现我们描述的索引分布,在节点1和节点2(较强的节点)的elasticsearch.yml配置文件 中添加node.zone: zone_one属性。在节点3和节点4(较弱的节点)的elasticsearch.yml配置文 件中添加类似的属性:node.zone: zone_two。
3. 索引的创建
现在创建索引。首先创建shop索引。将此索引放置到更强的节点。为此可以运行以下命令:
curl -XPUT 'http://localhost:9200/shop' -d '{ "settings" : { "index" : { "routing.allocation.include.zone" : "zone_one" } } }'
上述命令将创建shop索引并指定index.routing.allocation.include.zone属性的值 为zone_one,这意味着我们希望把shop索引放到node.zone属性等于zone_one的节点上。
为users索引执行类似的步骤:
curl -XPUT 'http://localhost:9200/users' -d '{ "settings" : { "index" : { "routing.allocation.include.zone" : "zone_two"} } }'
不过这一次,我们指定希望把users索引放到node.zone属性等于zone_two的节点上。
最后,promotions索引应该放到上述所有节点,因此使用下列命令来创建和配置这个索引:
curl -XPOST 'http://localhost:9200/promotions'
curl -XPUT 'http://localhost:9200/promotions/_settings' -d '{ "index.routing.allocation.include.zone" : "zone_one,zone_two" }'
这次使用了不同的命令集。第一个命令创建索引,第二个命令更新index.routing. allocation.include.zone属性的值。这样做是为了说明可以用这种方式来做。
4. 排除节点的分配
既然可以指定索引应该放在哪个节点,就可以指定应该排除哪些节点。参考之前的例子,如果 希望名为pictures的索引不放在node.zone属性等于zone_one的节点上,可以执行以下命令:
curl -XPUT 'localhost:9200/pictures/_settings' -d '{ "index.routing.allocation.exclude.zone" : "zone_one" }'
注意,这次使用index.routing.allocation.exclude.zone属性,而不是index. routing.allocation.include.zone属性。
5. 节点需求属性
除了节点的包含和排除规则,还可以指定分片必须匹配某种规则才能分配到给定节点上。不 同的是,使用 index.routing.allocation.include属性时,索引将被放置到与该属性中至少 一个值匹配的节点上。而使用index.routing.allocation.require属性值时,Elasticsearch将 把索引放置到与该属性的所有值都匹配的节点上。例如,我们已经为pictures索引做了如下设置:
curl -XPUT 'localhost:9200/pictures/_settings' -d '{ "index.routing.allocation.require.size" : "big_node", "index.routing.allocation.require.zone" : "zone_one" }'
执行以上命令后,Elasticsearch将只会把pictures索引的分片分配到node.size属性等于 big_node且node.zone属性等于zone_one的节点上。
6. 使用IP地址分配分片
除了在节点的配置中添加一个特殊的参数,也可以使用IP地址来指定应该包含或排除哪些节 点用来做分片和副本的分配。为此,替换index.routing.allocation.include.zone或 index.routing.allocation.exclude.zone属性的zone部分,而改用_ip。如果希望把shop索引只放置到IP地址为10.1.2.10和10.1.2.11的节点上,执行以下命令:
curl -XPUT 'localhost:9200/shop/_settings' -d '{ "index.routing.allocation.include._ip" : "10.1.2.10,10.1.2.11" }'
7. 基于磁盘的分片分配
除了上面描述的分片过滤方法外,Elasticsearch 1.0引入了一个额外的基于磁盘的方法,它允 许基于节点的磁盘使用情况来设置分配规则,因此不会有耗尽磁盘空间或类似的问题。
(1) 启用基于磁盘的分片分配
基于磁盘的分片分配默认是禁用的。可以通过设置cluster.routing.allocation. disk.threshold_enabled属性为true来启用它。可以在elasticsearch.yml文件中设置,或者使 用集群设置API动态设置(8.8节会介绍):
curl -XPUT localhost:9200/_cluster/settings -d '{ "transient" : { "cluster.routing.allocation.disk.threshold_enabled" : true } }'
(2) 配置基于磁盘的分片分配
以下三个属性可以用来控制基于磁盘的分片分配的行为,它们都可以动态更新,或者在 elasticsearch.yml配置文件中设置。
第一个属性是cluster.info.update.interval,默认值为30秒,定义了Elasticsearch更 新节点上磁盘使用信息的时间间隔。
第二个属性是cluster.routing.allocation.disk.watermark.low,默认值为0.70。 这意味着Elasticsearch不会在磁盘空间被使用超过70%的节点上分配新的分片。
第三个属性是cluster.routing.allocation.disk.watermark.high,默认值为0.85。 意味着Elasticsearch对磁盘使用大于等于85%的节点将开始重新分配分片。
cluster.routing.allocation.disk.watermark.low 和 cluster.routing.alloca tion.disk.watermark.high属性都可以设置成一个百分比(比如0.60,表示60%),或者一个 绝对值(600 mb,表示600兆字节)
8.4.2 集群范围的分配
除了在索引级别上指定分配的包含和排除规则(到目前为止我们讨论的),还可以在集群中 的所有索引上指定。如果希望把所有新索引都放置到IP地址为10.1.2.10和10.1.2.11的节点上,执
行如下命令:
curl -XPUT 'localhost:9200/_cluster/settings' -d '{ "transient" : { "cluster.routing.allocation.include._ip" : "10.1.2.10,10.1.2.11" } }'
我们注意到,命令发送到_cluster/settings REST端点,而不是INDEX_NAME/_settings 端点。当然,可以使用在索引级别上的所有包含、排除、需求规则。
请注意,集群的瞬时和永久属性在8.8节讨论。
8.4.3 每个节点上的分片和副本数量
除了指定分片和副本的分配外,还可以指定单一节点上为单一索引最多可以放置多少分片。 如果希望shop索引在每个节点上只有一个分片,执行以下命令:
curl -XPUT 'localhost:9200/shop/_settings' -d '{ "index.routing.allocation.total_shards_per_node" : 1 }'
该属性可以放在elasticsearch.yml文件中,或者使用上述命令更新生产环境的索引。请记住, 如果Elasticsearch无法分配所有的主分片,你的集群将维持在红色状态。
8.4.4 手动移动分片和副本
我们想讨论的最后一件事是手动在节点间移动分片的能力。这可能有用,例如,在关掉一个 节点之前,你想把该节点上的所有分片移动到其他地方。Elasticsearch公开了_cluster/ reroute REST端点,允许我们控制这个。
有以下可用的操作:
把分片从一个节点移到另一个节点;
取消分片的分配;
强制分片的分配。
1. 移动分片
假设有两个节点,分别为es_node_one和es_node_two。除此之外,我们的shop索引有两 个分片被Elasticsearch放置在第一个节点上。现在,我们想把第二个分片移动到第二个节点上。 为此,可以执行以下命令:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{ "commands" : [ { "move" : { "index" : "shop", "shard" : 1, "from_node" : "es_node_one", "to_node" : "es_node_two" } } ] }'
我们指定了move命令,它允许移动由index属性指定的索引的分片(和副本)。shard属性 是要移动的分片的编号。最后,from_node属性指定了希望从哪个节点上移动分片,to_node 属性指定了希望把分片放置到哪个节点上。
2. 取消分片的分配
如果想取消正在进行的分配过程,可以执行cancel命令,并指定想取消分片的索引、节点 和分片。例如以下命令:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{ "commands" : [ { "cancel" : { "index" : "shop", "shard" : 0, "node" : "es_node_one" } } ] }'
上述命令将取消es_node_one节点上shop索引编号为0的分片分配。
3. 强制分片的分配
除了取消和移动分片和副本,还可以分配一个未分配的分片到指定节点上。如果我们的 users索引有个编号为0的未分配分片,想把它分配到es_node_two节点上,执行以下命令:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{ "commands" : [ { "allocate" : { "index" : "users", "shard" : 0, "node" : "es_node_two" } } ] }'
4. 每个HTTP请求多个命令
当然,也可以在单个HTTP请求中包含多个命令,例如,考虑以下命令:
curl -XPOST 'localhost:9200/_cluster/reroute' -d '{ "commands" : [ {"move" : {"index" : "shop", "shard" : 1, "from_node" : "es_node_one", "to_node" : "es_node_two"}}, {"cancel" : {"index" : "shop", "shard" : 0, "node" : "es_node_one"}} ] }'
8.5预热
有时,可能需要为了处理查询而准备Elasticsearch。也可能因为你严重依赖字段数据缓存, 需要在生产查询到达之前加载它们,或者你可能想预热操作系统I/O缓存。不管什么原因, Elasticsearch允许为类型和索引定义预热查询(warning query)。
8.5.1 定义一个新的预热查询
预热查询跟普通查询没什么区别,只是它存储在Elasticsearch一个特殊的名为_warmer的索 引中。假设想使用下面的查询来做预热:
{ "query" : { "match_all" : {} }, "facets" : { "warming_facet" : { "terms" : { "field" : "tags" } } } }
为了把上述查询存储为library索引的预热查询,执行以下命令:
curl -XPUT 'localhost:9200/library/_warmer/tags_warming_query' -d '{ "query" : { "match_all" : {} }, "facets" : { "warming_facet" : { "terms" : { "field" : "tags" } } } }'
上诉命令将我们的查询注册为一个名为tags_warming_query的预热查询。你的索引可以
有多个预热查询,但每一个查询都需要一个唯一的名称。
我们不仅可以对整个索引定义预热查询,还可以为索引中的特定类型定义。为了把前面展现 的查询存为 library 索引中 book 类型的预热查询,执行之前的命令,但不再是 /library/_warmer URI,而是/library/book/_warmer。所以,整个命令将如下所示:
curl -XPUT 'localhost:9200/library/book/_warmer/tags_warming_query' -d '{ "query" : { "match_all" : {} }, "facets" : { "warming_facet" : { "terms" : { "field" : "tags" } } } }'
添加一个预热查询后,Elasticsearch允许一个新段执行搜索之前,会在那个段上执行定义的 预热查询。它允许Elasticsearch和操作系统缓存数据,以此来加速搜索。
正如1.1节中介绍的,Lucene把索引分为多个段,段一旦写入不再修改。每 个新的提交操作都会创建一个新段(如果段的数量太大,将会被合并),Lucene 使用它来搜索。
8.5.2 获取定义的预热查询
为了获取索引中的特定预热查询,我们只需知道它的名称。如果想获取library索引中名为 tags_warming_query的预热查询,执行下面的命令:
curl -XGET 'localhost:9200/library/_warmer/tags_warming_query?pretty=true'
Elasticsearch返回的结果将如下所示(注意我们使用了pretty=true参数让响应更易阅读):
{
"library": {
"warmers": {
"tags_warming_query": {
"types": [],
"source": {
"query": {
"match_all": {}
},
"facets": {
"warming_facet": {
"terms": {
"field": "tags"
}
}
}
}
}
}
}
}
也可以使用下面的命令来获取索引和类型的所有预热查询:
curl -XGET 'localhost:9200/library/_warmer'
最后,还可以获取所有以特定前缀开头的预热查询。例如,想得到library索引上所有以 tags前缀开头的预热查询,执行下面的命令:
curl -XGET 'localhost:9200/library/_warmer/tags*'
8.5.3 删除一个预热查询
删除预热查询跟获取预热查询非常类似,只需使用DELETE这个HTTP方法。为了从索引中删 除一个特定的预热查询,我们只需知道它的名称。例如,从library索引中删除名为 tags_warming_query的预热查询,执行以下命令:
curl -XDELETE 'localhost:9200/library/_warmer/tags_warming_query'
也可以使用下面命令来删除索引上的所有预热查询:
curl -XDELETE 'localhost:9200/library/_warmer/_all'
最后,也可以删除所有以给定前缀开头的预热查询。例如,要删除library索引上的所有以 tags前缀开头的预热查询,可执行以下命令:
curl -XDELETE 'localhost:9200/library/_warmer/tags*'
8.5.4 禁用预热功能
为了完全禁用预热查询,但仍把它们保存在_warmer索引中,你应该设置index.warmer. enabled属性为false(设置为true则启用预热功能)。该属性可以在elasticsearch.yml文件中设 置,也可以在生产集群上使用REST API。
如果想禁用library索引上的预热功能,执行以下命令:
curl -XPUT 'http://localhost:9200/library/_settings' -d '{ "index.warmer.enabled" : false }'
8.5.5 查询的选择
你可能会问哪个查询应该用做预热查询。通常要选择执行起来昂贵的和需要填充缓存的查 询。因此,可能会选择基于索引中的字段做切面和排序的查询。除此以外,父子查询和包括常用 过滤器的查询也可考虑。你也可以通过查看日志选择其他查询,找到性能表现不尽人意的,这些 也可以是很好的预热候选对象。
假设在elasticsearch.yml文件中设置了以下的日志配置:
index.search.slowlog.threshold.query.warn: 10s
index.search.slowlog.threshold.query.info: 5s
index.search.slowlog.threshold.query.debug: 2s
index.search.slowlog.threshold.query.trace: 1s
并且在logging.yml配置文件中设置了以下日志级别:
logger:
index.search.slowlog: TRACE, index_search_slow_log_file
注意,index.search.slowlog.threshold.query.trace属性设置成1s,而日志级别 index.search.slowlog属性设置成TRACE。这意味着每当一个查询执行时间查过1秒(在分片 上,不是总时间)时,它将被记录到慢查询日志文件中(日志文件由logging.yml配置文件中的 index_search_slow_log_file节点指定)。例如,慢查询日志文件中可能找到下面的条目:
[2013-01-24 13:33:05,518][TRACE][index.search.slowlog.query] [Local test] [library][1] took[1400.7ms], took_millis[1400], search_ type[QUERY_THEN_FETCH], total_shards[32], source[{"query":{"match_ all":{}}}], extra_source[]
可以看到,前面的日志行包含查询时间、搜索类型和搜索源本身,它显示了执行的查询。
当然,你的配置文件中可能有不同的值,但慢查询日志可以是一个很有价值的源,从中可以 找到执行时间过长的、可能需要定义预热的查询,它们可能是父子查询,需要获取一些标识符来 提高性能,或者你第一次使用了一些费时的过滤器?
应该记住,不要让你的Elasticsearch集群加载过多的预热查询,因为最终你 可能会花太多的时间预热,而不是处理你的生产查询。
8.6使用索引别名来简化你的日常工作
当在Elasticsearch中使用多个索引时,你可能有时会忘记它们。想象你在索引中存储日志的 场景。通常,日志消息的数量相当大,因此,把数据划分是一个好的解决方案。一种逻辑划分方 法是为每天的日志创建一个索引(如果你对管理日志的开源方案感兴趣,可以看看http://logstash.net上的Logstash)。但一段时间后,如果保存了所有索引,就会开始头疼如何管理 它们。应用程序需要管理所有这些信息,比如发送数据到哪个索引,查询哪个索引,等等。通过 使用别名,可以改变这个状况,使用一个名字来跟多个索引打交道,就像使用一个索引一样。
8.6.1 别名
什么是索引别名?它是一个或多个索引的一个附加名称,允许使用这个名称来查询索引。一 个别名可以对应多个索引,反之亦然,一个索引可以是多个别名的一部分。然而,请记住,你不 能使用对应多个索引的别名来进行索引或实时的GET操作。如果你这样做,Elasticsearch将抛出 一个异常(但可以使用对应单个索引的别名来进行索引操作),因为Elasticsearch不知道应该把索 引建立到哪个索引上,或从哪个索引获取文档。
8.6.2 创建别名
为创建一个索引别名,需要在_aliases REST端点上执行一个HTTP POST方法。例如,如 下的请求将创建一个名为week12的别名,它包含day10、day11和day12这些索引。
curl -XPOST 'localhost:9200/_aliases' -d '{ "actions" : [ { "add" : { "index" : "day10", "alias" : "week12" } }, { "add" : { "index" : "day11", "alias" : "week12" } }, { "add" : { "index" : "day12", "alias" : "week12" } } ] }'
如果我们的Elasticsearch集群中不存在week12别名,上述命令将创建它。如果存在,该命令 将只是把指定的索引添加进去。
之前,执行一个跨三个索引的搜索是这样的:
curl -XGET 'localhost:9200/day10,day11,day12/_search?q=test'
如果一切顺利,现在可以这样执行:
curl -XGET 'localhost:9200/week12/_search?q=test'
这不是更好吗?
8.6.3 修改别名
当然,你可以从别名中移除索引。这与添加索引到别名类似,但使用remove命令,而不是 add。例如,为了从week12中移除day9索引,执行以下命令:
curl -XPOST 'localhost:9200/_aliases' -d '{ "actions" : [ { "remove" : { "index" : "day9", "alias" : "week12" } } ] }'
8.6.4 合并命令
add和remove命令可以在一个请求中发送。例如,想合并之前发送的所有命令到一个单一的 请求中,可以发送以下命令:
curl -XPOST 'localhost:9200/_aliases' -d '{ "actions" : [ { "add" : { "index" : "day10", "alias" : "week12" } }, { "add" : { "index" : "day11", "alias" : "week12" } }, { "add" : { "index" : "day12", "alias" : "week12" } }, { "remove" : { "index" : "day9", "alias" : "week12" } } ] }'
8.6.5 获取所有别名
除了对别名添加或移除索引,使用Elasticsearch的应用程序,可能需要获取集群中的所有别 名或跟一个索引连接的所有别名。为了获取这些别名,发送一个HTTP GET命令。例如,下面的 第一个命令获取day10索引的所有别名,第二个命令获取所有可能的别名:
curl -XGET 'localhost:9200/day10/_aliases'
curl -XGET 'localhost:9200/_aliases'
第二个命令返回的响应如下:
{ "day10" : { "aliases" : { "week12" : { } } }, "day11" : { "aliases" : { "week12" : { } } }, "day12" : { "aliases" : { "week12" : { } } } }
8.6.6 移除别名
可以使用_alias端点移除一个别名。例如,发送下面命令将从data索引移除client别名:
curl -XDELETE localhost:9200/data/_alias/client
8.6.7 别名中的过滤
可以像在SQL数据库中使用视图一样来使用别名。你可以使用完整的查询DSL(第2章详细 讨论过),将你的查询应用到所有的count、search、delete,等等。
来看一个例子。假设想要一个别名返回特定客户的数据,以便在应用程序中使用。客户标识 符存在clientId字段上,我们对客户12345感兴趣。所以,在数据索引中创建一个名为client 的别名,它自动在clientId上应用一个过滤器:
curl -XPOST 'localhost:9200/_aliases' -d '{ "actions" : [ { "add" : { "index" : "data", "alias" : "client", "filter" : { "term" : { "clientId" : "12345" } } } } ] }'
所以,当使用该别名时,你的请求将总是被一个词条查询过滤,确保所有文档的clientId 字段都等于12345。
8.6.8 别名和路由
跟在别名中使用过滤器类似,可以在别名中添加路由值。假设我们在使用基于用户标识符的 路由,且想在别名中使用相同的路由值,则在名为client的别名中,我们将在查询中使用路由 值12345、12346、12347,而在索引建立中只使用12345。为此,使用下面的命令创建别名:
curl -XPOST 'localhost:9200/_aliases' -d '{ "actions" : [ { "add" : { "index" : "data", "alias" : "client", "search_routing" : "12345,12346,12347", "index_routing" : "12345" } } ] }'
这样,使用client别名索引数据时,将使用index_routing属性的值。在查询时,将使用 search_routing属性值。
还有一件事。请看发送到上述别名的如下查询:
curl -XGET 'localhost:9200/client/_search?q=test&routing=99999,12345'
它将使用12345作为路由值。这是因为Elasticsearch将使用search_routing属性值和查询路 由参数值的共同值,在我们的例子中是12345。
8.7Elasticsearch插件
8.7更新设置API
8.9小结