1. 服务器连接数监控告警系统设计与实现
最近在维护线上服务器时,经常遇到连接数激增导致服务响应变慢的问题。为了及时发现这类异常,我开发了一个基于Linux系统命令和钉钉机器人的连接数监控告警系统。这个方案不需要额外安装监控软件,仅用Shell脚本就能实现实时监控,特别适合中小规模部署环境。
这个系统主要解决三个核心问题:
- 实时监控服务器的TCP连接状态
- 在连接数超过阈值时触发告警
- 通过钉钉机器人推送详细的连接分析报告
整套方案由四个关键部分组成:连接数统计模块、告警逻辑判断模块、钉钉消息推送模块和定时任务调度模块。下面我会详细解析每个模块的实现原理和优化技巧。
2. 核心模块实现解析
2.1 服务器IP获取模块
bash复制get_server_ip() {
local ip=$(ip -4 addr show|grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v '^127\.' |head -1)
echo "$ip"
}
这个函数通过组合多个命令获取服务器的非回环IPv4地址:
ip -4 addr show显示所有IPv4网络接口信息grep -oP使用Perl正则提取IP地址grep -v '^127\.'过滤掉127.0.0.1等回环地址head -1取第一个非回环地址
注意:在生产环境中,如果服务器有多个网卡,建议明确指定要监控的网卡接口,避免获取到错误的IP地址。例如使用
ip -4 addr show eth0直接指定网卡。
2.2 连接数统计与分析模块
bash复制check_connections() {
local threshold=500
local server_ip=$(get_server_ip)
local conn_count=$(netstat -tlan | wc -l)
conn_count=$(echo "$conn_count" | tr -d ' ')
if [ "$conn_count" -gt "$threshold" ]; then
# 告警消息组装逻辑
...
fi
}
关键参数说明:
threshold=500:设置连接数告警阈值,这个值需要根据服务器配置和应用特点调整netstat -tlan:显示所有TCP监听和已建立的连接wc -l:统计总行数(即连接数)
进阶统计部分:
bash复制netstat -tlan | awk 'NR>2 {print $6}' | sort | uniq -c
这个管道命令分析各个连接状态的分布情况:
NR>2跳过表头行print $6提取连接状态列sort | uniq -c统计每种状态的数量
2.3 钉钉机器人消息推送模块
bash复制send_dingtalk(){
local message="$1"
local timestamp=$(date +%s%3N)
local request_url="$WEBHOOK_URL"
if [ -n "$SECRET" ];then
local string_to_sign="${timestamp}"$'\n'"${SECRET}"
local sign=$(echo -n "$string_to_sign" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
sign=$(echo -n "$sign" | xxd -plain | tr -d '\n' | sed 's/\(..\)/%\1/g')
request_url="${WEBHOOK_URL}×tamp=${timestamp}&sign=${sign}"
fi
local payload=$(cat <<-EOF
{
"msgtype": "markdown",
"markdown": {
"title": "连接告警",
"text": "${message}"
},
"at": {
"isAtAll": false
}
}
EOF
)
curl -s -H "Content-Type: application/json" -d "$payload" "$request_url"
}
安全验证机制解析:
- 时间戳:
date +%s%3N获取当前毫秒级时间戳 - 签名生成:
- 使用OpenSSL生成HMAC-SHA256签名
- Base64编码
- URL编码处理
- 最终请求URL构造:
${WEBHOOK_URL}×tamp=${timestamp}&sign=${sign}
重要提示:钉钉机器人安全设置建议使用"加签"方式而非IP白名单,因为服务器IP可能会变化。加签方式更灵活可靠。
3. 告警消息内容优化
原始脚本已经提供了不错的告警信息,但我们可以进一步丰富内容,使其更具可操作性:
bash复制alert_msg="#### 服务器连接数告警\n\n"
alert_msg+="- **服务器IP**: \`${server_ip}\`\n"
alert_msg+="- **主机名**: \`$(hostname)\`\n"
alert_msg+="- **当前连接数**: **${conn_count}**\n"
alert_msg+="- **告警阈值**: ${threshold}\n"
alert_msg+="- **触发时间**: `date '+%Y-%m-%d %H:%M:%S'`\n"
alert_msg+="- **系统负载**: `uptime | awk -F'load average: ' '{print $2}'`\n\n"
# 添加进程级别的连接统计
alert_msg+="**按进程统计连接数**: \n"
alert_msg+="$(netstat -tlanp | awk '$6=="ESTABLISHED" {print $7}' | cut -d'/' -f1 | sort | uniq -c | sort -rn | head -5 | awk '{printf "- PID %s: %s\\n", $2, $1}')\n\n"
# 添加连接状态统计
alert_msg+="**连接状态统计**: \n"
alert_msg+="$(netstat -tlan | awk 'NR>2 {print $6}' | sort | uniq -c | awk '{printf "- %s: %s\\n", $2, $1}')\n\n"
# 添加TOP连接IP
alert_msg+="**TOP 5 连接IP**: \n"
top_ips=$(netstat -tlan | awk 'NR>2 {print $5}' | grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' | sort | uniq -c | sort -rn | head -5 | awk '{printf "- %s (%s)\\n", $2, $1}')
alert_msg+="${top_ips:-无外部连接}\n\n"
# 添加历史连接数趋势
alert_msg+="**近1小时连接数趋势**: \n"
alert_msg+="$(sar -n TCP 1 60 | grep -v 'Average' | tail -n +3 | awk '{printf "- %s: ESTAB %s\\n", $1, $2}')\n"
优化后的告警消息包含:
- 基础服务器信息(IP、主机名)
- 系统负载指标
- 按进程统计的连接数
- 详细的连接状态分布
- 连接最多的远程IP
- 近1小时的连接数趋势图
4. 生产环境部署建议
4.1 脚本安装与配置
- 创建专用目录存放脚本:
bash复制mkdir -p /opt/scripts/monitoring
chmod 750 /opt/scripts/monitoring
- 保存脚本文件:
bash复制vi /opt/scripts/monitoring/connection_alert.sh
chmod +x /opt/scripts/monitoring/connection_alert.sh
- 配置文件建议(/etc/connection_alert.conf):
ini复制WEBHOOK_URL="https://oapi.dingtalk.com/robot/send?access_token=your_token"
SECRET="your_secret"
THRESHOLD=500
LOG_FILE="/var/log/connection_alert.log"
- 修改脚本读取配置文件:
bash复制# 在脚本开头添加
CONFIG_FILE="/etc/connection_alert.conf"
[ -f "$CONFIG_FILE" ] && source "$CONFIG_FILE"
4.2 定时任务配置优化
原始crontab配置:
bash复制*/30 * * * * /usr/bin/bash /opt/scripts/tongji.sh
改进建议:
- 添加错误日志记录
- 设置环境变量
- 添加锁机制防止重复执行
优化后的crontab:
bash复制*/5 * * * * /usr/bin/flock -xn /tmp/connection_alert.lock -c "export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin; /opt/scripts/monitoring/connection_alert.sh >> /var/log/connection_alert_error.log 2>&1"
关键改进点:
- 使用flock防止并发执行
- 明确设置PATH环境变量
- 记录错误日志便于排查
- 将监控频率提高到5分钟
4.3 日志轮转配置
创建日志轮转配置/etc/logrotate.d/connection_alert:
ini复制/var/log/connection_alert.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 root adm
sharedscripts
postrotate
/usr/bin/killall -HUP rsyslogd >/dev/null 2>&1 || true
endscript
}
5. 高级功能扩展
5.1 多级阈值告警
修改check_connections函数,实现多级告警:
bash复制check_connections() {
local warning_threshold=300
local critical_threshold=500
local server_ip=$(get_server_ip)
local conn_count=$(netstat -tlan | wc -l)
conn_count=$(echo "$conn_count" | tr -d ' ')
if [ "$conn_count" -ge "$critical_threshold" ]; then
send_dingtalk "$(build_alert_message "CRITICAL" "$conn_count" "$critical_threshold")"
elif [ "$conn_count" -ge "$warning_threshold" ]; then
send_dingtalk "$(build_alert_message "WARNING" "$conn_count" "$warning_threshold")"
fi
}
5.2 历史数据分析
添加历史数据分析功能,识别连接数增长趋势:
bash复制analyze_trend() {
local log_file="/var/log/connection_alert.log"
local trend=$(awk '/告警出发/ {print $6}' "$log_file" | tail -5 | tr '\n' ' ')
echo "$trend"
}
# 在告警消息中添加趋势分析
alert_msg+="**近期连接数趋势**: ${trend}\n"
5.3 自动化处置措施
对于严重告警,可以自动执行缓解措施:
bash复制if [ "$conn_count" -ge "$critical_threshold" ]; then
# 自动重启异常进程
local top_process=$(netstat -tlanp | awk '$6=="ESTABLISHED" {print $7}' | cut -d'/' -f1 | sort | uniq -c | sort -rn | head -1 | awk '{print $2}')
[ -n "$top_process" ] && kill -9 "$top_process"
# 记录处置日志
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 自动终止进程: $top_process" >> "$LOG_FILE"
fi
6. 常见问题排查指南
6.1 钉钉消息发送失败
可能原因及解决方案:
-
Token或签名错误:
- 检查WEBHOOK_URL是否正确
- 验证SECRET是否与钉钉机器人设置一致
- 确认服务器时间是否准确(影响签名时间戳)
-
网络连接问题:
bash复制curl -v "https://oapi.dingtalk.com/robot/send?access_token=your_token"测试是否能访问钉钉API
-
消息格式错误:
- 确保JSON格式正确
- 特殊字符需要转义
6.2 连接数统计不准确
排查步骤:
-
确认netstat命令选项:
bash复制netstat -tlan | wc -l # 应该与下面命令结果一致 ss -tan | wc -l -
检查是否有大量TIME_WAIT连接:
bash复制netstat -tan | awk '{print $6}' | sort | uniq -c -
考虑使用更精确的统计方法:
bash复制ss -tan state established | wc -l
6.3 脚本执行权限问题
常见错误:
-
"Permission denied" - 确保脚本有执行权限
bash复制chmod +x /opt/scripts/monitoring/connection_alert.sh -
crontab环境问题 - 在crontab中设置完整PATH
bash复制
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin -
日志文件不可写 - 确保日志目录存在且有写入权限
bash复制touch /var/log/connection_alert.log chown root:adm /var/log/connection_alert.log chmod 640 /var/log/connection_alert.log
7. 性能优化建议
-
使用ss替代netstat:
bash复制# 更高效的连接统计方式 conn_count=$(ss -tan | wc -l) -
减少不必要的统计:
bash复制# 只统计ESTABLISHED状态连接 conn_count=$(ss -tan state established | wc -l) -
添加执行时间限制:
bash复制timeout 30s /opt/scripts/monitoring/connection_alert.sh -
使用缓存机制:
bash复制# 缓存服务器IP SERVER_IP_FILE="/tmp/server_ip.cache" if [ ! -f "$SERVER_IP_FILE" ] || find "$SERVER_IP_FILE" -mtime +1 | grep -q .; then get_server_ip > "$SERVER_IP_FILE" fi server_ip=$(cat "$SERVER_IP_FILE") -
考虑使用更高效的语言重写核心逻辑(如Python),当连接数特别大时Shell脚本可能成为瓶颈