Python 官方文档:入门教程 => 点击学习
记 spring cloud Gateway 内存溢出查询过程 环境配置: org.springframework.boot : 2.1.4.RELEASE
由于网关存在 RequestBody 丢失的情况,顾采用了网上的通用解决方案,使用如下方式解决:
@Bean
public RouteLocator tpauditRoutes(RouteLocatorBuilder builder) {
return builder.routes().route("gateway-post", r -> r.order(1)
.method(HttpMethod.POST)
.and()
.readBody(String.class, requestBody -> {return true;}) # 重点在这
.and()
.path("/gateway
public <T> BooleanSpec readBody(Class<T> inClass, Predicate<T> predicate) {
return asyncPredicate(getBean(ReadBodyPredicateFactory.class)
.applyAsync(c -> c.setPredicate(inClass, predicate)));
}
异步调用的 ReadBodyPredicateFactory.applyAsync() 和 错误日志中的
org.springframework.cloud.gateway.handler.predicate.ReadBodyPredicateFactory.lambda$null$0(ReadBodyPredicateFactory.java:102)
指向方法一致。查看源码102行:
Flux<DataBuffer> cachedFlux = Flux.defer(() ->
Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount()))
);
此处 Spring Cloud Gateway 通过 dataBuffer.slice 切割出了新的 dataBuffer,但是通过 Netty 的内存检测工具判断,此处的 dataBuffer 并没有被回收。
ERROR io.netty.util.ResourceLeakDetector.reportTracedLeak:317 - LEAK: ByteBuf.release() was not called before it's garbage-collected. See http://netty.io/wiki/reference-counted-objects.html for more infORMation.
@Override
@SuppressWarnings("unchecked")
public AsyncPredicate<ServerWEBExchange> applyAsync(Config config) {
return exchange -> {
Class inClass = config.getInClass();
Object cachedBody = exchange.getAttribute(CACHE_REQUEST_BODY_OBJECT_KEY);
Mono<?> modifiedBody;
// We can only read the body from the request once, once that
// happens if we
// try to read the body again an exception will be thrown. The below
// if/else
// caches the body object as a request attribute in the
// ServerWebExchange
// so if this filter is run more than once (due to more than one
// route
// using it) we do not try to read the request body multiple times
if (cachedBody != null) {
try {
boolean test = config.predicate.test(cachedBody);
exchange.getAttributes().put(TEST_ATTRIBUTE, test);
return Mono.just(test);
} catch (ClassCastException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Predicate test failed because class in predicate "
+ "does not match the cached body object", e);
}
}
return Mono.just(false);
} else {
// Join all the DataBuffers so we have a single DataBuffer for
// the body
return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
// Update the retain counts so we can read the body twice,
// once to parse into an object
// that we can test the predicate against and a second time
// when the HTTP client sends
// the request downstream
// Note: if we end up reading the body twice we will run
// into
// a problem, but as of right
// now there is no Good use case for doing this
DataBufferUtils.retain(dataBuffer);
// Make a slice for each read so each read has its own
// read/write indexes
Flux<DataBuffer> cachedFlux = Flux
.defer(() -> Flux.just(dataBuffer.slice(0, dataBuffer.readableByteCount())));
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
# 新增如下代码
DataBufferUtils.release(dataBuffer);
return ServerRequest.create(exchange.mutate().request(mutatedRequest).build(), messageReaders)
.bodyToMono(inClass).doOnNext(objectValue -> {
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue);
exchange.getAttributes().put(CACHED_REQUEST_BODY_KEY, cachedFlux);
}).map(objectValue -> config.predicate.test(objectValue));
});
}
};
}
Spring Cloud Gateway 在配置的架构中,版本为2.1.1,修改以上代码后,启动项目测试,问题没有复现,正常运行。
同样这个问题,也可以选择升级 Spring Cloud Gateway 版本,在官方2.1.2版本中,此处代码已被重构,升级后测试也完全正常。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。
--结束END--
本文标题: Spring Cloud Gateway 内存溢出的解决方案
本文链接: https://lsjlt.com/news/130620.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0