spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information

Open linuxdf opened this issue 3 years ago • 2 comments

public class GlobalRequestLogFilter implements GlobalFilter, Ordered { // private final WebEndpointProperties endpointProperties;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	ServerHttpRequest request = exchange.getRequest();
	// 打印请求路径
	String path = request.getPath().pathWithinApplication().value();

	// 忽略 endpoint 请求

// String endpointBasePath = endpointProperties.getBasePath(); String endpointBasePath = ""; if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) { return chain.filter(exchange); }

	String requestUrl = RequestProvider.getOriginalRequestUrl(exchange);

	// 构建成一条长 日志,避免并发下日志错乱
	StringBuilder beforeReqLog = new StringBuilder(300);
	// 日志参数
	List<Object> beforeReqArgs = new ArrayList<>();
	beforeReqLog.append("\n\n================ Gateway Request Start  ================\n");
	// 打印路由
	beforeReqLog.append("===> {}: {}\n");
	// 参数
	String requestMethod = request.getMethodValue();
	beforeReqArgs.add(requestMethod);
	beforeReqArgs.add(requestUrl);

	// 打印请求头
	HttpHeaders headers = request.getHeaders();
	headers.forEach((headerName, headerValue) -> {
		beforeReqLog.append("===Headers===  {}: {}\n");
		beforeReqArgs.add(headerName);

// if (true) { // String value = headerValue.get(0); // // // beforeReqLog.append("===Headers=== {}: {}\n"); // beforeReqArgs.add(headerName.concat("-original")); // beforeReqArgs.add(StringUtils.join(headerValue.toArray())); // } else { // beforeReqArgs.add(StringUtils.join(headerValue.toArray())); // } beforeReqArgs.add(StringUtils.join(headerValue.toArray())); });

	beforeReqLog.append("================  Gateway Request End  =================\n");
	// 打印执行时间
	log.info(beforeReqLog.toString(), beforeReqArgs.toArray());
	return chain.filter(exchange);
}

@Override
public int getOrder() {
	return Ordered.LOWEST_PRECEDENCE;
}

}

public class GlobalResponseLogFilter implements GlobalFilter, Ordered { // private final WebEndpointProperties endpointProperties;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	ServerHttpRequest request = exchange.getRequest();
	// 打印请求路径
	String path = request.getPath().pathWithinApplication().value();
	// 忽略 endpoint 请求

// String endpointBasePath = endpointProperties.getBasePath(); String endpointBasePath = ""; if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) { return chain.filter(exchange); } return chain.filter(exchange).then( Mono.fromRunnable(() -> { MultiValueMap<String, String> queryParams = request.getQueryParams(); String requestUrl = UriComponentsBuilder.fromPath(path).queryParams(queryParams).build().toUriString();

			// 构建成一条长 日志,避免并发下日志错乱
			StringBuffer responseLog = new StringBuffer(300);
			// 日志参数
			List<Object> responseArgs = new ArrayList<>();
			responseLog.append("\n\n================ Gateway Response Start  ================\n");
			ServerHttpResponse response = exchange.getResponse();
			// 打印路由 200 get: /api/xxx/xxx
			responseLog.append("<=== {} {}: {}\n");
			// 参数
			String requestMethod = request.getMethodValue();
			responseArgs.add(response.getStatusCode().value());
			responseArgs.add(requestMethod);
			responseArgs.add(requestUrl);

			// 打印请求头
			HttpHeaders headers = response.getHeaders();
			headers.forEach((headerName, headerValue) -> {
				responseLog.append("===Headers===  {}: {}\n");
				responseArgs.add(headerName);
				responseArgs.add(StringUtils.join(headerValue.toArray()));
			});

			responseLog.append("================  Gateway Response End  =================\n");
			// 打印执行时间
			log.info(responseLog.toString(), responseArgs.toArray());
		})
	);
}

@Override
public int getOrder() {
	return Ordered.HIGHEST_PRECEDENCE;
}

}

linuxdf avatar Sep 05 '22 03:09 linuxdf

I got a similar error on mine as well I have tracked it down to a GRPC routing cal. I am trying to extract the code away from my gateway codenase to see if I can isolate it futher.

You can get this more frequently and predictable when you set the spring.netty.leak-deection to PARANOID.

One thing you may want to look at is to use ServerWebExchangeUtils.setAlreadyRouted. In addition, I think I may have narrowed the issue on mine in that Reactor Sleuth may be the cause of the error. Because I saw this block (after adding that setAlreadyRouted.

2022-09-06 05:56:13.809 ERROR [,,] 1 --- [or-http-epoll-2] io.netty.util.ResourceLeakDetector       : LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information.
Recent access records:
#1:
        io.netty.buffer.AdvancedLeakAwareByteBuf.retainedSlice(AdvancedLeakAwareByteBuf.java:89)
        org.springframework.cloud.gateway.support.ServerWebExchangeUtils$1.lambda$getBody$0(ServerWebExchangeUtils.java:375)
        reactor.core.publisher.MonoSupplier.call(MonoSupplier.java:86)
        reactor.core.publisher.FluxCallable.subscribe(FluxCallable.java:44)
        reactor.core.publisher.Mono.subscribe(Mono.java:4397)
        reactor.core.publisher.MonoZip.subscribe(MonoZip.java:128)
        reactor.core.publisher.Mono.subscribe(Mono.java:4397)
        reactor.core.publisher.MonoSubscribeOn$SubscribeOnSubscriber.run(MonoSubscribeOn.java:126)
        org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth.lambda$null$6(ReactorSleuth.java:324)
        reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84)
        reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37)
        io.micrometer.core.instrument.internal.TimedCallable.call(TimedCallable.java:51)
        java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
        java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        java.base/java.lang.Thread.run(Thread.java:833)

trajano avatar Sep 06 '22 05:09 trajano

收到,谢谢,我这边尝试下!

------------------ 原始邮件 ------------------ 发件人: "Archimedes @.>; 发送时间: 2022年9月6日(星期二) 中午1:07 收件人: @.>; 抄送: @.>; @.>; 主题: Re: [spring-cloud/spring-cloud-gateway] ERROR io.netty.util.ResourceLeakDetector - LEAK: ByteBuf.release() was not called before it's garbage-collected. See https://netty.io/wiki/reference-counted-objects.html for more information (Issue #2722)

I got a similar error on mine as well I have tracked it down to a GRPC routing cal. I am trying to extract the code away from my gateway codenase to see if I can isolate it futher.

You can get this more frequently and predictable when you set thespring.netty.leak-deectiontoPARANOID.

— Reply to this email directly,view it on GitHub, orunsubscribe. You are receiving this because you authored the thread.Message @.***与>

linuxdf avatar Sep 06 '22 05:09 linuxdf