资讯详情

资讯详情

Ubuntu Redis故障排查:从安装启动到连接运行期的完整指南

Ubuntu上跑Redis大部分时候是很省心的apt装好、改两行配置、service一拉就起来了。但真到出问题的时候那些报错往往不会直接告诉你“哪里错了”而是要一层层剥开看。这篇文章我按自己这几年在Ubuntu上排查Redis故障的实际经验把最常见的坑按阶段整理出来从安装、启动、连接到运行期内存和性能问题每一类都写了具体的报错特征、排查思路和最终解决办法。不管你是刚在虚拟机里装好Ubuntu准备练手Redis还是已经在生产环境上被Redis的某个诡异问题折磨了一下午这篇应该都能帮你少走几步弯路。1. 安装阶段的故障多数人还没跑到Redis就已经卡住了很多人以为Redis的故障都发生在运行期其实我发现相当一部分问题在安装阶段就埋下了。而且安装阶段出的问题往往最让人窝火——明明照着教程一步步敲结果第一步就报错。这块我拆成三个最常见的场景讲。1.1 apt搜不到redis-server包源的问题怎么定位在Ubuntu上装Redis最正统的方式就是apt install redis-server。但很多人敲完这条命令会看到类似这样的提示E: Unable to locate package redis-server第一次遇到这个报错十有八九会怀疑是不是自己把包名记错了。其实Ubuntu官方源里一直都有redis-server这个包真正的原因是软件源列表还没更新。新装的Ubuntu系统、或者刚把Ubuntu版本升级过比如从22.04升到24.04本地的包索引还是旧的需要先跑一次sudo apt update如果apt update之后还是找不到那就要检查一下是不是用了非官方源或者把某些第三方源给禁掉了。可以看看/etc/apt/sources.list和/etc/apt/sources.list.d/目录下的文件确认deb开头的行没有被注释掉。我自己遇到过一种情况为了装某个特定软件把整个universe仓库注释掉了结果Redis的包也跟着消失了因为redis-server在Ubuntu源里属于universe组件。还有一种情况是在Ubuntu 24.04上装Redis默认源里那个版本可能不是你想要的。这时候如果你有版本洁癖用Redis官方提供的ppa:redislabs/redis源也是可以的但优先级我还是建议先试官方源除非你真的需要新版本特性。1.2 编译安装时gcc报错和make test失败的真相有些场景下必须走编译安装比如你要在ARM架构的板子上跑Redis或者需要打特定补丁。源码编译最常见的报错是make: gcc: Command not found make: *** [Makefile:322: adlist.o] Error 1原因很简单Ubuntu最小化安装默认不带build工具链。解决办法是安装build-essentialsudo apt install build-essential这个包会把gcc、g、make这些一次性装齐。真正麻烦的是make test失败。很多人编译完之后习惯跑一遍测试套件结果看到failed用例就开始慌。说实话make test在资源受限的环境下比如1G内存的云主机、或者虚拟机里分配的内存太小出现个别测试失败并不代表编译出来的Redis二进制不能用。最常见的是valgrind相关的测试跳过以及一些和maxmemory有关的慢测试超时。我建议的做法是编译通过src/redis-server能正常启动再跑几个基本命令验证读写就足够了。不必被make test的失败吓到。1.3 版本选择与残留配置的两个隐藏坑很多新手会在Windows上先用着Redis然后转到Ubuntu发现自己装出来的版本和之前用的不太一样。这里提醒一句Ubuntu官方源的Redis版本通常比Windows下的最新版落后几个小版本但核心功能和命令接口是基本一致的。除非你的项目代码用到了特别新的命令否则不用太纠结版本号。另一个隐藏坑是卸载残留。你之前可能用apt install redis-server装过后来卸载了sudo apt remove redis-server这个命令不会删除/etc/redis/redis.conf配置文件和数据目录/var/lib/redis。等你重新安装的时候新版本会直接沿用旧的配置文件如果配置里的某些参数在新版本里已经被改名或废弃Redis启动时就会报错或表现异常。所以重装前要么把旧配置清掉sudo apt purge redis-server要么至少把/etc/redis/redis.conf备份后重置。这一点在生产环境的机器上尤其重要我见过因为旧配置里一个过时的save参数导致重启后持久化行为异常的情况。2. 服务启动与守护进程systemd、日志文件、端口占用一个都不能少安装完成后启动阶段是第二个事故高发区。这个阶段的报错信息通常会在systemctl的状态输出里或者躺在Redis自己的日志文件里。很多人一看systemctl status redis里面是红色的就慌了其实大部分问题原因很直接。2.1 前台运行与systemd的“恩怨”Redis在Ubuntu上通过apt安装后默认是由systemd管理的配置文件/etc/redis/redis.conf里有一项daemonize no我之前见过不少人在使用源码编译方式装Redis时习惯性地把daemonize改成yes因为在传统SysV init时代这是标准做法。但如果你同时用systemd的redis.service单元文件来管理它Ubuntu apt安装的Redis默认就是就会出现一个很经典的问题systemd认为服务没有正常进入运行状态或者进程莫名其妙退出。解释一下为什么systemd需要进程在前台运行这样才能监控它的状态。如果你让Redis自己daemonize成后台进程systemd会认为主进程已经退出从而尝试重启服务或者直接报告服务启动失败。排查方法先看redis.conf里的daemonize是不是yes如果是改成no然后sudo systemctl restart redis。如果你确实需要Redis在后台运行但又不希望通过systemd管理那可以直接用redis-server /path/to/redis.conf这样的方式来启动但那样的话进程崩溃后不会自动拉起生产环境不建议这么干。2.2 “Cant open the log file”这类权限问题的根因日志文件打不开是启动阶段最常见的一类报错。具体表现是# systemctl status redis ● redis-server.service - Advanced key-value store Loaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) Main PID: 12345 (codeexited, status1/FAILURE) ... redis-server[12345]: # Creating Server TCP listening socket *:6379: bind: Address already in use上面这个是端口占用下面这个才是日志权限问题的典型redis-server[12345]: Cant open the log file: /var/log/redis/redis-server.log: Permission denied日志目录权限不对通常发生在你把redis.conf里的logfile自定义到了一个非默认路径但没给对权限。Redis默认以redis用户运行apt安装会在系统里自动创建redis用户如果logfile指向的目录对redis用户没有写权限启动就会失败。解决办法sudo mkdir -p /var/log/redis sudo chown redis:redis /var/log/redis sudo chmod 755 /var/log/redis这里要注意chmod 755意味着只有属主能写正好够用。如果你图省事直接chmod 777也能跑起来但会让系统审计变得难堪不推荐。2.3 端口被占用如何干净利落地处理bind: Address already in use这个报错原因有三个方向一是你自己之前起过了一个redis-server进程忘了停二是同一个端口被别的服务占用比如另一个Redis实例、或者某些开发框架自带的缓存服务三是Redis异常崩溃后socket文件没有被清理。排查步骤# 看看端口到底被谁占着 sudo ss -tlnp | grep 6379 # 如果是redis自己之前的进程 ps -ef | grep redis sudo kill PID # 如果你确实想停掉所有redis进程 sudo systemctl stop redis sudo pkill -f redis-server如果是socket文件残留导致的检查/var/run/redis/redis-server.sock这种路径把它删掉再启动。一个重要提醒如果ss -tlnp显示6379端口被一个不属于redis的进程占用先别急着kill。有些软件会在随机端口上监听但也有一些会把Redis当作内部组件启动。比如某些PHP开发环境、Node.js的某些缓存中间件会在你不知情的时候占住6379。这时候搞清楚是谁在监听比直接kill更重要。3. 连接不上与超时问题十个案例里八个是这三类原因到了连接阶段故障的症状就开始变得千奇百怪了redis-cli能连上但远程工具连不上或者说刚才还能连突然一下超时还有的是重启之后就再也连不上了。这类问题我总结出一个规律绝大多数都是配置问题而不是Redis进程本身的问题。3.1 bind地址和protected-mode远程连不上的头号元凶Ubuntu上apt安装的Redis默认配置非常保守bind 127.0.0.1 -::1 protected-mode yes这组配置的含义是只监听本机回环地址同时开启保护模式。效果就是——只有本机上的程序可以通过localhost连接任何外部IP都会被拒绝。如果你在自己的电脑上装了Ubuntu虚拟机然后想从宿主机Windows或者macOS上用Redis可视化工具连接你会发现怎么配都连不上报错往往是Could not connect to Redis at IP:6379: Connection refused这时你需要在redis.conf里改两处bind 0.0.0.0 -::1 protected-mode no改完之后重启sudo systemctl restart redisbind 0.0.0.0的意思是监听所有网络接口。但这有一个非常直接的副作用任何能通过TCP访问到你主机的人都可以尝试连接这个Redis实例。所以我强烈建议如果你只是开发环境用可以这么改如果是生产环境千万别用protected-mode no正确的做法是下面这样bind写具体的内网IP而不是0.0.0.0protected-mode保持yes通过防火墙规则限制来源IP实际上还有一个很多人不知道的细节protected-mode只在“没有显式设置bind”或“没有设置密码”时生效。也就是说如果你设置了requirepass即使protected-mode yes带了密码的连接请求还是可以进来的。这个逻辑很多人搞反以为设了密码还要先关保护模式才能远程连。不是的设了密码之后保护模式根本不会阻止你。3.2 防火墙和云平台安全组Ubuntu本机不代表整个链路都通了哪怕你bind 0.0.0.0也改了、protected-mode no也设了外部工具还是连不上那就要考虑中间链路的问题了。Ubuntu默认是没开防火墙的但也保不齐有些云镜像预装了ufw。检查一下sudo ufw status如果状态是active那就需要放行6379端口sudo ufw allow 6379/tcp另外如果你用的是云服务器那还要登录云控制台在安全组规则里放行TCP 6379端口。这个安全组是在操作系统层面之外的即使Ubuntu本机防火墙没开安全组不放行外部同样连不进来。很多人折腾半天最后发现是安全组只开了22和80端口Redis的6379压根没放行。以我个人的经验这类问题的排查顺序应该是Ubuntu本机ss -tlnp确认Redis监听在非回环地址上本机redis-cli ping确认服务正常同一局域网内另一台机器telnet IP 6379确认端口通不通如果跨公网检查云安全组这样一层层排查很快就能定位到底卡在哪一环。3.3 可视化客户端连接报超时Lettuce超时之外的几个实战方向热词里有一条很典型的报错类似redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException。这通常出现在Java项目用Spring Data Redis Lettuce连接Redis时。这个问题的本质是客户端发了命令但在超时时间内没有收到响应。常见的诱因有三个第一Redis服务端阻塞。比如某个慢命令KEYS *把Redis单线程卡住了所有后续请求排队自然就超时了。这个可以通过redis-cli --latency来观察延迟或者用SLOWLOG GET看慢日志确认。第二网络链路本身有丢包或高延迟。比如跨公网直连Redis公网质量又不好握手阶段就超时了。这种情况建议在客户端配置里适当调大timeout参数同时检查从应用服务器到Redis服务器的延迟情况。第三连接池配置过小。Lettuce默认的池化配置在高并发时容易把连接耗尽新请求去获取连接时也要等待表现也是超时。这个通常在报错堆栈里能看到更详细的redisConnection相关异常。要提一下的是像“Another Redis Desktop Manager”这类可视化客户端连接超时倒不一定是你Redis的问题。很多可视化工具默认走的是SSH隧道方式连接云服务器SSH连不通那自然就超时了。这时候先在工具里选“直连”模式试试如果能连上说明问题出在SSH隧道配置上。4. 运行期内存与性能故障最容易被低估的一类坑Redis跑起来之后故障模式就变得更隐蔽了——服务没有宕机命令也没有报错但响应越来越慢内存占用越来越高有时候还会出现莫名其妙的key丢失。这一节我挑几个实际案例里出现频率最高的问题来讲。4.1 maxmemory设置不当Redis秒变“只读”数据库如果Redis没设置maxmemory那么它会一直使用内存直到系统内存耗尽然后触发OOM Kill。这时候的表现就是Redis进程直接消失日志里可以看到系统层的Killed记录。如果设置了maxmemory但是maxmemory-policy设置成了noeviction那当内存到达上限后所有写操作都会直接报错OOM command not allowed when used memory maxmemory.这个报错很直白内存已经满了而且不允许淘汰任何key所以写不了。解决办法是结合业务模式选择合适的淘汰策略策略行为适用场景noeviction内存满后写操作直接报错缓存类业务不推荐但某些用Redis存关键数据的场景宁可报错也不能丢数据allkeys-lru所有key按LRU算法淘汰最久没用的最常见的缓存场景allkeys-random随机淘汰任意key对key访问频率不敏感的场景volatile-lru仅在设置了过期时间的key中按LRU淘汰有部分key不能丢、部分key可以淘汰时volatile-ttl在有过期时间的key中优先淘汰剩余寿命短的有些key更早该过期但你还没来得及清理的场景这里有一个很重要、但是很多人忽略的知识点如果你设置maxmemory-policy allkeys-lru意味着Redis会主动淘汰你的key哪怕那些key根本没有设置过期时间。这在某些业务场景下会造成“数据莫名消失”的假象。所以选策略之前一定要想清楚这些key能不能丢。我自己在实践里会把maxmemory设置为可用内存的60%-70%左右并且预留足够给系统本身和其他进程的空间。比如一台4G内存的机器Redis的maxmemory我会设为2gb再配合allkeys-lru系统才能稳定运转。4.2 大key和慢命令Redis性能杀手往往藏在业务代码里在Ubuntu上跑着跑着突然某个命令卡了几秒然后一堆调用方跟着超时这种故障排查起来也很经典。根源往往是大key和慢查询。如何定位Redis自带了两个很好用的工具。# 1. 查看当前实例的慢查询日志默认超过10000微秒会记录 redis-cli SLOWLOG GET 100 # 2. 或用redis-cli 的--bigkeys参数扫描大key redis-cli --bigkeysSLOWLOG GET的输出里能看到具体是哪个命令执行时间超过了阈值。我见过一个案例某项目用SMEMBERS读取一个包含几十万元素的Set这个命令在Redis单线程模型里执行期间其他所有命令都处于等待状态。排查时就发现慢日志里全是SMEMBERS。怎么解决这类问题的本质是数据结构使用不当。大key的解决方案通常是改用SSCAN、HSCAN、ZSCAN这类游标式命令分批读取不要一次性拉全量如果单个key太大考虑拆分或者改用别的存储方案对耗时操作设置合理的timeout避免客户端无限等待另外KEYS *命令在生产环境是禁忌热度词里能看到很多人在搜redis命令其中肯定有不少是新手在拿KEYS做测试。这命令在key数量大时会严重阻塞Redis。要遍历key时用SCAN代替KEYS这一点再强调都不为过。4.3 AOF和RDB持久化故障重启后数据少了不是玄学还有一类故障尤其让人崩溃Redis重启之后数据少了。如果你没配置持久化那Redis本来就是个纯缓存重启丢数据是应当的不用惊讶。问题在于很多人以为默认配置有持久化但其实不是。Ubuntu apt安装的Redis默认配置是这样的/etc/redis/redis.confsave 900 1 save 300 10 save 60 10000 appendonly no这三个save配置的含义是900秒内至少有1个key变更触发一次RDB快照保存300秒内至少有10个key变更触发RDB60秒内至少有10000个key变更触发RDB可以看到这种快照式的持久化是有时间窗口的。如果Redis在内两次快照之间崩溃那么这段期间写入的数据就会丢失。要降低丢失窗口就要开启AOFappendonly yes appendfsync everysecappendfsync everysec是最平衡的配置最多丢1秒的数据性能开销也比较小。如果是严格的数据安全场景可以设always但这样每个写命令都会触发一次磁盘同步性能下降比较明显。关于持久化有两个常见的坑第一个坑AOF文件损坏。Redis启动时如果检测到AOF文件不完整或损坏会拒绝启动并提示。Bad file format reading the append only file这时候可以用自带的修复工具redis-check-aof --fix /var/lib/redis/appendonly.aof第二个坑RDB和AOF同时开启时Redis重启后优先加载AOF文件因为AOF的日志更完整。但很多人会改完appendonly yes之后发现重启后加载的还是老数据怀疑配置没生效。实际上是因为AOF文件是空的Redis会优先用空AOF而不是加载之前已经存在的RDB快照。刚开启AOF的那一瞬间AOF文件还没记录任何数据此时重启Redis它会加载AOF——空文件——于是数据“消失”了。解决技巧在开启AOF之前先手动触发一次BGSAVE生成最新的RDB然后在开启appendonly yes后立刻执行一次热切换。Redis其实在运行期就能动态开启AOFredis-cli CONFIG SET appendonly yes这样会在不重启的情况下原地生成AOF文件并从RDB中把已有数据迁移进去避免重启丢数据。这一点非常实用生产环境要开AOF时强烈推荐这样操作而不是改完配置文件直接重启。5. 安全与权限Redis默认配置在Ubuntu上其实是“裸奔”的最后这一节必须讲讲安全因为我觉得这是大家在排故障时最容易忽略的方向。很多Redis故障排查到最后发现是被人攻击了。5.1 未授权访问最容易被扫到然后Redis就“不是你的了”Redis早期版本默认没有密码也没有保护模式很多教程尤其是老教程让人直接启动就能用。这在公网环境下极为危险。如果有人扫到了你开放的6379端口而Redis没设密码攻击者可以直接执行FLUSHALL清空你的所有数据通过CONFIG SET dir、CONFIG SET dbfilename配合SAVE写入webshell拿到服务器权限这类攻击在公网上的扫描器里非常常见。我见过不少人在云服务器上Open了Redis端口第二天发现数据全没了只有一条FLUSHALL之后的提示。最小安全基线# 1. 设置密码 requirepass 你的强密码 # 2. 不要监听公网地址 bind 127.0.0.1 你的内网IP # 3. 如果必须公网访问安全组/防火墙限制来源IP # 4. 高危命令建议重命名或者直接禁用 rename-command FLUSHALL rename-command CONFIG rename-command EVAL 设置requirepass之后别忘了所有可视化客户端和项目代码里的连接配置都要同步加上密码否则会报NOAUTH Authentication required。这个错误在开发联调阶段极其常见Redis配了密码但客户端配置文件没更新。5.2 可视化工具的密码与认证兼容问题热度词里有不少人在搜“Another Redis Desktop Manager”和“Redis Desktop Manager”。这类工具在使用密码连接时有一个小坑有些版本默认会勾选“Use SSL/TLS”如果你没有在Redis服务端配置TLS证书连接时就会报错或者直接超时。如何区分看报错内容——如果提到handshake、SSL、TLS相关字样基本就是这个问题。解决办法是在工具的连接配置里把SSL/TLS选项关掉或者选“No Encryption”。另一个小坑是Redis的密码在redis-cli里可以用-a参数指定但这会触发一个Warning提示密码会暴露在进程列表里。如果只是本地开发无所谓但在涉及安全的场合更推荐用环境变量的方式REDISCLI_AUTH你的密码 redis-cli同时在可视化工具里密码是正常填写的一般不会踩这个坑但如果你是写脚本去调用就要注意不要在命令行里直接拼密码了。5.3 Ubuntu系统层面的加固超出Redis本身的一个建议最后聊一个不完全是Redis故障、但和“Ubuntu上Redis安全”强相关的问题。我在生产环境排查Redis故障时经常顺手发现系统里一堆不相关的风险点。如果你已经把Redis开放到非本机监听那我建议至少做这几件事用ufw或云安全组把6379端口限制到只有需要的IP能访问定期更新系统补丁sudo apt update sudo apt upgrade检查Redis进程的运行用户ps -ef | grep redis确保不是以root身份跑的。如果是立刻修正。Redis官方本身就建议不要用root运行万一被攻击者从Redis打到系统命令执行root的权限是灾难性的看日志journalctl -u redis-server -n 100检查有没有异常的频繁连接记录当然这些属于顺带加固。但说真的如果你把Redis暴露在外网却不对上面的安全基线负责那你排查故障的时间和被人攻击薅走数据的时间可能真的是个先后问题。常见问题速查表症状最可能的原因快速解决apt install redis-server提示找不到包源的索引没更新sudo apt update后重试make编译报gcc not found缺少build工具链sudo apt install build-essentialsystemctl start redis失败日志有Permission denied日志目录/数据目录属主不对chown redis:redis相关目录bind: Address already in use端口被其他实例占用ss -tlnp确认占用方再处理本机能连外部工具连不上bind只绑定了127.0.0.1设置bind 0.0.0.0加上防火墙放行Java项目报Command timed out慢命令阻塞或网络延迟SLOWLOG GET查慢日志必要时调大客户端timeout写入报OOM command not allowedmaxmemory打满且策略是noeviction改成allkeys-lru或扩容重启后数据丢失没开AOF或RDB时间窗口太大开AOF并先动态开启再重启提示NOAUTH Authentication required客户端没有配置密码在连接配置中加requirepass里设置的密码RedisDesktopManager连不上报SSL相关错误工具误开了SSL/TLS选项在连接设置里关闭SSL/TLS最后的实操体会我在Ubuntu上排查Redis故障这几年最大的体会是大部分问题都不是Redis本身的设计缺陷而是配置、环境和预期三者没对齐。默认配置、外部网络、内存策略、持久化机制每个环节都有自己的一套默认值而这些默认值在不同的场景下会有完全不同的表现。所以当你遇到一个看似诡异的Redis故障时先别急着怀疑程序写错了按照“安装→启动→连接→运行→安全”这条链路一层层排通常都能找到答案。最后再分享一个小技巧排查Redis问题的时候养成先看日志的习惯。Ubuntu上apt安装的Redis日志默认在/var/log/redis/redis-server.log而且systemd的journalctl -u redis-server -n 100也能看到最近的运行记录。很多人习惯直接改配置、重启试错其实大量问题看一眼日志就能定位到方向了。这个习惯比任何高级工具都管用。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →