Skip to content

Commit 38d8a66

Browse files
committed
fix(filter): enhance load detection logging and memory management
1 parent c72f2f4 commit 38d8a66

2 files changed

Lines changed: 35 additions & 26 deletions

File tree

hugegraph-server/hugegraph-api/src/main/java/org/apache/hugegraph/api/filter/LoadDetectFilter.java

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public class LoadDetectFilter implements ContainerRequestFilter {
5858
private static final RateLimiter GC_RATE_LIMITER =
5959
RateLimiter.create(1.0 / 30);
6060

61+
// Log at most 1 request per second to avoid too many logs when server is under heavy load
62+
private static final RateLimiter REJECT_LOG_RATE_LIMITER = RateLimiter.create(1.0);
63+
6164
@Context
6265
private jakarta.inject.Provider<HugeConfig> configProvider;
6366
@Context
@@ -71,10 +74,12 @@ public static boolean isWhiteAPI(ContainerRequestContext context) {
7174
return WHITE_API_LIST.contains(rootPath);
7275
}
7376

74-
private static void gcIfNeeded() {
77+
private static boolean gcIfNeeded() {
7578
if (GC_RATE_LIMITER.tryAcquire(1)) {
7679
System.gc();
80+
return true;
7781
}
82+
return false;
7883
}
7984

8085
@Override
@@ -90,10 +95,12 @@ public void filter(ContainerRequestContext context) {
9095
// There will be a thread doesn't work, dedicated to statistics
9196
int currentLoad = load.incrementAndGet();
9297
if (currentLoad >= maxWorkerThreads) {
93-
LOG.warn("Rejected request due to high worker load, method={}, path={}, " +
94-
"currentLoad={}, maxWorkerThreads={}",
95-
context.getMethod(), context.getUriInfo().getPath(),
96-
currentLoad, maxWorkerThreads);
98+
if (REJECT_LOG_RATE_LIMITER.tryAcquire()) {
99+
LOG.warn("Rejected request due to high worker load, method={}, path={}, " +
100+
"currentLoad={}, maxWorkerThreads={}",
101+
context.getMethod(), context.getUriInfo().getPath(),
102+
currentLoad, maxWorkerThreads);
103+
}
97104
throw new ServiceUnavailableException(String.format(
98105
"The server is too busy to process the request, " +
99106
"you can config %s to adjust it or try again later",
@@ -106,11 +113,17 @@ public void filter(ContainerRequestContext context) {
106113
long presumableFreeMem = (Runtime.getRuntime().maxMemory() -
107114
allocatedMem) / Bytes.MB;
108115
if (presumableFreeMem < minFreeMemory) {
109-
gcIfNeeded();
116+
boolean gcTriggered = gcIfNeeded();
117+
long allocatedMemAfterCheck = Runtime.getRuntime().totalMemory() -
118+
Runtime.getRuntime().freeMemory();
119+
long recheckedFreeMem = (Runtime.getRuntime().maxMemory() -
120+
allocatedMemAfterCheck) / Bytes.MB;
110121
LOG.warn("Rejected request due to low free memory, method={}, path={}, " +
111-
"presumableFreeMemMB={}, minFreeMemoryMB={}",
122+
"presumableFreeMemMB={}, recheckedFreeMemMB={}, gcTriggered={}, " +
123+
"minFreeMemoryMB={}",
112124
context.getMethod(), context.getUriInfo().getPath(),
113-
presumableFreeMem, minFreeMemory);
125+
presumableFreeMem, recheckedFreeMem, gcTriggered,
126+
minFreeMemory);
114127
throw new ServiceUnavailableException(String.format(
115128
"The server available memory %s(MB) is below than " +
116129
"threshold %s(MB) and can't process the request, " +

hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/api/filter/LoadDetectFilterTest.java

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.apache.hugegraph.config.ServerOptions;
2828
import org.apache.hugegraph.define.WorkLoad;
2929
import org.apache.hugegraph.testutil.Assert;
30+
import org.apache.hugegraph.testutil.Whitebox;
3031
import org.apache.hugegraph.unit.BaseUnitTest;
3132
import org.junit.Before;
3233
import org.junit.Test;
@@ -55,9 +56,8 @@ public void setup() {
5556
Mockito.when(this.requestContext.getMethod()).thenReturn("GET");
5657

5758
this.loadDetectFilter = new LoadDetectFilter();
58-
injectProvider(this.loadDetectFilter, "loadProvider", () -> this.workLoad);
59-
injectProvider(this.loadDetectFilter, "configProvider",
60-
() -> createConfig(8, 0));
59+
this.setLoadProvider(this.workLoad);
60+
this.setConfigProvider(createConfig(8, 0));
6161
}
6262

6363
@Test
@@ -74,8 +74,7 @@ public void testFilter_WhiteListPathIgnored() {
7474
public void testFilter_RejectsWhenWorkerLoadIsTooHigh() {
7575
setupPath("graphs/hugegraph/vertices",
7676
List.of("graphs", "hugegraph", "vertices"));
77-
injectProvider(this.loadDetectFilter, "configProvider",
78-
() -> createConfig(2, 0));
77+
this.setConfigProvider(createConfig(2, 0));
7978
this.workLoad.incrementAndGet();
8079

8180
ServiceUnavailableException exception = (ServiceUnavailableException) Assert.assertThrows(
@@ -92,8 +91,7 @@ public void testFilter_RejectsWhenWorkerLoadIsTooHigh() {
9291
public void testFilter_RejectsWhenFreeMemoryIsTooLow() {
9392
setupPath("graphs/hugegraph/vertices",
9493
List.of("graphs", "hugegraph", "vertices"));
95-
injectProvider(this.loadDetectFilter, "configProvider",
96-
() -> createConfig(8, Integer.MAX_VALUE));
94+
this.setConfigProvider(createConfig(8, Integer.MAX_VALUE));
9795

9896
ServiceUnavailableException exception = (ServiceUnavailableException) Assert.assertThrows(
9997
ServiceUnavailableException.class,
@@ -109,8 +107,7 @@ public void testFilter_RejectsWhenFreeMemoryIsTooLow() {
109107
public void testFilter_AllowsRequestWhenLoadAndMemoryAreHealthy() {
110108
setupPath("graphs/hugegraph/vertices",
111109
List.of("graphs", "hugegraph", "vertices"));
112-
injectProvider(this.loadDetectFilter, "configProvider",
113-
() -> createConfig(8, 0));
110+
this.setConfigProvider(createConfig(8, 0));
114111

115112
this.loadDetectFilter.filter(this.requestContext);
116113

@@ -138,14 +135,13 @@ private PathSegment createPathSegment(String path) {
138135
return segment;
139136
}
140137

141-
private <T> void injectProvider(LoadDetectFilter filter, String fieldName,
142-
Provider<T> provider) {
143-
try {
144-
java.lang.reflect.Field field = LoadDetectFilter.class.getDeclaredField(fieldName);
145-
field.setAccessible(true);
146-
field.set(filter, provider);
147-
} catch (Exception e) {
148-
throw new RuntimeException("Failed to inject provider: " + fieldName, e);
149-
}
138+
private void setLoadProvider(WorkLoad workLoad) {
139+
Whitebox.setInternalState(this.loadDetectFilter, "loadProvider",
140+
(Provider<WorkLoad>) () -> workLoad);
141+
}
142+
143+
private void setConfigProvider(HugeConfig config) {
144+
Whitebox.setInternalState(this.loadDetectFilter, "configProvider",
145+
(Provider<HugeConfig>) () -> config);
150146
}
151147
}

0 commit comments

Comments
 (0)