最让人头疼的不是网站一直打不开,而是它过一会儿又自己好了。用户报故障时你去看一眼,一切正常;等你走开,它又崩了。这种间歇性故障排查起来没有捷径,唯一有效的办法是把问题按层切开,从域名解析一路往下排到程序,逐层确认或排除。网站过段时间打不开怎么回事,先看下面这套分层顺序,再动手。
第一层:域名解析与网络链路
先确认问题是不是发生在你的服务器上。做法很简单:故障发生时,用 ping 和 nslookup 看域名能不能正常解析出 IP,解析出来的 IP 是不是你现在用的那台;再用 curl 直接带 IP 请求首页,加上 Host 头。如果直接用 IP 能访问、用域名不行,问题在解析层,重点查解析记录有没有被改、DNS 服务商的可用性、TTL 设置是否过短导致频繁切换。如果换了两个网络环境都打不开,而且是同一个时间点出问题,往下走第二层。
第二层:服务器资源
间歇性故障里,资源耗尽占比很高,典型表现是内存被吃满后系统把服务进程杀掉,进程自动重启,中间那几十秒网站就是打不开。要查三处:看系统日志里有没有内存不足相关的记录,看服务的运行时长是不是短得反常(说明它被反复重启),看有没有定时任务在这些时间点集中跑。还有一个常被忽略的点是连接数,程序里数据库连接没释放,跑上几天连接池就满了,表现出来也是过一会儿就好、过一会儿又坏。
第三层:程序与外部依赖
程序层面的间歇性故障,多数和一个共同点有关:某个外部依赖的超时。调用第三方接口、读取远程文件、查询外部数据源,这些动作一旦超时,页面就会卡住或者报错,而超时往往也不是每次都发生。判断办法是看错误日志里的时间戳,把报错时间和故障时间对齐,看看是不是每次都落在同一类操作上。另外一个方向是并发,量小的时候一切正常,一到高峰就崩,这就是典型的并发瓶颈。
用探测脚本把故障时间点固定下来
排查间歇性故障最吃亏的是拿不到现场。下面这段脚本放到另一台服务器或者本机跑,每隔一分钟请求一次你的首页,把时间、状态码、耗时记录下来,出错时把错误信息也写进去。URL 改成你的首页地址,间隔和次数按需要调,建议至少连续跑一天,覆盖面越广越容易抓到故障。拿到这份记录,再和服务器日志按时间对齐,故障到底是解析问题、资源问题还是程序问题,很快就能分辨。
# 周期性探测首页可用性,记录状态码与耗时,抓间歇性故障的现场
import time, urllib.request, urllib.error
URL = "https://www.example.com/" # 改成你的首页地址
TIMES = 1440 # 探测次数(1440 次约等于一天)
INTERVAL = 60 # 每次间隔秒数
for i in range(TIMES):
t0 = time.time()
try:
code = urllib.request.urlopen(URL, timeout=10).status
except urllib.error.HTTPError as e:
code = "HTTP %d" % e.code
except Exception as e:
code = type(e).__name__
cost = (time.time() - t0) * 1000
print("%s 状态: %-12s 耗时: %.0f ms" % (time.strftime("%Y-%m-%d %H:%M:%S"), code, cost))
time.sleep(INTERVAL)
记录跑起来之后,重点看两个形态:状态码间歇性变成超时或 5xx,说明服务器那一端确实短时不可用;耗时忽高忽低、偶尔飙到几千毫秒,说明还没到不可用的程度,但有明显的资源争抢。把出现的每个异常时间点单独标出来,和访问日志做个对照,看那个时间点有没有异常流量、有没有定时任务在跑。这一层对上了,原因基本就跑不掉了。
相关阅读:
申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!
