读书笔记《elasticsearch-server-third-edition》通过示例进行扩展
在上一章中,我们讨论了 Elasticsearch 管理。我们首先讨论了备份以及如何使用可用的 API 进行备份。我们监控了集群和节点的运行状况和状态,并学习了如何控制分片重新平衡。我们控制分片和副本分配,并使用人性化的 Cat API 来获取有关集群和节点的信息。我们看到了如何使用 warmers 来加速潜在的繁重查询,并且我们使用索引别名来更轻松地管理我们的索引。在本章结束时,您将学习以下主题:
运行 Elasticsearch 的硬件准备
调整单个 Elasticsearch 节点
准备高可用和容错的集群
纵向扩展 Elasticsearch
准备 Elasticsearch 以实现高查询和索引吞吐量
监控 Elasticsearch
在开始每个严肃的软件项目时,我们需要做出的第一个决定 是与硬件相关的一组选择。相信我们,这不仅是一个非常重要的选择,也是最困难的选择之一。通常决策是在项目的早期阶段做出的,那时只知道基本架构,我们没有关于查询、数据加载等的精确信息。项目架构师 必须平衡预防措施和整个解决方案的预计成本。太多时候,它是经验和千里眼的交集,可能导致伟大或可怕的结果。
让我们从一个决定开始:云、虚拟或物理机器。如今,这些都是有效的选择,但并非总是如此。以前唯一的选择是为每个环境部分购买新服务器,或者与同一台机器上的其他应用程序共享资源。第二种选择非常有意义,因为它更具成本效益但会带来风险。一个应用程序的问题,尤其是与硬件相关的问题,将导致另一个应用程序出现问题。您可以想象您的一个应用程序使用了物理机的大部分 I/O 子系统,而所有其他应用程序都因此受到大量 I/O 等待和性能问题的困扰。虚拟化承诺应用程序分离和更方便的资源管理方式,但您仍然受到底层硬件的限制。每个意外流量都可能成为问题并影响服务可用性。想象一下,您的电子商务网站突然获得了大量客户。您不会为出现高峰和您拥有更多潜在客户而感到高兴,而是寻找一个可以购买将尽快提供的额外硬件的地方。
另一方面,云计算意味着更灵活的成本模型。我们可以在需要时轻松添加新机器。我们可以在预计负载更大时临时添加它们(例如,电子商务网站在圣诞节前),并且只需为实际使用的处理能力付费。只需在管理面板中单击几下。更重要的是,我们还可以设置自动扩展,即新的虚拟机可以在我们需要的时候自动出现。当我们不再需要它们时,基于云的软件也可以关闭它们。云具有许多优点,例如较低的初始成本、轻松发展业务的能力以及对资源需求的时间波动不敏感,但它也有一些缺陷。云服务器的成本比物理机的成本上升得更快。此外,大容量存储虽然实际上是无限的,但其特性(每秒操作数)比物理服务器更差。这有时对我们来说是个大问题,尤其是对于基于磁盘的存储,例如 Elasticsearch。
在实践中,像往常一样,选择可能很困难,但通过以下几点可以帮助您做出决定:
业务需求可以直接指向自己的服务器;例如,一些与财务或医疗数据相关的程序会自动排除第三方供应商托管的云解决方案
对于概念验证和中低负载服务,云可能是一个不错的选择,因为它具有简单性、可扩展性和低成本
具有与 I/O 子系统相关的强烈要求的解决方案可能会在裸机上运行得更好
当流量可以在短时间内发生巨大变化时,云是您的理想场所
更多 GB 的 RAM 总是比更少 GB 的 RAM 更好。内存是必需的,尤其是对于聚合和排序。现在问题不大了,使用 Elasticsearch 2.0 和 doc
值,但是具有大量聚合的复杂查询仍然需要内存来处理数据。内存还用于索引缓冲区,可以提高索引速度,因为可以在内存中缓冲更多数据,从而减少磁盘的使用频率。如果您尝试使用比可用内存更多的内存,操作系统将使用硬盘作为临时空间(它开始交换),您应该不惜一切代价避免这种情况。请注意,您永远不应尝试强制 Elasticsearch 使用尽可能多的内存。第一个原因是 Java 垃圾收集器——更少的内存对 GC 更友好。第二个原因是操作系统实际上将未使用的内存用于缓冲区和磁盘缓存。实际上,当您的索引可以容纳此空间时,所有数据都是从这些缓存中读取的,而不是直接从磁盘中读取的。这可以极大地提高性能。默认情况下,Elasticsearch 和 I/O 子系统共享相同的 I/O 缓存,这为操作系统本身留出更多内存提供了另一个理由。
实际上,8GB 是对内存的最低要求。这并不意味着 Elasticsearch 永远不会使用更少的内存,但对于大多数情况和数据密集型应用程序来说,这是合理的最小值。另一方面,很少需要超过 64GB 的空间。取而代之的是,考虑水平扩展系统,而不是将如此多的内存分配给单个 Elasticsearch 节点。
我们说过,当整个索引适合内存时,我们处于良好的 状态。在实践中,这可能很难实现,因此良好和快速的磁盘非常重要。如果要求之一是高索引吞吐量,则更为重要。在这种情况下,您可以考虑使用快速 SSD 磁盘。不幸的是,如果您的数据量很大,这些磁盘会很昂贵。您可以通过避免使用 RAID 来改善这种情况(请参阅 https://en.wikipedia.org/wiki/RAID),RAID 0 除外。在大多数情况下,当您通过拥有多个服务器来处理容错时,额外的安全级别在 RAID 级别上是不必要的。最后 是避免使用外部存储,例如网络附加存储 (NAS) 或 NFS 卷。在这种情况下,网络延迟总是会扼杀这些解决方案的所有优势。
当您使用 Elasticsearch 集群时,每个节点都会打开多个与其他节点的连接以用于各种用途。当你索引时,数据被转发到不同的分片和副本。当您查询数据时,用于查询的节点可以对其他节点运行多个部分查询,并根据从其他节点获取的数据组成回复。这就是为什么您应该确保您的网络不是瓶颈的原因。在实践中,集群中的所有服务器使用一个网络,避免集群中的节点分散在数据中心之间的解决方案。
答案总是一样的,因为 取决于它。它取决于许多因素:每秒请求的数量、数据量、查询的复杂程度、聚合和排序的使用、每单位时间的新文档数量、新数据的搜索速度(刷新时间)、平均文档大小和使用的分析器。在实践中,最方便的答案是 - 测试它并进行近似。
经常被低估的一件事是数据安全性。当您考虑容错性和可用性时,您应该从三台服务器开始。为什么?我们在 Master 选举配置 部分讨论了脑裂的情况>第 9 章,Elasticsearch 集群详解。从三台服务器开始,我们能够在不关闭整个集群的情况下处理单个 Elasticsearch 节点故障。
您进行了一些测试,考虑了 仔细规划的功能、估计的数量和负载,并带着架构草案去找项目所有者。 “它太贵了”,他说,并要求你再考虑一下服务器。我们能做什么?
让我们考虑一下服务器角色并尝试介绍它们之间的一些差异。如果其中一个需求是索引大量与时间相关的数据(可能是日志),那么可能的方法是拥有两组服务器:热节点,当新数据到达时,冷节点,当旧数据移动时。由于这种方法,当快速磁盘不是这样时,与冷节点相反,热节点可能具有更快但更小的磁盘(即固态驱动器) 重要,但空间很重要。您还可以将您的体系结构分成几组,作为主服务器(功能较弱,磁盘相对较小)、数据节点(更大的磁盘)和查询聚合器节点(更多 RAM)。我们将在以下部分讨论这个问题。
当我们谈到垂直缩放时,我们通常的意思是向运行 Elasticsearch 的服务器。我们可以添加内存,或者我们可以切换到具有更好 CPU 或更快磁盘存储的机器。当然,有了更好的机器,我们可以期待性能的提升;根据我们的部署及其瓶颈,它可能是一个小的或大的改进。但是,在垂直缩放方面存在限制。例如, 限制之一是服务器可用的最大物理内存量或 JVM 运行所需的总内存量。当有大量数据和复杂查询时,您很快就会遇到内存问题,添加新内存可能根本没有帮助。在本节中,我们将尝试就单个 Elasticsearch 节点的查看位置和调整内容提供一般性建议。
调整系统时要记住的是性能测试,可以在相同情况下重复进行。进行更改后,您需要能够看到它如何影响整体性能。除此之外,Elasticsearch 的扩展性很好。使用这些知识,我们可以在单台机器(或其中几台)上运行性能测试并推断结果。这样的观察可能是进一步调整的一个很好的起点。
另外请记住,本节并未深入探讨所有与性能相关的主题,而是致力于向您展示最常见的内容。
除了我们将在本节中讨论的所有 内容外,您还需要记住三个与操作系统相关的主要内容:数字 允许的文件描述符、虚拟内存和避免交换。
请注意,以下部分包含有关 Linux 操作系统的信息,但您也可以在 Microsoft Windows 上实现类似的选项。
让我们从第三个开始。通常,基于 Elasticsearch 和 Java 虚拟机的应用程序不喜欢被交换。这意味着如果操作系统不将它们使用的内存放在交换空间中,这些应用程序会运行得最好。这很简单,因为要 访问交换后的内存,操作系统必须从磁盘中读取它,这很慢并且会影响表现非常糟糕。
如果我们有足够的内存,如果我们希望我们的 Elasticsearch 实例运行良好,我们应该有,我们可以配置 Elasticsearch 以避免交换。为此,我们只需要修改 elasticsearch.yml
文件并包含以下属性:
这是选项之一。第二种是将/etc/sysctl.conf
文件中的属性vm.swappiness
设置为0
(完全禁用交换)或 1
仅在紧急情况下交换(适用于内核版本 3.5 及更高版本)。
第三个选项是通过编辑 /etc/fstab
并删除包含 swap
单词的行来禁用交换。下面是一个示例 /etc/fstab
内容:
要禁用交换,我们只需从上述内容中删除第二行。我们还可以运行以下命令来禁用交换:
但是,请记住,这种效果在注销和重新登录系统之间不会持续存在,因此这只是一个临时解决方案。
另外,请记住,如果您没有足够的内存来运行 Elasticsearch,则操作系统会在禁用交换时终止该进程。
确保您有足够的 限制与运行 Elasticsearch 的用户相关的文件描述符(从官方软件包安装时,该用户将被称为 弹性搜索
)。如果不这样做,当 Elasticsearch 尝试刷新数据并创建新段或将段合并在一起时,您最终可能会遇到问题,这可能会导致索引损坏。
要调整允许的文件描述符的数量,您需要调整 /etc/security/limits.conf
文件(至少在大多数常见的 Linux 系统上)并调整或添加一个与给定用户相关的条目(对于软限制和硬限制)。例如:
建议将允许的文件描述符的数量至少设置为 65536
,但可能需要更多,具体取决于您的索引大小。
在某些 Linux 系统上,您可能还需要加载适当的限制模块才能使上述设置生效。要加载该模块,您需要调整 /etc/pam.d/login
文件并添加或取消注释以下行:
还可以通过添加 -Des.max-open- 显示 Elasticsearch 可用的文件描述符的数量files=true
参数到 Elasticsearch 启动参数。例如,像这样:
这样做时,Elasticsearch 将在日志中包含有关文件描述符的信息:
在考虑 Elasticsearch 配置相关的事情之前,我们应该记住要给 Elasticsearch 提供足够的内存。通常,我们不应将超过 50-60% 的总可用内存分配给运行 Elasticsearch 的 JVM 进程。我们这样做是因为 我们想为操作系统和操作系统 I/O 缓存留出内存。但是,我们需要记住,50-60% 的数字并不总是正确的。您可以想象在这样的节点上有 256GB RAM 的节点和总共 30GB 的索引。在这种情况下,即使将超过 60% 的物理 RAM 分配给 Elasticsearch,也会为操作系统留下大量 RAM。将 Xmx
和 Xms
属性设置为相同的值以避免 JVM 堆大小调整也是一个好主意。
要记住的另一件事 是所谓的压缩 oops (http://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance- enhancements-7.html#compressedOop),普通对象指针。可以通过添加 -XX:+UseCompressedOops
开关来告诉 Java 虚拟机使用它们。这允许 Java 虚拟机使用更少的内存来寻址堆上的对象。但是,这仅适用于小于或等于 31GB 的堆大小。选择更大的堆意味着没有压缩 oops 和更高的内存使用来寻址堆上的对象。
我们知道,默认情况下,Elasticsearch 中的字段数据缓存是无界的。这可能非常危险,尤其是当您对许多分析的字段使用聚合和排序时,因为它们不使用 doc
默认值。如果这些字段是高基数字段,那么您可能会遇到更多麻烦。我们所说的麻烦是指内存不足。
我们可以调整两个不同的因素,以确保我们不会遇到内存不足错误。首先,我们可以限制字段数据缓存的大小,我们应该这样做。第二件事是断路器,我们可以轻松地将其配置为仅抛出异常而不是加载太多数据。将这两件事结合在一起将确保我们不会遇到内存问题。
但是,我们还应该记住,如果数据的大小不足以处理聚合请求或排序,Elasticsearch 将从字段数据缓存中逐出数据。这会影响查询性能,因为加载字段数据信息效率不高,而且是资源密集型的。但是,在我们看来,最好让我们的查询慢一些,而不是因为内存不足错误而让我们的集群崩溃。
字段数据缓存和一般缓存在 Elasticsearch 缓存部分讨论ch09">第 9 章,Elasticsearch 集群详解。
每当您计划大量使用排序、聚合或脚本时,应尽可能使用 doc
值.这不仅可以节省字段数据缓存所需的内存,因为生成的对象更少,而且还可以使 Java 虚拟机以更少的垃圾收集器时间更好地工作。文档值已在 第 2 章的 映射配置 部分中讨论/a>,索引您的数据。
在 Chapter 9 的 Elasticsearch 缓存 部分中, Elasticsearch 集群详解,我们也讨论过。有几件事我们想提一下。首先,索引缓冲区的 RAM 越多,Elasticsearch 能够在内存中保存的文档就越多。因此,我们用于索引的 内存越多,刷新到磁盘的频率就越少,创建的段就越少。因此,您的索引会更快。但当然,我们不希望 Elasticsearch 占用 100% 的可用内存。请记住,RAM 缓冲区是按分片设置的,因此将使用的内存量取决于在给定节点上分配的分片和副本的数量以及您索引的文档数量。您应该设置上限,以便您的节点在分配了多个分片时不会崩溃。
Elasticsearch 使用 Lucene,我们现在已经知道了。 Lucene 的问题是索引视图不会在新数据被索引或创建段时刷新。要查看新索引的数据,我们需要刷新索引。默认情况下,Elasticsearch 每秒执行一次,刷新周期由 index.refresh_interval
属性控制,每个索引指定。刷新率越低,文档对搜索操作可见的速度就越快。但是,这也意味着 Elasticsearch 需要投入更多资源来刷新索引视图,这意味着索引和搜索操作会变慢。刷新率越高,您需要等待的时间就越长,才能在搜索结果中看到数据,但您的索引和查询速度会更快。
直到现在我们还没有讨论过线程池,但现在我们想提一下它们。每个 Elasticsearch 节点 拥有多个线程池,用于控制索引或查询等操作的执行队列。 Elasticsearch 使用多个池来控制线程的处理方式以及允许用户请求的内存消耗量。
Note
Java 虚拟机允许应用程序使用多个线程——同时运行多个 应用程序任务。有关 Java 线程的更多信息,请参阅 http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html。
有很多线程池(我们可以通过指定 type
属性来指定我们正在配置的类型)。但是,对于性能,最重要的是:
index
:这是线程池用于索引和删除操作。它的类型默认为fixed
,它的size
为可用处理器的数量,队列的大小为200
。search
:这是线程池用于搜索和计数请求。它的类型默认为fixed
,它的size
为可用处理器的数量乘以3再除以2,大小为队列默认为1000
。suggest
:这是用于建议请求的线程池。它的类型默认为fixed
,它的size
为可用处理器的数量,队列的大小为1000
。get
:这是实时使用的线程池get< /code> 请求。它的类型默认为
fixed
,它的size
为可用处理器的数量,队列的大小为1000
。bulk
:你可以猜到,这是用于批量操作的线程池。它的类型默认为fixed
,它的size
为可用处理器的数量,队列的大小为50
。percolate
:这是线程用于过滤请求的池。它的类型默认为fixed
,它的size
为可用处理器的数量,队列的大小为1000
。Note
在 Elasticsearch 2.1 之前,我们可以控制线程池的类型。从 Elasticsearch 2.1 开始,我们不能再这样做了。更多信息请参考官方文档 - https://www.elastic.co/guide/en/elasticsearch/reference/2.1/break_21_removed_features.html。
例如,如果我们想将索引操作的线程池配置为具有 100
的大小和 500
的队列,我们将在 elasticsearch.yml
配置文件中设置以下内容:
还要记住,可以使用集群更新 API 更新线程池配置。例如,像这样:
通常,您不需要使用线程池及其配置。但是,在配置集群时,您可能希望更加强调索引或查询,在这种情况下,为优先级分配更多线程或更大队列操作可能会导致更多资源用于此类操作。
Elasticsearch 是一个高度可扩展的搜索和分析平台。我们可以水平和垂直缩放它。我们在准备单个Elasticsearch节点 本章前面的部分,我们现在想关注水平缩放;如何处理同一个集群中的多个节点,它们应该具有什么角色,以及如何调整配置以拥有一个高度可靠、可用和容错的集群。
你可以想象垂直缩放就像建造一个摩天大楼——我们的可用空间有限,我们需要尽可能高。当然,这很昂贵,并且需要正确完成大量工程。另一方面,我们有水平缩放,就像在一个住宅区有很多房子一样。我们没有投资硬件并拥有强大的机器,而是选择拥有多台机器并将我们的数据在它们之间拆分。水平缩放为我们提供了几乎无限的缩放可能性。即使使用最强大的硬件,单台机器也不足以处理数据、查询或两者兼而有之的时候到了。在这种情况下,将数据分布在多个服务器之间可以节省我们的时间,并允许我们在整个集群中分布的多个索引中拥有数 TB 的数据,如下图所示:
我们有 4 个节点集群,其中 library
索引由四个分片创建和构建。
如果我们想增加我们集群的查询能力,我们可以增加额外的节点,比如四个。将新节点添加到集群后,我们可以创建由更多分片构建的新索引以更均匀地分散负载,或者将副本添加到已经存在的分片中。两种选择都是可行的。这是因为我们无法拆分分片或向现有索引添加更多主分片。当我们的硬件不足以处理它所拥有的数据量时,我们应该使用更多的主分片。在这种情况下,我们通常会遇到内存不足、分片查询执行时间长、交换或高 I/O 等待的情况。第二种选择,即拥有副本,是当我们的硬件愉快地处理我们拥有的数据但流量如此之高以至于节点无法跟上时的方式。
第一个选项很简单,但让我们看看第二种情况 - 拥有更多副本。因此,如果有四个额外的节点,我们的集群将如下所示:
我们的集群视图或多或少如下所示:
如您所见,构建 library
索引的每个初始分片都有一个副本存储在另一个节点上。分片及其副本的好处是 Elasticsearch 足够聪明,可以在单个索引中平衡分片并将它们放在不同的节点上。例如,您永远不会遇到分片及其副本在同一个节点上的情况。此外,Elasticsearch 能够在分片及其副本之间循环查询,这意味着所有节点都会被查询命中,我们不必关心这一点。因此,与初始部署相比,我们能够处理几乎两倍的查询负载。
让我们在副本周围多呆一会儿。 Elasticsearch 允许我们在集群足够大时自动扩展副本。这意味着在将新节点添加到集群时可以自动创建副本。您可能想知道这些功能在哪里可以有用。想象一下这样一种情况,您希望在每个节点上都存在一个小索引,这样您的插件就不必为了从中获取数据而运行分布式查询。除此之外,您的集群是动态变化的,即您可以从中添加和删除节点。实现此类功能的最简单方法是允许 Elasticsearch 自动扩展副本。为此,我们需要将 index.auto_expand_replicas
设置为 0-all
,这意味着索引可以有 0 个副本或存在于所有节点上。因此,如果我们的小索引名为 shops
,并且我们希望 Elasticsearch 自动将其副本扩展到集群中的所有节点,我们将使用以下命令创建索引:
如果该索引已经创建,我们还可以通过运行以下命令来更新该索引的设置:
The Elasticsearch replication mechanism not only gives us ability to handle higher query throughput, but also gives us redundancy and high availability. Imagine an Elasticsearch cluster hosting a single index called library
that is built of 2 shards and 0 replicas. Such a cluster would look as follows:
现在当其中一个节点发生故障时会发生什么?最简单的答案是我们丢失了大约 50% 的数据,如果失败是致命的,我们将永远丢失这些数据。即使有备份,我们也需要启动另一个节点并恢复备份,这需要时间。在此期间,您的应用程序或基于 Elasticsearch 的部分应用程序无法正常工作。如果您的业务依赖于 Elasticsearch,停机时间意味着金钱损失。当然,我们可以使用副本来创建更可靠的集群来处理硬件和软件故障。需要记住的一件事是,一切最终都会失败——如果软件不会,硬件也会。例如,前段时间谷歌表示,在他们的每个集群中,第一年至少有 1000 台机器会出现故障(您可以阅读更多关于该主题的信息在 http://www.cnet。 com/news/google-spotlights-data-center-inner-workings/)。因此,我们需要做好处理此类案件的准备。
让我们看看同一个集群,但只有一个副本:
现在失去一个 Elasticsearch 节点意味着我们仍然拥有可用的全部数据,我们可以在不停机的情况下恢复整个集群结构。当然,这只是一个由两个 Elasticsearch 节点集群构建的非常小的集群。集群越大,副本越多,您可以处理的故障就越多,而不必担心数据丢失。当然,性能会降低,具体取决于失败节点的百分比,但数据仍然存在并且集群将正常运行。
这就是为什么在设计您的架构并决定节点和索引的数量以及它们的 架构时,您应该考虑有多少节点,您想要失败生活。当然,你不能忘记等式中的性能 部分,但冗余和高可用性应该是扩展等式的因素之一。
Elasticsearch 的默认分布式特性及其水平扩展能力使我们能够灵活地在运行环境时的性能和成本方面。首先,具有高性能磁盘、众多 CPU 内核和大量 RAM 的高端服务器仍然很昂贵。除此之外,云计算越来越流行,如果您需要很大的灵活性并且不想拥有自己的硬件,您可以选择 解决方案,例如 Amazon (http://aws.amazon.com/),机架空间(http:// www.rackspace.com/), DigitalOcean (https://www.digitalocean.com /) 等等。它们不仅允许我们在租用的机器上运行我们的软件,还允许我们按需扩展。我们只需要添加更多机器,只需点击几下,甚至可以通过一定程度的工作实现自动化。
使用带有一键式机器租赁的托管解决方案可以拥有真正水平可扩展的解决方案。当然,这并不便宜——您需要为灵活性付费。但是,如果成本是我们业务计划中最关键的因素,我们很容易牺牲性能。当然,我们也可以反其道而行之。如果我们能负担得起大型裸机,Elasticsearch 集群可以推送到存储在索引中的数百 TB 数据,并且仍然可以获得不错的性能(当然,需要适当的硬件和分布式属性)。
在讨论 Elasticsearch 的可扩展性方面时,高可用性、成本和性能灵活性以及几乎无限的增长并不是唯一值得讨论的事情。在某个时间点,您可能希望将 Elasticsearch 集群升级到新版本。这可能是由于错误修复、性能改进、新功能或您能想到的任何事情。问题是,当您拥有每个分片的单个实例且没有副本时,升级意味着 Elasticsearch(或至少其部分)不可用,这可能意味着使用 Elasticsearch 的应用程序停机。这是水平缩放如此重要的另一个原因。您可以执行升级,至少到 Elasticsearch 等软件支持的程度。例如,您可以使用 Elasticsearch 2.0 并升级到 Elasticsearch 2.1,只需滚动重启(将一个节点从集群中取出、升级、带回,然后继续使用下一个节点,直到所有节点都完成),从而拥有所有数据仍可同时进行搜索和索引。
拥有具有大量内存和 CPU 内核的大型物理机 具有优势和一些挑战。首先,如果你决定在那台机器上运行一个 Elasticsearch 节点,你迟早会遇到垃圾收集问题,你会有很多单个节点上的分片将需要大量 I/O 操作来进行内部 Elasticsearch 通信(检索集群统计信息),等等。更重要的是,你通常不应该为单个 JVM 进程使用超过 31GB 的堆内存,因为你不能使用压缩的 普通对象指针(https://docs.oracle .com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html)。
在这种情况下,您可以在同一台裸机上运行多个 Elasticsearch 实例,在每个虚拟机中运行多个虚拟机和一个 Elasticsearch,或者在容器中运行 Elasticsearch,例如 作为 Docker (http://www.docker.com/) .这超出了本书的范围,但是,因为我们正在讨论缩放,我们认为提及在这种情况下可以做什么可能是一件好事。
Note
也有可能在单个物理机上运行多个 Elasticsearch 服务器,而无需运行多个虚拟机。走哪条路——虚拟机还是多实例——真的是你的选择。但是,我们喜欢将事物分开,因此我们通常会将任何大型服务器划分为多个虚拟机。将一台大型服务器划分为多个较小的虚拟机时,请记住 I/O 子系统将在这些较小的虚拟机之间共享。因此,明智地在虚拟机之间划分磁盘可能会很好。
还有一个 值得一提。当您将多个物理服务器划分为虚拟 机器时,确保分片及其副本不会最终位于同一物理机器上至关重要。默认情况下,Elasticsearch 足够智能,不会将 shard 及其副本放在同一个 Elasticsearch 实例上,但它对裸机机器一无所知,所以我们需要告诉它。我们可以通过集群分配 意识告诉 Elasticsearch 将分片和副本分开。在我们之前的案例中,我们有三台物理服务器。我们称它们为:server1
、server2
和 server3
。
现在对于物理服务器上的每个 Elasticsearch,我们定义 node.server_name
属性并将其设置为服务器的标识符(属性的名称可以是我们想要的任何名称) .例如,对于第一台物理服务器上的所有 Elasticsearch 节点,我们将在 elasticsearch.yml 中设置 以下属性
配置文件:
除此之外,每个 Elasticsearch 节点(无论在哪个物理服务器上)都需要在 elasticsearch.yml
配置文件中添加以下属性:
它告诉 Elasticsearch 不要将主分片及其副本放在 node.server_name
属性中具有相同值的节点上。这对我们来说已经足够了,剩下的交给 Elasticsearch 来处理。
我们还想讨论和强调一件事。对于大型集群,为集群中的所有节点分配角色非常重要。这允许一个真正完全容错且高度可用的 Elasticsearch 集群。我们可以分配给每个 Elasticsearch 节点的角色如下:
主合格节点
数据节点
查询聚合器节点
默认情况下,每个 Elasticsearch 节点都是主节点(它可以作为主节点),可以保存数据,并作为查询聚合器节点工作。您可能想知道为什么需要这样做。让我们举个简单的例子:如果主节点压力很大,它可能无法足够快地处理集群状态相关的命令,集群可能会变得不稳定。这只是一个简单的示例,您可以想到许多其他示例。
因此,大多数大于几个节点的 Elasticsearch 集群通常如下图所示:
可以看到,我们假设的集群包含三个客户端节点(因为我们知道会有很多查询),大量的数据节点因为数据量会很大,并且在 至少三个不应该做任何其他事情的主合格节点。当 Elasticsearch 在任何给定时间只使用一个主节点时,为什么要三个主节点?同样,由于冗余和能够通过将 discovery.zen.minimum_master_nodes
设置为 2
来防止脑裂情况,这将允许我们轻松处理集群中单个符合条件的主节点的故障。
现在让我们为您提供集群中每种类型节点的配置片段。我们已经在章节的了解节点发现部分讨论过这个问题9,详细介绍 Elasticsearch 集群,但我们想再次提及这一点。
在本章之前,我们主要讨论了 Elasticsearch 的不同功能,包括处理查询、索引数据和调优。但是,在生产环境中运行集群不仅仅是使用这个出色的搜索引擎,还需要让集群准备好处理 索引和查询负载。现在让我们 总结一下我们所掌握的知识,看看在准备集群以实现高索引和查询吞吐量时,我们需要注意哪些事项。
在本节中,我们将查看有关调整 Elasticsearch 的索引相关建议。每个生产环境数据不同,索引率不同,用户行为不同。考虑到这一点并在您的环境中运行性能测试。这将使您最好地了解预期的内容以及在您的系统中最有效的方法。
您应该注意的一般事项之一是索引刷新率。我们知道刷新率指定文档在搜索操作中可见的速度有多快。这个等式很简单——刷新率越快,查询越慢,索引吞吐量越低。如果我们可以允许自己有一个较慢的刷新率,例如 10s
或 30s,
就去吧。总体而言,它将减少对 Elasticsearch、Lucene 和硬件的压力。请记住,默认情况下刷新率设置为 1s
,这基本上意味着索引搜索器对象每秒重新打开一次。
为了让您对我们所说的性能提升有一些了解,我们进行了一些性能测试,包括 Elasticsearch 和不同的刷新率。凭借 1s
的刷新率,我们能够使用单个 Elasticsearch 节点每秒索引大约 1000 个文档.将刷新率提高到 5s
后,我们的索引吞吐量增加了 25% 以上,我们每秒可以索引大约 1250 个文档。将刷新率设置为 25s
与 1s
刷新率(大约 1700 个文档)相比,吞吐量提高了大约 70%每秒在相同的基础设施上。还值得记住的是,无限期地增加时间并没有多大意义,因为在某个点之后(取决于您的数据负载和您拥有的数据量),性能的提高可以忽略不计。
一些与索引吞吐量和索引刷新率相关的性能比较 可以在 http://blog.sematext.com/2013/07/08/elasticsearch-refresh -interval-vs-indexing-performance/。
默认情况下,当涉及到所有线程池配置时,Elasticsearch 提供了非常好的默认值。您应该记住,只有当您真正看到您的节点正在填满队列并且它们仍有剩余处理能力时,才应该调整默认线程池配置可以指定处理等待操作或当您想要增加一个或多个操作的优先级时。
例如,如果您进行了性能测试,发现您的 Elasticsearch 实例没有 100% 饱和,但另一方面您遇到了拒绝执行错误,那么您应该开始调整线程池。您可以增加允许同时执行的线程数量,也可以增加队列。当然,您还应该记住,将并发运行的线程数增加到 非常高的数字会导致许多 CPU 上下文切换(http://en.wikipedia.org/wiki/Context_switch) 这将导致性能下降。
在 Elasticsearch 2.0 之前,我们 必须关心我们的段进程是如何配置的,以及通常可以使用多少磁盘 I/O 合并,但情况发生了变化。现在,Elasticsearch 查看 I/O 子系统的行为方式,并在合并落后于索引时调整限制和合并过程。因此,我们不再需要 为基于磁盘的操作自动调整节流。您可以在 GitHub 上的 https://github.com/elastic/elasticsearch/pull/9243。
当您拥有基于时间的数据(例如日志)时,您的索引架构扮演着非常 重要的角色。假设我们已将日志索引到 Elasticsearch。这些通常大量出现,不断被索引,并且与时间相关(记录的事件发生在某个时间点)。假设您对数据有一定的保留,并且您希望数据在 Elasticsearch 中呈现和可搜索的时间。在那之后,您只需删除数据并忘记它。
考虑到这些假设,您可以只创建一个包含大量分片的索引,并尝试在那里索引大量日志。然而,这并不是完美的解决方案。首先,由于合并——索引越大,合并的成本就越高。 Elasticsearch 需要合并越来越大的段,并且需要更多的 I/O 和 CPU 来处理它们。这意味着放缓。除此之外,删除会很昂贵,因为您必须使用 TTL 或使用查询插件删除来删除数据——这两种方法在性能方面的使用成本很高,并且会导致更多的合并。这还不是全部——在查询期间,您必须遍历整个索引才能获得最小的数据片段。那么,对于基于时间的数据有更好的索引架构吗?
是的,最常见和最好的解决方案之一是使用基于时间的索引。根据数据量,您可以拥有每日、每周、每月甚至每小时索引。缺点是索引数量增加时您将拥有的分片数量,但除此之外只有优点:您可以控制每个索引,根据需要更改分片数量,并且合并速度更快,因为索引将与只有一个大索引相比要小。更重要的是,删除数据一点也不痛苦——想法是删除整个索引;例如,在每日指数的情况下,一天的数据。查询也将受益——您只需在基于单一时间的索引上运行查询即可缩小搜索结果的范围。最后,默认情况下,Elasticsearch 将为我们创建索引。例如,在使用每日索引时,我们可以有 logs_2016-01-01
、logs_2016-01-02
等名称,等等。
我们唯一需要关心的是根据日期提供索引名称并创建模板来配置每个新创建的索引,其余的由 Elasticsearch 完成。
随着 Elasticsearch 2.0 的发布,我们可以在 elasticsearch.yml
中指定多个 path.data
属性指向不同物理设备上的不同目录。 Elasticsearch 现在可以通过在不同的设备上放置不同的分片并 以最有效的方式使用多条路径来利用这一点。因此,如果我们有多个磁盘,我们可以并行写入磁盘。这对于索引大量数据的高索引用例特别有用。
众所周知,Elasticsearch 世界中的每个索引都可以分为多个 shard,每个 shard 可以有多个 个副本。如果您有多个 Elasticsearch 节点(并且您可能会在生产中拥有),您应该考虑分片和副本的数量以及这将如何影响您的节点。数据分布对于集群上的负载来说可能是至关重要的,并且不会让某些节点比其他节点做更多的工作。
让我们看下面的例子。假设我们有一个由 4 个节点构建的集群,它有一个名为 book
的索引,由 3 个分片和一个副本构建。这样的部署将如下所示:
如您所见,前两个节点分配了两个物理分片,而后两个节点各分配了一个分片。实际数据分配不均。在发送查询和索引数据时,我们将让前两个节点比其他两个节点做更多的工作——这是我们想要避免的。一种选择是让 book
索引有两个分片和一个副本,所以它看起来如下:
这种架构可以工作,而且非常好。我们不必在所有节点上都有主分片,我们可以 有副本,这取决于我们期望的瓶颈。对于查询,我们可能希望拥有更多的副本,以索引更多的主节点。
我们还可以让我们的主分片平均分割,如下图所示:
不过要记住的是,在这两种情况下,我们最终都会得到均匀分布的分片和副本,并且 Elasticsearch 将在所有节点上做类似的工作量。当然,如果有更多的索引(比如有每日索引),让数据均匀分布可能会更棘手,并且可能不可能有均匀分布的分片,但我们应该尝试达到这一点。
当涉及到数据分布、分片和副本时,要记住的另一件事是,在设计索引架构时,您应该记住要实现的目标。如果您要使用非常高的索引用例,您可能希望将索引分散到多个 分片中,以降低 CPU 和服务器的 I/O 子系统。这对于运行昂贵的查询也是如此,因为使用更多的分片可以降低单个服务器上的负载。但是,对于查询还有一件事——如果您的节点无法跟上查询引起的负载,您可以添加更多 Elasticsearch 节点并增加副本数量,以便将主分片的物理副本放在那些节点。这会使索引速度变慢一些,但会让您有能力同时处理更多查询。
这是非常明显的建议,但您会惊讶于有多少 Elasticsearch 用户忘记了批量索引数据而不是逐一发送文档。所以这里的建议是尽可能地做批量而不是一个一个的索引。不过要记住的是 不要用太多的批量请求使 Elasticsearch 过载,并将它们保持在合理的大小(不要将数百万个文档推送到一个要求)。请记住批量线程池及其大小,并尝试调整您的索引器不要超出它,否则您将首先开始对这些请求进行排队,如果 Elasticsearch 无法处理它们,您将很快开始看到被拒绝的执行异常和您的数据不会被索引。
举个例子,我们想展示我们前段时间对两种类型的索引进行的测试结果:一一索引和批量索引。在下图中,我们有一个一个文档运行索引时的索引吞吐量:
在下一张图片中,我们做同样的事情,但我们不是逐个索引文档,而是分批索引它们 10 个文档(这仍然是一个相对批量文档数量少):
如您所见,在逐个索引文档时,我们每秒可以索引大约 30 个文档,并且非常稳定。这种情况随着批量索引和 10 个文档的批量而改变;我们每秒能够索引超过 200 个文档。所以可以很明显的看出区别。
当然这是索引速度的一个非常基本的比较。为了显示真正的区别,我们应该使用几十个线程并将 Elasticsearch 推到极限。但是,前面的比较应该为您提供使用批量索引时索引吞吐量增益的基本视图。
请记住,索引缓冲区(indices.memory.index_buffer_size
属性)的可用 RAM 越多,Elasticsearch 可以在内存中保存的文档就越多。但是,我们 不希望 Elasticsearch 占用 100% 的可用内存。索引缓冲区可以帮助我们延迟刷新到磁盘,这意味着更少的 I/O 压力和更少的合并。您可以在第 9 章,Elasticsearch Cluster 中阅读更多关于索引缓冲区配置的信息< /em>。
Elasticsearch 的一大特色是它能够搜索和分析被索引的数据。但是,有时需要调整 Elasticsearch 和我们的查询,以便不仅获得 查询的结果,而且还可以快速(或以合理的数量)获得它们时间)。在本节中,我们将探讨为高查询吞吐量用例准备 Elasticsearch 的可能性,但不仅限于此。我们还将查看查询时的一般性能提示。
分片请求缓存的目的是缓存聚合、建议结果和命中数(它不会缓存返回的文档,因此仅适用于 < code class="literal">size=0)。当您的查询使用聚合或建议时,启用此缓存(默认禁用)可能是个好主意,以便 Elasticsearch 可以重用存储在那里的数据。缓存的最佳之处在于它承诺与未缓存的搜索相同的近实时搜索。您可以在 Chapter 9, 中了解更多关于缓存和分片请求缓存的信息Elasticsearch 集群详解。
这是我们实际上可以给出的最一般的建议——您应该始终考虑最佳查询结构、过滤器使用等。例如,让我们看一下以下查询:
它返回符合一些条件的书。但是,我们可以在前面的查询中改进一些事情。比如我们可以移动tag
、部门、
、category等静态的东西
字段相关条件到布尔查询的 filter
部分,这样下次我们使用查询的某些部分时,我们可以节省 CPU 周期并重新使用信息存储在缓存中。当它涉及到评分时,该静态过滤信息也无关紧要。因此,我们可以将这些静态元素移动到 filter
部分并省略它们的评分计算。例如,优化后的查询如下所示:
如您所见,我们做了一些事情。我们仍然使用 bool
查询,但我们引入了 filter
部分的使用。我们对静态的、未分析的字段使用过滤。这使我们能够在我们执行的下一个查询中轻松地重用过滤器。由于这种查询重组,我们能够简化主查询。这正是您在优化或设计查询时应该做的事情 - 牢记优化和 性能,并尽量保持最佳状态.这将导致更快的查询执行、更低的资源消耗和更好的整个 Elasticsearch 集群的运行状况。
通常被遗忘的一件事是需要并行化查询。想象一下,您的集群中有十几个节点,但您的索引是由单个分片构建的。如果索引很大,您的查询将执行得比您预期的要差。当然你可以增加副本的数量,但是 没有帮助。单个查询仍将转到该索引中的单个分片,因为副本不超过主分片的副本,并且它们包含相同的数据(或者至少它们应该包含相同的数据)。这不仅适用于具有一个分片的索引,而且如果您有多个分片,但它们非常大,您仍然可能会遇到与性能相关的问题。据说查询只和最慢的部分查询响应一样快。
当然,并行化也取决于用例。如果您对 Elasticsearch 运行大量查询,则可能不需要并行化查询,尤其是当分片足够小并且您看不到分片级别的问题时。通常,查看您的 Elasticsearch 节点并查看它们是否有未使用的 CPU 内核,如果是这种情况,您可能还有改进和并行化的空间。
我们可以调整两个不同的因素,以确保我们不会遇到内存不足错误。首先,我们可以限制字段数据缓存的大小。第二件事是断路器,我们可以很容易地配置为只抛出异常而不是加载太多数据。结合这两件事 将确保我们不会遇到内存问题。即使您经常使用 doc
值,您仍然可能会遇到内存不足的问题。例如,对于不能使用 doc
值并将使用字段数据缓存的分析字段 - 正确配置字段数据缓存和断路器。您可以在 Chapter 9, Elasticsearch Cluster 中详细了解如何配置它们。
在处理一些使用聚合的查询时,我们有可能使用两个属性:size
和 shard_size
。 size
参数定义了最终聚合结果应该返回多少个桶;聚合最终结果的 节点将从返回结果的每个分片中获取顶部存储桶,并且只会返回顶部 大小
给客户。 shard_size
参数告诉 Elasticsearch 大致相同,但在分片级别。增加 shard_size
参数的值将导致更准确的聚合(例如在重要术语聚合的情况下),但会以网络流量和内存使用为代价。降低该参数将导致聚合结果不太精确,但我们将受益于更低的内存消耗和更低的网络流量。如果我们发现内存使用量太大,我们可以针对有问题的查询降低 size
和 shard_size
属性,看看是否结果质量还是可以接受的。
Elasticsearch 监控 API 公开了大量信息,包括搜索引擎本身以及环境(例如操作系统)。我们在 第 10 章中看到,管理您的集群。由于这一点以及检索这些信息的便利性,构建了许多应用程序——这些应用程序允许我们进行监控及其他工作。其中一些应用程序很简单,无需任何持久存储即可实时读取数据,而 其他应用程序允许我们读取有关集群行为的历史数据。在本章中,我们只会稍微触及有关此类应用程序的大量信息,但我们强烈建议您熟悉其中的一些,因为它们可以使您的 Elasticsearch 日常工作更加轻松。
我们选择了三个监控 解决方案示例,它们采用了与 Elasticsearch 集成的不同方法。前两个工具可作为 Elasticsearch 插件使用,第三个工具采用不同的集成方法。
该工具可作为 Elasticsearch 插件使用,但也可以作为在浏览器中运行的 JavaScript 应用程序单独下载。
Elasticsearch HQ 使用 JavaScript 和 AJAX 技术,定期从集群中获取数据,准备在浏览器端进行可视化,并显示给用户。
该工具允许我们 跟踪特定节点的统计信息。浏览器可以显示有关集群和特定节点的重要信息。以下屏幕截图显示了 Elasticsearch HQ 的图形用户界面:
我们有关于集群、节点数量和 Elasticsearch 运行状况的基本信息。我们还可以看到我们正在查看哪个节点以及有关该节点的一些统计信息,其中包括内存使用情况(堆和非堆)、线程数、Java 虚拟机垃圾 收藏家工作,等等。该插件还提供有关架构和分片的简化信息,并允许执行简单的查询。
为了安装 Elasticsearch HQ,只需运行以下命令:
之后,GUI 将在 http://localhost:9200/_plugin/hq/
上可用。
要记住的一件事 是 Elasticsearch HQ 不会将获取的数据保存在任何地方,因此只有在浏览器运行并打开 Elasticsearch HQ 时才会获取数据.如果过去发生过某些事情,您将无法诊断它。
Marvel 是由 Elasticsearch 团队创建的工具 。在当前版本中,它被构建为一个可视化平台的插件称为Kibana (https://www.elastic.co/products/kibana) .
Marvel 还通过绘制随时间动态更新的漂亮图形来可视化有关集群和节点的基本信息。与 Elasticsearch HQ 的主要区别在于性能数据 存储在服务器端(在同一个或外部的 Elasticsearch 集群中),因此可以使用历史数据。示例 屏幕截图如下所示:
Marvel 的安装过程包含三个步骤:
最后,第三步 是通过运行以下命令在 Kibana 中安装 Marvel 插件:
此工具提供了 与前面提到的工具不同的方法。 SPM 是一种 软件即服务(SaaS) 解决方案,用于监控任何规模的 Elasticsearch 安装,并允许监控多个集群和不同的技术。虽然它的根源是基于 SaaS 的,但它也可以在本地使用,这意味着您可以在自己的机器上运行 SPM,而无需将指标发送到云。
信息通过安装在 Elasticsearch 机器上的简单客户端软件发送到 SPM 服务器。主要优点是可以在更广泛的时间内存储信息并查看过去发生的事情。您可以创建自己的仪表板并将指标与多个应用程序之间的日志相关联(SPM 允许您监控各种应用程序)。
以下屏幕截图显示了 SPM for Elasticsearch 的仪表板:
前面屏幕截图中显示的概览仪表板提供了有关集群节点、请求率和延迟、索引中的文档数量、CPU 使用率、负载、内存详细信息、Java 虚拟机内存、磁盘空间使用情况以及最后网络的信息交通。您可以通过进入专用于它的选项卡来获取有关每个元素的详细信息。
您可以在 有关 SPM 安装和可用选项的其他信息.html" target="_blank">http://sematext.com/spm/index.html。
在本章中,我们专注于扩展和调整 Elasticsearch。我们从需要做出的硬件准备和决策开始。接下来,我们尽可能多地调整单个 Elasticsearch 节点,然后我们将整个集群配置为尽可能好地工作。我们讨论了垂直扩展的可能性,并学习了如何在集群进入生产环境后对其进行监控。
所以现在我们已经到了本书的结尾。我们希望这是一次愉快的阅读体验,并且您发现这本书很有趣。自本书上一版以来,Elasticsearch 发生了很大变化。不仅在版本方面,而且在功能方面。一些功能不再存在,其中一些被移到插件中,当然还添加了新功能。我们真的希望您从这本书中学到了一些东西,现在您会发现每天使用 Elasticsearch 变得更加容易——无论您是这个世界的初学者还是半经验的 Elasticsearch 用户。作为本书的作者,同时也是 Elasticsearch 的用户,我们努力为您,我们的读者,提供我们力所能及的最佳阅读体验。当然,Elasticsearch 比我们在书中描述的要多,尤其是在监控和管理功能以及 API 方面。但是,页数是有限的,如果我们要详细描述所有内容,我们最终会写出一千页长的书。我们需要记住,Elasticsearch 不仅用户友好,而且提供了大量的配置选项、查询可能性等等。因此,我们必须选择更详细地描述哪些功能,哪些只需要提及,哪些必须完全跳过。与您所持有的这本书的前两个版本一样,我们希望我们做出了正确的选择,并且您对自己所读的内容感到满意。
我们还想说,值得记住的是 Elasticsearch 在不断发展。在编写本书时,我们经历了几个稳定的版本,最终发布到 Elasticsearch 2.2。甚至在那个时候,我们就知道新功能和改进即将到来,就像书中提到的一些更改将成为下一个版本的一部分,或者至少它们是计划中的。如果您想及时了解正在添加的新功能,请务必定期查看 Elasticsearch 的官方文档以获取 Elasticsearch 新版本的发行说明。我们还将在 www.elasticsearchserverbook.com. 所以如果您有兴趣,请不时访问该站点。
再次感谢您花在这本书上的时间。