别再傻傻分不清了!ss和netstat到底有啥区别,看完这篇你就懂了
不知道你们有没有发现有些服务器上用netstat命令特别慢,而用ss命令就很快。刚开始的时候我也是一直用netstat查看网络连接状态,直到有一天发现了ss这个命令。说实话,刚开始我也不太理解为什么要换工具,netstat用得好好的啊。但是随着工作中遇到的场景越来越复杂,特别是在一些高并发的生产环境中,我才真正体会到了两者的差异。
今天就来聊聊这两个命令的区别,以及在实际工作中应该怎么选择使用。
netstat的工作原理
netstat这个命令可以说是网络排查的经典工具了,我记得第一次学Linux的时候,老师就教我们用netstat -an来查看端口监听情况。
netstat的工作原理其实就是读取/proc文件系统中的信息。具体来说,它会读取这些文件:
- /proc/net/tcp:TCP连接信息
- /proc/net/udp:UDP连接信息
- /proc/net/unix:Unix socket信息
- /proc/net/raw:原始socket信息
我之前在一个客户项目中,经常需要查看服务器的连接数,那时候就习惯性地敲netstat -an | grep :80 | wc -l这样的命令。在连接数不多的时候,这个命令执行得还挺快的。
但是问题来了,随着业务量的增长,服务器上的连接数越来越多。有一次活动期间,我照常执行netstat命令查看连接状态,结果等了好几分钟都没出结果。
ss的工作机制
ss命令其实不算特别新了,它在2001年就已经出现了。ss的全称是Socket Statistics,它最大的优势就是直接从内核获取信息,而不是像netstat那样去解析/proc文件系统。
ss使用的是netlink socket与内核通信,这种方式效率更高。netlink是Linux内核提供的一种用户空间与内核空间通信的机制,专门用于获取网络统计信息。
用strace揭秘两者的性能差异
为了更直观地看出两个命令的差异,我用strace来跟踪它们的系统调用。
先看netstat的系统调用:
strace -c netstat -an > /dev/null
输出结果显示netstat主要的系统调用:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 26 read
0.00 0.000000 0 4 write
0.00 0.000000 0 14 close
0.00 0.000000 0 6 fstat
0.00 0.000000 0 17 mmap
0.00 0.000000 0 5 mprotect
0.00 0.000000 0 1 munmap
0.00 0.000000 0 3 brk
0.00 0.000000 0 1 1 ioctl
0.00 0.000000 0 2 pread64
0.00 0.000000 0 2 2 access
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 2 statfs
0.00 0.000000 0 1 arch_prctl
0.00 0.000000 0 1 set_tid_address
0.00 0.000000 0 24 10 openat
0.00 0.000000 0 1 set_robust_list
0.00 0.000000 0 1 prlimit64
0.00 0.000000 0 1 getrandom
0.00 0.000000 0 1 rseq
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 0 114 15 total
可以看到netstat执行了大量的read、openat、close操作,这些都是在读取/proc文件系统。
再看ss的系统调用:
strace -c ss -an > /dev/null
输出结果:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
0.00 0.000000 0 19 read
0.00 0.000000 0 8 write
0.00 0.000000 0 31 close
0.00 0.000000 0 20 fstat
0.00 0.000000 0 79 mmap
0.00 0.000000 0 19 mprotect
0.00 0.000000 0 2 munmap
0.00 0.000000 0 3 brk
0.00 0.000000 0 2 2 ioctl
0.00 0.000000 0 2 pread64
0.00 0.000000 0 2 2 access
0.00 0.000000 0 12 socket
0.00 0.000000 0 6 sendto
0.00 0.000000 0 11 sendmsg
0.00 0.000000 0 60 recvmsg
0.00 0.000000 0 12 bind
0.00 0.000000 0 12 getsockname
0.00 0.000000 0 36 setsockopt
0.00 0.000000 0 1 execve
0.00 0.000000 0 2 2 statfs
0.00 0.000000 0 6 4 prctl
0.00 0.000000 0 1 arch_prctl
0.00 0.000000 0 1 set_tid_address
0.00 0.000000 0 19 openat
0.00 0.000000 0 1 set_robust_list
0.00 0.000000 0 1 prlimit64
0.00 0.000000 0 1 getrandom
0.00 0.000000 0 1 rseq
------ ----------- ----------- --------- --------- ----------------
100.00 0.000000 0 370 10 total
ss的系统调用明显少很多,主要是socket、sendto、recvmsg这些网络相关的调用,这就是netlink通信的特征。
具体使用场景对比
查看监听端口
netstat方式:
netstat -tlnp
ss方式:
ss -tlnp
两者输出格式基本相同,但ss速度更快。
查看特定端口连接
netstat方式:
netstat -an | grep :80
ss方式:
ss -an sport = :80
# 或者
ss -an dport = :80
ss的过滤语法更强大,可以直接在命令中指定条件,不需要管道给grep。
统计连接状态
netstat方式:
netstat -an | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
ss方式:
ss -s
ss直接提供了统计功能,不需要额外的文本处理。
高级过滤功能
ss的过滤功能确实比netstat强大很多。比如我想查看所有连接到特定IP的连接:
ss -an dst 192.168.1.100
或者查看特定状态的连接:
ss -an state established
ss -an state time-wait
还可以组合多个条件:
ss -an state established dst 192.168.1.0/24
这些功能用netstat实现的话,就得写很复杂的grep和awk命令了。
内存使用对比
除了执行速度,内存使用也是一个重要指标。我用valgrind测试了两个命令的内存使用情况:
netstat在处理大量连接时,内存使用会线性增长,因为它需要将所有/proc文件内容读入内存再处理。
ss的内存使用相对稳定,因为它是流式处理netlink消息,不需要一次性加载所有数据。
在连接数达到10万级别时,netstat可能会消耗几百MB内存,而ss只需要几MB。
实际生产环境的选择
在日常工作中,我现在基本上都用ss了。特别是在写监控脚本的时候:
#!/bin/bash
# 监控TCP连接数
ESTABLISHED=$(ss -an state established | wc -l)
TIME_WAIT=$(ss -an state time-wait | wc -l)
echo "ESTABLISHED: $ESTABLISHED"
echo "TIME_WAIT: $TIME_WAIT"
这种脚本如果用netstat的话,在高并发环境下可能会因为执行时间过长而影响监控的实时性。
但是有些时候,我还是会用netstat。比如在一些比较老的系统上,可能ss的版本比较老,功能不够完善。还有就是查看路由表信息,ss是没有这个功能的:
netstat -rn # 查看路由表
输出格式差异
两个命令的输出格式略有不同。netstat的输出比较传统:
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
ss的输出信息更丰富:
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
ss还会显示一些额外的信息,比如拥塞窗口大小、重传次数等,这些对网络调优很有用。
兼容性考虑
从兼容性角度来说,netstat几乎在所有的Linux发行版中都有。ss虽然也很普及,但在一些比较老的系统中可能版本较旧。
我之前遇到过一个情况,在CentOS 6的系统上,ss命令的过滤功能就比较有限,很多高级特性都不支持。这时候还是得回到netstat。
不过现在大部分的生产环境都是比较新的系统,ss的兼容性问题基本不用担心。
脚本中的最佳实践
在写自动化脚本时,我建议优先使用ss,并且要考虑兼容性:
#!/bin/bash
# 检查命令是否存在
if command -v ss >/dev/null 2>&1; then
CONN_COUNT=$(ss -an state established | wc -l)
elif command -v netstat >/dev/null 2>&1; then
CONN_COUNT=$(netstat -an | grep ESTABLISHED | wc -l)
else
echo "Neither ss nor netstat found"
exit 1
fi
echo "Established connections: $CONN_COUNT"
这样既能利用ss的性能优势,又能保证在老系统上的兼容性。
写在最后
从netstat到ss的转变,其实也反映了Linux系统工具的发展趋势。新的工具往往在性能和功能上都有所改进,但老工具也有它存在的价值和适用场景。
通过strace的分析,我们可以清楚地看到两个命令在实现机制上的根本差异。netstat通过文件系统接口获取信息,而ss直接与内核通信,这就决定了它们在性能上的差异。
作为运维人员,我们需要与时俱进,学习新的工具和技术,但也不能完全抛弃传统的工具。关键是要理解每个工具的特点和适用场景,然后在实际工作中做出合适的选择。
在高并发、大连接数的环境中,ss明显是更好的选择。但在一些特殊场景下,netstat仍然有它的用武之地。掌握了两个命令的特点,在不同场景下灵活选择,才能更高效地完成工作。
如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!
公众号:运维躬行录
个人博客:躬行笔记