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 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 记time_wait状态引起的端口占用排查 -> 正文阅读

[系统运维]记time_wait状态引起的端口占用排查


0. 问题背景

在Liunx服务器上发现有 10倍于 LISTEN 服务的 time_wait 状态,服务并非高并发,日常的连接数也比较少,因此该现象明显异常
服务器time_wait状态

1. 问题定位

time_wait状态

回顾下 time_wait 状态处于 TCP 通信的哪个阶段:

在TCP四次挥手过程中,主动断开连接的一方会在发送完最后一个 ACK 包后,等待 2MSL(Maximum Segment Lifetime)的时间,这个阶段就处于 time_wait 状态
time_wait 状态是为了确保,当被动断开连接的一方没有收到最后一个 ACK 包时,会再次发送 FIN 包,如果此时已经建立了新连接,可能被该 FIN 包影响从而导致连接终止

一般在高并发、短连接(单个连接时长超过time_wait时间)的服务端容易出现大量time_wait并存的情况,但在此服务器应不存在

确认原因

首先查看服务器 2MSL 的设置,是正常范围
在这里插入图片描述
同时发现在 LISTEN 端口上同时存在多个处于 time_wait 状态的本机端口,此时确认应该是另一个本机的扫描程序导致的

2. 解决过程

长连接探测

因为此情况下,TCP 连接的两方都在同一台机器上,无法规避 time_wait 状态的存在,因此首先将探测程序改为长连接

这是之前的探测连接代码

// TCP连接端口
func Ping(host string, timeout int) bool {
	_timeout := time.Duration(timeout) * time.Millisecond
	if conn, err := net.DialTimeout("tcp", host, _timeout); err != nil {
		return false
	} else {
		conn.Close()
		return true
	}
}

修改后选择 HTTP 长连接的方式,这样可以最大程度规避 time_wait 状态
唯一需要注意的是,HTTP 长连接如果想要复用上一次的连接,哪怕不需要读取数据,也需要调用 ioutil.ReadAll(resp.Body)清空buffer里的数据,否则该连接不会被复用

p := net.TCPAddr{IP: net.ParseIP(addr), Port: port}
// 通过Transport设置最大连接、timeout、
client = &http.Client{
	Transport: &http.Transport{
		DialContext: (&net.Dialer{
			Timeout:   timeout,                                      // transport timeout
			KeepAlive: time.Duration(IdleConnTimeout) * time.Second,
			LocalAddr: &p,
		}).DialContext,
		IdleConnTimeout:       time.Duration(IdleConnTimeout) * time.Second,
		ResponseHeaderTimeout: timeout,
	},
	Timeout: timeout,
}
if req, err := http.NewRequest("POST", addr, nil); err == nil {
	// 创建请求
	q := req.URL.Query()
	req.URL.RawQuery = q.Encode()
	// 进行请求
	if resp, err := client.Do(req); err == nil {
		_, e := ioutil.ReadAll(resp.Body) // 必须读取response后才能复用连接
		if err = resp.Body.Close(); err != nil {
			log.Info("resp body close err: ", err, " ", e)
		}
	}
}

(PS:这里直接用 TCP 连接也可达到同样效果)

而且上述探测功能会固定占用和 LISTEN 端口一样数量的端口,如果和动态分配范围内的端口重合会存在问题
查看机器上动态分配端口的范围:一般为32768-61000
在这里插入图片描述
所以额外在 Transport 里指定了 LocalAddr,这一步可以绑定固定的端口,将探测端口绑定到61000以上,可以避免端口冲突的问题

预留端口

如果 time_wait 状态过多影响剩余端口的分配,可以设置预留端口,来保证time_wait状态不会影响其他功能的使用
Linux 的 net.ipv4.ip_local_port_range参数可以规划出一段端口段预留作为服务端口,可以将服务监听的端口以逗号分隔全部添加到ip_local_reserved_ports中,或直接设置一个端口范围段

这样当 Linux 调用 bind(0) 或者 connect 从ip_local_port_range(前面说的32768-61000)中随机选取源端口时,会排除ip_local_reserved_ports中定义的端口,因此就不会出现端口被占用了服务无法启动

vim /etc/sysctl.conf

# 加入下面这行
# net.ipv4.ip_local_reserved_ports=42310,51000-52000

sysctl -p

SO_REUSEADDR和SO_REUSEPORT

关于这两个参数的概念理解并不是本篇的重点,大家可以参考SO_REUSEADDR和SO_REUSEPORT作用这篇博文的解释

对于time_wait状态较多,但又无法解决的情况下(比如就是需要服务端主动断开连接or服务端还需要请求下游),可以通过设置 SO_REUSEADDR和SO_REUSEPORT 参数,让 time_wait 状态不要影响正常的服务

可以通过以下方式来进行设置:
(Golang版本可以用syscall来调用系统方法设置,其他语言也有类似方法可以设置)

		import (
			"syscall"
			"golang.org/x/sys/unix"
		)

		if fd, err := syscall.Socket(syscall.AF_INET, syscall.O_NONBLOCK|syscall.SOCK_STREAM, 0); err == nil && port > 0 {
			syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1) // 设置复用端口
			syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
			addr := syscall.SockaddrInet4{Port: port}
			copy(addr.Addr[:], net.ParseIP("0.0.0.0").To4())
			syscall.Bind(fd, &addr)
		}

以上是本篇文章的全部内容,下一篇会总结当服务端口频繁被其他随机分配端口占用的情况下,可以如何通过 Golang或其他代码来解决

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-10-17 13:11:56  更:2022-10-17 13:16:02 
 
开发: 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年12日历 -2024/12/28 3:26:51-

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