明明是异步网关,为什么吞吐量不够大?
是连接数的问题吗?
v1.0
回答
网关的瓶颈不是因为代码不好或者吞吐量不够大,反而是因为太大了,导致比如连接数上线,后端服务无法响应,或者fd生成的不够,直接reset,这些问题反而是由于吞吐量太大导致的。
打到后端服务把fd耗尽或者连接池耗尽,导致新的请求没有办法被处理,陷入卡死状态,所以如果我想要使网关的吞吐更高,我可以通过限流来提高网关的吞吐,通过调试让他和后端服务形成一种平衡,这样子就可以提高吞吐量了。
v2.0
回答
在我添加了限流之后并没有解决这个问题 可能不是上面那个问题,通过我的压测,其他网关,吞吐量远超我的网关的性能,一定是有的地方除了差错导致我的网关性能特别低
我可以专注于一条请求的实现链路,来观察每一步,我们是如何做的,并且人家和我们有什么区别
这个吞吐量不够大是由于线程卡死导致的,可以看下面的线程卡死的回答
通过日志发现同一个请求的结果被刷新了6遍?
一开始定位不到问题,莫名其妙走了6遍同样的方法,找不到方法的入口
v1.0
回答
这个是刷新的次数太多导致的,因为是递归调用,所以出方法都会走到那个地方,但是我们使用的是一个类里面的全局变量来判断的,所以会一直进入writeAndFlush,我们只需要改变一下递归位置就可以解决了。 但是这个问题,在我之后将项目重构了,所以这个问题已经天然不存在了
在压测完毕以后,某些线程会直接卡死,必须强制关闭才行
目前不知道为什么,这个问题出现在网关之中,我可以去看看没有出现该问题的网关的实现链路是怎么样的
所以接下来的目标就是参考多个网关的实现链路,去优化自己的网关,取长补短,一定要找到咱们网关的瓶颈,到底是什么导致我们的吞吐量那么小
v1.0
回答
经过测试,我们发现一旦端点时间过长,导致超时了,那个线程也会卡住,不知道是不是这个原因,(应该不是,因为我这边没有超时的报错),继续测试吧
v2.0
回答
这个问题和第一点是一样的,我们有两个返回响应的地方一个是正常返回响应,一个是在出异常的时候返回响应,这两个调用的不是一个响应方法(因为多了一些对于异常的处理和返回,所以不能用同一个),通过排查我们发现,每次都会有不定的线程卡死,这其实是因为长时间不清理线程的资源导致内存泄漏和溢出。 可以结合我的debug视频来看看其中的作用
可以看看AI的解答
在 GatewayContext 类的 releaseRequest() 方法中,使用了 ReferenceCountUtil.release(request.getFullHttpRequest()); 来释放资源,这里涉及到 Netty 的 引用计数机制。
Netty 的引用计数机制
Netty 使用引用计数(Reference Counting)来管理内存。引用计数的基本思想是:每个对象都有一个计数器,表示有多少个引用指向该对象。当引用计数为 0 时,表示没有任何引用指向该对象,它就可以被安全地释放。
Netty 的 ByteBuf(以及许多其他对象)采用了这种机制,以避免内存泄漏和未释放的资源占用。在这种机制下,当你对一个对象进行某些操作(如发送、接收等),该对象的引用计数会增加。当你不再使用这个对象时,你需要调用 release() 方法显式地减少引用计数。
ReferenceCountUtil.release() 的作用
ReferenceCountUtil 是 Netty 提供的一个工具类,用于方便地管理对象的引用计数。它提供了 release() 方法来减少对象的引用计数,通常在不再使用某个对象时调用。
这里的 request.getFullHttpRequest() 是什么?
request.getFullHttpRequest()返回的是FullHttpRequest对象,这个对象封装了整个 HTTP 请求的内容。FullHttpRequest是 Netty 中用来表示 HTTP 请求的一个类,它继承自HttpRequest,并且包含了请求的所有内容(例如请求头、请求体等)。由于
FullHttpRequest是一个 Netty 对象,它在内部使用ByteBuf来存储请求内容(例如请求体),而这些ByteBuf使用了引用计数机制来管理内存。
release(request.getFullHttpRequest()) 的作用
调用
ReferenceCountUtil.release(request.getFullHttpRequest());目的是释放request.getFullHttpRequest()对象及其内部的ByteBuf内存。如果
FullHttpRequest对象或其内部的ByteBuf被引用计数管理,则每次对它的引用计数减少时,Netty 会检查它的计数器。当引用计数降为 0 时,Netty 会自动释放该对象占用的内存(例如通过
ByteBuf.release()方法)。
为什么要释放资源?
避免内存泄漏:如果没有及时释放引用计数为 1 或更大的对象,就可能导致内存泄漏。在高并发的环境下,未释放的资源会不断堆积,最终可能导致内存耗尽或系统崩溃。
提高性能:通过显式释放内存,Netty 可以更高效地回收资源,减少内存的占用,提高系统的性能。
总结
在 GatewayContext 类中的 releaseRequest() 方法里,ReferenceCountUtil.release(request.getFullHttpRequest()); 用于减少 FullHttpRequest 对象的引用计数,当引用计数为 0 时,该对象会被释放。这是 Netty 内存管理机制的一部分,目的是避免内存泄漏,并确保请求对象的资源得到及时的回收。
这种引用计数管理通常用于 Netty 中的 ByteBuf、FullHttpRequest、FullHttpResponse 等对象,以确保高效和安全的内存使用。