|
@@ -30,6 +30,8 @@ import org.elasticsearch.common.settings.Setting.Property;
|
|
|
import org.elasticsearch.common.settings.Settings;
|
|
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
|
|
|
|
|
+import java.lang.management.ManagementFactory;
|
|
|
+import java.lang.management.MemoryMXBean;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
@@ -44,10 +46,21 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|
|
|
|
|
private static final String CHILD_LOGGER_PREFIX = "org.elasticsearch.indices.breaker.";
|
|
|
|
|
|
+ private static final MemoryMXBean MEMORY_MX_BEAN = ManagementFactory.getMemoryMXBean();
|
|
|
+
|
|
|
private final ConcurrentMap<String, CircuitBreaker> breakers = new ConcurrentHashMap<>();
|
|
|
|
|
|
+ public static final Setting<Boolean> USE_REAL_MEMORY_USAGE_SETTING =
|
|
|
+ Setting.boolSetting("indices.breaker.total.use_real_memory", true, Property.NodeScope);
|
|
|
+
|
|
|
public static final Setting<ByteSizeValue> TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING =
|
|
|
- Setting.memorySizeSetting("indices.breaker.total.limit", "70%", Property.Dynamic, Property.NodeScope);
|
|
|
+ Setting.memorySizeSetting("indices.breaker.total.limit", settings -> {
|
|
|
+ if (USE_REAL_MEMORY_USAGE_SETTING.get(settings)) {
|
|
|
+ return "95%";
|
|
|
+ } else {
|
|
|
+ return "70%";
|
|
|
+ }
|
|
|
+ }, Property.Dynamic, Property.NodeScope);
|
|
|
|
|
|
public static final Setting<ByteSizeValue> FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING =
|
|
|
Setting.memorySizeSetting("indices.breaker.fielddata.limit", "60%", Property.Dynamic, Property.NodeScope);
|
|
@@ -77,6 +90,7 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|
|
public static final Setting<CircuitBreaker.Type> IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_TYPE_SETTING =
|
|
|
new Setting<>("network.breaker.inflight_requests.type", "memory", CircuitBreaker.Type::parseValue, Property.NodeScope);
|
|
|
|
|
|
+ private final boolean trackRealMemoryUsage;
|
|
|
private volatile BreakerSettings parentSettings;
|
|
|
private volatile BreakerSettings fielddataSettings;
|
|
|
private volatile BreakerSettings inFlightRequestsSettings;
|
|
@@ -120,6 +134,8 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|
|
logger.trace("parent circuit breaker with settings {}", this.parentSettings);
|
|
|
}
|
|
|
|
|
|
+ this.trackRealMemoryUsage = USE_REAL_MEMORY_USAGE_SETTING.get(settings);
|
|
|
+
|
|
|
registerBreaker(this.requestSettings);
|
|
|
registerBreaker(this.fielddataSettings);
|
|
|
registerBreaker(this.inFlightRequestsSettings);
|
|
@@ -191,17 +207,15 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|
|
|
|
|
@Override
|
|
|
public AllCircuitBreakerStats stats() {
|
|
|
- long parentEstimated = 0;
|
|
|
List<CircuitBreakerStats> allStats = new ArrayList<>(this.breakers.size());
|
|
|
// Gather the "estimated" count for the parent breaker by adding the
|
|
|
// estimations for each individual breaker
|
|
|
for (CircuitBreaker breaker : this.breakers.values()) {
|
|
|
allStats.add(stats(breaker.getName()));
|
|
|
- parentEstimated += breaker.getUsed();
|
|
|
}
|
|
|
// Manually add the parent breaker settings since they aren't part of the breaker map
|
|
|
allStats.add(new CircuitBreakerStats(CircuitBreaker.PARENT, parentSettings.getLimit(),
|
|
|
- parentEstimated, 1.0, parentTripCount.get()));
|
|
|
+ parentUsed(0L), 1.0, parentTripCount.get()));
|
|
|
return new AllCircuitBreakerStats(allStats.toArray(new CircuitBreakerStats[allStats.size()]));
|
|
|
}
|
|
|
|
|
@@ -211,15 +225,28 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
|
|
|
return new CircuitBreakerStats(breaker.getName(), breaker.getLimit(), breaker.getUsed(), breaker.getOverhead(), breaker.getTrippedCount());
|
|
|
}
|
|
|
|
|
|
+ private long parentUsed(long newBytesReserved) {
|
|
|
+ if (this.trackRealMemoryUsage) {
|
|
|
+ return currentMemoryUsage() + newBytesReserved;
|
|
|
+ } else {
|
|
|
+ long parentEstimated = 0;
|
|
|
+ for (CircuitBreaker breaker : this.breakers.values()) {
|
|
|
+ parentEstimated += breaker.getUsed() * breaker.getOverhead();
|
|
|
+ }
|
|
|
+ return parentEstimated;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //package private to allow overriding it in tests
|
|
|
+ long currentMemoryUsage() {
|
|
|
+ return MEMORY_MX_BEAN.getHeapMemoryUsage().getUsed();
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Checks whether the parent breaker has been tripped
|
|
|
*/
|
|
|
- public void checkParentLimit(String label) throws CircuitBreakingException {
|
|
|
- long totalUsed = 0;
|
|
|
- for (CircuitBreaker breaker : this.breakers.values()) {
|
|
|
- totalUsed += (breaker.getUsed() * breaker.getOverhead());
|
|
|
- }
|
|
|
-
|
|
|
+ public void checkParentLimit(long newBytesReserved, String label) throws CircuitBreakingException {
|
|
|
+ long totalUsed = parentUsed(newBytesReserved);
|
|
|
long parentLimit = this.parentSettings.getLimit();
|
|
|
if (totalUsed > parentLimit) {
|
|
|
this.parentTripCount.incrementAndGet();
|