ElasticSearch集群节点过滤策略
ElasticSearch 集群节点过滤策略基础概念
节点在 ElasticSearch 集群中的角色
在 ElasticSearch 集群中,节点是其基本组成单元。不同类型的节点承担着不同的职责,主要包括以下几种:
- 主节点(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
该配置定义了一个仅作为协调节点的节点,它既不参与主节点选举也不存储数据。
节点过滤策略的重要性
- 资源优化:通过合理的节点过滤策略,可以将不同类型的任务分配到特定的节点上,避免资源浪费。例如,将计算密集型的搜索任务分配到配置较高的数据节点上,而将管理类任务集中在主节点上,这样可以充分利用每个节点的硬件资源,提高集群整体性能。
- 提高可用性:当集群规模较大时,节点故障的可能性增加。通过节点过滤策略,可以确保关键任务不会依赖于某个单一节点,提高集群的容错能力。例如,将重要索引的数据副本分布在不同的数据节点上,当某个数据节点出现故障时,其他副本可以继续提供服务,保证数据的可用性。
- 数据安全与隔离:在多租户环境中,节点过滤策略可以实现数据的隔离。不同租户的数据可以存储在不同的数据节点集合上,通过过滤策略防止其他租户对数据的非法访问,提高数据的安全性。
基于节点属性的过滤策略
自定义节点属性
- 定义节点属性:在 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
的节点上。
内置节点属性过滤
- 基于节点角色属性过滤:如前面提到的主节点、数据节点和协调节点的角色属性,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
,上述索引就会被分配到这些节点上。
基于标签的节点过滤策略
创建和管理节点标签
- 添加标签:可以通过 ElasticSearch 的 REST API 为节点添加标签。首先,需要获取节点的唯一标识符(可以通过
_cat/nodes
API 获取)。假设节点 ID 为node1_id
,可以使用以下 API 为节点添加标签:
POST /_nodes/node1_id/_tags
{
"tags": {
"environment": "production",
"service": "search"
}
}
上述请求为 node1_id
对应的节点添加了 environment
和 service
两个标签。
2. 删除标签:同样通过 REST API 可以删除节点标签。例如,删除刚才添加的 service
标签:
DELETE /_nodes/node1_id/_tags/service
使用标签进行索引分配
- 在索引创建时指定标签:在创建索引时,可以使用
index.routing.allocation.require
参数结合标签来指定索引的分配位置。例如,创建一个仅分配到environment
标签为production
的节点上的索引:
PUT /production_index
{
"settings": {
"index.routing.allocation.require.environment": "production"
}
}
- 动态调整索引分配:如果集群中的节点标签发生变化,可以通过更新索引设置来动态调整索引的分配。例如,将
production_index
索引的分配策略调整为同时要求environment
为production
和service
为search
:
PUT /production_index/_settings
{
"index.routing.allocation.require.environment": "production",
"index.routing.allocation.require.service": "search"
}
这样,索引的数据就会根据新的标签要求重新分配到符合条件的节点上。
基于索引设置的节点过滤策略
索引分片分配设置
- 控制主分片分配:通过
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
}
}
上述设置会确保副本分片和主分片不会在同一个节点上,从而提高数据的容错能力。
索引路由设置
- 自定义路由值:在写入文档时,可以指定一个自定义的路由值,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"
}
}
这样就实现了基于路由的节点过滤,将特定路由值的文档分配到符合条件的节点上。
基于集群状态的节点过滤策略
监控集群状态
- 获取集群状态 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"
}
],
// 其他分片信息
}
}
// 其他索引分片信息
}
}
}
- 监控节点健康状态:使用
_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
}
根据集群状态调整节点过滤策略
- 节点故障处理:当通过监控发现某个节点出现故障(集群状态变为黄色或红色)时,可以动态调整节点过滤策略。例如,如果一个数据节点故障,可以临时将其负责的索引分片重新分配到其他健康节点上。可以通过更新索引设置来实现:
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_node1
和 low_load_node2
的负载较低的节点上,实现集群的负载均衡。
复杂场景下的节点过滤策略组合应用
多租户场景
- 租户数据隔离:在多租户环境中,为每个租户的数据创建独立的索引,并使用节点属性或标签来实现数据隔离。例如,为租户 A 和租户 B 分别创建索引
tenantA_index
和tenantB_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"
}
}
- 资源限制与共享:除了数据隔离,还可以通过节点过滤策略实现资源限制与共享。例如,为每个租户的数据节点分配一定比例的资源(如 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 的索引只分配到这些设置了资源限制的节点上。
混合云场景
- 本地与云端节点协同:在混合云场景下,可能既有本地数据中心的节点,又有云端(如 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"
}
}
- 跨云与本地的负载均衡:为了实现跨云与本地的负载均衡,可以结合集群状态监控和节点过滤策略。通过监控不同节点的负载情况,动态调整索引分配。例如,如果发现云端节点负载过高,可以将部分索引分片迁移到本地节点上:
PUT /high_load_index/_settings
{
"index.routing.allocation.include.location": "local"
}
同时,也可以根据网络带宽等因素,合理分配索引的读写请求到不同位置的节点上,提高整体性能。
节点过滤策略的性能与维护
性能影响因素
- 过滤策略复杂度:过于复杂的节点过滤策略可能会增加 ElasticSearch 的计算开销。例如,同时使用多个节点属性、标签以及索引设置进行过滤,会导致在索引分配和文档路由时需要进行更多的匹配计算。在设计过滤策略时,应尽量保持简洁,避免不必要的复杂性。
- 动态调整频率:频繁地动态调整节点过滤策略(如索引设置的频繁更改)会触发 ElasticSearch 的分片重新分配操作,这会占用大量的网络和磁盘 I/O 资源,影响集群的性能。因此,应根据实际业务需求,合理规划动态调整的频率,尽量减少不必要的分片迁移。
维护要点
- 配置备份与版本管理:对节点的配置文件(如
elasticsearch.yml
)进行定期备份,并进行版本管理。这样在需要恢复配置或回滚到某个版本的配置时,可以快速操作。同时,在对配置文件进行修改时,应遵循一定的流程,确保修改的准确性和一致性。 - 监控与预警:建立完善的监控体系,对节点的状态、索引的分配情况、集群的健康状态等进行实时监控。设置合理的预警阈值,当出现节点故障、索引分配异常等情况时,及时发出预警通知,以便运维人员及时处理。例如,通过监控工具(如 Elasticsearch Exporter 结合 Prometheus 和 Grafana)实时监控节点的 CPU、内存、磁盘使用率等指标,并设置当 CPU 使用率超过 80% 时发出预警。
通过深入理解和合理应用 ElasticSearch 集群节点过滤策略,可以优化集群的性能、提高可用性和数据安全性,满足不同业务场景的需求。在实际应用中,需要根据具体的业务需求、硬件资源和运维能力等因素,灵活选择和组合各种过滤策略,并注意性能和维护方面的要点。