MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch从gateway到allocation流程的转换技巧

2022-06-116.6k 阅读

ElasticSearch 存储基础概念

1. 索引(Index)

在 Elasticsearch 中,索引是一个存储数据的逻辑容器,类似于关系型数据库中的数据库概念。它是文档的集合,这些文档可以是各种类型的数据,比如日志、文章、产品信息等。每个索引都有一个唯一的名称,并且可以通过这个名称来对索引中的数据进行操作,例如索引文档、搜索文档等。

2. 分片(Shard)

由于单个 Elasticsearch 节点的存储和处理能力有限,为了处理大规模的数据,索引会被分割成多个部分,这些部分就称为分片。每个分片本身就是一个功能完整的小型搜索引擎,它可以独立地进行数据的存储和检索。分片机制使得 Elasticsearch 能够在多个节点上分布式存储数据,从而提高了系统的可扩展性和性能。Elasticsearch 支持两种类型的分片:主分片(Primary Shard)和副本分片(Replica Shard)。主分片负责数据的写入和初始存储,而副本分片则是主分片的拷贝,主要用于提高数据的可用性和读取性能。

3. 节点(Node)

节点是 Elasticsearch 集群中的一个运行实例,它可以存储数据、参与集群的索引和搜索操作。一个 Elasticsearch 集群可以由一个或多个节点组成。根据节点的角色不同,可以分为以下几种类型:

  • 数据节点(Data Node):负责存储数据,执行数据的 CRUD(创建、读取、更新、删除)操作。数据节点对硬件资源的要求较高,因为它们需要处理大量的数据存储和 I/O 操作。
  • 主节点(Master Node):负责管理集群的元数据,如索引的创建、删除,节点的加入和离开等。主节点并不存储数据,它主要处理集群的管理任务,对 CPU 和内存资源有一定的要求。
  • 客户端节点(Client Node):不存储数据,也不参与集群的管理,主要用于接收用户的请求,并将请求转发到合适的节点上执行。客户端节点可以分担主节点和数据节点的负载,提高集群的整体性能。

Gateway 机制

Gateway 概述

Gateway 是 Elasticsearch 用于持久化集群状态和数据的机制,它在节点重启或集群故障恢复时起着至关重要的作用。Gateway 的主要功能是在集群启动时恢复集群状态和数据,确保集群能够快速、准确地恢复到故障前的状态。

Gateway 类型

  1. 本地文件系统 Gateway(Local Gateway):这是 Elasticsearch 默认的 Gateway 类型,它将集群状态和数据存储在本地文件系统中。每个节点都会在本地磁盘上保存一份数据副本,这种方式简单直接,但在节点故障或磁盘损坏时可能会导致数据丢失。本地文件系统 Gateway 的配置相对简单,只需要在 elasticsearch.yml 文件中指定数据存储路径即可:
path.data: /var/lib/elasticsearch
  1. 共享文件系统 Gateway(Shared File System Gateway):共享文件系统 Gateway 允许集群中的多个节点共享同一个数据存储,通常使用 NFS(Network File System)或 GlusterFS 等分布式文件系统。这种方式提高了数据的可用性,因为即使某个节点故障,其他节点仍然可以从共享文件系统中访问数据。配置共享文件系统 Gateway 需要在每个节点的 elasticsearch.yml 文件中指定共享文件系统的挂载点:
gateway.type: shared_file_system
gateway.recover_after_nodes: 2
gateway.expected_nodes: 3
  1. Amazon S3 Gateway:对于使用 Amazon Web Services(AWS)的用户,Elasticsearch 提供了与 Amazon S3 集成的 Gateway。这种 Gateway 类型将数据存储在 Amazon S3 中,利用 S3 的高可用性和持久性来保护数据。配置 Amazon S3 Gateway 需要在 elasticsearch.yml 文件中指定 S3 的相关配置,如访问密钥、存储桶名称等:
gateway.type: s3
gateway.s3.bucket: my-elasticsearch-bucket
gateway.s3.region: us-west-1
gateway.s3.credentials.access_key: your-access-key
gateway.s3.credentials.secret_key: your-secret-key

Gateway 工作流程

  1. 数据写入 Gateway:当 Elasticsearch 集群中的节点接收到新的数据写入请求时,首先会将数据写入内存缓冲区。然后,每隔一段时间(默认 1 秒),这些数据会被刷新到文件系统缓存中,并生成一个新的段(Segment)文件。当段文件达到一定大小或满足其他条件时,会被合并成更大的段文件。同时,集群状态信息也会被定期保存到 Gateway 中。
  2. 从 Gateway 恢复数据:在集群启动时,节点会首先尝试从 Gateway 中恢复集群状态。主节点会读取 Gateway 中的集群状态信息,然后根据这些信息来协调各个节点的恢复过程。数据节点会从 Gateway 中读取数据文件,并将其加载到内存中,从而恢复到故障前的状态。

Allocation 机制

Allocation 概述

Allocation 是 Elasticsearch 中负责将分片分配到集群中各个节点的过程。合理的分片分配策略可以提高集群的性能、可用性和资源利用率。Elasticsearch 的 Allocation 机制会考虑多个因素,如节点的负载、磁盘空间、节点的角色等,以确保分片能够均匀地分布在集群中。

Allocation 策略

  1. 基于节点负载的分配:Elasticsearch 会监控每个节点的 CPU、内存、磁盘 I/O 等资源使用情况,并根据这些指标来评估节点的负载。在分配分片时,会优先将分片分配到负载较低的节点上,以避免某个节点负载过高而影响整个集群的性能。
  2. 基于磁盘空间的分配:磁盘空间是另一个重要的分配因素。Elasticsearch 会避免将分片分配到磁盘空间不足的节点上,以防止数据写入失败。当某个节点的磁盘空间达到一定阈值时,Elasticsearch 会自动将该节点上的分片迁移到其他磁盘空间充足的节点上。
  3. 基于节点角色的分配:根据节点的角色不同,Elasticsearch 会有不同的分配策略。例如,主分片通常会优先分配到主节点上,以确保集群的稳定性;而副本分片则会尽量分配到与主分片不同的节点上,以提高数据的可用性。

Allocation 流程

  1. 初始分配:当创建一个新的索引时,Elasticsearch 的主节点会根据当前集群的状态和分配策略,决定将索引的主分片和副本分片分配到哪些节点上。主节点会向选中的节点发送分配请求,节点接收到请求后会创建相应的分片并开始初始化数据。
  2. 动态分配:在集群运行过程中,当节点加入或离开集群、节点负载发生变化、磁盘空间不足等情况时,Elasticsearch 的主节点会重新评估分片的分配情况,并进行动态调整。例如,如果某个节点负载过高,主节点会将该节点上的部分分片迁移到其他负载较低的节点上;如果某个节点故障,主节点会将该节点上的分片重新分配到其他可用节点上。

从 Gateway 到 Allocation 流程的转换技巧

1. 理解 Gateway 和 Allocation 的关系

Gateway 和 Allocation 是 Elasticsearch 中两个紧密相关的机制。Gateway 负责数据的持久化存储和恢复,而 Allocation 则负责在集群中合理分配分片。在进行从 Gateway 到 Allocation 流程的转换时,首先要明确两者的功能和相互依赖关系。例如,在从 Gateway 恢复数据后,Allocation 机制会根据集群的当前状态和配置,重新分配分片,以确保集群的性能和可用性。

2. 优化 Gateway 配置以支持 Allocation

  • 选择合适的 Gateway 类型:根据实际需求选择合适的 Gateway 类型,如本地文件系统 Gateway、共享文件系统 Gateway 或 Amazon S3 Gateway。如果对数据的可用性要求较高,建议选择共享文件系统 Gateway 或 Amazon S3 Gateway,这样在节点故障时可以更快地恢复数据,为 Allocation 提供更好的基础。
  • 调整 Gateway 恢复参数:在 elasticsearch.yml 文件中,可以调整一些 Gateway 恢复参数,如 gateway.recover_after_nodesgateway.expected_nodesgateway.recover_after_nodes 表示在等待多少个节点加入集群后开始恢复数据,gateway.expected_nodes 表示期望的集群节点总数。合理调整这些参数可以控制数据恢复的时机和速度,避免在集群节点未完全准备好时进行分片分配,导致分配失败或性能问题。

3. 配置 Allocation 策略

  • 设置节点属性:通过在 elasticsearch.yml 文件中设置节点属性,可以影响 Allocation 策略。例如,可以设置节点的 node.attr.rack 属性来表示节点所在的机架,然后在分配分片时,可以使用 cluster.routing.allocation.awareness.rack 配置项,将主分片和副本分片分配到不同的机架上,以提高数据的可用性。
node.attr.rack: rack1
cluster.routing.allocation.awareness.rack: rack
  • 调整分片分配权重:Elasticsearch 允许通过配置来调整分片分配的权重,例如,可以根据节点的硬件资源(如 CPU、内存、磁盘空间等)来设置不同的权重。在 elasticsearch.yml 文件中,可以使用 cluster.routing.allocation.node_concurrent_recoveries 配置项来控制每个节点同时进行的恢复任务数量,从而影响分片分配的速度和资源占用。
cluster.routing.allocation.node_concurrent_recoveries: 2

4. 监控和调整

  • 使用 Elasticsearch 监控工具:Elasticsearch 提供了一些监控工具,如 Elasticsearch Head、Kibana 等,可以实时监控集群的状态、节点负载、分片分配情况等。通过这些工具,可以及时发现 Gateway 恢复和 Allocation 过程中出现的问题,如分片分配不均衡、节点负载过高、磁盘空间不足等。
  • 动态调整配置:根据监控结果,及时调整 Gateway 和 Allocation 的配置。例如,如果发现某个节点负载过高,可以通过调整 cluster.routing.allocation.exclude 配置项,将该节点排除在分片分配范围之外,或者增加节点的资源来降低负载。如果发现分片分配不均衡,可以手动调整分片的分配,或者优化分配策略,确保分片能够均匀地分布在集群中。

代码示例:自定义 Allocation 策略

有时候,默认的 Allocation 策略可能无法满足特定的业务需求,这时可以通过编写自定义的 Allocation 插件来实现个性化的分配策略。以下是一个简单的自定义 Allocation 策略的代码示例:

  1. 创建自定义 Allocation 插件项目:首先,使用 Maven 创建一个新的 Elasticsearch 插件项目:
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>custom-allocation-plugin</artifactId>
    <version>1.0.0</version>

    <properties>
        <elasticsearch.version>7.10.2</elasticsearch.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${maven.compiler.source}</source>
                    <target>${maven.compiler.target}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.elasticsearch.plugins</groupId>
                <artifactId>maven-elasticsearch-plugin</artifactId>
                <version>7.10.2</version>
                <executions>
                    <execution>
                        <id>build-plugin</id>
                        <goals>
                            <goal>build</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  1. 编写自定义 Allocation 策略类:在项目中创建一个类,实现 AllocationDecider 接口,该接口定义了决定分片是否可以分配到某个节点的逻辑:
package com.example;

import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.routing.ShardRouting;
import org.elasticsearch.cluster.routing.allocation.AllocationDecider;
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
import org.elasticsearch.common.settings.Settings;

public class CustomAllocationDecider implements AllocationDecider {
    public static final String NAME = "custom_allocation_decider";

    public CustomAllocationDecider(Settings settings) {
    }

    @Override
    public Decision canAllocate(ShardRouting shardRouting, ClusterState clusterState) {
        // 自定义分配逻辑,例如根据节点属性判断
        String nodeAttribute = clusterState.nodes().get(shardRouting.currentNodeId()).getAttributes().get("custom_attribute");
        if ("specific_value".equals(nodeAttribute)) {
            return Decision.YES;
        }
        return Decision.NO;
    }

    @Override
    public AllocationDeciders.Decision canRemain(ShardRouting shardRouting, ClusterState clusterState) {
        return Decision.YES;
    }

    @Override
    public String getKey() {
        return NAME;
    }
}
  1. 注册自定义 Allocation 策略:创建一个插件类,用于注册自定义的 Allocation 策略:
package com.example;

import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.cluster.routing.allocation.AllocationDecider;
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;

import java.util.Arrays;
import java.util.Collection;

public class CustomAllocationPlugin extends Plugin implements SearchPlugin {
    @Override
    public Collection<AllocationDecider> getAllocationDeciders() {
        return Arrays.asList(new CustomAllocationDecider(Settings.EMPTY));
    }
}
  1. 构建和安装插件:使用 Maven 构建插件,生成插件压缩包:
mvn clean install

将生成的插件压缩包复制到 Elasticsearch 的插件目录,并重启 Elasticsearch 集群,使插件生效。

通过以上步骤,就可以实现一个自定义的 Allocation 策略,根据特定的业务需求来分配分片。

总结从 Gateway 到 Allocation 转换的关键要点

  1. 深入理解机制:透彻理解 Gateway 和 Allocation 各自的功能、工作流程以及它们之间的相互关系是进行转换的基础。只有清楚了解每个环节,才能准确地进行配置和优化。
  2. 合理配置 Gateway:根据实际的业务场景和数据需求,选择合适的 Gateway 类型,并精细调整相关恢复参数。这不仅能确保数据的可靠持久化与恢复,还为后续的 Allocation 提供良好的基础条件。
  3. 优化 Allocation 策略:通过设置节点属性、调整分片分配权重等方式,优化 Allocation 策略,以达到提高集群性能、可用性和资源利用率的目的。
  4. 持续监控与调整:利用 Elasticsearch 提供的监控工具,实时关注集群状态,依据监控数据及时动态调整 Gateway 和 Allocation 的配置,使集群始终处于最佳运行状态。同时,通过自定义 Allocation 策略等手段,满足特定的业务需求,确保数据在集群中的合理分配与高效处理。