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

ElasticSearch集群节点过滤策略

2022-09-117.5k 阅读

ElasticSearch 集群节点过滤策略基础概念

节点在 ElasticSearch 集群中的角色

在 ElasticSearch 集群中,节点是其基本组成单元。不同类型的节点承担着不同的职责,主要包括以下几种:

  1. 主节点(Master-eligible Node):主节点负责管理集群的元数据,如索引的创建、删除,节点的加入和离开等操作。一个 ElasticSearch 集群会选举出一个主节点来执行这些管理任务。可以通过在 elasticsearch.yml 配置文件中设置 node.master: true 来定义一个节点为主节点候选。例如:
node.name: master_candidate_1
node.master: true
node.data: false

上述配置定义了一个名为 master_candidate_1 的节点,它可以参与主节点选举,但不存储数据。 2. 数据节点(Data Node):数据节点负责存储和处理实际的索引数据。它们执行数据的增删改查等操作。在 elasticsearch.yml 中通过设置 node.data: true 来定义数据节点。示例如下:

node.name: data_node_1
node.master: false
node.data: true

此配置定义了名为 data_node_1 的数据节点,它不参与主节点选举,专注于数据存储和处理。 3. 协调节点(Coordinating Node):协调节点接收客户端请求,并将请求转发到合适的数据节点进行处理,然后将结果汇总返回给客户端。每个节点默认都是协调节点,因为 node.coordinating_only 属性默认未设置。如果要明确设置一个纯协调节点,可以如下配置:

node.name: coordinating_node_1
node.master: false
node.data: false
node.coordinating_only: true

该配置定义了一个仅作为协调节点的节点,它既不参与主节点选举也不存储数据。

节点过滤策略的重要性

  1. 资源优化:通过合理的节点过滤策略,可以将不同类型的任务分配到特定的节点上,避免资源浪费。例如,将计算密集型的搜索任务分配到配置较高的数据节点上,而将管理类任务集中在主节点上,这样可以充分利用每个节点的硬件资源,提高集群整体性能。
  2. 提高可用性:当集群规模较大时,节点故障的可能性增加。通过节点过滤策略,可以确保关键任务不会依赖于某个单一节点,提高集群的容错能力。例如,将重要索引的数据副本分布在不同的数据节点上,当某个数据节点出现故障时,其他副本可以继续提供服务,保证数据的可用性。
  3. 数据安全与隔离:在多租户环境中,节点过滤策略可以实现数据的隔离。不同租户的数据可以存储在不同的数据节点集合上,通过过滤策略防止其他租户对数据的非法访问,提高数据的安全性。

基于节点属性的过滤策略

自定义节点属性

  1. 定义节点属性:在 ElasticSearch 中,可以通过在 elasticsearch.yml 配置文件中添加自定义属性来标识节点。例如,假设我们有一组用于处理不同业务线数据的节点,可以为每个业务线的节点添加一个 business_line 属性。
node.name: data_node_business1
node.master: false
node.data: true
business_line: business1
node.name: data_node_business2
node.master: false
node.data: true
business_line: business2

这样就分别为两个数据节点定义了不同的 business_line 属性。 2. 使用节点属性进行索引分配:在创建索引时,可以指定将索引分配到具有特定属性的节点上。通过索引模板或者直接在创建索引请求中使用 settings.index.routing.allocation.require 参数。例如,创建一个属于 business1 业务线的索引:

PUT /business1_index
{
    "settings": {
        "index.routing.allocation.require.business_line": "business1"
    }
}

上述请求会确保 business1_index 索引的数据只会分配到 business_line 属性为 business1 的节点上。

内置节点属性过滤

  1. 基于节点角色属性过滤:如前面提到的主节点、数据节点和协调节点的角色属性,ElasticSearch 提供了基于这些角色进行索引分配的功能。例如,如果希望某个索引只存储在数据节点上,可以在创建索引时设置:
PUT /data_only_index
{
    "settings": {
        "index.routing.allocation.require.data": "true"
    }
}

此设置会将 data_only_index 索引的数据分配到 node.data 属性为 true 的节点上,即数据节点。 2. 基于节点磁盘类型属性过滤:ElasticSearch 可以识别节点的磁盘类型(如 SSD 或 HDD),这在 node.attr.disk_type 属性中体现。如果希望将对读写性能要求高的索引存储在使用 SSD 磁盘的节点上,可以这样设置:

PUT /high_performance_index
{
    "settings": {
        "index.routing.allocation.require.disk_type": "ssd"
    }
}

假设在 elasticsearch.yml 中已经为使用 SSD 磁盘的节点配置了 node.attr.disk_type: ssd,上述索引就会被分配到这些节点上。

基于标签的节点过滤策略

创建和管理节点标签

  1. 添加标签:可以通过 ElasticSearch 的 REST API 为节点添加标签。首先,需要获取节点的唯一标识符(可以通过 _cat/nodes API 获取)。假设节点 ID 为 node1_id,可以使用以下 API 为节点添加标签:
POST /_nodes/node1_id/_tags
{
    "tags": {
        "environment": "production",
        "service": "search"
    }
}

上述请求为 node1_id 对应的节点添加了 environmentservice 两个标签。 2. 删除标签:同样通过 REST API 可以删除节点标签。例如,删除刚才添加的 service 标签:

DELETE /_nodes/node1_id/_tags/service

使用标签进行索引分配

  1. 在索引创建时指定标签:在创建索引时,可以使用 index.routing.allocation.require 参数结合标签来指定索引的分配位置。例如,创建一个仅分配到 environment 标签为 production 的节点上的索引:
PUT /production_index
{
    "settings": {
        "index.routing.allocation.require.environment": "production"
    }
}
  1. 动态调整索引分配:如果集群中的节点标签发生变化,可以通过更新索引设置来动态调整索引的分配。例如,将 production_index 索引的分配策略调整为同时要求 environmentproductionservicesearch
PUT /production_index/_settings
{
    "index.routing.allocation.require.environment": "production",
    "index.routing.allocation.require.service": "search"
}

这样,索引的数据就会根据新的标签要求重新分配到符合条件的节点上。

基于索引设置的节点过滤策略

索引分片分配设置

  1. 控制主分片分配:通过 index.number_of_shards 设置索引的主分片数量,同时可以使用 index.routing.allocation.total_shards_per_node 来限制每个节点上允许分配的主分片数量。例如,创建一个有 3 个主分片的索引,并限制每个节点最多分配 1 个主分片:
PUT /shard_control_index
{
    "settings": {
        "index.number_of_shards": 3,
        "index.routing.allocation.total_shards_per_node": 1
    }
}

这样可以确保主分片均匀分布在不同的节点上,提高数据的可用性和查询性能。 2. 副本分片分配:使用 index.number_of_replicas 设置索引的副本分片数量,并且可以通过 index.routing.allocation.same_shard.host 来防止副本分片和主分片分配到同一节点上。例如:

PUT /replica_control_index
{
    "settings": {
        "index.number_of_replicas": 1,
        "index.routing.allocation.same_shard.host": false
    }
}

上述设置会确保副本分片和主分片不会在同一个节点上,从而提高数据的容错能力。

索引路由设置

  1. 自定义路由值:在写入文档时,可以指定一个自定义的路由值,ElasticSearch 会根据这个路由值将文档分配到特定的分片上。例如,假设我们有一个订单索引,根据订单所属地区进行路由:
// Java 代码示例
IndexRequest indexRequest = new IndexRequest("orders_index")
      .id("1")
      .source("region", "north", "order_amount", 100)
      .routing("north");
client.index(indexRequest, RequestOptions.DEFAULT);

在上述 Java 代码中,通过 routing("north") 指定了路由值为 north,ElasticSearch 会根据这个路由值将文档分配到相应的分片上。 2. 基于路由的节点过滤:结合前面的自定义路由值,可以在索引设置中通过 index.routing.allocation.include.{attribute} 来将包含特定路由值的文档分配到具有相应属性的节点上。例如,如果有节点属性 region,并且希望将路由值为 north 的文档分配到 region 属性为 north 的节点上,可以这样设置索引:

PUT /orders_index
{
    "settings": {
        "index.routing.allocation.include.region": "north"
    }
}

这样就实现了基于路由的节点过滤,将特定路由值的文档分配到符合条件的节点上。

基于集群状态的节点过滤策略

监控集群状态

  1. 获取集群状态 API:可以使用 _cluster/state API 获取集群的详细状态信息,包括节点信息、索引信息、分片分配等。例如,通过以下命令获取集群状态:
GET /_cluster/state

返回的结果包含了丰富的信息,如:

{
    "cluster_name": "my_cluster",
    "version": 123,
    "state_uuid": "abcdef1234567890",
    "nodes": {
        "node1_id": {
            "name": "node1",
            "roles": [
                "data"
            ],
            "attributes": {
                "disk_type": "ssd"
            }
        },
        // 其他节点信息
    },
    "metadata": {
        "indices": {
            "index1": {
                "settings": {
                    "index.number_of_shards": 3,
                    "index.number_of_replicas": 1
                },
                // 其他索引元数据
            }
            // 其他索引信息
        }
    },
    "routing_table": {
        "indices": {
            "index1": {
                "shards": {
                    "0": [
                        {
                            "state": "STARTED",
                            "primary": true,
                            "node": "node1_id"
                        },
                        {
                            "state": "STARTED",
                            "primary": false,
                            "node": "node2_id"
                        }
                    ],
                    // 其他分片信息
                }
            }
            // 其他索引分片信息
        }
    }
}
  1. 监控节点健康状态:使用 _cluster/health API 可以获取集群的健康状态摘要,包括集群状态(绿、黄、红)、节点数量、活动分片数量等。例如:
GET /_cluster/health

返回结果类似:

{
    "cluster_name": "my_cluster",
    "status": "green",
    "timed_out": false,
    "number_of_nodes": 3,
    "number_of_data_nodes": 2,
    "active_primary_shards": 3,
    "active_shards": 6,
    "relocating_shards": 0,
    "initializing_shards": 0,
    "unassigned_shards": 0,
    "delayed_unassigned_shards": 0,
    "number_of_pending_tasks": 0,
    "number_of_in_flight_fetch": 0,
    "task_max_waiting_in_queue_millis": 0,
    "active_shards_percent_as_number": 100
}

根据集群状态调整节点过滤策略

  1. 节点故障处理:当通过监控发现某个节点出现故障(集群状态变为黄色或红色)时,可以动态调整节点过滤策略。例如,如果一个数据节点故障,可以临时将其负责的索引分片重新分配到其他健康节点上。可以通过更新索引设置来实现:
PUT /affected_index/_settings
{
    "index.routing.allocation.exclude._name": "failed_node_name"
}

上述设置会将 affected_index 索引的分片从名为 failed_node_name 的故障节点上排除,ElasticSearch 会自动将这些分片重新分配到其他健康节点上。 2. 负载均衡调整:如果发现某个节点负载过高(可以通过监控节点的 CPU、内存、磁盘 I/O 等指标判断),可以调整索引分配策略,将部分索引分片迁移到负载较低的节点上。例如,通过以下设置将索引 high_load_index 的一些分片迁移出去:

PUT /high_load_index/_settings
{
    "index.routing.allocation.include._name": "low_load_node1,low_load_node2"
}

这样就会将 high_load_index 索引的部分分片分配到名为 low_load_node1low_load_node2 的负载较低的节点上,实现集群的负载均衡。

复杂场景下的节点过滤策略组合应用

多租户场景

  1. 租户数据隔离:在多租户环境中,为每个租户的数据创建独立的索引,并使用节点属性或标签来实现数据隔离。例如,为租户 A 和租户 B 分别创建索引 tenantA_indextenantB_index,并为每个租户的数据节点添加相应的租户标签。
# 租户 A 数据节点配置
node.name: tenantA_data_node1
node.master: false
node.data: true
tenant: tenantA
# 租户 B 数据节点配置
node.name: tenantB_data_node1
node.master: false
node.data: true
tenant: tenantB

在创建索引时,通过索引设置将租户数据分配到对应的节点上:

PUT /tenantA_index
{
    "settings": {
        "index.routing.allocation.require.tenant": "tenantA"
    }
}
PUT /tenantB_index
{
    "settings": {
        "index.routing.allocation.require.tenant": "tenantB"
    }
}
  1. 资源限制与共享:除了数据隔离,还可以通过节点过滤策略实现资源限制与共享。例如,为每个租户的数据节点分配一定比例的资源(如 CPU、内存)。可以使用 ElasticSearch 的资源分配插件(如 X-Pack 中的资源控制功能)结合节点过滤策略来实现。假设通过插件为租户 A 数据节点设置 CPU 使用率上限为 50%,可以在节点配置中添加相关设置:
node.name: tenantA_data_node1
node.master: false
node.data: true
tenant: tenantA
xpack.resources.cpu.limit: 50%

同时,在索引分配时确保租户 A 的索引只分配到这些设置了资源限制的节点上。

混合云场景

  1. 本地与云端节点协同:在混合云场景下,可能既有本地数据中心的节点,又有云端(如 AWS、Azure)的节点。可以通过设置节点属性来区分本地和云端节点。例如,为本地节点设置 location: local,为云端节点设置 location: cloud
# 本地节点配置
node.name: local_node1
node.master: false
node.data: true
location: local
# 云端节点配置
node.name: cloud_node1
node.master: false
node.data: true
location: cloud

根据数据的敏感性和访问需求,将不同类型的索引分配到合适的节点上。例如,对于敏感数据索引,只分配到本地节点:

PUT /sensitive_data_index
{
    "settings": {
        "index.routing.allocation.require.location": "local"
    }
}

而对于一些对成本敏感且不太敏感的数据索引,可以分配到云端节点:

PUT /cost_sensitive_index
{
    "settings": {
        "index.routing.allocation.require.location": "cloud"
    }
}
  1. 跨云与本地的负载均衡:为了实现跨云与本地的负载均衡,可以结合集群状态监控和节点过滤策略。通过监控不同节点的负载情况,动态调整索引分配。例如,如果发现云端节点负载过高,可以将部分索引分片迁移到本地节点上:
PUT /high_load_index/_settings
{
    "index.routing.allocation.include.location": "local"
}

同时,也可以根据网络带宽等因素,合理分配索引的读写请求到不同位置的节点上,提高整体性能。

节点过滤策略的性能与维护

性能影响因素

  1. 过滤策略复杂度:过于复杂的节点过滤策略可能会增加 ElasticSearch 的计算开销。例如,同时使用多个节点属性、标签以及索引设置进行过滤,会导致在索引分配和文档路由时需要进行更多的匹配计算。在设计过滤策略时,应尽量保持简洁,避免不必要的复杂性。
  2. 动态调整频率:频繁地动态调整节点过滤策略(如索引设置的频繁更改)会触发 ElasticSearch 的分片重新分配操作,这会占用大量的网络和磁盘 I/O 资源,影响集群的性能。因此,应根据实际业务需求,合理规划动态调整的频率,尽量减少不必要的分片迁移。

维护要点

  1. 配置备份与版本管理:对节点的配置文件(如 elasticsearch.yml)进行定期备份,并进行版本管理。这样在需要恢复配置或回滚到某个版本的配置时,可以快速操作。同时,在对配置文件进行修改时,应遵循一定的流程,确保修改的准确性和一致性。
  2. 监控与预警:建立完善的监控体系,对节点的状态、索引的分配情况、集群的健康状态等进行实时监控。设置合理的预警阈值,当出现节点故障、索引分配异常等情况时,及时发出预警通知,以便运维人员及时处理。例如,通过监控工具(如 Elasticsearch Exporter 结合 Prometheus 和 Grafana)实时监控节点的 CPU、内存、磁盘使用率等指标,并设置当 CPU 使用率超过 80% 时发出预警。

通过深入理解和合理应用 ElasticSearch 集群节点过滤策略,可以优化集群的性能、提高可用性和数据安全性,满足不同业务场景的需求。在实际应用中,需要根据具体的业务需求、硬件资源和运维能力等因素,灵活选择和组合各种过滤策略,并注意性能和维护方面的要点。