bigywater.tech
Elasticsearch · 120

Awareness 与 Forced Awareness

给本机唯一节点加上node.attr.zone属性后真实对比三种配置:不开awareness、开启非强制awareness.attributes、开启声明了不存在zone的forced awareness,用allocation/explain的真实输出证明非强制awareness只是软性打分参考不产生任何额外拒绝,而forced awareness则是真实的硬性配额限制,即使声明的zone在集群里根本不存在任何节点也照样生效。

不开awareness的基线
副本unassigned,explain只有same_shard这一条
开启非强制awareness
真实结果跟基线一字不差,零额外拒绝
开启forced awareness声明不存在的zone2
真实多出awareness决策器,写出具体配额计算

做的事:真实给唯一的节点加上node.attr.zone:zone1这个属性,重启后用一个没开awareness的索引建立对照基线

代码elasticsearch.yml 真实加一行: node.attr.zone: zone1 # 真实重启ES GET /_nodes → 真实确认 node-1 的 attributes 里真实多了 "zone":"zone1" PUT /aw_test {"settings":{"number_of_shards":1,"number_of_replicas":1}}

验证:不开awareness时,副本真实因为没有第二个节点而unassigned,explain真实只看到same_shard这一条原因

实测 · 本机 Elasticsearch 8.15.0 执行输出
aw_test 0 p STARTED  node-1
aw_test 0 r UNASSIGNED

allocation/explain(shard=0, primary=false):
→ decider: "same_shard", decision: "NO"
→ explanation: "a copy of this shard is already allocated to this node"

这组真实结果建立了一条清晰的基线:本机真实只有node-1这一个节点,副本不可能跟主分片放在同一个节点上,所以真实卡在最基础的same_shard决策器上,跟awareness这个概念本身真实毫无关系——这是接下来对比的真实参照点。

真实开启非强制的cluster.routing.allocation.awareness.attributes,重新建一个同样配置的索引

代码PUT /_cluster/settings {"persistent":{ "cluster.routing.allocation.awareness.attributes":"zone" }} PUT /aw_test2 {"settings":{"number_of_shards":1,"number_of_replicas":1}}

验证:真实结果跟刚才的基线一字不差,非强制awareness真实没有产生任何额外的硬性拒绝

实测 · 本机执行输出
aw_test2 0 p STARTED  node-1
aw_test2 0 r UNASSIGNED

allocation/explain(shard=0, primary=false):
→ 真实只有一条decider: "same_shard", decision: "NO"   ← 跟基线完全相同
这是一个真实容易被忽视的关键区别:非强制的awareness.attributes这个设置,真实只是告诉ES"分配和rebalance的时候,优先把副本往不同zone的节点上摆、优先把集群尽量摊匀",它真实是一个参与打分排名的软性参考,而不是一条会出现在deciders列表里、能直接否决分配的硬性规则。本次实测开启它之后,explain结果真实跟完全没开启时一模一样,证明这个设置在真实的否决逻辑里完全不起作用,它真实只在"有多个候选节点可选、需要决定摊到哪一个更合理"这种场景下才会真实发挥作用。

真实开启forced awareness,并声明一个实际不存在的zone2,看会不会产生额外的硬性拒绝

代码PUT /_cluster/settings {"persistent":{ "cluster.routing.allocation.awareness.force.zone.values":"zone1,zone2" }} PUT /aw_test3 {"settings":{"number_of_shards":1,"number_of_replicas":1}}

验证:真实多出了一条awareness决策器,原文直接写出了具体的配额计算过程

实测 · 本机执行输出
allocation/explain(shard=0, primary=false):
→ decider: "same_shard", decision: "NO"
→ decider: "awareness", decision: "NO"   ← 真实新增的一条
   explanation: "there are [2] copies of this shard and [2] values for
     attribute [zone] ([zone1] from nodes in the cluster and [zone1, zone2]
     from forced awareness) so there may be at most [1] copies of this shard
     allocated to nodes with each value, but (including this copy) there
     would be [2] copies allocated to nodes with [node.attr.zone: zone1]"
这条真实报错把forced awareness的工作机制交代得非常具体:它真实会用force.zone.values里声明的zone数量(本次是zone1和zone2两个值)去除总副本数(主+副本=2),算出每个zone真实最多能放多少份拷贝——本次计算结果是每个zone最多1份。即使zone2这个zone在真实的集群里压根不存在任何节点,forced awareness也完全不关心这件事,它真实只按"声明过的zone数量"做配额计算,一旦某个zone(本次是真实唯一存在的zone1)已经用满了自己的配额,哪怕集群里还有理论上的容量,这个zone也不会再接收新的副本——这跟非强制awareness那种"软性参考、从不否决"的行为真实是两种完全不同的强度。这也解释了为什么生产环境如果真实用forced awareness配置了3个可用区,却只真实部署了2个可用区的节点,索引的副本真实会一直卡在unassigned,直到第三个可用区真实有节点加入为止——这正是forced awareness"宁可牺牲可用性也要保证真实的跨区分布"这条设计取向的真实代价。

收尾:真实清理测试索引,清除awareness设置,确认集群恢复到green

代码DELETE /aw_test,aw_test2,aw_test3 PUT /_cluster/settings {"persistent":{ "cluster.routing.allocation.awareness.attributes": null, "cluster.routing.allocation.awareness.force.zone.values": null }}

验证:集群真实恢复到green,unassigned_shards归零

实测 · 本机执行输出
status: "green"
unassigned_shards: 0

分步演示:从不开awareness的基线,到非强制awareness的零差异,再到forced awareness真实产生的硬性配额拒绝

每一步都是本文上面在本机真实的Elasticsearch 8.15.0上跑出来的原始结果。

非强制awareness是软性打分参考,forced awareness是真实的硬性配额限制
这一步新验证的awareness场景

    本文用到的工具

    • 本机真实部署的 Elasticsearch 8.15.0(单节点,tar包直接启动,真实加了node.attr.zone属性)
    • 真实的 cluster.routing.allocation.awareness.attributes 与 awareness.force.*.values 设置
    京ICP备2026067502号-1京公网安备11010502063487号