mirror of https://github.com/apache/lucene.git
Revert "SOLR-14588: Implement Circuit Breakers (#1606)"
This reverts commit 7b54902f68
.
This commit is contained in:
parent
45763b6531
commit
529faf1241
|
@ -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"
|
||||
|
|
|
@ -83,10 +83,6 @@
|
|||
|
||||
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
|
||||
|
||||
<useCircuitBreakers>false</useCircuitBreakers>
|
||||
|
||||
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
|
||||
|
||||
<listener event="newSearcher" class="solr.QuerySenderListener">
|
||||
<arr name="queries">
|
||||
</arr>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -55,8 +55,6 @@
|
|||
"queryResultMaxDocsCached":1,
|
||||
"enableLazyFieldLoading":1,
|
||||
"boolTofilterOptimizer":1,
|
||||
"useCircuitBreakers":10,
|
||||
"memoryCircuitBreakerThreshold":20,
|
||||
"maxBooleanClauses":1},
|
||||
"jmx":{
|
||||
"agentId":0,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -42,8 +42,6 @@
|
|||
<enableLazyFieldLoading>true</enableLazyFieldLoading>
|
||||
<queryResultWindowSize>20</queryResultWindowSize>
|
||||
<queryResultMaxDocsCached>20</queryResultMaxDocsCached>
|
||||
<useCircuitBreakers>false</useCircuitBreakers>
|
||||
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
|
||||
|
||||
<useColdSearcher>true</useColdSearcher>
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -35,10 +35,6 @@
|
|||
|
||||
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
|
||||
|
||||
<useCircuitBreakers>false</useCircuitBreakers>
|
||||
|
||||
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
|
||||
|
||||
<documentCache size="512"
|
||||
initialSize="512"
|
||||
autowarmCount="0"/>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -53,8 +53,6 @@
|
|||
<enableLazyFieldLoading>true</enableLazyFieldLoading>
|
||||
<queryResultWindowSize>20</queryResultWindowSize>
|
||||
<queryResultMaxDocsCached>200</queryResultMaxDocsCached>
|
||||
<useCircuitBreakers>false</useCircuitBreakers>
|
||||
<memoryCircuitBreakerThreshold>100</memoryCircuitBreakerThreshold>
|
||||
<useColdSearcher>false</useColdSearcher>
|
||||
|
||||
</query>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue