SpringCloudGateway内存泄漏问题(记录解决过程)

SpringCloudGateway内存泄漏问题

项目完善差不多,在进入压力测试阶段期间,发现了gateway有内存泄漏问题,问题发现的起因是,当时启动一台gateway,一台对应的下游应用服务,在压力测试期间,发现特别不稳定,并发量时高时低,而且会有施压机卡住的现象,然后找到容器对应的宿主机,并使用container stats命令观察内存,经过观察发现,压力测试时内存会暴涨,并由于超过限制最大内存导致容器挂掉(这里由于用的swarm所以会自动选择节点重启)最终发现由于之前测试服务器配置低,所以限制了堆大小为1g,容器cpu 1,容器内存限制为了1g,经过调整后将内存改为4g且不限制容器资源的情况下,并发稳定,单机qps也不错,但是多次压力测试后依然会有卡住的问题,观察了日志之后确定为内存泄漏

io.netty.util.internal.OutOfDirectMemoryError: 
failed to allocate 16777216 byte(s) of direct memory 
(used: 4110417927, max: 4116185088)
- LEAK: ByteBuf.release() was not called before it's garbage-collected. 

发现问题之后,我进入容器内dump了内存快照,并下载到本机由jvisualvm分析,分析过程中并没有发现异常情况,由于gateway底层是netty,所以怀疑是堆外内存出了问题,这时候我从快照中查询bytebuff,依然很小,后来直接使用arthas去线上分析,分析发现堆内存正常,gc也没有问题
在这里插入图片描述
最后为了快速测试出异常,我调小了堆外内存大小,并配合nmt调查

-XX:NativeMemoryTracking=detail -XX:MaxDirectMemorySize=100M

在线上使用pmap去查看内存,发现了很多的anon,并且每次并发都会增长
在这里插入图片描述
转移到本地进行测试,发现内存远超出分配的堆大小,最终确定为堆外内存出了问题
在这里插入图片描述

既然是堆外内存出的问题,我们就只关心是否申请了buff没有释放,通过对代码的检查发现,只有两个地方使用到了相关的内容

 DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
        return serverHttpResponse.writeWith(Flux.just(buffer));

对上面的代码进行大量压测后发现并无问题,内存没有异常增长不回收

 ServerHttpRequest httpRequest = exchange.getRequest().mutate().headers(httpHeaders -> {
                            httpHeaders.add(GatewayConstants.LOGIN_USER_KEY, JSON.toJSONString(s));
                        }).build();
                        return chain.filter(exchange.mutate().request(httpRequest).build());

还有一处就是修改请求头这部分代码,当注释掉这部分时,内存稳定没有异常增长,当放开时,3000并发几乎增加800M内存,几次就怼到了5g+,由于gateway内置了一个请求头工厂(AddRequestHeaderGatewayFilterFactory),我去查看对应的源代码,是怎么实现的
在这里插入图片描述
如图,除了多了解析配置之外和我写的基本也一样,那为何会内存异常呢?只能去github上找找问题看看有人遇到相同的事没。

在这里插入图片描述
这个老哥遇到的问题也类似,他是修改请求体的内容时出现的
在这里插入图片描述

这个问题我也遇到了在这里插入图片描述
看起来这个问题还是挺严重的,最后我也反手提了一个问题
在这里插入图片描述
没有啥回答,最后还是参考了一些别人的写法最后内存不会飙升了,但是不知其为何,还得继续调查
在这里插入图片描述
内存飙升现象减少了,但是依然存在,在减少了堆大小和容器的容量后,并发量没有减少,内存也减少了,一般保持在85左右,多次大量的并发压测之后也会上90,会有少量下降趋势(猜测是堆回收),问题还在继续调查中。。。


第二天,问题似乎依然没有解决,最终我将设置heaer放在下游服务器(因为最终定位出现问题的代码就是在设置header这里),修改完之后,最后再次测试以为万事大吉,结果问题出现了,内存依然在飙升,我:??????(由于着急要压测的数据结果,所以项目组其他人建议将gateway组件移除后直接压下游服务…)但是能那么容易放弃吗。

所以这个时候一边压下游服务,我一遍偷偷调试gateway,就在快下班时突然发现一个问题,请求发出去后被hold住了没有反应,我用postman尝试请求后发现了一个之前没有出现的异常

在这里插入图片描述
然后我突然灵光一闪感觉有啥东西不对,然后我就打开了pom文件发现
在这里插入图片描述
这里引入了两个redis的依赖,下面响应式的,上面的是正常服务要用的,他们有redistemplate,然后我删除了上面的依赖后发现貌似内存不飙升了…,但是并发感觉很低,而且cpu居高不下,我猜是redis客户端配置的max-active太低了,最后询问了阿里云的最大配置是2W,我将客户端修改为了5000,这个时候单机吞吐达到1500+,cpu很快就降下,内存也没有飙升。问题到此算是告一段落,为了测试真实性,还需要继续进行大量连续测试来证明结果,
最后我准备抽时间看一下两个依赖的源码有啥区别。

最终解决是因为依赖了一个公共库,我吐了…,移除了就好了,解决bug有时候真的很简单…

感谢阅读

  • 6
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
结合CAS单点登录实现Spring Cloud Gateway的认证和鉴权可以通过以下步骤实现: 1. 配置CAS Server和CAS Client 首先需要配置一个CAS Server和一个CAS Client,可以使用Apereo CAS来实现。配置CAS Server时需要指定CAS的登录地址、校验地址、注销地址等。配置CAS Client时需要指定CAS Server的地址、客户端地址以及需要保护的资源等。 2. 配置Spring Cloud GatewaySpring Cloud Gateway中需要配置CAS的过滤器和路由规则。可以使用spring-security-cas和spring-cloud-starter-gateway来实现。配置过滤器时需要指定CAS Server的地址、客户端地址以及需要保护的资源等。配置路由规则时需要根据需要进行配置。例如,可以配置一个/login路由,该路由请求转发到CAS Server的登录地址。如果用户已经登录,则可以将请求转发到实际的服务。 3. 测试单点登录 完成以上步骤后,可以测试单点登录是否正常工作。首先需要访问需要保护的资源,例如Spring Cloud Gateway中的一个微服务。如果用户没有登录,则自动跳转到CAS Server的登录页面。用户登录后,就可以访问受保护的资源了。如果用户注销,则自动跳转到CAS Server的注销页面。 总体来说,结合CAS单点登录实现Spring Cloud Gateway的认证和鉴权需要进行一些配置和调试工作,但是实现起来并不难。同时需要注意保护用户隐私和数据安全,避免泄露用户信息和敏感数据。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值