本文目录导读:

可以的,市面上确实有很多实用的脚本能够自动监控Redis性能,这类脚本通常能帮你收集关键指标,并在出现异常时报警。
下面我为你详细介绍几种常用方案,从轻量级脚本到企业级工具都有,你可以根据实际环境选择。
轻量级Shell脚本:快速部署,适合小规模环境
这种方案依赖Redis自带的redis-cli工具和系统命令,无需额外安装软件。
示例脚本:redis_monitor.sh
#!/bin/bash
# Redis连接信息
REDIS_CLI="/usr/bin/redis-cli" # 请根据实际路径修改
HOST="127.0.0.1"
PORT="6379"
PASSWORD="" # 如有密码,填在这里,如 -a 'yourpassword'
# 报警阈值(可根据需要调整)
MAX_MEMORY_MB=1024 # 内存使用超过1024MB报警
MAX_LATENCY_MS=100 # 延迟超过100ms报警
MAX_CONNECTIONS=500 # 连接数超过500报警
REPL_LAG_THRESHOLD=10 # 主从复制延迟超过10秒报警
SLOW_LOG_THRESHOLD=100000 # 慢查询阈值,微秒
# 报警函数(可自定义,如发送邮件、钉钉等)
alert() {
local message="$1"
echo "[ALERT] $(date '+%Y-%m-%d %H:%M:%S') - $message" >> /var/log/redis_monitor.log
# 可在此添加发送邮件或Webhook的代码
# curl -X POST -H "Content-Type: application/json" -d '{"text":"'"$message"'"}' your_webhook_url
}
# 获取INFO命令的输出
if [ -n "$PASSWORD" ]; then
INFO=$($REDIS_CLI -h $HOST -p $PORT -a "$PASSWORD" INFO 2>/dev/null)
else
INFO=$($REDIS_CLI -h $HOST -p $PORT INFO 2>/dev/null)
fi
if [ $? -ne 0 ]; then
alert "无法连接到Redis服务器 $HOST:$PORT"
exit 1
fi
# 提取关键性能指标
used_memory=$(echo "$INFO" | grep "^used_memory:" | cut -d ':' -f2)
used_memory_rss=$(echo "$INFO" | grep "^used_memory_rss:" | cut -d ':' -f2)
used_memory_peak=$(echo "$INFO" | grep "^used_memory_peak:" | cut -d ':' -f2)
total_connections_received=$(echo "$INFO" | grep "^total_connections_received:" | cut -d ':' -f2)
connected_clients=$(echo "$INFO" | grep "^connected_clients:" | cut -d ':' -f2)
instantaneous_ops_per_sec=$(echo "$INFO" | grep "^instantaneous_ops_per_sec:" | cut -d ':' -f2)
instantaneous_input_kbps=$(echo "$INFO" | grep "^instantaneous_input_kbps:" | cut -d ':' -f2)
instantaneous_output_kbps=$(echo "$INFO" | grep "^instantaneous_output_kbps:" | cut -d ':' -f2)
rejected_connections=$(echo "$INFO" | grep "^rejected_connections:" | cut -d ':' -f2)
keyspace_hits=$(echo "$INFO" | grep "^keyspace_hits:" | cut -d ':' -f2)
keyspace_misses=$(echo "$INFO" | grep "^keyspace_misses:" | cut -d ':' -f2)
uptime_in_seconds=$(echo "$INFO" | grep "^uptime_in_seconds:" | cut -d ':' -f2)
role=$(echo "$INFO" | grep "^role:" | cut -d ':' -f2)
# 内存检查(转换为MB)
used_memory_mb=$((used_memory / 1024 / 1024))
if [ $used_memory_mb -gt $MAX_MEMORY_MB ]; then
alert "Redis内存使用超限: ${used_memory_mb}MB (阈值: ${MAX_MEMORY_MB}MB)"
fi
# 连接数检查
if [ "$connected_clients" -gt "$MAX_CONNECTIONS" ]; then
alert "Redis客户端连接数过高: $connected_clients (阈值: $MAX_CONNECTIONS)"
fi
# 拒绝连接检查(如果有拒绝连接,通常意味着达到最大连接限制)
if [ -n "$rejected_connections" ] && [ "$rejected_connections" -gt 0 ]; then
alert "Redis出现拒绝连接: $rejected_connections次"
fi
# 主从复制检查(仅对从节点有效)
if [ "$role" = "slave" ]; then
master_link_status=$(echo "$INFO" | grep "^master_link_status:" | cut -d ':' -f2)
master_last_io_seconds_ago=$(echo "$INFO" | grep "^master_last_io_seconds_ago:" | cut -d ':' -f2)
slave_repl_offset=$(echo "$INFO" | grep "^slave_repl_offset:" | cut -d ':' -f2)
master_repl_offset=$(echo "$INFO" | grep "^master_repl_offset:" | cut -d ':' -f2)
if [ "$master_link_status" != "up" ]; then
alert "Redis主从复制链接断开!"
fi
if [ -n "$master_last_io_seconds_ago" ] && [ "$master_last_io_seconds_ago" -gt "$REPL_LAG_THRESHOLD" ]; then
alert "Redis主从复制延迟: ${master_last_io_seconds_ago}秒 (阈值: ${REPL_LAG_THRESHOLD}秒)"
fi
fi
# 慢查询检查
SLOW_LOG=$($REDIS_CLI -h $HOST -p $PORT SLOWLOG GET 5 2>/dev/null)
if [ -n "$SLOW_LOG" ]; then
# 简单判断有没有慢查询
echo "$SLOW_LOG" | while read line; do
duration=$(echo "$line" | awk '{print $2}' | tr -d ',') # 微秒
if [ "$duration" -gt "$SLOW_LOG_THRESHOLD" ]; then
alert "Redis慢查询记录: 耗时 ${duration}微秒, 命令: $line"
fi
done
fi
# 记录正常状态
echo "$(date '+%Y-%m-%d %H:%M:%S') - OK - 内存:${used_memory_mb}MB, 连接:${connected_clients}, OPS:${instantaneous_ops_per_sec}" >> /var/log/redis_monitor.log
使用方法:
- 保存为
redis_monitor.sh并赋予执行权限:chmod +x redis_monitor.sh - 设置crontab定期执行(例如每1分钟):
* * * * * /path/to/redis_monitor.sh - 在脚本中完善
alert()函数,对接你的报警通道(企业微信、钉钉、邮件等)。
Python脚本:更强大、更灵活
Python方案可以利用redis-py库和丰富的数据处理能力。
示例脚本:redis_perf_monitor.py
#!/usr/bin/env python3
import redis
import time
import smtplib
import json
from datetime import datetime
import os
# Redis连接配置
REDIS_CONFIG = {
'host': '127.0.0.1',
'port': 6379,
'password': None,
'db': 0,
'socket_connect_timeout': 5
}
# 报警阈值
ALERTS = {
'memory_usage_mb': 1024,
'connected_clients': 500,
'hit_rate_low': 0.8, # 缓存命中率低于80%报警
'latency_ms': 100,
'rejected_connections': 1,
'replication_lag_seconds': 10,
}
# 报警配置
ALERT_WEBHOOK_URL = "https://your-alert-webhook-url" # 如钉钉、企业微信机器人
SMTP_CONFIG = {
'server': 'smtp.example.com',
'port': 587,
'username': 'your@email.com',
'password': 'your-password',
'from_addr': 'monitor@example.com',
'to_addr': 'admin@example.com'
}
class RedisMonitor:
def __init__(self, redis_config):
self.client = redis.StrictRedis(**redis_config)
self.info = {}
self.alerts = []
def collect_metrics(self):
"""收集所有关键指标"""
try:
self.info = self.client.info()
except redis.ConnectionError as e:
self._add_alert(f"无法连接到Redis: {str(e)}")
return False
return True
def check_memory(self):
"""检查内存使用"""
used_memory = self.info.get('used_memory', 0)
used_memory_mb = used_memory / 1024 / 1024
max_memory = self.info.get('maxmemory', 0)
max_memory_mb = max_memory / 1024 / 1024
if used_memory_mb > ALERTS['memory_usage_mb']:
self._add_alert(f"内存使用超限: {used_memory_mb:.1f}MB (阈值: {ALERTS['memory_usage_mb']}MB)")
if max_memory > 0:
usage_percent = (used_memory / max_memory) * 100
if usage_percent > 80:
self._add_alert(f"内存使用率超过80%: {usage_percent:.1f}%")
# 检查RSS内存 vs 已使用内存(判断内存碎片)
used_memory_rss = self.info.get('used_memory_rss', 0)
if used_memory_rss > 0:
fragmentation = used_memory_rss / used_memory if used_memory > 0 else 0
if fragmentation > 1.5:
self._add_alert(f"内存碎片率高: {fragmentation:.2f}")
def check_connections(self):
"""检查连接数和拒绝连接"""
connected_clients = self.info.get('connected_clients', 0)
rejected_connections = self.info.get('rejected_connections', 0)
if connected_clients > ALERTS['connected_clients']:
self._add_alert(f"客户端连接数过高: {connected_clients} (阈值: {ALERTS['connected_clients']})")
if rejected_connections > ALERTS['rejected_connections']:
self._add_alert(f"出现拒绝连接: {rejected_connections}次")
def check_hit_rate(self):
"""检查缓存命中率"""
hits = self.info.get('keyspace_hits', 0)
misses = self.info.get('keyspace_misses', 0)
total = hits + misses
if total > 0:
hit_rate = hits / total
if hit_rate < ALERTS['hit_rate_low']:
self._add_alert(f"缓存命中率过低: {hit_rate:.1%} (阈值: {ALERTS['hit_rate_low']:.0%})")
def check_latency(self):
"""检查延迟"""
try:
start = time.time()
self.client.ping()
latency = (time.time() - start) * 1000
if latency > ALERTS['latency_ms']:
self._add_alert(f"Redis延迟过高: {latency:.1f}ms (阈值: {ALERTS['latency_ms']}ms)")
except Exception as e:
self._add_alert(f"延迟检查失败: {str(e)}")
def check_replication(self):
"""检查主从复制状态"""
role = self.info.get('role', 'master')
if role == 'slave':
master_link_status = self.info.get('master_link_status', 'down')
master_last_io_seconds_ago = self.info.get('master_last_io_seconds_ago', 0)
if master_link_status != 'up':
self._add_alert(f"主从复制链接断开! 状态: {master_link_status}")
if master_last_io_seconds_ago > ALERTS['replication_lag_seconds']:
self._add_alert(f"主从复制延迟: {master_last_io_seconds_ago}秒 (阈值: {ALERTS['replication_lag_seconds']}秒)")
# 检查复制积压缓冲区
repl_backlog_active = self.info.get('repl_backlog_active', 0)
repl_backlog_size = self.info.get('repl_backlog_size', 0)
if repl_backlog_active == 0:
self._add_alert("复制积压缓冲区未启用!")
def check_slow_log(self):
"""检查慢查询日志"""
try:
slow_logs = self.client.slowlog_get(10)
for log in slow_logs:
# slow_logs返回的是列表,每个元素是一个元组 (id, timestamp, duration, command, ...)
if len(log) >= 4:
duration = log[2] # 微秒
command = ' '.join(log[3]) if isinstance(log[3], list) else str(log[3])
if duration > 100000: # 100ms以上
self._add_alert(f"慢查询: {duration}微秒, 命令: {command}")
except Exception as e:
pass
def _add_alert(self, message):
"""添加报警信息"""
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
alert_msg = f"[{timestamp}] {message}"
self.alerts.append(alert_msg)
print(alert_msg)
def send_alerts(self):
"""发送报警信息(可对接多种通道)"""
if not self.alerts:
return
alert_text = "\n".join(self.alerts)
# 示例1:发送到Webhook
self._send_webhook(alert_text)
# 示例2:发送邮件
self._send_email("Redis监控报警", alert_text)
def _send_webhook(self, message):
"""发送Webhook报警"""
try:
import requests
payload = {
"msgtype": "text",
"text": {
"content": f"# Redis监控报警\n{message}"
}
}
requests.post(ALERT_WEBHOOK_URL, json=payload, timeout=5)
except Exception as e:
print(f"发送Webhook报警失败: {e}")
def _send_email(self, subject, body):
"""发送邮件报警"""
try:
with smtplib.SMTP(SMTP_CONFIG['server'], SMTP_CONFIG['port']) as server:
server.starttls()
server.login(SMTP_CONFIG['username'], SMTP_CONFIG['password'])
msg = f"Subject: {subject}\n\n{body}"
server.sendmail(SMTP_CONFIG['from_addr'], SMTP_CONFIG['to_addr'], msg)
except Exception as e:
print(f"发送邮件报警失败: {e}")
def generate_report(self):
"""生成性能报告"""
report = {
"timestamp": datetime.now().isoformat(),
"host": REDIS_CONFIG['host'],
"port": REDIS_CONFIG['port'],
"metrics": {
"used_memory_mb": self.info.get('used_memory', 0) / 1024 / 1024,
"connected_clients": self.info.get('connected_clients', 0),
"ops_per_sec": self.info.get('instantaneous_ops_per_sec', 0),
"hit_rate": self._calc_hit_rate(),
"uptime_days": self.info.get('uptime_in_seconds', 0) / 86400,
"keys_count": sum(self.info.get('db0', {}).get('keys', 0) for key in self.info if key.startswith('db')),
"avg_ttl": self.client.info('keyspace').get('db0', {}).get('avg_ttl', 0)
},
"alerts": self.alerts
}
return report
def _calc_hit_rate(self):
hits = self.info.get('keyspace_hits', 0)
misses = self.info.get('keyspace_misses', 0)
total = hits + misses
return hits / total if total > 0 else 0
def run(self):
"""执行监控主流程"""
if not self.collect_metrics():
self.send_alerts()
return
self.check_memory()
self.check_connections()
self.check_hit_rate()
self.check_latency()
self.check_replication()
self.check_slow_log()
if self.alerts:
self.send_alerts()
self._log_to_file(self.generate_report())
else:
print(f"[{datetime.now()}] 性能正常")
def _log_to_file(self, report):
"""将报告写入日志文件"""
log_dir = "/var/log/redis_monitor"
os.makedirs(log_dir, exist_ok=True)
log_file = f"{log_dir}/redis_monitor_{datetime.now().strftime('%Y%m%d')}.log"
with open(log_file, 'a') as f:
f.write(json.dumps(report) + "\n")
if __name__ == "__main__":
monitor = RedisMonitor(REDIS_CONFIG)
monitor.run()
进阶方案:Prometheus + Grafana
对于生产环境,推荐使用成熟的监控体系:
- 数据采集:使用
redis_exporter(一个专门导出Redis指标的Prometheus exporter) - 数据存储:Prometheus负责抓取和存储指标
- 可视化:Grafana提供丰富的仪表盘
快速部署命令:
# 启动Redis Exporter docker run -d --name redis_exporter \ -e REDIS_ADDR=redis://your-redis-host:6379 \ -p 9121:9121 \ oliver006/redis_exporter # 配置Prometheus(prometheus.yml) # 添加: # - job_name: 'redis' # static_configs: # - targets: ['localhost:9121'] # Grafana导入Redis仪表盘(ID: 11835 或 763)
关键性能指标说明
无论使用哪种方案,都应关注以下核心指标:
| 指标 | 说明 | 建议阈值 |
|---|---|---|
| used_memory | 已用内存 | 不超过maxmemory的80% |
| connected_clients | 当前连接数 | 小于maxclients的80% |
| instantaneous_ops_per_sec | 每秒操作数 | 根据机型,lt;100K |
| hit_rate | 缓存命中率 | >90%为佳 |
| latency | 延迟 | lt;10ms |
| rejected_connections | 拒绝连接数 | 应为0 |
| keyspace_hits/misses | 键空间命中/未命中 | 反映缓存效率 |
| evicted_keys | 被淘汰键数 | 应尽量为0 |
| 慢查询 | 执行时间超过阈值的命令 | 根据业务调整 |
建议
- 脚本化监控适合快速部署,但功能有限
- Prometheus+Grafana是生产环境首选
- 对于云Redis(如阿里云、腾讯云),建议使用云厂商自带的监控服务
- 报警规则要合理:避免阈值过低导致报警风暴,也要避免过高导致故障遗漏
- 结合日志分析:将监控数据与业务日志关联,定位根因
如果需要更详细的配置说明或针对特定场景(如集群模式、哨兵模式)的监控脚本,可以进一步沟通。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播