应避免直接用ssh批量执行top、free、df、ss等命令:top依赖tty易卡住,df不加-p导致字段错位,ss缺-s无汇总;推荐用ps aux替代top、free -b统一单位、df -p过滤虚拟文件系统、/proc/net/sockstat替代ss,并用threadpoolexecutor并发采集,统一返回结构化字典。

用 ssh 批量执行 top、free、df、ss 会丢数据
直接在远程节点上跑 top -bn1 或 free -h 看起来简单,但实际采集时容易出问题:比如 top 默认依赖 TTY,非交互式 SSH 下可能卡住或返回空;df 不加 -P 会导致字段错位,解析失败;ss 统计连接数时没加 -s 就只输出连接列表,不带汇总。这些命令本身不是为自动化设计的,硬套会埋坑。
实操建议:
- 用
ps aux --sort=-%cpu | head -n 6替代top,避免 TTY 依赖,且字段稳定 -
free -b(不用-h)保证数值单位统一为字节,便于后续计算使用率 -
df -P -x tmpfs -x devtmpfs排除虚拟文件系统,只采真实磁盘,-P强制 POSIX 输出格式 - 网络指标优先用
cat /proc/net/sockstat拿 TCP/UDP 套接字总数,比ss更轻量、更可靠
Python 脚本里怎么并发采集并防止单点失败拖垮全部
用 paramiko 串行连 50 台机器,一台超时就卡住整个流程;用 asyncio + asyncssh 虽快,但异常处理复杂,出错后连接状态难清理。折中方案是用 concurrent.futures.ThreadPoolExecutor 控制并发数(如 10),每台机器独立超时、独立重试。
关键细节:
- 每个线程内必须设
socket.setdefaulttimeout(10),否则paramiko默认无超时,卡死风险高 - 捕获
paramiko.SSHException和socket.timeout,失败后记录 IP 和错误类型,不抛出异常中断主线程 - 命令拼接用
shlex.quote()包裹变量,防止节点路径含空格或特殊字符导致执行失败 - 结果统一用字典结构返回:
{"ip": "10.0.1.5", "cpu": 23.4, "mem_used_pct": 67.2, "disk_root_used_pct": 81.0, "tcp_sockets": 1245}
磁盘使用率怎么避开 /dev/mapper、LVM 伪设备干扰
df 默认会列出所有挂载点,包括 LVM 的 /dev/mapper/vg-lv、加密卷、bind mount,这些不是物理磁盘,但占着行、干扰阈值判断。巡检真正关心的是根分区、/var、/data 这类业务挂载点。
安全做法:
- 先用
findmnt -D -n -o SOURCE,TARGET获取“设备→挂载点”映射,过滤掉 SOURCE 以/dev/mapper/、/dev/loop开头的条目 - 再对剩余挂载点逐个跑
df -P <mountpoint></mountpoint>,确保只统计真实存储位置 - 特别注意容器环境:如果节点跑 Docker,
/var/lib/docker下的 overlay2 子目录不能被当成独立磁盘,要合并到宿主机/var分区一起看
网络指标选 netstat 还是 /proc/net/snmp?
netstat 已被标记为废弃,很多新系统默认不装;ss 虽快但输出不规整,不同内核版本字段顺序可能变。最稳的是直接读内核接口:/proc/net/snmp 提供标准 TCP、UDP 统计,/proc/net/dev 提供网卡收发字节数——这两者无依赖、无格式漂移、开销极低。
常用字段对应关系:
- TCP 当前连接数 →
grep "Tcp:" /proc/net/snmp | awk '{print $14}'(Currestab) - 网卡入流量(字节)→
awk '/eth0:/ {print $2}' /proc/net/dev(注意冒号后有空格) - UDP 入包错误数 →
grep "Udp:" /proc/net/snmp | awk '{print $5}'(InErrors) - 所有指标采集应在同一秒内完成,避免跨秒统计造成速率计算偏差
真正难的不是拿到数字,而是让 100 台异构节点(CentOS 7、Rocky 8、Ubuntu 22.04、还有几台老 AIX)返回结构一致、单位统一、异常可定位的结果。别省那几行预检逻辑——比如先跑 uname -s 判断系统类型,再决定用 df 还是 zfs list,比事后写一堆 if-else 修数据强得多。











