IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> 网关gateway出现netty_data_buffer(OOM)内存溢出问题 -> 正文阅读

[开发测试]网关gateway出现netty_data_buffer(OOM)内存溢出问题

现象描述

  1. 网关Hoxton.RELEASE版本,接入Apollo。
  2. 在项目开启限流、压测一段时间后,netty_data_buffer的内存逐渐变大,最终导致内存溢出。
  3. 项目在运行过程中开启了ReadBodyPredicateFactory断言。

问题定位

? ? ? ? 1、在ReadBodyPredicateFactory中进行请求体缓存。

public class ReadBodyPredicateFactory
		extends AbstractRoutePredicateFactory<ReadBodyPredicateFactory.Config> {
	...
	
	@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 (log.isDebugEnabled()) {
						log.debug("Predicate test failed because class in predicate "
								+ "does not match the cached body object", e);
					}
				}
				return Mono.just(false);
			}
			else {
				return ServerWebExchangeUtils.cacheRequestBodyAndRequest(exchange,
						(serverHttpRequest) -> ServerRequest
								.create(exchange.mutate().request(serverHttpRequest)
										.build(), messageReaders)
								.bodyToMono(inClass)
								.doOnNext(objectValue -> exchange.getAttributes()
										.put(CACHE_REQUEST_BODY_OBJECT_KEY, objectValue))
								.map(objectValue -> config.getPredicate()
										.test(objectValue)));
			}
		};
	}
	...
}

? ? ? ? 2、ServerWebExchangeUtils和上下文属性

ServerWebExchangeUtils?里面存放了很多静态公有的字符串KEY值(?这些字符串KEY的实际值是?org.springframework.cloud.gateway.support.ServerWebExchangeUtils.?+ 下面任意的静态公有KEY?),这些字符串KEY值一般是用于?ServerWebExchange?的属性(?Attribute?,见上文的?ServerWebExchange#getAttributes()?方法)的KEY,这些属性值都是有特殊的含义,在使用过滤器的时候如果时机适当可以直接取出来使用,下面逐个分析。

  • PRESERVE_HOST_HEADER_ATTRIBUTE?:是否保存Host属性,值是布尔值类型,写入位置是?PreserveHostHeaderGatewayFilterFactory?,使用的位置是?NettyRoutingFilter?,作用是如果设置为true,HTTP请求头中的Host属性会写到底层Reactor-Netty的请求Header属性中。
  • CLIENT_RESPONSE_ATTR?:保存底层Reactor-Netty的响应对象,类型是?reactor.netty.http.client.HttpClientResponse?。
  • CLIENT_RESPONSE_CONN_ATTR?:保存底层Reactor-Netty的连接对象,类型是?reactor.netty.Connection?。
  • URI_TEMPLATE_VARIABLES_ATTRIBUTE?:?PathRoutePredicateFactory?解析路径参数完成之后,把解析完成后的占位符KEY-路径Path映射存放在?ServerWebExchange?的属性中,KEY就是?URI_TEMPLATE_VARIABLES_ATTRIBUTE?。
  • CLIENT_RESPONSE_HEADER_NAMES?:保存底层Reactor-Netty的响应Header的名称集合。
  • GATEWAY_ROUTE_ATTR?:用于存放?RoutePredicateHandlerMapping?中匹配出来的具体的路由(?org.springframework.cloud.gateway.route.Route?)实例,通过这个路由实例可以得知当前请求会路由到下游哪个服务。
  • GATEWAY_REQUEST_URL_ATTR?:?java.net.URI?类型的实例,这个实例代表直接请求或者负载均衡处理之后需要请求到下游服务的真实URI。
  • GATEWAY_ORIGINAL_REQUEST_URL_ATTR?:?java.net.URI?类型的实例,需要重写请求URI的时候,保存原始的请求URI。
  • GATEWAY_HANDLER_MAPPER_ATTR?:保存当前使用的?HandlerMapping?具体实例的类型简称(一般是字符串"RoutePredicateHandlerMapping")。
  • GATEWAY_SCHEME_PREFIX_ATTR?:确定目标路由URI中如果存在schemeSpecificPart属性,则保存该URI的scheme在此属性中,路由URI会被重新构造,见?RouteToRequestUrlFilter?。
  • GATEWAY_PREDICATE_ROUTE_ATTR?:用于存放?RoutePredicateHandlerMapping?中匹配出来的具体的路由(?org.springframework.cloud.gateway.route.Route?)实例的ID。
  • WEIGHT_ATTR?:实验性功能(此版本还不建议在正式版本使用)存放分组权重相关属性,见?WeightCalculatorWebFilter?。
  • ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR?:存放响应Header中的ContentType的值。
  • HYSTRIX_EXECUTION_EXCEPTION_ATTR?:?Throwable?的实例,存放的是Hystrix执行异常时候的异常实例,见?HystrixGatewayFilterFactory?。
  • GATEWAY_ALREADY_ROUTED_ATTR?:布尔值,用于判断是否已经进行了路由,见?NettyRoutingFilter?。
  • GATEWAY_ALREADY_PREFIXED_ATTR?:布尔值,用于判断请求路径是否被添加了前置部分,见?PrefixPathGatewayFilterFactory?。

解决办法

? ? ? ? 1、在网关全局异常处理逻辑中,对databuffer的内存进行释放

Object object = exchange.getAttribute("cacheRequestBody");
if(object != null){
    DataBufferUtils.release((DataBuffer) object);
}
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2022-04-22 19:07:17  更:2022-04-22 19:07:36 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 13:09:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码