【Elasticsearch】AwarenessAllocationDecider 感知分片决策器的处理逻辑

本 `AllocationDecider` 根据节点配置中定义的 **感知键值对(awareness key-value pairs)** 来控制分片分配。

**感知机制(awareness)** 的核心目的是:

**明确控制副本应该被分配到哪些位置**,从而避免所有副本扎堆在同一物理位置(如同一个机架、同一个机房、同一个可用区),确保即使某个位置整体故障,仍至少有一个副本可用。


举个例子:按机架(rack)分配

设置:

```yaml

cluster.routing.allocation.awareness.attributes: rack_id

```

表示:**尽量把同一份分片的主副本和各个副本分配到不同的机架上**。

要让这一规则生效,节点启动时必须带上对应的属性值,例如:

```yaml

node.attr.rack_id: 1

```

这样,ES 在分配时就会统计每个机架上已有的副本数,**避免多个副本落在同一机架**,达到"机架级容灾"的效果。


再举个例子:按云端"可用区(zone)"分配

设置:

```yaml

cluster.routing.allocation.awareness.attributes: zone

```

再加上强制声明:

```yaml

cluster.routing.allocation.awareness.force.zone.values: zone1, zone2

```

表示:

  • 集群当前可能只有 `zone1` 的节点在线,但你告诉 ES **未来一定会有 zone2**。

  • 因此 ES 会把副本数按 **总 zone 数 = 2** 来均分计算上限,**不会因为是"当前只有 zone1"就把副本全堆在 zone1**。

  • 即使 `zone2` 暂时无节点或部分故障,**也不会出现"zone1 超载"**的情况。

zone2 节点没上线前,**ES 不会把副本硬塞进一个不存在的节点**;

它只会 **"先不分配"**(shard 状态保持 `UNASSIGNED`),直到:

  1. 你启动了带有 `node.attr.zone: zone2` 的节点 → 副本立刻被分配到这些节点上。

  2. 你主动把 `force.zone.values` 里的 `zone2` 去掉 → ES 重新按 **实际只有 1 个 zone** 计算上限,原来卡住的副本才允许在 `zone1` 补完。

所以 **"不超载" ≠ "强行放过去"**,而是 **"宁可暂时少一份,也不破坏容灾布局"**。

集群表现为 **部分分片处于未分配状态**,直到对应 zone 的节点加入。

节点侧只需照常声明自己所在的 zone:

```yaml

node.attr.zone: zone1

```


总结一句话

**感知机制 = 让 ES 按"你指定的物理维度"去均分副本,防止扎堆;

`force.values` = 提前声明未来才会有的维度值,避免过渡期超载。**

**只要任意一个 AllocationDecider 返回 NO**,这条分片就 **不会被分配到任何节点**,状态保持 **UNASSIGNED**,直到:

  • 你**调整规则/配置**(让 decider 通过),或

  • 你**增加/修复节点**(让规则自然满足),或

  • 你**手动干预**(比如调低副本数、关闭感知强制值等)。

ES 的分配流程是 **"一票否决"制**:

**所有 decider 都 YES → 才能落地;任何一个 NO → 继续等着。**

下面把 `underCapacity` 的完整流程按"**判断顺序 + 分支走向**"拆开,让你一眼看清每一步在拦什么、怎么走。


  1. **感知功能开没开**

```java

if (awarenessAttributes.isEmpty()) return YES_NOT_ENABLED;

```

  • 集群没配 `cluster.routing.allocation.awareness.attributes`

→ **直接放行**,后面逻辑全跳过。


  1. **索引是否"扩到全节点"**

```java

if (indexMetadata.getAutoExpandReplicas().expandToAllNodes()) return YES_AUTO_EXPAND_ALL;

```

  • 索引设置了 `"auto_expand_replicas" : "0-all"`

→ **无视感知规则,直接放行**。


  1. **逐个维度循环检查**

对 `awarenessAttributes` 里每一个 `awarenessAttribute`(如 zone、rack)执行下列 **4-8** 步:


  1. **目标节点有没有这个维度**

```java

if (node.node().getAttributes().containsKey(awarenessAttribute) == false)

return Decision.NO; // 或 debugNoMissingAttribute

```

  • 节点没写 `node.attr.zone` 之类

→ **拒绝 + 给出 missing 理由**。


  1. **运行时 double-check**(assert,非业务分支)

两句 `assert`:

  • 节点该属性值不能为 null

  • 该值必须出现在"集群已见值 + 强制值"集合里

**生产默认关闭,失败抛 AssertionError,防止手抖写错。**


  1. **统计"目标区"已有多少份该分片**

6a. **遍历已分配副本**

```java

for (ShardRouting assignedShard : allocation.routingNodes().assignedShards(shardId))

if (assignedShard.started() || assignedShard.initializing())

如果副本所在节点的维度值 == targetAttributeValue → 计数器 +1

```

6b. **moveToNode 场景再补 0/1 份**

  • 分片已迁出源节点(relocating)或未分配

→ **跨区移动/新增** 会让目标区"净多"1 份,于是 `+1`;同区移动则不加。

**结果:shardsForTargetAttributeValue = 目标区当前份数 + 未来份数变化**


  1. **计算上限**

```java

valueCount = 实际值 ∪ 强制值 去重后总数

maximumShardsPerAttributeValue = ceil( shardCount / valueCount )

```

  • shardCount = 1(主)+ 副本数

  • 即"每个感知值最多可放几份"。


  1. **是否超标**

```java

if (shardsForTargetAttributeValue > maximumShardsPerAttributeValue)

return Decision.NO; // 或 debugNoTooManyCopies

```

  • 目标区份数 > 上限 → **拒绝**,打出当前区、上限、已份数等详情。

  • 未超标 → **继续下一个维度**;全部维度通过 → 返回 `YES_ALL_MET`。


分支全景图(简化)

```

┌─ YES_NOT_ENABLED

├─ YES_AUTO_EXPAND_ALL

│ ↓

对每个维度 ── 缺属性 ──→ NO

│ ↓

assert 自检(异常抛 AssertionError)

│ ↓

统计目标区份数 + 移动修正

│ ↓

计算 ceil(总分片 / 总区数) 上限

│ ↓

份数>上限 ──→ NO + debug

│ ↓

全部维度通过 ──→ YES_ALL_MET

```

走完这张图,就完成了 **"感知维度层面是否允许把这份分片放到该节点"** 的全部判断。

相关推荐
transitory_truth15 小时前
es-api介绍
elasticsearch
q***47181 天前
使用Canal将MySQL数据同步到ES(Linux)
linux·mysql·elasticsearch
...对方正在输入......1 天前
Elasticsearch集群部署实战指南
elasticsearch·jenkins
Hello.Reader1 天前
使用 Flink CDC 搭建跨库 Streaming ETLMySQL + Postgres → Elasticsearch 实战
大数据·elasticsearch·flink
Elasticsearch1 天前
Elastic AI agent builder 介绍(五)- 备份 tools 及 agents
elasticsearch
练习时长一年1 天前
git常用命令总结
大数据·git·elasticsearch
little_xianzhong2 天前
把一个本地项目导入gitee创建的仓库中
大数据·elasticsearch·gitee
哈__2 天前
exa 在 HarmonyOS 上的构建与适配
elasticsearch·华为·harmonyos