网络端口占用问题的综合调研与解决方案

news2024/12/24 11:31:33

原创 Randy 拍码场

问题背景

去年底信息安全团队进行网络权限治理,要求所有应用实例使用静态IP,公网访问策略与静态IP绑定;之后实例重启时偶现端口被占用错误。通过分析总结应用日志,共有以下4种错误类型,实质都是端口被占用。

// Netty框架Caused by: java.net.BindException: Address already in use

// JettyFailed to start jetty server at port 8080, cause: Address already in use

// Embedded TomcatEmbedded servlet container failed to start. Port 8080 was already in use.

// TomcatThe Tomcat connector configured to listen on port 8080 failed to start. The port ay already be in use or the connector may be misconfigured.

原因分析

学过计算机网络的同学应该知道,网络连接的建立需要通过调用操作系统内核函数来实现;查询linux的官方文档,确定端口被占用的校验发生在系统调用bind()阶段。

端口被占用原因

TCP/IP连接断开后,进入TIME_WAIT状态,等待2MSL(Maximum Segment Lifetime)时间后才会释放网络资源,在此过程中重新打开相同端口会报:bind: address already in use错误。

为什么需要等待2MSL时间

1.可靠的实现TCP全双工连接终止,正确处理关闭连接的四次握手。

2.确保迷路的数据包在网络中消失,防止上一次连接中的包影响新连接(数据包及应答均被丢弃。

不同操作系统中MSL默认值

Windows: 120s

Linux(centos, ubuntu): 60s

Unix: 30s

为什么治理前未发生问题

在采用动态IP时,实例每次重启都会从IP池中选取一个未被使用的IP,新建socketIP与之前socketIP不同,属于不同的连接,因此不会报错。

linux源码分析

由于不能使用动态IP,为了寻找解决方案,在对端口被占用逻辑有了大致了解后,我们进一步研读源代码了解端口被占用的详细判断逻辑。

//  系统调用bind()对应的入口函数是__sys_bind()//  端口被占用判断逻辑是inet_bind_conflict函数

static bool inet_bind_conflict(const struct sock *sk, struct sock *sk2,                            kuid_t sk_uid, bool relax,                        bool reuseport_cb_ok, bool reuseport_ok){  int bound_dev_if2;

       if (sk == sk2)           return false;

       bound_dev_if2 = READ_ONCE(sk2->sk_bound_dev_if);

       if (!sk->sk_bound_dev_if || !bound_dev_if2 ||         sk->sk_bound_dev_if == bound_dev_if2) {              if (sk->sk_reuse && sk2->sk_reuse &&             sk2->sk_state != TCP_LISTEN) {                if (!relax || (!reuseport_ok && sk->sk_reuseport &&                                   sk2->sk_reuseport && reuseport_cb_ok &&                                 (sk2->sk_state == TCP_TIME_WAIT ||                            uid_eq(sk_uid, sock_i_uid(sk2)))))                       return true;         } else if (!reuseport_ok || !sk->sk_reuseport ||                      !sk2->sk_reuseport || !reuseport_cb_ok ||                        (sk2->sk_state != TCP_TIME_WAIT &&                       !uid_eq(sk_uid, sock_i_uid(sk2)))) {                  return true;         }     }     return false;}

可以看到判断端口占用逻辑用到如下字段:

// 端口被占用判断字段sk_bound_dev_if --> 网卡编号sk_reuse --> 套接字复用sk_reuseport --> 端口复用sk_state --> 当前状态listen还是time_waitsk_uid socket --> 所属用户IDreuseport_cb_ok --> 内核是否支持端口复用

这些字段中网卡编号、用户ID、内核是否支持端口复用均无法修改,能够调整的参数是端口复用和超时时间。

解决方案

鉴于公司所有应用都绑定了静态IP,应用重启时创建的socket与上一个socket必定是同一个应用,此时开启端口复用,不会出现超时报文被其他应用接收的情况,因此开启端口复用(sk_reuseport)是比较合理解决方式。

端口复用开启方式

开启端口复用主要有两种方式:

1. 应用级别:每个业务项目在启动时自行开启端口复用,由于需要修改业务代码,并且不同框架实现方式不同,推广难度大

2. 操作系统层次:直接修改系统内核的net.ipv4.tcp_tw_reuse=1

其中第2种方式对用户无感,便于集中处理,因此我们对第2种方式进行验证。

NodePod系统参数相互隔离

在我们研究如何修改tcp_tw_reuse时,发现Node节点的端口复用开关是开启状态,但是运行在上面的Pod中的端口复用开关却是关闭的,而应用容器使用的端口复用状态是Pod中的值,此时问题变成了如何开启pod中的端口复用开关。

Node上的端口复用开启

Pod中的端口复用关闭

开启Pod中的端口复用

默认情况Pod是无法修改内核相关配置的,经过调研得知Pod需要获取系统级权限(securityContext.privileged=true)才能修改内核参数,但是次权限太大存在安全风险,如果直接在应用容器开通此权限可能影响宿主机的稳定性;最终我们决定增加一个init容器,当系统参数修改成功后再退出,这样既能有足够权限修改内核参数,又不扩大业务容器的权限。测试实例如下:

# 增加一个busybox的init容器,修改完端口复用开关后退出

apiVersion: apps/v1kind: Deploymentmetadata:  name: my-deploymentspec:  replicas: 2  selector:   matchLabels:      app: my-app  template:    metadata:      labels:        app: my-app    spec:      containers:      - name: my-container        image: nginx      initContainers:      - name: sysctl-modifier        image: busybox        securityContext:          privileged: true        command: ["sysctl -w net.ipv4.tcp_tw_reuse=1 && exit"]

使用kubectl部署yaml文件之后,使用kubectl exec -it进入Pod,可以看到pod中的端口被占用功能已经开启。

参考文档

linux源码 https://github.com/torvalds/linux

linux man手册:https://www.man7.org/linux/man-pages/man2/bind.2.html

作者介绍

Randy,现任技术架构资深专家

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1665784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WAAP全站防护理念,发现和保护敏感数据

数据是现代企业的新石油:正确使用它可以促进公司的发展并帮助企业在竞争中领先。就像石油一样,原始数据和未被发现的数据是毫无用处的,企业将无法从中受益;在最坏的情况下,它可能会导致安全事件。这也是企业投资敏感数…

MySQL数据库的初始化(创建库、创建表、向数据库添加测试数据)

MySQL数据库的初始化(创建库、创建表、向数据库添加测试数据) MySQL数据库简介MySQL创建一个新的数据库MySQL创建一张新的数据表简单(设置)表复杂(设置)表 填充测试数据SQL语句mysql>模式下输入的每句sq…

Spring Cloud | “微服务“ 架构 与 Spring Cloud

“微服务” 架构 与 Spring Cloud 目录: "微服务" 架构 与 Spring Cloud1. 认识架构"单体" 架构"SOA" 架构"微服务" 架构 2. "微服务架构" 的功能 :① 微服务架构的 "自动化部署"② 服务 "集中化管理"③…

PostgreSQL的学习心得和知识总结(一百四十三)|深入理解PostgreSQL数据库之Support event trigger for logoff

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《PostgreSQL数据库内核分析》 2、参考书籍:《数据库事务处理的艺术:事务管理与并发控制》 3、PostgreSQL数据库仓库…

转载:ubuntu18.04 安装wine以及添加mono和gecko打开简单.net应用的方法

https://www.cnblogs.com/jinanxiaolaohu/p/12191576.html 1. 今天突然想试试能不能用ubuntu跑一下公司的.net的智能客户端(SmartClient). 想到的办法就是 安装wine 但是过程略坑..这里简单说一下总结之后的过程. 2. 第一步安装wine相关内容 查了下有winehq和wine两种. …

凸优化理论学习二|凸函数及其相关概念

系列文章目录 凸优化理论学习一|最优化及凸集的基本概念 文章目录 系列文章目录一、凸函数(一)凸集(二)凸函数的定义及举例(三)凸函数的证明1、将凸函数限制在一条直线上2、判断函数是否为凸函数的一阶条件…

iphone进入恢复模式怎么退出?分享2种退出办法!

iPhone手机莫名其妙的进入到了恢复模式,或者是某些原因需要手机进入恢复模式,但是之后我们不知道如何退出恢复模式怎么办? 通常iPhone进入恢复模式的常见原因主要是软件问题、系统升级失败、误操作问题等导致。那iphone进入恢复模式怎么退出&…

【工具篇】-什么是.NET

“.NET":.NET Core是由Microsoft开发,目前在.NET Foundation(一个非营利的开源组织)下进行管理。.NET Core是用C#和C编写的,并采用MIT协议作为开源协议。 简单来说:就是开发框架。 .NET 又称 .NET 平台或 .NET 框架&#xf…

Centos 7.9 安装 tigervnc-server

环境:当前使用的 Centos 7.9 的光盘作为的本地源。 1 检查是否已安装 tigervnc [rootlocalhost /]# rpm -q tigervnc tigervnc-server 未安装软件包 tigervnc tigervnc-server-1.8.0-21.el7.x86_64 如果安装过卸掉 卸载: rpm -e [rootlocalhost /]# rpm -e tige…

Django项目运行报错:ModuleNotFoundError: No module named ‘MySQLdb‘

解决方法: 在__init__.py文件下,新增下面这段代码 import pymysql pymysql.install_as_MySQLdb() 注意:确保你的 python 有下载 pymysql 库,没有的话可以使用 pip install pymysql安装 原理:用pymysql来代替mysqlL…

【Qt 学习笔记】Qt常用控件 | 容器类控件 | Group Box的使用及说明

博客主页:Duck Bro 博客主页系列专栏:Qt 专栏关注博主,后期持续更新系列文章如果有错误感谢请大家批评指出,及时修改感谢大家点赞👍收藏⭐评论✍ Qt常用控件 | 容器类控件 | Group Box的使用及说明 文章编号&#xff…

力扣例题(用栈实现队列)

目录 链接. - 力扣(LeetCode) 描述 思路 push pop peek empty 代码 链接. - 力扣(LeetCode) 描述 思路 push 例如我们将10个元素放入栈中,假设最左边为栈顶,最右侧为栈底 则为10,9,8,7,6,5,4,3,…

JavaScript之数据类型(3)——object进阶

前言&#xff1a; 利用基础知识来构建对象会发现十分复杂&#xff0c;我们可以结合其他的知识点来为我们object的构建进行优化。 <1>工厂法&#xff1a; 基本格式&#xff1a; function creatObject(属性值1,属性值2,属性值3,...,属性值n) {var 对象名 new Object();对…

VR全景技术在养老院的应用优势浅析

随着时代的快速发展&#xff0c;人口老龄化越来越严重&#xff0c;如何利用VR技术提升养老服务的质量&#xff0c;成为了社会各界关注的焦点。为养老院拍摄制作VR全景&#xff0c;不仅能够为养老院的老人子女们跨越空间限制&#xff0c;实现与家人的情感连接&#xff0c;还可以…

Debian安装Redis、RabbitMQ、Nacos

安装Redis&#xff1a; 启动Redis、开机自启动 sudo systemctl start redis-server #启动sudo systemctl enable redis-server #开机自启 Redis状态(是否在运行) sudo systemctl status redis-server #查看运行状态 redis-cli ping # 客户端尝试连接 安装RabbitMQ&#xff0c;…

Zynq开发-使用PYNQ快速入门摄像头MIPI驱动(OV5640)

目录 1. 简介 2. 配置代码 2.1 初始化寄存器 2.2 分辨率寄存器 2.3 白平衡寄存器 2.4 配置寄存器代码 2.5 顶层代码 3. 细节指引 4. 总结 1. 简介 PYNQ是一种基于Python的开发环境&#xff0c;专门设计用于快速、简便地在Xilinx的Zynq平台上进行开发。在《Zynq开发之…

STM32睡眠模式

文章目录 前言PWR介绍电源框图上电复位和掉电复位可编程电压检测器低功耗模式模式选择电源控制寄存器 睡眠模式停止模式待机模式 前言 在单片机产品中&#xff0c;例如遥控这类产品&#xff0c;长时间处于待机状态下&#xff0c;所以对于这类产品在待机时就应该尽可能的减少不…

您的文件和驱动器上的“密码保护”有多安全?

某些行业&#xff08;例如医疗保健、法律和公司&#xff09;的人们在通过电子邮件发送文件时通常依赖密码保护&#xff0c;认为它可以提供足够的安全性来防止窥探。然而&#xff0c;对 PDF 或 Excel 文件进行简单的密码保护并不像看起来那样万无一失。 使用密码保护文件而不加…

01.Net基础知识

.Net的用途 Web、移动、云、桌面、游戏开发、物联网 &#xff08;IDE&#xff1a;集成开发环境&#xff09; .Net学习资源 Microsoft Learn、GitHub、G码云&#xff08;Gitee&#xff09; Visual Studio初步使用 1&#xff09;可创建的项目种类&#xff08;主要学习以下四…

前后端完全开源!功能丰富的在线教室项目:Agora Flat

Agora Flat&#xff1a;高效集成的在线教室解决方案&#xff0c;重塑互动学习新体验。- 精选真开源&#xff0c;释放新价值。 概览 Agora Flat是在GitHub平台上公开分享的一个全面开源项目&#xff0c;它精心设计为一个高性能的在线教室解决方案&#xff0c;旨在便捷地搭建支持…