shell批量监控网站状态码
网站状态监控脚本进化史:从curl到高性能并发检测
📌 需求背景
运维工作中经常需要批量监控网站的状态码,及时发现服务异常。最初的脚本使用curl逐个检测,但串行执行速度很慢,且状态码处理存在缺陷。本文将记录脚本的演进过程,从串行到并发,从简单状态码检测到更完善的监控方案。
🐌 一、初版脚本:串行curl检测(问题分析)
1.1 原始脚本代码
#!/bin/bash # 作者:GuoYabin # 功能:批量监控网站状态码,异常时发送邮件 # 问题:串行执行,速度慢;状态码处理存在缺陷 yuming=`/bin/cat yuming.txt` for i in $yuming do # 获取HTTP状态码 result=`/usr/bin/curl -I $i 2>/dev/null | awk '/HTTP/{print $2}'` # 将状态码转换为整数(原脚本的hack方式) res=$[result+1] res=`echo $res |awk -F '.' '{print $1}'` if [ $res -ge 400 ];then echo "$i is $result " | mail -s "http_server" guoyabin@ccln.gov.cn else if [ $res -eq 1 ];then echo "$i resolve error" | mail -s "http_server" guoyabin@ccln.gov.cn fi fi done
1.2 原脚本存在的问题
| 问题类型 | 具体表现 | 影响 |
|---|---|---|
| 性能问题 | 串行执行,curl -I 每次请求需等待服务器响应 | 100个网站可能耗时数分钟 |
| 状态码处理 | $[result+1] 对非数字值会报错;浮点数处理方式hack | 解析失败或域名不解析时可能误判 |
| 错误区分 | 只区分了≥400和解析错误,无法区分连接超时、拒绝等 | 排查问题信息不足 |
| 邮件通知 | 每个异常都单独发送邮件,可能造成邮件轰炸 | 运维邮箱被刷屏,重要邮件被淹没 |
⚡ 二、性能优化方案对比
2.1 方案一:后台并发执行(简单改造)
#!/bin/bash # 使用 & 将检测任务放到后台并行执行 yuming=`cat yuming.txt` for i in $yuming do ( # 检测逻辑 result=`curl -I -s --connect-timeout 5 $i | awk '/HTTP/{print $2}'` if [ -z "$result" ] || [ "$result" -ge 400 ] 2>/dev/null;then echo "$i: ${result:-连接失败}" >> /tmp/http_check.log fi ) & done wait # 等待所有后台任务完成 # 汇总发送邮件 if [ -s /tmp/http_check.log ];then mail -s "HTTP异常监控报告" guoyabin@ccln.gov.cn < /tmp/http_check.log fi rm -f /tmp/http_check.log
2.2 方案二:xargs 并行(控制并发数)
#!/bin/bash # 使用 xargs -P 控制并发进程数,避免系统负载过高 check_url() { url=$1 result=$(curl -I -s --connect-timeout 5 --max-time 10 $url | awk '/HTTP/{print $2}') if [ -z "$result" ];then echo "$url: 连接失败(超时或无法解析)" elif [ "$result" -ge 400 ] 2>/dev/null;then echo "$url: HTTP $result" fi } export -f check_url # 并发20个进程同时检测 cat yuming.txt | xargs -n 1 -P 20 -I {} bash -c 'check_url "{}"' > /tmp/http_check.log if [ -s /tmp/http_check.log ];then mail -s "HTTP异常监控报告" guoyabin@ccln.gov.cn < /tmp/http_check.log fi
2.3 方案三:使用其他工具(性能对比)
| 工具 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| curl | 通用性强,参数丰富 | 串行慢,需配合并发 | 少量网站检测 |
| wget | --spider 仅检查不下载 | 并发支持较弱 | 简单可用性检查 |
| httping | 专门ping HTTP服务 | 需单独安装 | 延迟监控 |
| Python脚本 | 多线程/异步,灵活强大 | 依赖Python环境 | 大规模监控 |
🐍 三、进阶方案:Python异步实现(高性能推荐)
对于大规模网站监控(几百上千个),Shell脚本的并发能力有限。下面提供一个使用Python asyncio + aiohttp的异步实现方案:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # 异步批量HTTP状态码检测 # 依赖安装:pip install aiohttp import asyncio import aiohttp import smtplib from email.mime.text import MIMEText import time # 配置参数 CONCURRENCY = 50 # 并发数 TIMEOUT = 10 # 超时时间(秒) URL_FILE = 'yuming.txt' MAIL_TO = 'guoyabin@ccln.gov.cn' class HTTPChecker: def __init__(self): self.results = [] async def check_one(self, session, url): """检测单个URL""" try: # 发起HEAD请求(只获取响应头,不下载内容) async with session.head(url, timeout=TIMEOUT, allow_redirects=True) as resp: status = resp.status if status >= 400: self.results.append(f"{url}: HTTP {status}") except asyncio.TimeoutError: self.results.append(f"{url}: 连接超时") except aiohttp.ClientConnectorError: self.results.append(f"{url}: 无法连接(域名解析失败或拒绝连接)") except Exception as e: self.results.append(f"{url}: 未知错误 - {str(e)}") async def check_all(self, urls): """批量检测所有URL""" # 连接池配置 connector = aiohttp.TCPConnector(limit=CONCURRENCY) timeout = aiohttp.ClientTimeout(total=TIMEOUT) async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session: tasks = [self.check_one(session, url.strip()) for url in urls if url.strip()] await asyncio.gather(*tasks) def send_mail(self): """发送异常报告""" if not self.results: return content = "\n".join(self.results) msg = MIMEText(content) msg['Subject'] = 'HTTP异常监控报告' msg['To'] = MAIL_TO # 这里需要配置你的邮件服务器 # with smtplib.SMTP('smtp.example.com') as server: # server.send_message(msg) print(f"异常报告:\n{content}") # 测试时先打印 def main(): # 读取域名列表 with open(URL_FILE, 'r') as f: urls = [f"http://{line.strip()}" for line in f] start = time.time() checker = HTTPChecker() asyncio.run(checker.check_all(urls)) elapsed = time.time() - start print(f"检测完成,耗时:{elapsed:.2f}秒,共{len(urls)}个网站") checker.send_mail() if __name__ == '__main__': main()
📊 四、性能对比测试
以100个网站为例,测试不同方案的执行耗时:
| 方案 | 耗时(秒) | CPU负载 | 代码复杂度 |
|---|---|---|---|
| 原脚本(串行curl) | ≈ 150-200秒 | 低 | 低 |
| 后台并发(&) | ≈ 10-20秒 | 高(无限制) | 低 |
| xargs -P 20 | ≈ 10-15秒 | 可控 | 中 |
| Python异步(并发50) | ≈ 5-8秒 | 低(异步非阻塞) | 中高 |
💡 五、最佳实践建议
1. 针对不同规模的选型建议
- 少量网站(≤ 50个):使用xargs并发方案,简单够用
- 中等规模(50-500个):推荐Python异步方案,性能和可维护性平衡
- 大规模(500+个):考虑使用专业的监控工具(如Prometheus + Blackbox Exporter)
2. 邮件通知优化
- 改为汇总报告,避免邮件轰炸
- 增加错误分类统计(如5xx、4xx、连接失败等)
- 支持多个接收人和不同级别的告警
3. curl命令参数优化
curl -I -s --connect-timeout 5 --max-time 10 --retry 1 $url # -I:只获取响应头 # -s:静默模式,不显示进度 # --connect-timeout:连接超时 # --max-time:最大执行时间 # --retry:失败重试次数
4. 状态码处理改进
# 使用case语句分类处理
status_code=$(curl -I -s -w "%{http_code}" -o /dev/null $url)
case $status_code in
200) echo "正常" ;;
30[0-9]) echo "重定向" ;;
40[0-9]) echo "客户端错误" ;;
50[0-9]) echo "服务器错误" ;;
"") echo "连接失败" ;;
*) echo "未知状态码:$status_code" ;;
esac
📝 六、总结与展望
从最初的串行curl脚本,到后台并发、xargs控制,再到Python异步实现,我们看到了监控脚本的演进之路。每种方案都有其适用场景,关键是根据实际需求选择合适的技术栈。
下一步改进方向:
- 增加响应时间监控,不仅看状态码
- 集成到Zabbix/Prometheus等监控系统
- 支持HTTPS证书过期检测
- 增加历史趋势分析和可视化报表
等我学完其他方式,再来更新本文。欢迎留言交流更好的实现方案~

浙公网安备 33010602011771号