Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题

这篇具有很好参考价值的文章主要介绍了Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、问题描述

使用Spring Cloud Gateway开发内部API网关时,当业务的Http请求体大小超过256K时,会出现如下报错:Exceeded limit on max bytes to buffer : 262144。

Spring Boot框架给了两种方式来修改这个大小的方式:
方式一:使用修改配置参数值,spring.max-in-memory-size: 1024 * 1024 的方式

spring:
  application:
    name: gateway
  codec:
    max-in-memory-size: 1024 * 1024

方式二:使用WebFluxConfigurer,通过set方法设置max-in-memory-size

	@Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize((int) maxInMemorySize.toBytes());
    }

但在实际上线以后发现并为解决256K的限制,这是为什么呢?

二、问题定位

首先排查了SpringBoot是如何使用spring.max-in-memory-size这个参数的,当业务在启动时候设置的参数到底是怎么执行的。

第一步:SpringBoot首先会自动加载autoconfigure包下面的CodecsAutoConfiguration类:

Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway这个类主要是加载Encoders和Decoders,如果我们使用的application/json的请求格式,并且项目里面也存在jackson2的包,则SpringBoot会加载,Jackson2JsonDecoder 和Jackson2JsonEncoder:

org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(ObjectMapper.class)
	static class JacksonCodecConfiguration {

		@Bean
		@Order(0)
		@ConditionalOnBean(ObjectMapper.class)
		CodecCustomizer jacksonCodecCustomizer(ObjectMapper objectMapper) {
			return (configurer) -> {
				CodecConfigurer.DefaultCodecs defaults = configurer.defaultCodecs();
				// 这里会new一个Jackson2JsonDecoder
				defaults.jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, EMPTY_MIME_TYPES));
				defaults.jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, EMPTY_MIME_TYPES));
			};
		}

	}

第二步:将设置的Jackson2JsonDecoder交给org.springframework.http.codec.support.BaseDefaultCodecs类去做初始化的工作:

Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway
Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway通过追踪到这里,我们可以看出来是执行了setMaxInMemorySize方法的,那么我们只需要知道这个set之前的值是从哪里来的。

第三步:setMaxInMemorySize修改参数

如果通过上述的两个方式来修改setMaxInMemorySize,会调用BaseDefaultCodecs的maxInMemorySize方法来设置的:

org.springframework.http.codec.support.BaseDefaultCodecs

 @Override
	public void maxInMemorySize(int byteCount) {
		if (!ObjectUtils.nullSafeEquals(this.maxInMemorySize, byteCount)) {
			this.maxInMemorySize = byteCount;
			initReaders();
		}
	}

到这里可以确定的逻辑是,不管是通过哪种set maxInMemorySize的方式,都会执行Jackson2JsonDecoder父类AbstractJackson2Decoder的setMaxInMemorySize方法来修改maxInMemorySize这个私有属性:Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway
而这个maxInMemorySize默认的256 * 1024 就是控制256K请求体的大小。具体可以查看org.springframework.http.codec.json.AbstractJackson2Decoder的decodeToMono方法,这个方法负责将http请求的body转换成json格式:

@Override
	public Mono<Object> decodeToMono(Publisher<DataBuffer> input, ResolvableType elementType,
			@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {

		return DataBufferUtils.join(input, this.maxInMemorySize)
				.flatMap(dataBuffer -> Mono.justOrEmpty(decode(dataBuffer, elementType, mimeType, hints)));
	}

DataBufferUtils.join(input, this.maxInMemorySize)方法里面使用了LimitedDataBufferList:
Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway

如果超过了maxByteCount则会抛出raiseLimitException,这里就是异常具体抛出的地方:
Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway

第四步:通过工具排查执行setMaxInMemorySize以后maxInMemorySize

既然代码流程里面执行了setMaxInMemorySize,但是却没生效,那么这里到底执行以后maxInMemorySize的值是多少呢?

通过arthas工具查看了AbstractJackson2Decoder值:

// sc 获取classLoadHash:
sc -d org.springframework.http.codec.json.AbstractJackson2Decoder

// 获取value
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[0].maxInMemorySize'
@Integer[1048576]
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[1].maxInMemorySize'
@Integer[262144]
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[2].maxInMemorySize'
@Integer[262144]
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[3].maxInMemorySize'
@Integer[262144]
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[4].maxInMemorySize'
@Integer[262144]
[arthas@48]$ vmtool -c 18b4aac2 -a getInstances --className org.springframework.http.codec.json.AbstractJackson2Decoder --express '#val=instances[5].maxInMemorySize'

通过获取多个AbstractJackson2Decoder实例的maxInMemorySize属性发现只有一个设置了1048576=1M,其他都是262144=256K,看到这里已经可以得出结论,不是setMaxInMemorySize没有生效,而是只生效了一个实例,因为初始化的时候只new了一个Jackson2JsonDecoder。

那其他的Jackson2JsonDecoder是从哪里来的?

第五步:查看Spring Cloud Gateway源码:源码地址

查看了Spring Cloud Gateway源码,发现了它给的代码中将Http Request Body 转换成Json的方式如下:

org.springframework.cloud.gateway.filter.factory.JsonToGrpcGatewayFilterFactory

Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway
在witeWith方法里面定义一个将Reques转换成Json的方法deserializeJSONRequest:
Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway
这里我们会发现如果你按照官方给的这种写法,每次请求进来会new Jackson2JsonDecoder,每次new出来的新对象是没有执行setMaxInMemorySize操作的,所以后期new的对象都默认使用了256 * 1024。

到此问题已经得到结论,不是SpringBoot框架setMaxInMemorySize没有生效,而是后期new的对象没有重新setMaxInMemorySize。

三、解决方案

如果要解决上述问题,我们需要保证每个新new的Jackson2JsonDecoder都能够使用设置的spring.max-in-memory-size,方法可以参考如下几种解决方案:

方案一:重写org.springframework.http.codec.json.AbstractJackson2Decoder

这种方法简单粗暴,直接将AbstractJackson2Decoder的maxInMemorySize改成spring.max-in-memory-size,通过自己写的AbstractJackson2Decoder覆盖SpringBoot框架里的AbstractJackson2Decoder,亲测有效。

Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway

方案二:将maxInMemorySize修改成static的私有属性

将maxInMemorySize改成static以后,则SpringBoot框架在初始化的时候执行一次setMaxInMemorySize则也能解决其他new的Jackson2JsonDecoder 对象maxInMemorySize不生效问题:
Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题,SpringBoot,Spring Cloud Gateway,springboot,spring cloud,gateway文章来源地址https://www.toymoban.com/news/detail-691187.html

方案三:每次new Jackson2JsonDecoder对像时执行setMaxInMemorySize

private Flux<JsonNode> deserializeJSONRequest(ServerWebExchange exchange) {
        return exchange.getRequest().getBody().map(dataBufferBody -> {
            ResolvableType targetType = ResolvableType.forType(JsonNode.class);
            Jackson2JsonDecoder Jackson2JsonDecoder = new Jackson2JsonDecoder();
            // 每次创建对象以后需要设置setMaxInMemorySize
            Jackson2JsonDecoder.setMaxInMemorySize(1024 * 1024);
            return Jackson2JsonDecoder.decode(dataBufferBody, targetType, null, null);
        }).cast(JsonNode.class);
    }

到了这里,关于Spring Cloud Gateway 彻底解决Exceeded limit on max bytes to buffer : 262144报错问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ResizeObserver loop limit exceeded报错解决方案

    ​ 公司内部搭建了前端监控系统Sentry,我把一些项目接入进去,一周后发现上报数量最多的事件是ResizeObserver loop limit exceeded。这些事件上报得太多,给Sentry服务造成很大压力,于是研究一番准备解决之。 element ui中table组件的resize回调代码如下 如果在一个动画帧内,ResizeOb

    2024年02月16日
    浏览(39)
  • element-plus 报错 ResizeObserver loop limit exceeded 解决

    不多说,报错信息就长上面这个样子,网上找了很多方案都没解决,例如在 onerror 钩子中忽略这个错误,所以我上我的解决方案,代码如下: 这个写在 main.js 里面就可以了,或者写在 app.vue 里面,反正在出现这个问题页面之前的页面都行。

    2024年02月11日
    浏览(40)
  • java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决

    出现该问题的原因:当GC为释放很小空间占用大量时间时会抛出此异常,即(Sun 官方对此的定义,超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常)。一般是因为堆太小,导致异常的原因:没有足够的内存。 对于该项目我的启动命令如下:堆内存空间开辟的

    2024年01月21日
    浏览(52)
  • Spring Cloud Gateway集成Actuator的安全漏洞和解决方案

    Spring Cloud Gateway是一个基于Spring Boot2.0和Spring WebFlux的API网关,它可以将请求转发到多个微服务并对请求进行路由、过滤和修改。Spring Cloud Gateway集成Actuator后可以提供更多的监控和管理功能,但是也可能导致安全漏洞。 最近线上环境出现一起安全事件,就是由于Spring Cloud Gat

    2024年02月09日
    浏览(49)
  • 解决Error:java: java.lang.OutOfMemoryError: WrappedJavaFileObject...GC overhead limit exceeded的错误

    今天在启动项目时,报出如下错误: 即 Error:java: java.lang.OutOfMemoryError: WrappedJavaFileObject[org.jetbrains.jps.javac.InputFileObject[file:xxx.java]]@pos242:@pos242: GC overhead limit exceeded 将错误 Error:java: java.lang.OutOfMemoryError: WrappedJavaFileObject[org.jetbrains.jps.javac.InputFileObject[file:xxx.java]]@pos242:@pos242: GC

    2024年02月04日
    浏览(43)
  • YOLO训练产出warning: NMS time limit 1.060s exceeded原因与解决办法

    在进行模型训练结束后,模型代码会执行 对模型进行map准确率的验证,使用时候出现 talk is cheap ,show me the code. 找到warning的代码出处: 以上是NMS非极大值抑制代码实现过程,其原理也很简单,解决的是多个锚框重叠的问题。 其实原因来看,进行NMS的时间断点太长了,将阈值

    2024年02月11日
    浏览(42)
  • IDEA 编译项目时报错:java: java.lang.OutOfMemoryError:GC overhead limit exceeded解决方法

    在Intellij IDEA下编译Java项目,报错:java.lang.OutOfMemoryError: …(此处忽略) GC overhead limit exceeded 错误是发生在编译阶段,而不是运行阶段。通过查询相关资料发现, 1.idea编译Java项目使用的虚拟机和idea软件自身使用的虚拟机是分开的(也就是独立的进程) 2.只需要给编译器使用的

    2024年02月05日
    浏览(42)
  • 解决Elasticsearch索引报错问题之Limit of total fields 1000 has been exceeded ...

    在Kibana上查询生产环境的日志时,发现某个一直无法查询到,怀疑想要的日志被丢弃了,遂登录服务器查询原始日志,果然发现日志存在被丢弃的问题。经定位,在Logstash的日志中发现问题所在: Elasticsearch的Mapping做了映射保护,为了防止索引中错误的内容导致Mapping

    2024年02月11日
    浏览(36)
  • 【IDEA启动项目报错java: java.lang.OutOfMemoryError: GC overhead limit exceeded解决方案】

    使用IDEA启动Spring Boot项目时,报内存溢出错误,导致服务启动失败: Error:java: java.lang.OutOfMemoryError: GC overhead limit exceeded 报此错说明启动期间内存不够用了,把idea的启动进程堆内存值设大点就行了。 设置窗口:Settings —Build,Execution,Deployment— Complier 把 build process heap size 值改

    2024年02月02日
    浏览(65)
  • 【爬虫 | Python】解决‘Requests Max Retries Exceeded With Url‘报错的问题

    我们在写爬虫的时候,经常会遇到这样的报错信息: HTTPConnectionPool(host=‘xxx.xxx.com’, port=443): Max retries exceeded with url: /api/v2/oauth (Caused by NewConnectionError(’urllib3.connection.HTTPConnection object at 0x7fac5953ab70: Failed to establish a new connection: [Errno 110] Connection timed out’)) 这里有3个重要的信

    2023年04月12日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包