Linux下Docker Compose里运行Redis内存数据库故障诊断脚本

发布时间:2026/7/12 4:41:01
Linux下Docker Compose里运行Redis内存数据库故障诊断脚本 在 Redis 所在服务器的 docker-compose 项目目录执行chmodx redis_troubleshoot.sh指定容器名sudo./redis_troubleshoot.sh myapp_redis_1#!/bin/bash# # Redis 意外中断系统化排查脚本 (Docker Compose 环境)# 适用场景Redis 容器异常退出、无响应需要快速定位根因# 运行权限建议 root 或具有 sudo 权限部分命令需要读取系统日志和内核信息# 使用方法bash redis_troubleshoot.sh [容器名称或ID]# # 颜色定义RED\033[0;31mGREEN\033[0;32mYELLOW\033[1;33mCYAN\033[0;36mNC\033[0m# No Color# ---- 参数处理 ----CONTAINER$1if[-z$CONTAINER];then# 如果未指定容器名尝试自动查找名称包含 redis 的容器包括已停止的CONTAINER$(dockerps-a--format{{.Names}}|grep-iredis|head-1)if[-z$CONTAINER];thenecho-e${RED}[错误] 未找到任何名称包含 redis 的容器请手动指定。${NC}echo用法:$0容器名或IDexit1fiecho-e${YELLOW}[信息] 自动选择容器${CONTAINER}${NC}fi# 分隔线函数divider(){echo-e\n${CYAN}${NC}echo-e${CYAN}$1${NC}echo-e${CYAN}${NC}\n}# ---- 1. 容器基础状态检查 ----divider1. 容器状态与退出码echo执行命令: docker ps -a --filter name${CONTAINER}dockerps-a--filtername${CONTAINER}--formattable {{.Names}}\t{{.Status}}\t{{.Image}}\t{{.CreatedAt}}# 提取退出码EXIT_CODE$(dockerinspect-f{{.State.ExitCode}}$CONTAINER2/dev/null)if[$?-ne0];thenecho-e${RED}[错误] 无法获取容器信息请确认容器名称是否正确。${NC}exit1fiecho-e\n退出码:${EXIT_CODE}case$EXIT_CODEin0)echo-e${GREEN}正常退出 (0)${NC};;137)echo-e${RED}收到 SIGKILL极可能是 OOM 或资源限制 (137)${NC};;139)echo-e${RED}段错误 SIGSEGV可能是程序 bug (139)${NC};;143)echo-e${RED}收到 SIGTERM正常终止信号 (143)${NC};;255)echo-e${RED}容器启动失败 (255)${NC};;*)echo-e${YELLOW}其他退出码需结合日志分析${NC};;esac# 手工检验提示catEOF${YELLOW}[手工检验步骤]${NC}1. 确认容器启动命令和 Docker Compose 服务名: docker inspect${CONTAINER}| grep -i compose 2. 查看 Docker Compose 文件: cat docker-compose.yml | grep -A 10 redis 3. 如果是重启策略导致频繁重启留意 STATUS 中的 Restarting 信息。 EOF# ---- 2. 容器日志分析 ----divider2. Redis 容器日志 (最近 200 行)echo执行命令: docker logs --tail 200${CONTAINER}dockerlogs--tail200$CONTAINER21echo-e\n${YELLOW}[分析提示]${NC}echo- 若日志末尾无任何错误且进程消失 - 怀疑 OOM Killecho- 若出现 Cant save in background: fork: Cannot allocate memory - 宿主机内存不足fork 失败echo- 若出现 MISCONF Redis is configured to save RDB snapshots... - 磁盘空间满或权限问题echo- 若出现 I/O error 或 Permission denied - 磁盘异常或挂载卷权限错误# 手工检验将日志保存到文件用编辑器仔细查看echo-e\n${YELLOW}[手工检验步骤]${NC}echodocker logs${CONTAINER} redis_crash.log # 导出日志完整分析# ---- 3. 宿主机 OOM Killer 日志检查 ----divider3. 系统 OOM Killer 记录echo检查 dmesg 中与 OOM 相关的信息...OOM_LOG$(dmesg|grep-ioom\|out of memory\|killed process|tail-20)if[-z$OOM_LOG];thenecho-e${GREEN}未在 dmesg 中发现近期 OOM 记录。${NC}elseecho-e${RED}发现以下 OOM 相关记录${NC}echo$OOM_LOG# 进一步查看被杀进程名echo-e\n${YELLOW}被杀进程列表${NC}dmesg|grep-ikilled process|tail-5fi# 检查系统日志 /var/log/messages如果可读if[-r/var/log/messages];thenecho-e\n检查 /var/log/messages 中的 OOM 记录...SYS_OOM$(grep-iout of memory\|oom-killer/var/log/messages|tail-10)if[-n$SYS_OOM];thenecho-e${RED}$SYS_OOM${NC}fifiecho-e\n${YELLOW}[手工检验步骤]${NC}echo1. 运行 free -h 查看内存使用历史趋势需借助监控系统echo2. 检查同宿主机其他容器内存占用: docker stats --no-streamecho3. 查看具体被杀进程的详细信息: dmesg | grep -A 10 Killed process# ---- 4. Docker 资源限制与 OOMKilled 标记 ----divider4. Docker 层面的资源限制与 OOMKilled 状态OOMKILLED$(dockerinspect-f{{.State.OOMKilled}}$CONTAINER2/dev/null)echoOOMKilled 标记:${OOMKILLED}if[$OOMKILLEDtrue];thenecho-e${RED}Docker 已确认此容器因 OOM 被杀死${NC}elseechoDocker 未标记为 OOM但系统日志可能仍有记录fiecho-e\n内存限制 (如果设置)dockerinspect-f{{.HostConfig.Memory}}$CONTAINER|awk{if($10) print 未设置内存限制; else printf 限制: %.2f MB\n, $1/1024/1024}echo-e\nCPU 限制 (如果设置)CPU_QUOTA$(dockerinspect-f{{.HostConfig.CpuQuota}}$CONTAINER)CPU_PERIOD$(dockerinspect-f{{.HostConfig.CpuPeriod}}$CONTAINER)CPUSET$(dockerinspect-f{{.HostConfig.CpusetCpus}}$CONTAINER)if[$CPU_QUOTA-eq0][$CPU_PERIOD-eq0][-z$CPUSET];thenecho未设置 CPU 限制else[-n$CPUSET]echoCPU 绑定:${CPUSET}[$CPU_QUOTA-ne0]echoCPU Quota:${CPU_QUOTA}, Period:${CPU_PERIOD}(约$((CPU_QUOTA/CPU_PERIOD))核)ficatEOF${YELLOW}[手工检验步骤]${NC}1. 检查 docker-compose.yml 中是否配置了 mem_limit, cpus, mem_reservation 等资源限制。 2. 确认宿主机总体内存是否过载: free -h 3. 如果限制过小需调大或移除限制并重启服务。 EOF# ---- 5. 宿主机资源使用情况 ----divider5. 宿主机资源全景echo-e${CYAN}--- 内存 ---${NC}free-hecho-e\n${CYAN}--- 磁盘空间 ---${NC}df-hecho-e\n${CYAN}--- inode 使用 ---${NC}df-iecho-e\n${CYAN}--- CPU 负载 ---${NC}uptimeecho-e\nCPU 核心数:$(nproc)echo-e\n当前占用 CPU 最高的进程psaux--sort-%cpu|head-6catEOF${YELLOW}[手工检验步骤]${NC}1. 重点关注 /data 分区或 Redis 持久化目录的使用率是否接近 100%inode 是否耗尽。 2. 若磁盘满清理旧 AOF/RDB 文件、日志或扩容。 3. 若 inode 满检查是否有海量小文件如 Session 文件: find /data -xdev -type f | wc -l 4. 检查 Redis 持久化目录权限: ls -ld /path/to/redis/data EOF# ---- 6. Redis 持久化与配置检查如果容器可执行命令 ----divider6. Redis 持久化及配置探测# 判断容器是否正在运行尝试执行 redis-cliRUNNING$(dockerinspect-f{{.State.Running}}$CONTAINER2/dev/null)if[$RUNNINGtrue];thenecho-e${GREEN}容器正在运行尝试获取 Redis 配置...${NC}REDIS_CLIdocker exec$CONTAINERredis-cliecho-e\n--- Redis maxmemory ---$REDIS_CLICONFIG GET maxmemory2/dev/null||echo无法连接echo-e\n--- 持久化配置 ---$REDIS_CLICONFIG GET save2/dev/null$REDIS_CLICONFIG GET appendonly2/dev/null$REDIS_CLICONFIG GETdir2/dev/nullecho-e\n--- 持久化文件状态 ---DIR$($REDIS_CLI CONFIG GETdir2/dev/null|tail-1)if[-n$DIR];thenechoRedis 数据目录:$DIRdockerexec$CONTAINERls-lh$DIR/*.rdb$DIR/*.aof2/dev/null||echo未找到 RDB/AOF 文件fielseecho-e${YELLOW}容器已停止无法直接执行 redis-cli。尝试从挂载卷推断配置。${NC}# 获取容器的挂载信息MOUNTS$(dockerinspect-f{{range .Mounts}}{{.Source}} - {{.Destination}}{{\n}}{{end}}$CONTAINER)if[-n$MOUNTS];thenecho-e挂载点:\n$MOUNTS# 尝试在常见路径查找 redis.confCONF_MOUNT$(echo$MOUNTS|grep/usr/local/etc/redis|awk{print $1})if[-n$CONF_MOUNT][-f$CONF_MOUNT/redis.conf];thenecho-e\n${GREEN}找到 Redis 配置文件:${CONF_MOUNT}/redis.conf${NC}grep-Esave |appendonly|maxmemory|dir $CONF_MOUNT/redis.conf|grep-v^#fi# 尝试在数据目录查找持久化文件DATA_DIR$(echo$MOUNTS|grep/data|awk{print $1})if[-n$DATA_DIR][-d$DATA_DIR];thenecho-e\n数据目录内容:ls-lh$DATA_DIR/*.rdb$DATA_DIR/*.aof2/dev/null||echo未发现 RDB/AOF 文件echo该目录磁盘使用:du-sh$DATA_DIR2/dev/nullfifificatEOF${YELLOW}[手工检验步骤]${NC}1. 检查 Redis 配置文件是否设置 stop-writes-on-bgsave-error yes默认如果是磁盘满时会拒绝写入。 2. 若容器停止直接检查宿主机上的持久化目录如 ./data/redis/大小和权限。 3. 如果 AOF 文件过大考虑设置 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size。 EOF# ---- 7. 操作系统级参数检查 ----divider7. 操作系统与内核参数检查echo-e${CYAN}--- 内存 overcommit 设置 ---${NC}cat/proc/sys/vm/overcommit_memoryecho0启发式1允许 overcommit2禁止。建议值为 1避免 fork 失败echo-e\n${CYAN}--- 透明大页 (THP) 状态 ---${NC}if[-f/sys/kernel/mm/transparent_hugepage/enabled];thencat/sys/kernel/mm/transparent_hugepage/enabledecho建议值为 [never]否则可能导致延迟和内存碎片elseecho无法检测 THP非标准路径fiecho-e\n${CYAN}--- 系统时间状态 ---${NC}timedatectl status2/dev/null||echo未安装 timedatectl使用 datedateecho检查容器日志中是否有时间跳跃警告: The server detected a time jumpecho-e\n${CYAN}--- 文件系统只读检查 ---${NC}mount|grep-E(ro,|,ro)|grep-vtmpfs\|sysfs\|proc||echo未发现明显的只读挂载文件系统catEOF${YELLOW}[手工检验步骤]${NC}1. 如欲永久修改 overcommit: echo vm.overcommit_memory1 /etc/sysctl.conf sysctl -p 2. 关闭 THP: echo never /sys/kernel/mm/transparent_hugepage/enabled (临时)永久需配置 tuned 或 grub。 3. 如果时间不同步检查 NTP 服务: systemctl status chronyd 或 ntpq -p 4. 如果怀疑文件系统只读导致持久化失败尝试 touch /data/test 测试写入。 EOF# ---- 8. 网络与端口检查若容器运行中 ----divider8. 网络连通性简测if[$RUNNINGtrue];thenecho检查容器端口映射...dockerport$CONTAINER2/dev/nullecho-e\n尝试本地连接 Redis...REDIS_PORT$(dockerport$CONTAINER6379/tcp2/dev/null|awk-F:{print $2})if[-n$REDIS_PORT];thentimeout2bash-cecho PING | nc -w 1 localhost$REDIS_PORT2/dev/nullecho-e${GREEN}Redis 响应正常${NC}||echo-e${RED}Redis 无响应${NC}fielseecho容器未运行跳过网络测试。fiecho-e\n${YELLOW}[手工检验步骤]${NC}echo1. 检查 docker-compose 网络配置是否正常是否因网络策略隔离。echo2. 在客户端机器测试: redis-cli -h IP -p port PING# ---- 9. 总结与建议 ----divider9. 排查摘要echo根据上述输出请按以下线索聚焦问题echo- 退出码 137 OOMKilledtrue → 内存限制过小或宿主机内存不足echo- 退出码 137 dmesg 显示 Killed process → 宿主机 OOM考虑调整限制或扩容echo- 日志显示 fork Cannot allocate memory → overcommit 为 0 或内存不足echo- 日志显示 MISCONF / disk I/O error → 磁盘满 / inode 满 / 只读echo- CPU 负载极高但未退出 → 资源争抢需限制其他容器 CPUecho- 操作系统参数不当 (THP/overcommit) → 引发性能问题或 fork 失败echoecho完成排查后建议完善监控内存、磁盘、Redis 连通性并根据根因调整 Docker Compose 配置。