news 2026/7/12 4:40:51

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux下Docker Compose里运行Redis内存数据库故障诊断脚本

在 Redis 所在服务器的 docker-compose 项目目录执行

chmod+x 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;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'CYAN='\033[0;36m'NC='\033[0m'# No Color# ---- 参数处理 ----CONTAINER="$1"if[-z"$CONTAINER"];then# 如果未指定容器名,尝试自动查找名称包含 "redis" 的容器(包括已停止的)CONTAINER=$(dockerps-a--format'{{.Names}}'|grep-iredis|head-1)if[-z"$CONTAINER"];thenecho-e"${RED}[错误] 未找到任何名称包含 redis 的容器,请手动指定。${NC}"echo"用法:$0<容器名或ID>"exit1fiecho-e"${YELLOW}[信息] 自动选择容器:${CONTAINER}${NC}"fi# 分隔线函数divider(){echo-e"\n${CYAN}============================================================${NC}"echo-e"${CYAN}$1${NC}"echo-e"${CYAN}============================================================${NC}\n"}# ---- 1. 容器基础状态检查 ----divider"1. 容器状态与退出码"echo"执行命令: docker ps -a --filter name=${CONTAINER}"dockerps-a--filter"name=${CONTAINER}"--format"table {{.Names}}\t{{.Status}}\t{{.Image}}\t{{.CreatedAt}}"# 提取退出码EXIT_CODE=$(dockerinspect-f'{{.State.ExitCode}}'"$CONTAINER"2>/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# 手工检验提示cat<<EOF${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. 容器日志分析 ----divider"2. Redis 容器日志 (最近 200 行)"echo"执行命令: docker logs --tail 200${CONTAINER}"dockerlogs--tail200"$CONTAINER"2>&1echo-e"\n${YELLOW}[分析提示]${NC}"echo"- 若日志末尾无任何错误且进程消失 -> 怀疑 OOM Kill"echo"- 若出现 'Can't 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}"echo"docker logs${CONTAINER}> redis_crash.log # 导出日志完整分析"# ---- 3. 宿主机 OOM Killer 日志检查 ----divider"3. 系统 OOM Killer 记录"echo"检查 dmesg 中与 OOM 相关的信息..."OOM_LOG=$(dmesg|grep-i"oom\|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-i"killed process"|tail-5fi# 检查系统日志 /var/log/messages(如果可读)if[-r/var/log/messages];thenecho-e"\n检查 /var/log/messages 中的 OOM 记录..."SYS_OOM=$(grep-i"out of memory\|oom-killer"/var/log/messages|tail-10)if[-n"$SYS_OOM"];thenecho-e"${RED}$SYS_OOM${NC}"fifiecho-e"\n${YELLOW}[手工检验步骤]${NC}"echo"1. 运行 free -h 查看内存使用历史趋势(需借助监控系统)"echo"2. 检查同宿主机其他容器内存占用: docker stats --no-stream"echo"3. 查看具体被杀进程的详细信息: dmesg | grep -A 10 'Killed process'"# ---- 4. Docker 资源限制与 OOMKilled 标记 ----divider"4. Docker 层面的资源限制与 OOMKilled 状态"OOMKILLED=$(dockerinspect-f'{{.State.OOMKilled}}'"$CONTAINER"2>/dev/null)echo"OOMKilled 标记:${OOMKILLED}"if["$OOMKILLED"="true"];thenecho-e"${RED}Docker 已确认此容器因 OOM 被杀死!${NC}"elseecho"Docker 未标记为 OOM(但系统日志可能仍有记录)"fiecho-e"\n内存限制 (如果设置):"dockerinspect-f'{{.HostConfig.Memory}}'"$CONTAINER"|awk'{if($1==0) 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"]&&echo"CPU 绑定:${CPUSET}"["$CPU_QUOTA"-ne0]&&echo"CPU Quota:${CPU_QUOTA}, Period:${CPU_PERIOD}(约$((CPU_QUOTA/CPU_PERIOD))核)"ficat<<EOF${YELLOW}[手工检验步骤]${NC}1. 检查 docker-compose.yml 中是否配置了 mem_limit, cpus, mem_reservation 等资源限制。 2. 确认宿主机总体内存是否过载: free -h 3. 如果限制过小,需调大或移除限制并重启服务。 EOF# ---- 5. 宿主机资源使用情况 ----divider"5. 宿主机资源全景"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-6cat<<EOF${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 持久化与配置检查(如果容器可执行命令) ----divider"6. Redis 持久化及配置探测"# 判断容器是否正在运行,尝试执行 redis-cliRUNNING=$(dockerinspect-f'{{.State.Running}}'"$CONTAINER"2>/dev/null)if["$RUNNING"="true"];thenecho-e"${GREEN}容器正在运行,尝试获取 Redis 配置...${NC}"REDIS_CLI="docker exec$CONTAINERredis-cli"echo-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"];thenecho"Redis 数据目录:$DIR"dockerexec"$CONTAINER"ls-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-E"save |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_DIR"2>/dev/nullfifificat<<EOF${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. 操作系统级参数检查 ----divider"7. 操作系统与内核参数检查"echo-e"${CYAN}--- 内存 overcommit 设置 ---${NC}"cat/proc/sys/vm/overcommit_memoryecho"0=启发式,1=允许 overcommit,2=禁止。建议值为 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,使用 date"dateecho"检查容器日志中是否有时间跳跃警告: 'The server detected a time jump'"echo-e"\n${CYAN}--- 文件系统只读检查 ---${NC}"mount|grep-E"(ro,|,ro)"|grep-v"tmpfs\|sysfs\|proc"||echo"未发现明显的只读挂载文件系统"cat<<EOF${YELLOW}[手工检验步骤]${NC}1. 如欲永久修改 overcommit: echo 'vm.overcommit_memory=1' >> /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. 网络与端口检查(若容器运行中) ----divider"8. 网络连通性简测"if["$RUNNING"="true"];thenecho"检查容器端口映射..."dockerport"$CONTAINER"2>/dev/nullecho-e"\n尝试本地连接 Redis..."REDIS_PORT=$(dockerport"$CONTAINER"6379/tcp2>/dev/null|awk-F:'{print $2}')if[-n"$REDIS_PORT"];thentimeout2bash-c"echo PING | nc -w 1 localhost$REDIS_PORT"2>/dev/null&&echo-e"${GREEN}Redis 响应正常${NC}"||echo-e"${RED}Redis 无响应${NC}"fielseecho"容器未运行,跳过网络测试。"fiecho-e"\n${YELLOW}[手工检验步骤]${NC}"echo"1. 检查 docker-compose 网络配置是否正常,是否因网络策略隔离。"echo"2. 在客户端机器测试: redis-cli -h <IP> -p <port> PING"# ---- 9. 总结与建议 ----divider"9. 排查摘要"echo"根据上述输出,请按以下线索聚焦问题:"echo"- 退出码 137 + OOMKilled=true → 内存限制过小或宿主机内存不足"echo"- 退出码 137 + dmesg 显示 Killed process → 宿主机 OOM,考虑调整限制或扩容"echo"- 日志显示 fork Cannot allocate memory → overcommit 为 0 或内存不足"echo"- 日志显示 MISCONF / disk I/O error → 磁盘满 / inode 满 / 只读"echo"- CPU 负载极高但未退出 → 资源争抢,需限制其他容器 CPU"echo"- 操作系统参数不当 (THP/overcommit) → 引发性能问题或 fork 失败"echo""echo"完成排查后,建议完善监控(内存、磁盘、Redis 连通性),并根据根因调整 Docker Compose 配置。"
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/12 4:37:44

Unity游戏架构实战:从模块化设计到性能优化的完整指南

1. 项目概述&#xff1a;为什么你需要一份“从零到架构”的指南&#xff1f;刚接触Unity&#xff0c;或者已经用它做过几个小Demo&#xff0c;但一遇到稍微复杂点的项目就感觉代码乱成一团&#xff0c;功能加不动也改不动&#xff1f;这感觉我太熟悉了。市面上大多数教程要么教…

作者头像 李华
网站建设 2026/7/12 4:36:53

等价类划分法实战:3变量场景下4种测试策略的用例数量与覆盖度对比

等价类划分法实战&#xff1a;3变量场景下4种测试策略的用例数量与覆盖度对比在软件测试领域&#xff0c;我们常常面临一个核心挑战&#xff1a;如何在有限的测试资源下&#xff0c;设计出既能高效发现缺陷又能全面覆盖各种场景的测试用例。等价类划分法作为黑盒测试的经典方法…

作者头像 李华
网站建设 2026/7/12 4:36:19

职场英语学习打卡Day007

&#x1f31f;计划1&#xff1a;&#x1f4c5;学习时间&#xff1a;2026.7.9 周四内容&#xff1a;视频06主题&#xff1a;English at Work Episode 6: Double-booked Offering to help消耗时长&#xff1a;学新 共 35 min▶ kind regards 此致&#xff08;用于书信或邮件结尾表…

作者头像 李华
网站建设 2026/7/12 4:35:42

UnityPy实战:Python自动化提取游戏资源与批量处理指南

1. 项目概述&#xff1a;为什么我们需要提取Unity游戏资源&#xff1f;在游戏开发、独立创作乃至数字艺术领域&#xff0c;我们常常会面临一个看似简单却异常棘手的问题&#xff1a;如何高效地获取并复用那些高质量的3D模型、贴图、动画和音效&#xff1f;无论是想学习优秀游戏…

作者头像 李华
网站建设 2026/7/12 4:32:58

x86-64 汇编实战:从 BombLab 6 个 Phase 解析函数调用与数据结构

x86-64 汇编实战&#xff1a;从 BombLab 6 个 Phase 解析函数调用与数据结构在计算机系统底层探索中&#xff0c;理解汇编语言与高级语言特性的对应关系是至关重要的技能。本文将以经典实验 BombLab 的 6 个 Phase 为案例&#xff0c;深入剖析 x86-64 汇编中的函数调用约定、栈…

作者头像 李华