30
30
import org .elasticsearch .common .settings .Settings ;
31
31
import org .elasticsearch .common .unit .ByteSizeValue ;
32
32
33
+ import java .lang .management .ManagementFactory ;
34
+ import java .lang .management .MemoryMXBean ;
33
35
import java .util .ArrayList ;
34
36
import java .util .List ;
35
37
import java .util .concurrent .ConcurrentHashMap ;
@@ -44,10 +46,21 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
44
46
45
47
private static final String CHILD_LOGGER_PREFIX = "org.elasticsearch.indices.breaker." ;
46
48
49
+ private static final MemoryMXBean MEMORY_MX_BEAN = ManagementFactory .getMemoryMXBean ();
50
+
47
51
private final ConcurrentMap <String , CircuitBreaker > breakers = new ConcurrentHashMap <>();
48
52
53
+ public static final Setting <Boolean > USE_REAL_MEMORY_USAGE_SETTING =
54
+ Setting .boolSetting ("indices.breaker.total.use_real_memory" , true , Property .NodeScope );
55
+
49
56
public static final Setting <ByteSizeValue > TOTAL_CIRCUIT_BREAKER_LIMIT_SETTING =
50
- Setting .memorySizeSetting ("indices.breaker.total.limit" , "70%" , Property .Dynamic , Property .NodeScope );
57
+ Setting .memorySizeSetting ("indices.breaker.total.limit" , settings -> {
58
+ if (USE_REAL_MEMORY_USAGE_SETTING .get (settings )) {
59
+ return "95%" ;
60
+ } else {
61
+ return "70%" ;
62
+ }
63
+ }, Property .Dynamic , Property .NodeScope );
51
64
52
65
public static final Setting <ByteSizeValue > FIELDDATA_CIRCUIT_BREAKER_LIMIT_SETTING =
53
66
Setting .memorySizeSetting ("indices.breaker.fielddata.limit" , "60%" , Property .Dynamic , Property .NodeScope );
@@ -77,6 +90,7 @@ public class HierarchyCircuitBreakerService extends CircuitBreakerService {
77
90
public static final Setting <CircuitBreaker .Type > IN_FLIGHT_REQUESTS_CIRCUIT_BREAKER_TYPE_SETTING =
78
91
new Setting <>("network.breaker.inflight_requests.type" , "memory" , CircuitBreaker .Type ::parseValue , Property .NodeScope );
79
92
93
+ private final boolean trackRealMemoryUsage ;
80
94
private volatile BreakerSettings parentSettings ;
81
95
private volatile BreakerSettings fielddataSettings ;
82
96
private volatile BreakerSettings inFlightRequestsSettings ;
@@ -120,6 +134,8 @@ public HierarchyCircuitBreakerService(Settings settings, ClusterSettings cluster
120
134
logger .trace ("parent circuit breaker with settings {}" , this .parentSettings );
121
135
}
122
136
137
+ this .trackRealMemoryUsage = USE_REAL_MEMORY_USAGE_SETTING .get (settings );
138
+
123
139
registerBreaker (this .requestSettings );
124
140
registerBreaker (this .fielddataSettings );
125
141
registerBreaker (this .inFlightRequestsSettings );
@@ -191,17 +207,15 @@ public CircuitBreaker getBreaker(String name) {
191
207
192
208
@ Override
193
209
public AllCircuitBreakerStats stats () {
194
- long parentEstimated = 0 ;
195
210
List <CircuitBreakerStats > allStats = new ArrayList <>(this .breakers .size ());
196
211
// Gather the "estimated" count for the parent breaker by adding the
197
212
// estimations for each individual breaker
198
213
for (CircuitBreaker breaker : this .breakers .values ()) {
199
214
allStats .add (stats (breaker .getName ()));
200
- parentEstimated += breaker .getUsed ();
201
215
}
202
216
// Manually add the parent breaker settings since they aren't part of the breaker map
203
217
allStats .add (new CircuitBreakerStats (CircuitBreaker .PARENT , parentSettings .getLimit (),
204
- parentEstimated , 1.0 , parentTripCount .get ()));
218
+ parentUsed ( 0L ) , 1.0 , parentTripCount .get ()));
205
219
return new AllCircuitBreakerStats (allStats .toArray (new CircuitBreakerStats [allStats .size ()]));
206
220
}
207
221
@@ -211,15 +225,28 @@ public CircuitBreakerStats stats(String name) {
211
225
return new CircuitBreakerStats (breaker .getName (), breaker .getLimit (), breaker .getUsed (), breaker .getOverhead (), breaker .getTrippedCount ());
212
226
}
213
227
228
+ private long parentUsed (long newBytesReserved ) {
229
+ if (this .trackRealMemoryUsage ) {
230
+ return currentMemoryUsage () + newBytesReserved ;
231
+ } else {
232
+ long parentEstimated = 0 ;
233
+ for (CircuitBreaker breaker : this .breakers .values ()) {
234
+ parentEstimated += breaker .getUsed () * breaker .getOverhead ();
235
+ }
236
+ return parentEstimated ;
237
+ }
238
+ }
239
+
240
+ //package private to allow overriding it in tests
241
+ long currentMemoryUsage () {
242
+ return MEMORY_MX_BEAN .getHeapMemoryUsage ().getUsed ();
243
+ }
244
+
214
245
/**
215
246
* Checks whether the parent breaker has been tripped
216
247
*/
217
- public void checkParentLimit (String label ) throws CircuitBreakingException {
218
- long totalUsed = 0 ;
219
- for (CircuitBreaker breaker : this .breakers .values ()) {
220
- totalUsed += (breaker .getUsed () * breaker .getOverhead ());
221
- }
222
-
248
+ public void checkParentLimit (long newBytesReserved , String label ) throws CircuitBreakingException {
249
+ long totalUsed = parentUsed (newBytesReserved );
223
250
long parentLimit = this .parentSettings .getLimit ();
224
251
if (totalUsed > parentLimit ) {
225
252
this .parentTripCount .incrementAndGet ();
0 commit comments