Linux中停服导致问题的思考

Linux中停服导致问题的思考

引言

某个后端java服务程序监控听18090端口,同时程序中又启动12020, 13020两个socket tcp server端口,监听socket连接。

在某次更新服务过程中,是这样操作的:先kill -9 pid,然后java -jar xxx.jar。通过netstat -nltpu 查看服务启动情况,发现18090端口处于监控状态,而12020, 13020这两个端口却始终没有处于监听状态。

可能原因总结

SELinux

SELinux可能会阻止某些端口的监听。如果SELinux的策略不允许的应用程序绑定到12020, 13020端口,那么即使应用程序尝试启动,这些端口也不会被监听。可以查看SELinux的日志(通常位于/var/log/audit/audit.log),以确定是否有SELinux拒绝的记录。如果SELinux是原因,可以使用semanage命令调整策略,或者临时通过设置SELinux为宽容模式来测试是否是SELinux导致的问题:

shell 复制代码
setenforce 0

防火墙

系统的防火墙可能会阻止外部访问某些端口。可以使用firewall-cmd命令检查端口是否在防火墙中放行

java 复制代码
firewall-cmd --query-port=12020/tcp
firewall-cmd --query-port=13020/tcp

如果端口没有放行,需要添加规则来允许这些端口的流量:

shell 复制代码
irewall-cmd --zone=public --add-port=12020/tcp --permanent
firewall-cmd --zone=public --add-port=13020/tcp --permanent
firewall-cmd --reload

网络配置问题

如果在云环境中部署应用程序,可能需要检查网络安全组规则是否允许访问12020和13020端口。

应用程序启动问题

应用程序可能在启动时没有正确配置,或则各服务启动依赖于特定顺序,导致初始化12020和13020端口的监听服务未成功启动。检查应用程序的配置文件和启动日志,检查应用程序的启动逻辑,确认是否有关于端口监听的错误或警告信息。

端口已占用

应用程序可能未能成功绑定到12020和13020端口。这可能是由于端口已经被其他进程占用,或者应用程序内部的绑定逻辑存在问题。可以使用netstat -tulnp或ss -tulnp命令来查看所有监听的端口及其关联的进程信息,确认是否有进程绑定到12020和13020端口。

结合可能原因分析本问题

由于服务在原来都能正常启动和运行,且服务器相关配置没有修改过。所以大概率可以排除是selinux,防火墙和网络三方面的问题(事实上,selinux已经设置为宽松模式且防火墙也关闭了)。同时原来服务正常启动,且此次更新没有修改启动socket服务这里的代码,大概率也不是这里的问题。同时在日志中也没有发现什么错误日志。最后只剩下端口占用。

分析问题出现的过程

使用脚本重启服务,脚本中首先查询java进程pid。

shell 复制代码
kill -9 pid
nohup java -jar xxx.jar >/dev/null 2>&1

杀掉进程,然后立刻启动服务。kill -9 是一个"强制终止"信号,发送的是 SIGKILL 信号,用于立即终止进程。这是一个较为粗暴的信号,它不会给进程清理资源的机会,包括网络连接和文件描述符。在TCP协议中,正常的连接终止需要四次挥手(四次握手),而 kill -9 导致进程突然终止,可能会导致TCP连接处于 TIME_WAIT 状态,这是一种等待状态,用于确保所有数据包都被接收,防止新连接被旧连接的数据干扰。

kill -9 之后立刻启动服务,这可能导致程序结束后,12020 和13020两个端口还没有被成功回收,新的程序就启动。导致新的程序为能成功绑定这两个端口。原来是通过手动kill -9 pid之后,在手动输入nohup java -jar xxx.jar >/dev/null 2>&1命令启动程序。这之间的时间间隔有大概4-5秒。因而可以正常启动。此次改用shell脚本重启服务,两条指令间的时间间隔极短,导致了此次问题。按照这个思路,问题也得以复现。

问题的解决

在进程结束和服务启动之间添加时间间隔,此后服务正常重启。

shell 复制代码
kill -9 pid
sleep 5
nohup java -jar xxx.jar >/dev/null 2>&1

相关知识

kill -SIGTERM PID 和 kill -9 PID 都用于终止进程,但它们之间有几个关键的区别

信号类型

  • kill -SIGTERM PID 发送的是 SIGTERM(信号编号15),这是一个"终止"信号,它请求进程自行终止。这是一个较为温和的信号,进程接收到 SIGTERM 后,操作系统会允许进程捕获这个信号并进行清理操作,比如关闭文件描述符、释放资源等,然后优雅地退出。
  • kill -9 PID 发送的是 SIGKILL(信号编号9),这是一个"强制终止"信号,用于立即终止进程,不给进程任何清理或保存状态的机会。这是一个较为粗暴的信号,进程无法捕获或忽略 SIGKILL。

默认行为

  • kill PID 默认发送 SIGTERM信号,所以 kill -SIGTERM PID 和 kill PID 实际上是一样的。
  • kill -9 PID 是发送 SIGKILL 的另一种写法,通常用于当进程不响SIGTERM 信号时。

安全性和数据完整性

  • 使用 SIGTERM 可以减少数据丢失或损坏的风险,因为它允许进程保存状态和清理资源。
  • 使用 SIGKILL 可能会导致数据丢失,因为它不允许进程进行任何清理。

使用场景

  • 通常建议首先使用 kill -SIGTERM PID(kill PID),因为它允许进程有机会进行清理和优雅地退出。
  • 如果进程不响应 SIGTERM,或者需要立即终止进程以避免潜在的数据损坏或安全问题,那么可以使用 kill -9 PID。
  • 总的来说,kill -SIGTERM PID 是一个更安全、更优雅的终止进程的方式,而 kill -9 PID 则是一种紧急情况下使用的强制手段。在可能的情况下,应优先考虑使用 SIGTERM。

愿你我都能在各自的领域里不断成长,勇敢追求梦想,同时也保持对世界的好奇与善意。

相关推荐
开航母的李大4 分钟前
软件系统运维常见问题
运维·服务器·系统架构·运维开发
xcya5 分钟前
Java ReentrantLock 核心用法
后端
用户4665370150518 分钟前
如何在 IntelliJ IDEA 中可视化压缩提交到生产分支
后端·github
小楓120124 分钟前
MySQL數據庫開發教學(一) 基本架構
数据库·后端·mysql
天天摸鱼的java工程师26 分钟前
Java 解析 JSON 文件:八年老开发的实战总结(从业务到代码)
java·后端·面试
白仑色27 分钟前
Spring Boot 全局异常处理
java·spring boot·后端·全局异常处理·统一返回格式
之诺33 分钟前
MySQL通信过程字符集转换
后端·mysql
喵手33 分钟前
反射机制:你真的了解它的“能力”吗?
java·后端·java ee
用户4665370150534 分钟前
git代码压缩合并
后端·github
武大打工仔38 分钟前
从零开始手搓一个MVC框架
后端