Revert "SOLR-14588: Implement Circuit Breakers (#1606)"

This reverts commit 7b54902f68.
This commit is contained in:
Atri Sharma 2020-06-27 23:44:32 +05:30
parent 45763b6531
commit 529faf1241
28 changed files with 2 additions and 743 deletions

View File

@ -123,17 +123,6 @@
The purpose is to enable easy caching of user/application level data.
The regenerator argument should be specified as an implementation
of solr.search.CacheRegenerator if autowarming is desired. -->
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!--
<cache name="myUserCache"
class="solr.CaffeineCache"

View File

@ -83,10 +83,6 @@
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<listener event="newSearcher" class="solr.QuerySenderListener">
<arr name="queries">
</arr>

View File

@ -224,11 +224,6 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
queryResultWindowSize = Math.max(1, getInt("query/queryResultWindowSize", 1));
queryResultMaxDocsCached = getInt("query/queryResultMaxDocsCached", Integer.MAX_VALUE);
enableLazyFieldLoading = getBool("query/enableLazyFieldLoading", false);
useCircuitBreakers = getBool("query/useCircuitBreakers", false);
memoryCircuitBreakerThreshold = getInt("query/memoryCircuitBreakerThreshold", 100);
validateMemoryBreakerThreshold();
useRangeVersionsForPeerSync = getBool("peerSync/useRangeVersions", true);
@ -527,10 +522,6 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
public final int queryResultWindowSize;
public final int queryResultMaxDocsCached;
public final boolean enableLazyFieldLoading;
// Circuit Breaker Configuration
public final boolean useCircuitBreakers;
public final int memoryCircuitBreakerThreshold;
public final boolean useRangeVersionsForPeerSync;
@ -813,14 +804,6 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
loader.reloadLuceneSPI();
}
private void validateMemoryBreakerThreshold() {
if (useCircuitBreakers) {
if (memoryCircuitBreakerThreshold > 100 || memoryCircuitBreakerThreshold < 0) {
throw new IllegalArgumentException("memoryCircuitBreakerThreshold is not a valid percentage");
}
}
}
public int getMultipartUploadLimitKB() {
return multipartUploadLimitKB;
}
@ -890,8 +873,6 @@ public class SolrConfig extends XmlConfigFile implements MapSerializable {
m.put("queryResultMaxDocsCached", queryResultMaxDocsCached);
m.put("enableLazyFieldLoading", enableLazyFieldLoading);
m.put("maxBooleanClauses", booleanQueryMaxClauseCount);
m.put("useCircuitBreakers", useCircuitBreakers);
m.put("memoryCircuitBreakerThreshold", memoryCircuitBreakerThreshold);
for (SolrPluginInfo plugin : plugins) {
List<PluginInfo> infos = getPluginInfos(plugin.clazz.getName());
if (infos == null || infos.isEmpty()) continue;

View File

@ -94,7 +94,6 @@ import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.ObjectReleaseTracker;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.DirectoryFactory.DirContext;
import org.apache.solr.core.snapshots.SolrSnapshotManager;
@ -158,13 +157,13 @@ import org.apache.solr.update.processor.RunUpdateProcessorFactory;
import org.apache.solr.update.processor.UpdateRequestProcessorChain;
import org.apache.solr.update.processor.UpdateRequestProcessorChain.ProcessorInfo;
import org.apache.solr.update.processor.UpdateRequestProcessorFactory;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.util.IOFunction;
import org.apache.solr.util.NumberUtils;
import org.apache.solr.util.PropertiesInputStream;
import org.apache.solr.util.PropertiesOutputStream;
import org.apache.solr.util.RefCounted;
import org.apache.solr.util.TestInjection;
import org.apache.solr.util.circuitbreaker.CircuitBreakerManager;
import org.apache.solr.util.plugin.NamedListInitializedPlugin;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.apache.solr.util.plugin.SolrCoreAware;
@ -220,8 +219,6 @@ public final class SolrCore implements SolrInfoBean, Closeable {
private final Codec codec;
private final MemClassLoader memClassLoader;
private final CircuitBreakerManager circuitBreakerManager;
private final List<Runnable> confListeners = new CopyOnWriteArrayList<>();
private final ReentrantLock ruleExpiryLock;
@ -941,7 +938,6 @@ public final class SolrCore implements SolrInfoBean, Closeable {
this.configSetProperties = configSet.getProperties();
// Initialize the metrics manager
this.coreMetricManager = initCoreMetricManager(solrConfig);
this.circuitBreakerManager = initCircuitBreakerManager();
solrMetricsContext = coreMetricManager.getSolrMetricsContext();
this.coreMetricManager.loadReporters();
@ -1168,12 +1164,6 @@ public final class SolrCore implements SolrInfoBean, Closeable {
return coreMetricManager;
}
private CircuitBreakerManager initCircuitBreakerManager() {
CircuitBreakerManager circuitBreakerManager = CircuitBreakerManager.buildDefaultCircuitBreakerManager(this);
return circuitBreakerManager;
}
@Override
public void initializeMetrics(SolrMetricsContext parentContext, String scope) {
newSearcherCounter = parentContext.counter("new", Category.SEARCHER.toString());
@ -1509,10 +1499,6 @@ public final class SolrCore implements SolrInfoBean, Closeable {
return updateProcessors;
}
public CircuitBreakerManager getCircuitBreakerManager() {
return circuitBreakerManager;
}
// this core current usage count
private final AtomicInteger refCount = new AtomicInteger(1);

View File

@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.lucene.index.ExitableDirectoryReader;
@ -52,18 +51,13 @@ import org.apache.solr.security.AuthorizationContext;
import org.apache.solr.security.PermissionNameProvider;
import org.apache.solr.util.RTimerTree;
import org.apache.solr.util.SolrPluginUtils;
import org.apache.solr.util.circuitbreaker.CircuitBreaker;
import org.apache.solr.util.circuitbreaker.CircuitBreakerManager;
import org.apache.solr.util.circuitbreaker.CircuitBreakerType;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.common.params.CommonParams.DISTRIB;
import static org.apache.solr.common.params.CommonParams.FAILURE;
import static org.apache.solr.common.params.CommonParams.PATH;
import static org.apache.solr.common.params.CommonParams.STATUS;
/**
@ -303,29 +297,6 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
final RTimerTree timer = rb.isDebug() ? req.getRequestTimer() : null;
Map<CircuitBreakerType, CircuitBreaker> trippedCircuitBreakers;
if (timer != null) {
RTimerTree subt = timer.sub("circuitbreaker");
rb.setTimer(subt.sub("circuitbreaker"));
CircuitBreakerManager circuitBreakerManager = req.getCore().getCircuitBreakerManager();
trippedCircuitBreakers = circuitBreakerManager.checkAllCircuitBreakers();
rb.getTimer().stop();
subt.stop();
} else {
CircuitBreakerManager circuitBreakerManager = req.getCore().getCircuitBreakerManager();
trippedCircuitBreakers = circuitBreakerManager.checkAllCircuitBreakers();
}
if (trippedCircuitBreakers != null) {
String errorMessage = CircuitBreakerManager.constructFinalErrorMessageString(trippedCircuitBreakers);
rsp.add(STATUS, FAILURE);
rsp.setException(new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, "Circuit Breakers tripped " + errorMessage));
return;
}
final ShardHandler shardHandler1 = getAndPrepShardHandler(req, rb); // creates a ShardHandler object only if it's needed
if (timer == null) {
@ -337,7 +308,7 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
// debugging prepare phase
RTimerTree subt = timer.sub( "prepare" );
for( SearchComponent c : components ) {
rb.setTimer(subt.sub( c.getName() ) );
rb.setTimer( subt.sub( c.getName() ) );
c.prepare(rb);
rb.getTimer().stop();
}

View File

@ -1,51 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.util.circuitbreaker;
import org.apache.solr.core.SolrCore;
/**
* Default class to define circuit breakers for Solr.
*
* TODO: This class should be grown as the scope of circuit breakers grow.
*/
public abstract class CircuitBreaker {
public static final String NAME = "circuitbreaker";
protected final SolrCore solrCore;
public CircuitBreaker(SolrCore solrCore) {
this.solrCore = solrCore;
}
// Global config for all circuit breakers. For specific circuit breaker configs, define
// your own config
protected boolean isCircuitBreakerEnabled() {
return solrCore.getSolrConfig().useCircuitBreakers;
}
/**
* Check if this allocation will trigger circuit breaker.
*/
public abstract boolean isCircuitBreakerGauntletTripped();
/**
* Print debug useful info
*/
public abstract String printDebugInfo();
}

View File

@ -1,105 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.util.circuitbreaker;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.core.SolrCore;
/**
* Manages all registered circuit breaker instances. Responsible for a holistic view
* of whether a circuit breaker has tripped or not.
*
* There are two typical ways of using this class's instance:
* 1. Check if any circuit breaker has triggered -- and know which circuit breaker has triggered.
* 2. Get an instance of a specific circuit breaker and perform checks.
*
* It is a good practice to register new circuit breakers here if you want them checked for every
* request.
*
* NOTE: The current way of registering new default circuit breakers is minimal and not a long term
* solution. There will be a follow up with a SIP for a schema API design.
*/
public class CircuitBreakerManager {
private final Map<CircuitBreakerType, CircuitBreaker> circuitBreakerMap = new HashMap<>();
// Allows replacing of existing circuit breaker
public void registerCircuitBreaker(CircuitBreakerType circuitBreakerType, CircuitBreaker circuitBreaker) {
circuitBreakerMap.put(circuitBreakerType, circuitBreaker);
}
public CircuitBreaker getCircuitBreaker(CircuitBreakerType circuitBreakerType) {
assert circuitBreakerType != null;
return circuitBreakerMap.get(circuitBreakerType);
}
/**
* Check if any circuit breaker has triggered.
* @return CircuitBreakers which have triggered, null otherwise
*/
public Map<CircuitBreakerType, CircuitBreaker> checkAllCircuitBreakers() {
Map<CircuitBreakerType, CircuitBreaker> triggeredCircuitBreakers = new HashMap<>();
for (Map.Entry<CircuitBreakerType, CircuitBreaker> entry : circuitBreakerMap.entrySet()) {
CircuitBreaker circuitBreaker = entry.getValue();
if (circuitBreaker.isCircuitBreakerEnabled() &&
circuitBreaker.isCircuitBreakerGauntletTripped()) {
triggeredCircuitBreakers.put(entry.getKey(), circuitBreaker);
}
}
return triggeredCircuitBreakers.size() > 0 ? triggeredCircuitBreakers : null;
}
/**
* Construct the final error message to be printed when circuit breakers trip
* @param circuitBreakerMap Input list for circuit breakers
* @return Constructed error message
*/
public static String constructFinalErrorMessageString(Map<CircuitBreakerType, CircuitBreaker> circuitBreakerMap) {
assert circuitBreakerMap != null;
StringBuilder sb = new StringBuilder();
for (CircuitBreakerType circuitBreakerType : circuitBreakerMap.keySet()) {
sb.append(circuitBreakerType.toString() + " " + circuitBreakerMap.get(circuitBreakerType).printDebugInfo());
}
return sb.toString();
}
/**
* Register default circuit breakers and return a constructed CircuitBreakerManager
* instance which serves the given circuit breakers.
*
* Any default circuit breakers should be registered here
*/
public static CircuitBreakerManager buildDefaultCircuitBreakerManager(SolrCore solrCore) {
CircuitBreakerManager circuitBreakerManager = new CircuitBreakerManager();
// Install the default circuit breakers
CircuitBreaker memoryCircuitBreaker = new MemoryCircuitBreaker(solrCore);
circuitBreakerManager.registerCircuitBreaker(CircuitBreakerType.MEMORY, memoryCircuitBreaker);
return circuitBreakerManager;
}
}

View File

@ -1,26 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.util.circuitbreaker;
/**
* Types of circuit breakers
*/
public enum CircuitBreakerType {
MEMORY,
CPU
}

View File

@ -1,87 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.util.circuitbreaker;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import org.apache.solr.core.SolrCore;
public class MemoryCircuitBreaker extends CircuitBreaker {
private static final MemoryMXBean MEMORY_MX_BEAN = ManagementFactory.getMemoryMXBean();
private final long currentMaxHeap = MEMORY_MX_BEAN.getHeapMemoryUsage().getMax();
// Assumption -- the value of these parameters will be set correctly before invoking printDebugInfo()
private ThreadLocal<Long> seenMemory = new ThreadLocal<>();
private ThreadLocal<Long> allowedMemory = new ThreadLocal<>();
public MemoryCircuitBreaker(SolrCore solrCore) {
super(solrCore);
if (currentMaxHeap <= 0) {
throw new IllegalArgumentException("Invalid JVM state for the max heap usage");
}
}
// TODO: An optimization can be to trip the circuit breaker for a duration of time
// after the circuit breaker condition is matched. This will optimize for per call
// overhead of calculating the condition parameters but can result in false positives.
@Override
public boolean isCircuitBreakerGauntletTripped() {
if (!isCircuitBreakerEnabled()) {
return false;
}
allowedMemory.set(getCurrentMemoryThreshold());
seenMemory.set(calculateLiveMemoryUsage());
return (seenMemory.get() >= allowedMemory.get());
}
@Override
public String printDebugInfo() {
return "seenMemory=" + seenMemory.get() + " allowedMemory=" + allowedMemory.get();
}
private long getCurrentMemoryThreshold() {
int thresholdValueInPercentage = solrCore.getSolrConfig().memoryCircuitBreakerThreshold;
double thresholdInFraction = thresholdValueInPercentage / (double) 100;
long actualLimit = (long) (currentMaxHeap * thresholdInFraction);
if (actualLimit <= 0) {
throw new IllegalStateException("Memory limit cannot be less than or equal to zero");
}
return actualLimit;
}
/**
* Calculate the live memory usage for the system. This method has package visibility
* to allow using for testing
* @return Memory usage in bytes
*/
protected long calculateLiveMemoryUsage() {
// NOTE: MemoryUsageGaugeSet provides memory usage statistics but we do not use them
// here since MemoryUsageGaugeSet provides combination of heap and non heap usage and
// we are not looking into non heap usage here. Ideally, this call should not add noticeable
// latency to a query -- but if it does, please signify on SOLR-14588
return MEMORY_MX_BEAN.getHeapMemoryUsage().getUsed();
}
}

View File

@ -55,8 +55,6 @@
"queryResultMaxDocsCached":1,
"enableLazyFieldLoading":1,
"boolTofilterOptimizer":1,
"useCircuitBreakers":10,
"memoryCircuitBreakerThreshold":20,
"maxBooleanClauses":1},
"jmx":{
"agentId":0,

View File

@ -70,10 +70,6 @@
<queryResultWindowSize>10</queryResultWindowSize>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- boolToFilterOptimizer converts boolean clauses with zero boost
into cached filters if the number of docs selected by the clause exceeds
the threshold (represented as a fraction of the total index)

View File

@ -76,10 +76,6 @@
<queryResultWindowSize>10</queryResultWindowSize>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- boolToFilterOptimizer converts boolean clauses with zero boost
into cached filters if the number of docs selected by the clause exceeds
the threshold (represented as a fraction of the total index)

View File

@ -42,8 +42,6 @@
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<queryResultWindowSize>20</queryResultWindowSize>
<queryResultMaxDocsCached>20</queryResultMaxDocsCached>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<useColdSearcher>true</useColdSearcher>

View File

@ -1,91 +0,0 @@
<?xml version="1.0" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<config>
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
<dataDir>${solr.data.dir:}</dataDir>
<xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
<schemaFactory class="ClassicIndexSchemaFactory"/>
<requestHandler name="/select" class="solr.SearchHandler" />
<query>
<!-- Maximum number of clauses in a boolean query... can affect
range or wildcard queries that expand to big boolean
queries. An exception is thrown if exceeded.
-->
<maxBooleanClauses>${solr.max.booleanClauses:1024}</maxBooleanClauses>
<!-- Cache specification for Filters or DocSets - unordered set of *all* documents
that match a particular query.
-->
<filterCache
enabled="${filterCache.enabled}"
size="512"
initialSize="512"
autowarmCount="2"/>
<queryResultCache
enabled="${queryResultCache.enabled}"
size="512"
initialSize="512"
autowarmCount="2"/>
<documentCache
enabled="${documentCache.enabled}"
size="512"
initialSize="512"
autowarmCount="0"/>
<cache
name="user_definied_cache_XXX"
enabled="${user_definied_cache_XXX.enabled:false}"
/>
<cache
name="user_definied_cache_ZZZ"
enabled="${user_definied_cache_ZZZ.enabled:false}"
/>
<!-- If true, stored fields that are not requested will be loaded lazily.
-->
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<queryResultWindowSize>10</queryResultWindowSize>
<useCircuitBreakers>true</useCircuitBreakers>
<memoryCircuitBreakerThreshold>75</memoryCircuitBreakerThreshold>
<!-- boolToFilterOptimizer converts boolean clauses with zero boost
into cached filters if the number of docs selected by the clause exceeds
the threshold (represented as a fraction of the total index)
-->
<boolTofilterOptimizer enabled="false" cacheSize="32" threshold=".05"/>
</query>
<initParams path="/select">
<lst name="defaults">
<str name="df">text</str>
</lst>
</initParams>
</config>

View File

@ -35,10 +35,6 @@
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<documentCache size="512"
initialSize="512"
autowarmCount="0"/>

View File

@ -119,16 +119,6 @@
-->
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>80</memoryCircuitBreakerThreshold>
<!--
<cache name="myUserCache"

View File

@ -53,8 +53,6 @@
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<queryResultWindowSize>20</queryResultWindowSize>
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<useCircuitBreakers>false</useCircuitBreakers>
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<useColdSearcher>false</useColdSearcher>
</query>

View File

@ -266,8 +266,6 @@ public class SolrCoreTest extends SolrTestCaseJ4 {
assertEquals("wrong config for maxBooleanClauses", 1024, solrConfig.booleanQueryMaxClauseCount);
assertEquals("wrong config for enableLazyFieldLoading", true, solrConfig.enableLazyFieldLoading);
assertEquals("wrong config for queryResultWindowSize", 10, solrConfig.queryResultWindowSize);
assertEquals("wrong config for useCircuitBreakers", false, solrConfig.useCircuitBreakers);
assertEquals("wrong config for memoryCircuitBreakerThreshold", 80, solrConfig.memoryCircuitBreakerThreshold);
}
/**

View File

@ -46,8 +46,6 @@ public class TestConfigOverlay extends SolrTestCase {
assertTrue(isEditableProp("query.queryResultMaxDocsCached", false, null));
assertTrue(isEditableProp("query.enableLazyFieldLoading", false, null));
assertTrue(isEditableProp("query.boolTofilterOptimizer", false, null));
assertTrue(isEditableProp("query.useCircuitBreakers", false, null));
assertTrue(isEditableProp("query.memoryCircuitBreakerThreshold", false, null));
assertTrue(isEditableProp("jmx.agentId", false, null));
assertTrue(isEditableProp("jmx.serviceUrl", false, null));
assertTrue(isEditableProp("jmx.rootName", false, null));

View File

@ -1,190 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.solr.util;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.core.SolrCore;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.util.circuitbreaker.CircuitBreaker;
import org.apache.solr.util.circuitbreaker.CircuitBreakerType;
import org.apache.solr.util.circuitbreaker.MemoryCircuitBreaker;
import org.junit.AfterClass;
import org.junit.BeforeClass;
public class TestCircuitBreaker extends SolrTestCaseJ4 {
private final static int NUM_DOCS = 20;
@BeforeClass
public static void setUpClass() throws Exception {
System.setProperty("filterCache.enabled", "false");
System.setProperty("queryResultCache.enabled", "false");
System.setProperty("documentCache.enabled", "true");
initCore("solrconfig-memory-circuitbreaker.xml", "schema.xml");
for (int i = 0 ; i < NUM_DOCS ; i ++) {
assertU(adoc("name", "john smith", "id", "1"));
assertU(adoc("name", "johathon smith", "id", "2"));
assertU(adoc("name", "john percival smith", "id", "3"));
//commit inside the loop to get multiple segments to make search as realistic as possible
assertU(commit());
}
}
@Override
public void tearDown() throws Exception {
super.tearDown();
}
@AfterClass
public static void afterClass() {
System.clearProperty("filterCache.enabled");
System.clearProperty("queryResultCache.enabled");
System.clearProperty("documentCache.enabled");
}
public void testCBAlwaysTrips() throws IOException {
HashMap<String, String> args = new HashMap<String, String>();
args.put(QueryParsing.DEFTYPE, CircuitBreaker.NAME);
args.put(CommonParams.FL, "id");
CircuitBreaker circuitBreaker = new MockCircuitBreaker(h.getCore());
h.getCore().getCircuitBreakerManager().registerCircuitBreaker(CircuitBreakerType.MEMORY, circuitBreaker);
expectThrows(SolrException.class, () -> {
h.query(req("name:\"john smith\""));
});
}
public void testCBFakeMemoryPressure() throws IOException {
HashMap<String, String> args = new HashMap<String, String>();
args.put(QueryParsing.DEFTYPE, CircuitBreaker.NAME);
args.put(CommonParams.FL, "id");
CircuitBreaker circuitBreaker = new FakeMemoryPressureCircuitBreaker(h.getCore());
h.getCore().getCircuitBreakerManager().registerCircuitBreaker(CircuitBreakerType.MEMORY, circuitBreaker);
expectThrows(SolrException.class, () -> {
h.query(req("name:\"john smith\""));
});
}
public void testBuildingMemoryPressure() {
ExecutorService executor = ExecutorUtil.newMDCAwareCachedThreadPool(
new SolrNamedThreadFactory("TestCircuitBreaker"));
HashMap<String, String> args = new HashMap<String, String>();
args.put(QueryParsing.DEFTYPE, CircuitBreaker.NAME);
args.put(CommonParams.FL, "id");
AtomicInteger failureCount = new AtomicInteger();
try {
CircuitBreaker circuitBreaker = new BuildingUpMemoryPressureCircuitBreaker(h.getCore());
h.getCore().getCircuitBreakerManager().registerCircuitBreaker(CircuitBreakerType.MEMORY, circuitBreaker);
for (int i = 0; i < 5; i++) {
executor.submit(() -> {
try {
h.query(req("name:\"john smith\""));
} catch (SolrException e) {
failureCount.incrementAndGet();
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}
});
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e.getMessage());
}
assertEquals("Number of failed queries is not correct", 1, failureCount.get());
} finally {
if (!executor.isShutdown()) {
executor.shutdown();
}
}
}
private class MockCircuitBreaker extends CircuitBreaker {
public MockCircuitBreaker(SolrCore solrCore) {
super(solrCore);
}
@Override
public boolean isCircuitBreakerGauntletTripped() {
// Always return true
return true;
}
@Override
public String printDebugInfo() {
return "MockCircuitBreaker";
}
}
private class FakeMemoryPressureCircuitBreaker extends MemoryCircuitBreaker {
public FakeMemoryPressureCircuitBreaker(SolrCore solrCore) {
super(solrCore);
}
@Override
protected long calculateLiveMemoryUsage() {
// Return a number large enough to trigger a pushback from the circuit breaker
return Long.MAX_VALUE;
}
}
private class BuildingUpMemoryPressureCircuitBreaker extends MemoryCircuitBreaker {
private AtomicInteger count = new AtomicInteger();
public BuildingUpMemoryPressureCircuitBreaker(SolrCore solrCore) {
super(solrCore);
}
@Override
protected long calculateLiveMemoryUsage() {
if (count.getAndIncrement() >= 4) {
return Long.MAX_VALUE;
}
return 5; // Random number guaranteed to not trip the circuit breaker
}
}
}

View File

@ -502,16 +502,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -505,16 +505,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -502,16 +502,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -498,16 +498,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -513,16 +513,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -554,16 +554,6 @@
-->
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
<!-- Enable Circuit Breakers
-->
<useCircuitBreakers>false</useCircuitBreakers>
<!-- Memory Circuit Breaker Threshold In Percentage
Post this percentage usage of the heap, incoming queries will be rejected
-->
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
<!-- Query Related Event Listeners
Various IndexSearcher related events can trigger Listeners to

View File

@ -202,10 +202,6 @@ _Query Sizing and Warming_
* `query.queryResultWindowSize`
* `query.queryResultMaxDocCached`
_Query JVM Metrics Control_
* `query.useCircuitBreakers`
* `query.memoryCircuitBreakerThreshold`
*RequestDispatcher Settings*
See <<requestdispatcher-in-solrconfig.adoc#requestdispatcher-in-solrconfig,RequestDispatcher in SolrConfig>> for defaults and acceptable values for these settings.

View File

@ -172,24 +172,6 @@ This parameter sets the maximum number of documents to cache for any entry in th
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
----
=== useCircuitBreakers
This parameter allows enabling circuit breakers for query control.
[source,xml]
----
<useCircuitBreakers>true</useCircuitBreakers>
----
=== memoryCircuitBreakerThreshold
Memory threshold in percentage for JVM heap usage
[source,xml]
----
<memoryCircuitBreakerThreshold>75</memoryCircuitBreakerThreshold>
----
=== useColdSearcher
This setting controls whether search requests for which there is not a currently registered searcher should wait for a new searcher to warm up (false) or proceed immediately (true). When set to "false", requests will block until the searcher has warmed its caches.