香港VPS的磁盘I/O超售有一个很讨厌的特点:它不像CPU steal那样有一列数字直接摆在那里让你看。CPU被偷了时间片,top里%st一栏清清楚楚;但磁盘被邻居抢了带宽,你看到的只是“数据库查询变慢了”“写入卡了一下”“SSH敲命令要等半秒才回显”。这些体感很难量化,也容易被误判成“机器配置不够”或者“网络延迟”。实际上,香港VPS的磁盘I/O是超售最隐蔽、也最普遍的重灾区,因为存储层的资源隔离比CPU和内存更难做,成本也更高。下面从现象识别到量化测试,给出一套能在十分钟内跑完的判断流程。
先分清是磁盘慢还是别的慢
磁盘I/O被超售的典型症状,和CPU超售、网络拥堵有重叠但不完全一样。一个实用的区分方法是看命令的卡顿发生在哪个阶段。
如果ls、cat这类纯读操作很快,但一旦涉及写文件——比如echo test > /tmp/test要顿一下、systemctl restart nginx的日志写入明显延迟、MySQL的INSERT比平时慢好几倍——那嫌疑就落在写入路径上。反过来,如果SSH登录本身都卡,top显示%st持续高于5%,那问题在CPU,磁盘可能只是被连带影响。
另一个容易混淆的是内存不足触发的swap。free -h看一眼swap使用量,如果swap被大量占用,磁盘I/O的繁忙来自系统自己在换页,和超售无关。排除掉CPU steal和swap之后,再往下查磁盘。
用iostat看“等待”,而不是看“繁忙”
很多教程会告诉你iostat的%util超过80%就是磁盘饱和。这个说法在SSD和共享存储环境下已经不太可靠了。%util的算法源自机械硬盘时代的串行模型,对于能并行处理I/O的SSD和RAID,%util跑到100%并不一定意味着你拿不到I/O带宽——它只说明设备“有事情在做”,但可能同时在做很多件事。
真正值得盯的是await列。await是每个I/O请求从发出到完成的平均等待时间,单位毫秒。这个数字包含了排队时间和服务时间。对于一台正常的香港VPS,SSD存储的await在空闲或轻负载时应该在个位数毫秒,超过20ms就说明存储层已经有排队压力了。如果await在几十到几百毫秒之间剧烈跳动,而你自己并没有跑任何重I/O任务,那基本可以判定有邻居在抢同一块物理磁盘的带宽。
运行方式:
iostat -x 2 30
-x输出扩展统计,2表示每2秒采样一次,30表示共采样30次(约一分钟)。跑完之后看await和%util两列的分布,而不是只看最后一个值。超售节点上的I/O性能方差往往比均值更能说明问题:如果await大部分时间在5ms以下,偶尔跳到80ms,这种尖刺就是邻居在突发写入的痕迹。
同时可以配合iotop看是哪个进程在产生I/O。如果iotop里你自己的进程几乎没动静,但磁盘await很高,答案就很明显了。
fio:把“感觉慢”变成可比较的数字
iostat告诉你存储层有没有压力,fio告诉你压力有多大、你的份额被挤压到什么程度。香港VPS上做磁盘测试,关键是模拟真实负载:随机小IO,而不是顺序大文件。数据库、网站会话、日志追加,这些都是4K随机读写的模式,而dd测的是顺序写入,和实际业务关系不大,也容易被缓存和突发配额糊弄过去。
先安装fio:
apt install fio -y
# 或
yum install fio -y
跑一个30秒的4K随机写测试:
fio --name=randwrite --ioengine=libaio --iodepth=16 --rw=randwrite \
--bs=4k --direct=1 --size=512M --numjobs=4 --runtime=30 \
--time_based --group_reporting
参数里--direct=1绕过系统缓存,测的是真实磁盘路径;--iodepth=16模拟并发I/O队列,--numjobs=4用四个并发任务施压。输出中重点看两个数:iops和clat(完成延迟)。
一个判断基准:如果这台香港VPS标称SSD存储,4K随机写的IOPS长期在几百甚至更低,完成延迟的百分位数值(比如clat的99th)跳到几十毫秒以上,而正常SSD在这个测试下应该能跑到数千到上万IOPS、延迟在个位数毫秒,那磁盘超售的嫌疑就很大了。
比单次结果更有说服力的是跑三次看波动。在同一时段连续跑三轮,记录每轮的IOPS。如果三轮之间的IOPS差距超过40%,说明存储性能极不稳定,邻居的I/O在持续干扰你的份额。一台资源隔离做得好的VPS,三次结果的方差应该很小。
如果想测读的性能,把--rw=randwrite换成--rw=randread,其余参数不变。读通常比写受超售影响小一些,但缓存层如果被邻居挤占,读延迟同样会飙升。
晚高峰的数据才有说服力
磁盘I/O超售和网络拥堵有一个共同点:凌晨三点的测试结果几乎没有参考价值。宿主机上的邻居们白天跑业务、晚上跑备份和批处理,磁盘争抢往往在晚间加剧。你如果在下午两三点跑出一个漂亮的IOPS,不能说明任何问题。
正确的做法是在香港时间晚上八点到十一点之间,重复上面的iostat和fio测试。和白天(比如上午十点)的结果做对比。如果晚高峰的await是白天的三到五倍,或者fio的IOPS掉了一半以上,同时你自己的业务负载并没有显著变化,那这台机器的存储层在高峰期被人抢了。
另一个细节是持续性。偶尔一次晚高峰波动可能是邻居在跑一次性的任务,但如果连续三四个晚上都在同一时段出现磁盘延迟飙升,那就不是偶发事件,而是宿主机长期处于超载状态。
磁盘I/O超售之后能做什么?
测出来磁盘I/O确实被严重超售,首先可以尝试联系服务商。部分商家在收到具体数据(iostat截图、fio结果对比)后,可能愿意把你迁移到负载较低的宿主机上,这比直接换商家省事。但如果服务商的回复是“共享资源就是这样”或者“建议升级套餐”,那基本意味着他们没有做存储层的资源隔离,或者隔离策略形同虚设。
对于跑数据库、需要稳定写入的业务,磁盘I/O超售比CPU超售更致命。CPU被抢了时间片,请求至少还能排队处理,只是慢一些;磁盘I/O被挤占,数据库的写入延迟会直接传导到每一个事务提交,慢查询堆积起来能把连接池耗尽。如果你的业务属于这一类,而测试数据又不乐观,换一台存储隔离更明确的机器,比在上面继续调优划算得多。
常见误区:
误区一:dd测出来写入速度有200MB/s,是不是说明磁盘没被超售?
不能这么下结论。dd测的是顺序写入,受缓存和突发配额影响很大,而且和大多数业务场景(数据库、网站)的实际I/O模式(4K随机读写)完全不同。一块被严重超售的SSD在顺序写入时可能仍然跑出不错的数字,但随机写IOPS已经掉到几百。判断超售要用fio跑随机读写,而不是dd跑顺序写。
误区二:白天测没问题,晚上卡,一定是超售吗?
不一定全是超售,但晚高峰的磁盘性能下降是超售的典型信号。也可能是你自己的业务在晚间有备份任务或定时脚本在跑。先确认iotop里是不是你自己的进程在产生I/O,排除之后如果磁盘await仍然很高而你的进程很安静,那就是邻居的问题。连续观察几个晚上,如果规律性出现,超售的判断就比较可靠。
误区三:iostat的%util到100%了,是不是就说明磁盘被超售了?
不一定。%util的算法在SSD和共享存储上有局限性,它反映的是“设备有没有在忙”,而不是“你拿到的带宽够不够”。一台健康的SSD在并发I/O下%util跑到100%是正常的。判断超售应该看await(等待时间)是否异常升高,以及fio测出的IOPS和延迟是否远低于预期、波动是否过大。
相关内容
