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 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> SpringCloudGateway tcp连接无法回收的分析与修复 -> 正文阅读

[网络协议]SpringCloudGateway tcp连接无法回收的分析与修复

SpringCloudGateway tcp连接无法回收的分析与修复

scg tcp连接不回收的分析与修复

一、springcloud版本

第一个版本:Hoxton.SR12
第二个版本:2021.0.2
在第一个版本出问题后升级了第二个版本,可是问题还是依旧出现。

二、网关功能

包含数据加解密、websocket转发这两个额外的功能;

三、 生产描述

2,网关基本上每分钟都有人访问,tcp连接数持续增长,到65535左右后,不再接受新的请求,服务就无法访问,只能重启
在这里插入图片描述

四、 解决方式一(tcp连接还是不回收,对我的网关没效果)

https://blog.csdn.net/weixin_43142697/article/details/122605048,参照了这个里面的修改意见,我在nacos里面增加了网关配置,可是观察了快两个小时,没有一个链接回收掉,以下是我的配置:

// An highlighted block
  cloud:
    gateway:
      httpclient:
        pool:
          max-idle-time: PT1S
          eviction-interval: PT30S
        connect-timeout: 20000
        response-timeout: PT30S

使用 ss -aoen|grep 443|grep ESTAB 命令获取以下图片内容,左侧红圈中是用户ip,隔一段时间就使用该命令查看,发现ip一个不少,不知道是我配的有问题还是什么原因,我也暂时没有时间细究了,等有时间我要再定位下看看
在这左边里插入图片描述

五、解决方式二(验证通过)

1、使用netstat -tnpoa|sed -n -e 2p -e /443/p,看下图,查看这些tcp连接的状态,无一例外都是ESTABLISHED off
先看看这个的英文解释:
keepalive - when the keepalive timer is ON for the socket
on - when the retransmission timer is ON for the socket
off - none of the above is ON
其实很明白,说这些连接当前的监听器既不是keepalive 也不是on,换句话说就是没有用于回收的监听器,连接永远无法回收
在这里插入图片描述
2、再使用ss -aoen|grep 443|grep ESTAB查看有没有监听器Timer,看下图,右侧红圈中只有ino,没有出现timer字段,也就是没有用上tcp的keepalive功能,说明确实链接没有用到监听回收器
在这左边里插入图片描述
3、不禁要疑问下,会不会是代码的问题,不然springcloud gateway不可能犯这种低级错误,但时间紧,也不能再细想了,但有时间我还得看看自己的代码坑。
4、我们看下正常情况下的tcp链接的keepalive功能,可以看到下图中的
Timer:(keepalive,119min,0),说明这几个tcp都是会被服务器探测是否失效的,其中119min是指119分钟后开始探测该链接是否有效,0代表第一次探测失败后的重试探测次数。

5、通过sysctl -a |grep keepalive,可以查看到linux下默认的配置,虽然这里看到配置了keepalive,但是Tcp进程必须额外开启keepalive,才能生效。
在这里插入图片描述
tcp_keepalive_time:表示多长时间后,开始探测TCP链接是否有效,一般系统默认两小时。
tcp_keepalive_probes:表示如果探测失败的话,会继续探测 9 次。
tcp_keepalive_intvl:tcp_keepalive_probes的探测时间间隔为 75 秒。
如果服务的访问量比较大,建议将tcp_keepalive_time按需设置,比如五分钟,十分钟
6、既然需要开启tcp的keepalive功能,就需要对springcloud gateway中关于tcp的源码进行分析了,在网上搜索gateway tcp相关的源码就可以搜索到TcpServerBind这个类,其实tcp相关的代码都在reactor.netty.tcp这个包下,也很好找,我们看下TcpServerBind这个类,可以发现使用了ChannelOption.SO_REUSEADDR:
这个参数表示允许重复使用本地地址和端口,比如,某个服务器进程占用了TCP的80端口进行监听,此时再次监听该端口就会返回错误,使用该参数就可以解决问题,该参数允许共用该端口,这个在服务器程序中比较常使用,比如某个进程非正常退出,该程序占用的端口可能要被占用一段时间才能允许其他进程使用,而且程序死掉以后,内核一需要一定的时间才能够释放此端口,不设置SO_REUSEADDR就无法正常使用该端口。

	static final TcpServerBind INSTANCE = new TcpServerBind();

	final TcpServerConfig config;

	TcpServerBind() {
		Map<ChannelOption<?>, Boolean> childOptions = new HashMap<>(2);
		childOptions.put(ChannelOption.AUTO_READ, false);
		childOptions.put(ChannelOption.TCP_NODELAY, true);
		this.config = new TcpServerConfig(
				// 可以看到gateway
				Collections.singletonMap(ChannelOption.SO_REUSEADDR, true),
				childOptions,
				() -> new InetSocketAddress(DEFAULT_PORT));
	}

	TcpServerBind(TcpServerConfig config) {
		this.config = config;
	}

7、而我们现在配置另一个参数:Channeloption.SO_KEEPALIVE,对应于套接字选项中的SO_KEEPALIVE,服务器会启动定时器去探测该tcp连接的有效性。当设置该选项以后,如果在两小时内没有数据的通信时,TCP会自动发送一个活动探测数据报文。
那在哪里设置这个ChannelOption.SO_KEEPALIVE呢,NettyReactiveWebServerFactory这个类会负责
配置一些启动参数,比如里面的NettyServerCustomizer,字面意思就是netty服务器自定义,那很明显,我可以设置一些自定义属性

	/**
	 * Set {@link NettyServerCustomizer}s that should be applied to the Netty server
	 * builder. Calling this method will replace any existing customizers.
	 * @param serverCustomizers the customizers to set
	 */
	public void setServerCustomizers(Collection<? extends NettyServerCustomizer> serverCustomizers) {
		Assert.notNull(serverCustomizers, "ServerCustomizers must not be null");
		this.serverCustomizers = new LinkedHashSet<>(serverCustomizers);
	}

	/**
	 * Add {@link NettyServerCustomizer}s that should be applied while building the
	 * server.
	 * @param serverCustomizers the customizers to add
	 */
	public void addServerCustomizers(NettyServerCustomizer... serverCustomizers) {
		Assert.notNull(serverCustomizers, "ServerCustomizer must not be null");
		this.serverCustomizers.addAll(Arrays.asList(serverCustomizers));
	}

8、再继续看NettyServerCustomizer 这个接口的实现,可以看到继承了函数,并且入参和出参都是HttpServer,

/**
 * Mapping function that can be used to customize a Reactor Netty server instance.
 *
 * @author Brian Clozel
 * @since 2.1.0
 * @see NettyReactiveWebServerFactory
 */
@FunctionalInterface
public interface NettyServerCustomizer extends Function<HttpServer, HttpServer> {

}

9、再继续看 HttpServer,代码如下,在类里面搜索关键字childOption和tcp,我们很容易定位到以下代码,可以看到注释中其实告诉我们怎么设置childOption了


	/**
	 * Apply a {@link TcpServer} mapping function to update TCP configuration and
	 * return an enriched {@link HttpServer} to use.
	 * <p>
	 * <strong>Note:</strong>
	 * There isn't only one method that replaces this deprecated method.
	 * The configuration that can be done with this deprecated method,
	 * can also be done with the other methods exposed by {@link HttpServer}.
	 * </p>
	 * <p>Examples:</p>
	 * <p>Configuration via the deprecated '.tcpConfiguration(...)' method</p>
	 * <pre>
	 * {@code

	 * HttpServer.tcpConfiguration(tcpServer ->
	 *     tcpServer.attr(...) // configures the channel attributes
	 *              .bindAddress(...) // configures the bind (local) address
	 *              .channelGroup(...) // configures the channel group
	 *              .childAttr(...) // configures the child channel attributes
	 *              .childObserve(...) // configures the child channel connection observer
	 *              .childOption(...) // 	 可用于设置keepalive
	 *              .doOnBound(...) // configures the doOnBound callback
	 *              .doOnChannelInit(...) // configures the channel handler
	 *              .doOnConnection(...) // configures the doOnConnection callback
	 *              .doOnUnbound(...) // configures the doOnUnbound callback
	 *              .handle(...) // configures the I/O handler
	 *              .host(...) // configures the host name
	 *              .metrics(...) // configures the metrics
	 *              .noSSL() // removes SSL configuration
	 *              .observe() // configures the connection observer
	 *              .option(...) // configures the channel options
	 *              .port(...) // configures the port
	 *              .runOn(...) // configures the event loop group
	 *              .secure() // configures the SSL
	 *              .wiretap()) // configures the wire logging
	 * }
	 * </pre>
	 *
	 * <p>Configuration via the other methods exposed by {@link HttpServer}</p>
	 * <pre>
	 * {@code
	 * HttpServer.attr(...) // configures the channel attributes
	 *           .bindAddress(...) // configures the bind (local) address
	 *           .channelGroup(...) // configures the channel group
	 *           .childAttr(...) // configures the child channel attributes
	 *           .childObserve(...) // configures the child channel connection observer
	 *           .childOption(...) // configures the child channel options
	 *           .doOnBound(...) // configures the doOnBound callback
	 *           .doOnChannelInit(...) // configures the channel handler
	 *           .doOnConnection(...) // configures the doOnConnection callback
	 *           .doOnUnbound(...) // configures the doOnUnbound callback
	 *           .handle(...) // configures the I/O handler
	 *           .host(...) // configures the host name
	 *           .metrics(...) // configures the metrics
	 *           .noSSL() // removes SSL configuration
	 *           .observe() // configures the connection observer
	 *           .option(...) // configures the channel options
	 *           .port(...) // configures the port
	 *           .runOn(...) // configures the event loop group
	 *           .secure() // configures the SSL
	 *           .wiretap() // configures the wire logging
	 * }
	 * </pre>
	 *
	 * <p>Wire logging in plain text</p>
	 * <pre>
	 * {@code
	 * HttpServer.wiretap("logger", LogLevel.DEBUG, AdvancedByteBufFormat.TEXTUAL)
	 * }
	 * </pre>
	 *
	 * @param tcpMapper A {@link TcpServer} mapping function to update TCP configuration and
	 * return an enriched {@link HttpServer} to use.
	 * @return a new {@link HttpServer}
	 * @deprecated Use the other methods exposed by {@link HttpServer} to achieve the same configurations.
	 * This method will be removed in version 1.1.0.
	 */
	@Deprecated
	@SuppressWarnings("ReturnValueIgnored")
	public final HttpServer tcpConfiguration(Function<? super TcpServer, ? extends TcpServer> tcpMapper) {
		Objects.requireNonNull(tcpMapper, "tcpMapper");
		HttpServerTcpConfig tcpServer = new HttpServerTcpConfig(this);
		// ReturnValueIgnored is deliberate
		tcpMapper.apply(tcpServer);
		return tcpServer.httpServer;
	}

10、源码观察到这里,那就把写好的类贴在这里,代码如下:

@Component
public class NettyServerChannelOptionCustomization extends ReactiveWebServerFactoryCustomizer {

	public NettyServerChannelOptionCustomization(ServerProperties serverProperties) {
		super(serverProperties);
	}

	@SuppressWarnings("deprecation")
	@Override
	public void customize(ConfigurableReactiveWebServerFactory factory) {
		super.customize(factory);
		NettyReactiveWebServerFactory nettyFactory = (NettyReactiveWebServerFactory) factory;
		nettyFactory.setResourceFactory(null);
		nettyFactory.addServerCustomizers(server -> server
				.tcpConfiguration(tcpServer -> tcpServer.childOption(ChannelOption.SO_KEEPALIVE, true)));
	}
}

11、将上面代码放在网关代码里面重新部署上线,tcp趋势图如下,部署一段时间后,用户访问开始激增,并且随着时间推移,用户访问量减缓后,可以看到tcp回收很明显,有明显的下降趋势
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-05-24 18:32:39  更:2022-05-24 18:33:45 
 
开发: 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:17:56-

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