Files
java-template/utils/monitor_alert_cache_performance.py
BrunoGaoandClaude e402548e45 fix: 修复customer_id字段缺失问题,完成数据库schema同步
数据库修复:
- t_user_health_data_daily: 添加customer_id字段(租户ID)
- t_user_health_data_weekly: 添加customer_id字段(租户ID)

ljwx-boot同步更新:
- TUserHealthDataDailyMapper.xml: 添加customer_id字段映射
- TUserHealthDataWeeklyMapper.xml: 添加customer_id字段映射

其他改进:
- 告警规则缓存优化
- Redis缓存性能提升
- 健康数据处理性能优化
- 添加完整的文档和工具脚本

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2025-09-10 13:49:59 +08:00

342 lines
13 KiB
Python

#!/usr/bin/env python3
"""
告警规则缓存性能监控脚本
实时监控Redis缓存告警系统的性能指标
"""
import time
import json
import logging
import sys
import os
from datetime import datetime, timedelta
from typing import Dict, List, Any
import threading
# 添加当前路径
current_dir = os.path.dirname(__file__)
sys.path.insert(0, current_dir)
from redis_cache_generate_alerts import get_redis_cached_generator
# 设置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class AlertCacheMonitor:
"""告警缓存性能监控器"""
def __init__(self, interval: int = 10):
self.interval = interval # 监控间隔(秒)
self.running = False
self.monitor_thread = None
self.generator = None
self.history = [] # 历史数据
self.max_history = 100 # 最大历史记录数
def start_monitoring(self):
"""开始监控"""
if self.running:
logger.warning("监控器已在运行中")
return
print("🔍 启动告警缓存性能监控器")
try:
self.generator = get_redis_cached_generator()
self.running = True
self.monitor_thread = threading.Thread(
target=self._monitor_loop,
daemon=True,
name="AlertCacheMonitor"
)
self.monitor_thread.start()
print(f"✅ 监控器已启动,监控间隔: {self.interval}秒")
except Exception as e:
print(f"❌ 监控器启动失败: {e}")
self.running = False
def stop_monitoring(self):
"""停止监控"""
self.running = False
print("🛑 监控器已停止")
def _monitor_loop(self):
"""监控主循环"""
print("📊 开始性能监控...")
print("-" * 80)
while self.running:
try:
# 收集性能数据
metrics = self._collect_metrics()
# 保存历史数据
self._save_metrics(metrics)
# 显示实时数据
self._display_metrics(metrics)
# 检查告警
self._check_alerts(metrics)
# 等待下一次监控
time.sleep(self.interval)
except Exception as e:
logger.error(f"监控循环异常: {e}")
time.sleep(self.interval)
def _collect_metrics(self) -> Dict[str, Any]:
"""收集性能指标"""
try:
# 获取基础统计
stats = self.generator.get_stats()
# 获取当前时间
timestamp = datetime.now()
# 构建指标数据
metrics = {
'timestamp': timestamp,
'total_processed': stats.get('total_processed', 0),
'cache_hits': stats.get('cache_hits', 0),
'db_fallbacks': stats.get('db_fallbacks', 0),
'cache_hit_rate': stats.get('cache_hit_rate', '0.00%'),
'alerts_generated': stats.get('alerts_generated', 0),
'avg_processing_time': stats.get('avg_processing_time', '0.000s'),
}
# Redis连接状态
cache_manager_status = stats.get('cache_manager_status', {})
if isinstance(cache_manager_status, dict):
redis_status = cache_manager_status.get('redis_connection_status', {})
metrics['bigscreen_redis_ok'] = redis_status.get('bigscreen_redis', False)
metrics['boot_redis_ok'] = redis_status.get('boot_redis', False)
metrics['local_cache_size'] = cache_manager_status.get('local_cache_size', 0)
metrics['subscriber_running'] = cache_manager_status.get('subscriber_running', False)
else:
metrics['bigscreen_redis_ok'] = False
metrics['boot_redis_ok'] = False
metrics['local_cache_size'] = 0
metrics['subscriber_running'] = False
return metrics
except Exception as e:
logger.error(f"收集指标失败: {e}")
return {'timestamp': datetime.now(), 'error': str(e)}
def _save_metrics(self, metrics: Dict[str, Any]):
"""保存历史指标"""
self.history.append(metrics)
# 保持历史记录数量限制
if len(self.history) > self.max_history:
self.history.pop(0)
def _display_metrics(self, metrics: Dict[str, Any]):
"""显示实时指标"""
timestamp = metrics.get('timestamp', datetime.now())
print(f"\n⏰ {timestamp.strftime('%Y-%m-%d %H:%M:%S')}")
print(f"📊 处理统计: 总计={metrics.get('total_processed', 0)}, 告警={metrics.get('alerts_generated', 0)}")
print(f"🔥 缓存性能: 命中={metrics.get('cache_hits', 0)}, 兜底={metrics.get('db_fallbacks', 0)}, 命中率={metrics.get('cache_hit_rate', 'N/A')}")
print(f"⚡ 处理时间: 平均={metrics.get('avg_processing_time', 'N/A')}")
# Redis连接状态
bigscreen_ok = metrics.get('bigscreen_redis_ok', False)
boot_ok = metrics.get('boot_redis_ok', False)
subscriber_ok = metrics.get('subscriber_running', False)
bigscreen_status = "✅" if bigscreen_ok else "❌"
boot_status = "✅" if boot_ok else "❌"
subscriber_status = "✅" if subscriber_ok else "❌"
print(f"🔗 连接状态: bigscreen-redis={bigscreen_status}, boot-redis={boot_status}, 订阅者={subscriber_status}")
print(f"📋 本地缓存: {metrics.get('local_cache_size', 0)}个客户")
print("-" * 80)
def _check_alerts(self, metrics: Dict[str, Any]):
"""检查性能告警"""
alerts = []
# 检查Redis连接
if not metrics.get('bigscreen_redis_ok', True):
alerts.append("❌ ljwx-bigscreen Redis连接异常")
if not metrics.get('boot_redis_ok', True):
alerts.append("❌ ljwx-boot Redis连接异常")
# 检查订阅者状态
if not metrics.get('subscriber_running', True):
alerts.append("⚠️ Redis订阅者未运行")
# 检查缓存命中率
cache_hit_rate_str = metrics.get('cache_hit_rate', '0.00%')
try:
cache_hit_rate = float(cache_hit_rate_str.replace('%', ''))
if cache_hit_rate < 80:
alerts.append(f"⚠️ 缓存命中率过低: {cache_hit_rate_str}")
except:
pass
# 检查数据库兜底频率
db_fallbacks = metrics.get('db_fallbacks', 0)
cache_hits = metrics.get('cache_hits', 0)
total_queries = db_fallbacks + cache_hits
if total_queries > 0:
fallback_rate = db_fallbacks / total_queries * 100
if fallback_rate > 20:
alerts.append(f"⚠️ 数据库兜底频率过高: {fallback_rate:.1f}%")
# 显示告警
if alerts:
print("🚨 性能告警:")
for alert in alerts:
print(f" {alert}")
def get_performance_report(self) -> Dict[str, Any]:
"""生成性能报告"""
if not self.history:
return {"error": "无历史数据"}
# 计算统计指标
total_records = len(self.history)
recent_records = self.history[-10:] if len(self.history) >= 10 else self.history
# 最新状态
latest = self.history[-1]
# 处理量趋势
if len(self.history) >= 2:
first = self.history[0]
last = self.history[-1]
processed_growth = last.get('total_processed', 0) - first.get('total_processed', 0)
else:
processed_growth = 0
# Redis连接稳定性
redis_stability = sum(1 for m in recent_records if m.get('bigscreen_redis_ok') and m.get('boot_redis_ok')) / len(recent_records) * 100
return {
'report_time': datetime.now().isoformat(),
'monitoring_duration': f"{total_records * self.interval}秒",
'total_records': total_records,
'latest_status': {
'total_processed': latest.get('total_processed', 0),
'cache_hit_rate': latest.get('cache_hit_rate', 'N/A'),
'local_cache_size': latest.get('local_cache_size', 0),
'redis_connections_ok': latest.get('bigscreen_redis_ok', False) and latest.get('boot_redis_ok', False)
},
'performance_trends': {
'processed_growth': processed_growth,
'redis_stability': f"{redis_stability:.1f}%",
},
'recommendations': self._generate_recommendations(recent_records)
}
def _generate_recommendations(self, recent_records: List[Dict]) -> List[str]:
"""生成性能建议"""
recommendations = []
if not recent_records:
return recommendations
# 检查缓存命中率
avg_cache_hits = sum(r.get('cache_hits', 0) for r in recent_records) / len(recent_records)
avg_db_fallbacks = sum(r.get('db_fallbacks', 0) for r in recent_records) / len(recent_records)
if avg_db_fallbacks > avg_cache_hits:
recommendations.append("建议检查Redis缓存配置,数据库兜底频率过高")
# 检查Redis连接稳定性
disconnection_count = sum(1 for r in recent_records
if not (r.get('bigscreen_redis_ok', True) and r.get('boot_redis_ok', True)))
if disconnection_count > 0:
recommendations.append("发现Redis连接不稳定,建议检查网络和Redis服务状态")
# 检查订阅者状态
subscriber_down_count = sum(1 for r in recent_records if not r.get('subscriber_running', True))
if subscriber_down_count > 0:
recommendations.append("Redis订阅者存在中断,建议检查订阅者服务状态")
# 检查本地缓存大小
latest_cache_size = recent_records[-1].get('local_cache_size', 0)
if latest_cache_size == 0:
recommendations.append("本地缓存为空,可能需要预加载常用客户的告警规则")
elif latest_cache_size > 100:
recommendations.append("本地缓存过大,建议优化缓存策略或增加内存限制")
if not recommendations:
recommendations.append("系统运行正常,无特殊建议")
return recommendations
def save_report_to_file(self, filename: str = None):
"""保存性能报告到文件"""
if not filename:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"alert_cache_performance_report_{timestamp}.json"
report = self.get_performance_report()
try:
with open(filename, 'w', encoding='utf-8') as f:
json.dump(report, f, ensure_ascii=False, indent=2, default=str)
print(f"📄 性能报告已保存: {filename}")
except Exception as e:
print(f"❌ 保存报告失败: {e}")
def main():
"""主函数"""
import argparse
parser = argparse.ArgumentParser(description="告警规则缓存性能监控")
parser.add_argument('-i', '--interval', type=int, default=10, help='监控间隔(秒)')
parser.add_argument('-d', '--duration', type=int, default=0, help='监控时长(秒),0表示持续监控')
parser.add_argument('-r', '--report', action='store_true', help='生成性能报告文件')
args = parser.parse_args()
monitor = AlertCacheMonitor(interval=args.interval)
try:
# 启动监控
monitor.start_monitoring()
if args.duration > 0:
# 定时监控
print(f"⏱️ 将监控{args.duration}秒后自动停止")
time.sleep(args.duration)
monitor.stop_monitoring()
# 生成报告
if args.report:
monitor.save_report_to_file()
else:
# 持续监控
print("⌨️ 按 Ctrl+C 停止监控")
try:
while monitor.running:
time.sleep(1)
except KeyboardInterrupt:
print("\n⏹️ 收到停止信号")
monitor.stop_monitoring()
if args.report:
monitor.save_report_to_file()
except Exception as e:
print(f"❌ 监控过程出现异常: {e}")
monitor.stop_monitoring()
print("👋 监控结束")
if __name__ == "__main__":
main()