#!/bin/bash # Redis 内存使用诊断脚本 # 分析 Redis 内存占用情况并提供优化建议 echo "==========================================" echo "Redis 内存使用诊断报告" echo "==========================================" echo "生成时间: $(date '+%Y-%m-%d %H:%M:%S')" echo "" # 检查 Redis 是否运行 if ! redis-cli ping > /dev/null 2>&1; then echo "错误: Redis 未运行或无法连接" exit 1 fi echo "1. 内存使用概览" echo "----------------------------------------" redis-cli INFO memory | grep -E "used_memory_human|used_memory_peak_human|maxmemory_human|mem_fragmentation_ratio|used_memory_rss_human" echo "" echo "2. 配置信息" echo "----------------------------------------" redis-cli CONFIG GET maxmemory | xargs printf "最大内存限制: %s = %s\n" redis-cli CONFIG GET maxmemory-policy | xargs printf "淘汰策略: %s = %s\n" echo "" echo "3. 数据库统计" echo "----------------------------------------" printf "Key 总数: " redis-cli DBSIZE echo "" echo "4. 各类型 Key 数量分布" echo "----------------------------------------" echo "注意: 此操作可能耗时较长..." # 统计不同前缀的 key 数量 declare -A key_counts while IFS= read -r key; do prefix=$(echo "$key" | cut -d':' -f1) ((key_counts[$prefix]++)) done < <(redis-cli --scan) echo "前缀统计:" for prefix in "${!key_counts[@]}"; do printf " %-30s %d 个\n" "$prefix:" "${key_counts[$prefix]}" done | sort -k2 -rn | head -20 echo "" echo "5. 最大的 Key (Top 10)" echo "----------------------------------------" redis-cli --bigkeys 2>/dev/null | grep -A 20 "Biggest" echo "" echo "6. 没有过期时间的 Key 统计" echo "----------------------------------------" no_ttl_count=0 total_keys=$(redis-cli DBSIZE | awk '{print $1}') # 采样检查 (最多检查1000个key) sample_size=1000 checked=0 no_ttl_samples="" while IFS= read -r key && [ $checked -lt $sample_size ]; do ttl=$(redis-cli TTL "$key") if [ "$ttl" = "-1" ]; then ((no_ttl_count++)) if [ $no_ttl_count -le 5 ]; then no_ttl_samples="$no_ttl_samples\n $key" fi fi ((checked++)) done < <(redis-cli --scan) if [ $checked -ge $total_keys ]; then echo "检查了全部 $total_keys 个 key" echo "没有过期时间的 key: $no_ttl_count 个 ($(awk "BEGIN {printf \"%.1f\", $no_ttl_count/$total_keys*100}")%)" else echo "采样检查了 $checked 个 key (总数: $total_keys)" echo "采样中没有过期时间的 key: $no_ttl_count 个 ($(awk "BEGIN {printf \"%.1f\", $no_ttl_count/$checked*100}")%)" fi if [ $no_ttl_count -gt 0 ]; then echo -e "示例:$no_ttl_samples" fi echo "" echo "7. 内存使用率评估" echo "----------------------------------------" used_memory=$(redis-cli INFO memory | grep "used_memory:" | cut -d':' -f2 | tr -d '\r') max_memory=$(redis-cli CONFIG GET maxmemory | tail -1 | tr -d '\r') if [ "$max_memory" = "0" ]; then echo "⚠️ 警告: 未设置最大内存限制!" echo " 建议: 执行 ./configure_redis_memory.sh 设置内存限制" else usage_percent=$(awk "BEGIN {printf \"%.1f\", $used_memory/$max_memory*100}") echo "内存使用率: $usage_percent%" if (( $(echo "$usage_percent > 90" | bc -l) )); then echo "🔴 严重: 内存使用率超过 90%!" echo " 建议: 立即清理缓存或增加内存限制" elif (( $(echo "$usage_percent > 80" | bc -l) )); then echo "🟡 警告: 内存使用率超过 80%" echo " 建议: 清理不必要的缓存" elif (( $(echo "$usage_percent > 70" | bc -l) )); then echo "🟢 正常: 内存使用率在合理范围内" else echo "🟢 良好: 内存使用率较低" fi fi echo "" echo "8. 优化建议" echo "----------------------------------------" # 检查是否设置了最大内存 if [ "$max_memory" = "0" ]; then echo "✓ 设置 Redis 最大内存限制" echo " 命令: redis-cli CONFIG SET maxmemory 512mb" fi # 检查是否有很多没有过期时间的 key if [ $no_ttl_count -gt $(($checked / 2)) ]; then echo "✓ 大量 key 没有过期时间,建议设置 TTL" echo " 自动修复: 应用中的 RedisCacheCleanupTask 会自动处理" fi # 检查淘汰策略 eviction_policy=$(redis-cli CONFIG GET maxmemory-policy | tail -1 | tr -d '\r') if [ "$eviction_policy" = "noeviction" ]; then echo "✓ 当前淘汰策略为 noeviction,建议改为 volatile-lru" echo " 命令: redis-cli CONFIG SET maxmemory-policy volatile-lru" fi echo "" echo "==========================================" echo "诊断完成!" echo "==========================================" echo "" echo "快速操作:" echo "1. 配置 Redis 内存: ./configure_redis_memory.sh" echo "2. 清理 Redis 数据: redis-cli FLUSHDB (谨慎!)" echo "3. 重启应用以应用新的缓存策略"