熔断器

Solr 的熔断器基础设施允许防止导致节点超出其容量或宕机的操作。熔断器的前提是确保更高质量的服务,并且仅接受当前资源配置下可服务的请求负载。

何时使用熔断器

当用户希望以牺牲请求吞吐量为代价来换取更高的 Solr 稳定性时,应使用熔断器。如果启用了熔断器,则在节点高压力的情况下,可能会拒绝请求,并返回 HTTP 错误代码 429“请求过多”。客户端需要处理此错误,并可能构建重试逻辑,因为这应该是一种瞬态情况。

也可以在“仅警告”模式下启用单个熔断器。已超过阈值的“仅警告”熔断器会被记录下来,但不用于阻止或短路请求。这可以用作在不影响流量的情况下调整熔断器阈值的方法。

在对分片集合的请求中,仅在处理初始请求的节点上检查熔断器,而不对节点间请求进行检查。因此,建议跨 Solr 节点对客户端请求进行负载均衡,以避免热点。

熔断器配置

可以为整个节点全局配置熔断器,也可以为每个集合单独配置熔断器,或者两者结合配置。会先检查每个集合的熔断器,然后再检查全局熔断器,如果发生冲突,则每个集合的熔断器优先。通常,任何每个集合的熔断器阈值都设置得低于全局阈值。

断路器可以注册自身以检查查询请求和/或更新请求。用户可以为每种请求类型注册具有不同阈值的相同类型的断路器。

全局断路器

可以使用环境变量(例如在 solr.in.sh 中)或系统属性全局配置断路器。可用的变量有

名称 环境变量名称 系统属性名称

JVM 堆使用率

SOLR_CIRCUITBREAKER_QUERY_MEM, SOLR_CIRCUITBREAKER_UPDATE_MEM

solr.circuitbreaker.query.mem, solr.circuitbreaker.update.mem

系统 CPU 使用率

SOLR_CIRCUITBREAKER_QUERY_CPU, SOLR_CIRCUITBREAKER_UPDATE_CPU

solr.circuitbreaker.query.cpu, solr.circuitbreaker.update.cpu

系统平均负载

SOLR_CIRCUITBREAKER_QUERY_LOADAVG, SOLR_CIRCUITBREAKER_UPDATE_LOADAVG

solr.circuitbreaker.query.loadavg, solr.circuitbreaker.update.loadavg

可以通过添加带有布尔值的 "warnonly" 后缀的环境变量或系统属性,将断路器配置为“仅警告”模式。

例如,您可以通过设置以下环境变量启用一个全局 CPU 断路器,当 CPU 负载高于 95% 时拒绝更新请求:SOLR_CIRCUITBREAKER_UPDATE_CPU=95。如果希望此断路器处于“仅警告”模式,可以设置 SOLR_CIRCUITBREAKER_UPDATE_CPU_WARNONLY=true 环境变量或 solr.circuitbreaker.update.cpu.warnonly=true 系统属性。

每个集合的断路器

断路器在 solrconfig.xml 中配置为独立的 <circuitBreaker> 条目,如下面的示例所示。默认情况下,只有搜索请求会受到影响。可用配置选项的语法和语义会根据配置的断路器类型略有不同。但是,所有断路器都支持一个布尔值 “warnOnly” 设置,可用于将断路器设置为“仅警告”模式(例如,<bool name="warnOnly">true</bool>

当前支持的断路器

自 Solr 9.4 起,使用 CircuitBreakerManager 的旧配置语法已弃用,但仍将继续工作。当配置 cpuThreshold 时,此旧插件使用的“CPU”断路器实际上是下面描述的 LoadAverageCircuitBreaker。此外,CircuitBreakerManager 将返回 HTTP 503 代码,而不是新断路器使用的 HTTP 429 代码。

JVM 堆使用率

此断路器跟踪 JVM 堆内存使用率,如果堆使用率超过 JVM 分配的最大堆 ( -Xmx ) 的配置百分比,则会使用 429 错误代码拒绝传入的请求。此断路器的主要配置是控制断路器跳闸的阈值百分比。

要启用和配置基于 JVM 堆使用率的断路器,请添加以下内容

每个集合在 solrconfig.xml
<circuitBreaker class="org.apache.solr.util.circuitbreaker.MemoryCircuitBreaker">
 <double name="threshold">75</double>
</circuitBreaker>
全局在 solr.in.sh
SOLR_CIRCUITBREAKER_QUERY_MEM=75

threshold 定义为 JVM 分配的最大堆的百分比。

对于断路器配置,值“0”映射到 0% 使用率,值“100”映射到 100% 使用率。

将阈值设置在 JVM 分配的最大堆的 50% 以下或 95% 以上在逻辑上没有意义。因此,此参数的有效值范围是 [50, 95],包括边界值。

考虑以下示例

JVM 已分配了 5GB 的最大堆 (-Xmx),threshold 设置为 75。在这种情况下,断路器跳闸时的堆使用率为 3.75GB。

系统 CPU 使用率断路器

此断路器跟踪系统 CPU 使用率,如果最近的 CPU 使用率超过可配置的阈值,则会触发。

这是通过 JMX 指标 OperatingSystemMXBean.getSystemCpuLoad() 进行跟踪的。该指标测量整个系统的最近 CPU 使用率。该指标由 com.sun.management 包提供,该包并非在所有 JVM 上都实现。如果该指标不可用,断路器将被禁用并记录错误消息。另一种方法是使用 系统平均负载断路器

要启用和配置基于 CPU 利用率的断路器

每个集合在 solrconfig.xml
<circuitBreaker class="org.apache.solr.util.circuitbreaker.CPUCircuitBreaker">
 <double  name="threshold">75</double>
</circuitBreaker>
全局在 solr.in.sh
SOLR_CIRCUITBREAKER_QUERY_CPU=75

触发阈值以 CPU 使用率的百分比定义。值 “0” 映射到 0% 使用率,值 “100” 映射到 100% 使用率。上面的示例将在 CPU 使用率等于或大于 75% 时触发。

系统平均负载断路器

此断路器跟踪系统平均负载,如果最近的平均负载超过可配置的阈值,则会触发。

这是通过 JMX 指标 OperatingSystemMXBean.getSystemLoadAverage() 进行跟踪的。该指标测量整个系统的最近平均负载。“平均负载”是使用或等待 CPU 的进程数,通常在一分钟内平均得出。某些系统将等待 IO 的进程也包括在平均负载中。请查看您的系统和 JVM 的文档以了解此指标。有关更多信息,请参阅负载维基百科页面

要启用和配置平均负载断路器

每个集合在 solrconfig.xml
<circuitBreaker class="org.apache.solr.util.circuitbreaker.LoadAverageCircuitBreaker">
 <double  name="threshold">8.0</double>
</circuitBreaker>
全局在 solr.in.sh
SOLR_CIRCUITBREAKER_QUERY_LOADAVG=8.0

触发阈值是一个与平均负载匹配的浮点数。上面的示例断路器将在平均负载等于或大于 8.0 时触发。

系统平均负载断路器的行为取决于操作系统,并且可能无法在某些操作系统(如 Microsoft Windows)上运行。有关更多信息,请参阅 JavaDoc

高级示例

在此示例中,我们将阻止 CPU 负载高于 80% 的更新请求,并阻止 CPU 负载高于 95% 的查询请求。支持的请求类型为 queryupdate。这将防止代价高昂的批量更新影响搜索。另请注意对短形式类名称的支持。

每个集合在 solrconfig.xml
<config>
  <circuitBreaker class="solr.CPUCircuitBreaker">
   <double  name="threshold">80</double>
   <arr name="requestTypes">
     <str>update</str>
   </arr>
  </circuitBreaker>

  <circuitBreaker class="solr.CPUCircuitBreaker">
   <double  name="threshold">95</double>
   <arr name="requestTypes">
     <str>query</str>
   </arr>
  </circuitBreaker>
</config>
全局在 solr.in.sh
SOLR_CIRCUITBREAKER_UPDATE_CPU=80
SOLR_CIRCUITBREAKER_QUERY_CPU=95

性能注意事项

虽然 JVM 或 CPU 断路器不会为每个请求增加任何明显的开销,但是对于单个请求检查过多的断路器可能会导致性能开销。

此外,在繁忙的节点上重试请求时,最好使用指数退避策略。请参阅 指数退避维基百科页面