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。

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

相关推荐
Asthenia04126 小时前
Spring AOP 和 Aware:在Bean实例化后-调用BeanPostProcessor开始工作!在初始化方法执行之前!
后端
Asthenia04127 小时前
什么是消除直接左递归 - 编译原理解析
后端
Asthenia04127 小时前
什么是自上而下分析 - 编译原理剖析
后端
Asthenia04128 小时前
什么是语法分析 - 编译原理基础
后端
Asthenia04128 小时前
理解词法分析与LEX:编译器的守门人
后端
uhakadotcom8 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
Asthenia04129 小时前
Spring扩展点与工具类获取容器Bean-基于ApplicationContextAware实现非IOC容器中调用IOC的Bean
后端
bobz9659 小时前
ovs patch port 对比 veth pair
后端
Asthenia04129 小时前
Java受检异常与非受检异常分析
后端