Spring Cloud Gateway内存溢出问题如何解决
本篇内容主要讲解“Spring Cloud Gateway内存溢出问题如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring Cloud Gateway内存溢出问题如何解决”吧!
记 Spring Cloud Gateway 内存溢出查询过程
环境配置:
org.springframework.boot : 2.1.4.RELEASE
org.springframework.cloud :Greenwich.SR1
事故记录:
由于网关存在 RequestBody 丢失的情况,顾采用了网上的通用解决方案,使用如下方式解决:
@Beanpublic 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版本中,此处代码已被重构,升级后测试也完全正常。
到此,相信大家对“Spring Cloud Gateway内存溢出问题如何解决”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341