上周有个同事在群里喊:Redis装好了,redis-cli也能进,项目里怎么就是连不上?我第一反应是问他,你改过bind吗?他愣了半天说,bind是什么东西。这个场景我见过太多次了。
Ubuntu安装Redis,听起来是最简单不过的操作——apt install redis-server回车,绿色OK,就以为大功告成。但真正能连、能扛数据、能放进生产环境的Redis,从来不是一条安装命令能搞定的。网上关于这个话题的教程满天飞,但大部分只教你怎么把包装上,没教你装上之后会发生什么、哪些默认配置会坑你、出了问题怎么从零开始定位。这篇文章我会从选择安装方式、核心配置、可视化客户端、故障排查到容器化部署,把Ubuntu上装Redis这条链路完整过一遍,希望你看完能少走几趟弯路。
1. Ubuntu上装Redis,先搞清楚你装的是什么东西
1.1 Redis不是"一个软件",是四件套
很多新手把Redis理解成"一个程序",其实apt install redis-server之后,你的系统里至少多了四个可执行文件:redis-server(服务端)、redis-cli(命令行客户端)、redis-benchmark(压测工具)和redis-check-aof/redis-check-rdb(数据文件修复工具)。
这个区别很重要。比如你遇到的项目连不上,但你在服务器上执行redis-cli ping却返回PONG,这时候问题往往不在Redis本身,而在网络层或者客户端配置。redis-cli因为是本机回环,走的是127.0.0.1:6379;项目里如果填了服务器公网IP或者内网IP,就走的是另一条路。能分清服务端和客户端,排查思路就清晰了一半。
另外还有一个容易忽略的文件:redis-tools包里带了一堆辅助脚本,比如redis-cli --stat可以快速看实时吞吐,redis-cli --latency可以看网络延迟。这些工具在日常排障时非常好用。安装之前我建议先看看系统里装了哪些相关包:
dpkg -l | grep redis正常情况你会看到redis-server、redis-tools两个包。如果只有redis-tools没有redis-server,说明你只装了客户端,服务端根本没起来。
1.2 Ubuntu版本和Redis版本的对应关系,为什么得提前知道
我见过一个很典型的坑:项目代码里用了Redis 6.0才引入的ACL权限模型,结果部署到Ubuntu 18.04上,默认装出来的是Redis 4.0.9,ACL相关的命令全部报错。所以安装前先搞清楚你的Ubuntu版本对应哪一版Redis,很有必要。
| Ubuntu版本 | 默认Redis版本 | 主要特性节点 |
|---|---|---|
| 18.04 LTS | Redis 4.0.9 | 混合持久化起步 |
| 20.04 LTS | Redis 5.0.7 | Stream完整支持 |
| 22.04 LTS | Redis 6.0.16 | ACL、多线程IO |
| 24.04 LTS | Redis 7.0.x | Redis Functions、命令粒度权限 |
查看方式很简单:
lsb_release -a redis-server --version如果你确定项目不需要高版本特性,用系统源里的版本完全没问题,省心、稳定。如果要用7.x的新东西,我建议直接看下面的源码编译方案,或者用Docker拿官方镜像,而不是去折腾第三方PPA源。
2. 两条安装路线怎么选:apt一条命令还是源码编译
2.1 apt路线:三分钟装完,但得学会确认它真的活着
最省事的路线永远是apt,Ubuntu 22.04上执行:
sudo apt update sudo apt install redis-server -y装完以后第一件事不是写代码,而是确认服务状态:
systemctl status redis-server redis-cli pingping返回PONG,说明服务端正常响应了。这里说一下apt版本的关键配置差异:Ubuntu 22.04的Redis包会创建一个redis系统用户,用systemd管理服务,配置文件在/etc/redis/redis.conf,数据目录默认是/var/lib/redis,日志在/var/log/redis/redis-server.log。为什么强调这些路径?因为后面你改配置、查日志、看数据文件都要依赖这些位置。
apt路线的优点是和系统包管理器深度集成,apt upgrade的时候Redis会跟着升级,依赖自动处理。缺点也明显:版本滞后,且不能自定义编译参数。所以这条路线适合大多数常规业务场景,尤其是你只是想搭一个内部缓存或者学习环境。
确认redis-server开机自启也很重要:
sudo systemctl enable redis-server很多人装完忘了这一步,服务器重启之后项目Redis数据库连不上,又以为是密码错了,实际是服务压根没起来。
2.2 源码编译路线:什么时候该走,每一步在干什么
需要源码编译的场景通常是这三种:官方仓库版本太旧、需要启用TLS支持、或者你想自己加编译参数定制Redis。源码编译没有apt那么省事,但每一步都透明可控。
以Redis 7.0.15为例,完整流程是这样:
# 第一步:装编译工具链 sudo apt install -y build-essential pkg-config libssl-dev # 第二步:下载源码包(看清楚版本号) wget https://download.redis.io/releases/redis-7.0.15.tar.gz tar xzf redis-7.0.15.tar.gz cd redis-7.0.15/ # 第三步:并行编译 make -j$(nproc) # 第四步:可选,跑一遍内置测试 make test # 第五步:安装到指定目录 sudo make install PREFIX=/usr/local/redis编译完成后的二进制不像apt那样有systemd服务,你需要自己准备配置文件、用户和启动方式。我建议按照apt包的布局来组织:
# 创建redis用户(不允许登录shell) sudo useradd -r -s /bin/false redis # 准备配置和数据目录 sudo mkdir -p /etc/redis /var/lib/redis /var/log/redis sudo cp redis.conf /etc/redis/redis.conf sudo chown -R redis:redis /var/lib/redis /var/log/redis然后写一个systemd的unit文件,放在/etc/systemd/system/redis-server.service:
[Unit] Description=Redis Server After=network.target [Service] ExecStart=/usr/local/redis/bin/redis-server /etc/redis/redis.conf ExecStop=/usr/local/redis/bin/redis-cli shutdown Restart=always User=redis Group=redis [Install] WantedBy=multi-user.target最后systemctl daemon-reload && systemctl enable --now redis-server。源码编译没有帮你做任何初始化,路径、权限、开机启动全是自己管的,这也是很多人源码装完Redis却"找不到"进程的原因。
2.3 make阶段的gcc报错,九成是这几种情况
源码编译最常翻车的就是make阶段,热搜里专门有"ubuntu安装gcc失败"这个话题,说明踩的人不少。我实际遇到的make报错主要有三类:
第一类是gcc: command not found。这是最基础的,因为精简版Ubuntu服务器镜像可能没装编译工具链。解决办法就是:
sudo apt install build-essential这个包不是只有gcc,而是把gcc、g++、make、libc6-dev等一系列编译必需的工具都带上了。
第二类是编译过程中提示找不到某个头文件,比如openssl/ssl.h。这是因为Redis编译时检测到系统有OpenSSL库,想启用TLS支持,结果开发头文件没装全。装libssl-dev即可,注意不是libssl。
第三类比较隐蔽,编译到一半进程被杀,提示Killed。这种多半是云服务器内存太小,make -j$(nproc)开了太多并行编译任务,把内存吃满了。解决办法是降低并行度:
make -j2如果你在编译时还遇到jemalloc相关的报错,比如提示No such file or directory,可以用make MALLOC=libc临时绕过,改用系统的glibc内存分配器。这个一般不影响功能,但要做压测的话建议回头排查为什么jemalloc构建失败。
3. 装完别急着写代码:bind、密码和持久化这三大件先落地
3.1 bind和protected-mode这对组合,决定了谁能连进来
默认安装完Redis,配置是bind 127.0.0.1 -::1,只监听本机回环。这意味着只有服务器自己可以连,项目远程连不上是正常的,不是故障,是安全设计。
protected-mode和bind经常被混在一起讲,实际是两个层面。简单说:bind决定了Redis监听哪些网卡IP,protected-mode则是最后一道保险——当你没有显式配置bind、没有设置密码、也没改ACL时,它会强制只允许回环和Unix socket连接,阻止外部访问。一旦你设置了密码,protected-mode的默认拦截大部分就不再生效,安全重心就转移到密码本身了。
如果你确实需要远程访问,修改/etc/redis/redis.conf:
bind 127.0.0.1 -::1 192.168.1.100这里的意思是同时监听回环和内网某IP。不建议直接写0.0.0.0,特别是云服务器上有点公网IP还挂着Redis,等于把数据库裸奔在公网上,扫描工具不到十分钟就能发现你的6379端口。我之前处理过一台被挖矿程序写进Redis的机器,就是bind 0.0.0.0且没密码,直接被人用CONFIG SET dir写了个定时任务进去。这种攻击不稀奇,完全是配置疏忽。
3.2 密码怎么设:requirepass和ACL的一次性选择
设置密码最传统的方式:
requirepass YourStrongPassword然后在命令行验证:
redis-cli -a YourStrongPassword ping注意,redis-cli -a会有明文密码出现在进程列表的警告。不想让密码暴露在shell历史里,可以用环境变量:
export REDISCLI_AUTH=YourStrongPassword redis-cli pingRedis 6.0之后引入了ACL,可以做到比requirepass更细粒度的权限控制。比如给某个应用只开SET/GET权限:
redis-cli ACL SETUSER app_user on >AppPass123 +set +get ~*如果只是个单机内部使用,requirepass够用;如果Redis会被多个团队或多个应用共享,ACL能避免"一个密码走天下"的局面。真正上线前,至少要做到:默认用户不是nopass,生产禁止用CONFIG命令,因为这是被利用的高危点。
3.3 RDB和AOF:数据不丢这件事,配置文件里就得想清楚
很多人装完Redis直接写业务,完全没意识到默认持久化策略只是兜底级别。默认save规则是:
save 900 1 save 300 10 save 60 10000意思是900秒内至少1个key变了就做一次RDB快照,300秒内10个key变化做一次,60秒内10000个key变化做一次。这套规则对数据量小的场景勉强够用,但极端情况下会丢最近一分钟的数据。
更稳的做法是同时开启AOF:
appendonly yes appendfilename "appendonly.aof" appendfsync everyseceverysec是性能和安全的折中,每秒同步一次,最多丢一秒数据。Redis 4.0之后还有混合持久化,默认aof-use-rdb-preamble yes,AOF文件开头是RDB格式、后面跟增量命令,重启恢复速度比纯AOF快很多,文件体积也小。
我建议生产环境RDB和AOF都开,不要二选一。RDB负责快速恢复,AOF负责减少丢失窗口。这两个文件都在dir指定的目录下,比如apt安装是/var/lib/redis,源码安装你要自己确认清楚。
3.4 日志、dir和daemonize:把Redis交给systemd前的最后细节
三个高频细节,任何一个都会让你栽跟头。
第一是日志。apt安装默认日志在/var/log/redis/redis-server.log,问题不大。源码安装时如果你没创建日志目录,Redis会直接报Can't open the log file然后退出。配置里指定:
logfile /var/log/redis/redis-server.log没有权限就chown redis:redis /var/log/redis。看日志永远是排查Redis故障的第一步,我后面会频繁用到。
第二是dir。这个配置决定RDB快照和AOF文件落在哪个目录。默认情况下,如果你没配置dir,Redis会写到启动时的工作目录。有次我在/home/xxx目录下手动跑了redis-server,重启后发现快照文件找不到,因为dump.rdb被写到了/home/xxx下面。这件事会在你重启Redis后演变成"数据丢失"的灵异事件,排查半天才恍然大悟。
第三是daemonize。apt版本由systemd托管,配置里是daemonize no配合supervised systemd或者supervised auto。你手动在终端里跑redis-server时,它会在前台运行,日志直接打到终端,看着直观;但放进systemd服务里如果还开daemonize yes,服务管理器会以为进程意外退出,导致状态一直是activating或failed。这条经验适用所有把Redis托管给systemd的场景。
4. 可视化客户端怎么选:三款工具横向对比和三种连接姿势
4.1 三款主流可视化客户端的横向对比
redis-cli虽然强大,但整天用它来看几百个key的分布太伤眼睛了。可视化客户端这块我试过好几款,目前主流的是Redis Desktop Manager、Another Redis Desktop Manager和RedisInsight。
| 工具 | 是否免费 | SSH隧道 | 集群支持 | 内存分析 | 适合场景 |
|---|---|---|---|---|---|
| Redis Desktop Manager | 部分版本收费 | 有 | 有 | 一般 | 老用户延续习惯 |
| Another Redis Desktop Manager | 开源免费 | 有 | 有 | 一般 | 日常数据浏览首选 |
| RedisInsight | 官方免费 | 有 | 有 | 强 | 深度排障、性能分析 |
我的使用习惯是:日常查看key和结构用Another Redis Desktop Manager,它基于Tauri实现,启动快、内存占用低,多平台都有;要做内存分析、实时查看慢命令、跑Workbench,切到RedisInsight,官方出品的数据分析能力明显比第三方强。RDM现在有点老牌包袱,界面偏传统,除非你已经买了它的license,否则没必要从它起步。
这里提醒一点:不管用哪个工具,生产环境不要随手点KEYS *。Redis是单线程,KEYS *在key数量大的时候会拖垮整个实例。用可视化工具浏览时选SCAN模式,或者直接开RedisInsight内置的浏览器,它默认就是基于SCAN的。
4.2 本机连接、远程直连和SSH隧道,三种姿势各有用场
本机连接最简单,Host填127.0.0.1,Port填6379,密码填requirepass设置的密码。
远程直连的前提是你在3.1节改了bind,并确保防火墙放行。连接时填服务器IP和端口就行。但直连是有代价的,密码会暴露在网络上,虽然有加密协议要求,但很多老版本客户端不强制TLS。所以我不太推荐把Redis端口直接暴露给公网。
更稳的姿势是SSH隧道,特别是Redis在云服务器内网、你的工作机在外网的情况下:
ssh -N -L 6379:127.0.0.1:6379 user@跳板机IP-N表示不执行远程命令,-L做本地端口转发。执行完这条命令之后,你本地的6379端口会通过SSH隧道转发到跳板机上的127.0.0.1:6379,可视化工具连接127.0.0.1:6379即可。这样Redis不需要对外监听,防火墙只要开22端口,安全面小了很多。这个姿势在做临时排障的时候特别有用,不用改任何Redis配置就能从本地连上内网Redis。
5. 连不上Redis?四类典型故障的完整排查链路
5.1 排查链路一:本地redis-cli都连不上
如果服务器本机执行redis-cli ping都失败,先把问题范围锁定在本机。按下面顺序走:
systemctl status redis-server ps -ef | grep redis-server ss -lntp | grep 6379systemctl显示active说明服务进程正常;ss -lntp如果看不到6379端口监听,说明进程起来了但没正常监听网络。这种情况优先看配置文件的port是不是被改了,或者配置语法有没有错。确认配置没问题后重启服务:
sudo systemctl restart redis-server journalctl -u redis-server -n 50journalctl -u拉出的日志会把启动时的报错打得清清楚楚,比如"Bad directive or wrong number of arguments"这类就是配置文件语法错误。
5.2 排查链路二:本地能连,远程和项目连不上
这是最经典的场景,本地PONG,项目报Connection refused或者超时。分三步走:
第一步,在远程机器上用redis-cli直接探一下:
redis-cli -h 服务器IP -p 6379 ping错误信息会给你明确方向。Connection refused是TCP层就没通;NOAUTH Authentication required是密码没输;WRONGPASS就是密码错了。三种错误,三种完全不同的排障路径。
第二步,如果是Connection refused,从Redis本身查起。看配置文件里的bind,是不是只监听了127.0.0.1。很多云服务器的Redis都是死在这一步,你可以在服务器上验证:
redis-cli -h 服务器内网IP -p 6379 ping如果这条能通,说明Redis确实没监听公网IP,问题就在bind。如果这条也不通,再去查防火墙。Ubuntu常见的是ufw:
sudo ufw status sudo ufw allow 6379/tcp第三步,查云厂商的安全组。这个和Ubuntu没关系,但在云服务器上比系统防火墙更常见。你本地连不上而服务器本机能连,大概率是安全组入方向没放行6379。这个我不展开,但你排查顺序一定是:Redis监听范围 → 系统防火墙 → 云安全组。
5.3 排查链路三:redis-cli command not found,还牵连出PATH隐患
源码编译安装后,经常遇到redis-cli: command not found。原因是make install PREFIX=/usr/local/redis把可执行文件放到了/usr/local/redis/bin,而你的PATH里根本没这个目录。
临时解决:
/usr/local/redis/bin/redis-cli ping永久解决,编辑~/.bashrc(当前用户)或者全局的/etc/profile.d/redis.sh:
echo 'export PATH=$PATH:/usr/local/redis/bin' | sudo tee /etc/profile.d/redis.sh source /etc/profile.d/redis.sh这里必须提醒一句:千万不要手滑去乱改/etc/environment或者/etc/profile里已有的PATH。热搜词里挂着"ubuntu环境变量配置错误",就是因为有人把PATH改坏,导致所有命令都变成command not found,连ls和sudo都用不了。万一你已经改坏了,当前会话还能抢救一下,用绝对路径恢复PATH:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin然后重新编辑环境变量文件修回来。PATH是Linux的命脉,改它之前先把原始内容备份,教训都是这么来的。
5.4 排查链路四:日志写不进去,服务反复启动失败
源码安装后自己搭建systemd服务时,最容易出现的一个报错是:
Can't open the log file: Permission denied这是因为systemd托管下Redis进程以redis用户运行,但/var/log/redis目录属主不是redis。处理方式:
sudo chown -R redis:redis /var/log/redis /var/lib/redis日志级别也可以顺带调一下。配置里loglevel notice是默认值,如果排障阶段想看更细的信息,改成debug,定位完再改回来。别忘了Redis还内置了一个慢查询日志,排查线上性能问题很有用:
slowlog-log-slower-than 10000 slowlog-max-len 12810ms以上的命令会被记下来,用SLOWLOG GET查看。这个跟连接故障没有直接关系,但项目报告"Redis卡住"的时候,先看slowlog永远比瞎猜来得快。
顺便说一个连接层面经典的坑:高并发下Redis日志里刷Error accepting a client connection: Resource temporarily unavailable。这不是Redis本身的问题,而是内核backlog队列满了。Redis默认tcp-backlog 511,但内核参数net.core.somaxconn如果用默认128,实际生效值会被压到128。调高内核参数:
sudo sysctl -w net.core.somaxconn=1024再配合配置里的tcp-backlog 511,这个报错基本就消失了。这个问题在写redis-benchmark压测时最容易暴露出来,普通连接量下根本看不出来。
6. 再进一步:Docker部署Redis和主从复制的完整落地
6.1 为什么我推荐用Docker装Redis,以及它和裸机的本质差异
如果项目本身已经在用容器化,Redis没有理由不跟着容器化。Docker装Redis有几点明显优势:版本切换干净,redis:5.0切到redis:7.0只是换镜像标签的事;环境隔离,不会把编译残留或系统库弄乱;主从和集群编排可以由docker-compose统一管理,不用一台台手工配。
但容器化和裸机有一个本质差异必须想清楚:容器是易失的,容器删除后内部数据默认全丢。所以生产级的容器化Redis,必须把数据和配置都挂载到宿主机。记住一句话,没有volume挂载和持久化开关的Redis容器,只是临时玩具。
6.2 单机容器化:一条命令背后的参数逻辑
先看最基础的启动方式:
docker run -d \ --name redis \ -p 6379:6379 \ -v /opt/redis/data:/data \ redis:7.0 \ redis-server --appendonly yes --requirepass YourStrongPassword注意最后一个参数位置:镜像名后面的所有内容会作为命令传给容器内的redis-server。--appendonly yes和--requirepass都是redis-server的命令行配置覆盖,等效于改配置文件里的appendonly和requirepass。官方镜像默认配置里daemonize no,所以容器能保持前台运行,你千万不要在后面又加一个--daemonize yes,不然容器秒退。
如果配置项多,还是建议挂载配置文件:
mkdir -p /opt/redis/conf vim /opt/redis/conf/redis.conf然后:
docker run -d \ --name redis \ -p 6379:6379 \ -v /opt/redis/conf/redis.conf:/etc/redis/redis.conf \ -v /opt/redis/data:/data \ redis:7.0 \ redis-server /etc/redis/redis.conf注意数据挂载点必须是容器里的/data,因为官方镜像的配置里dir /data,RDB和AOF都会写到这个目录。挂载错路径,容器重启后照样"数据丢失"。
6.3 主从复制:docker-compose一把梭,验证从库到位
单机装完只是开始,很多项目的下一步是读写分离。用docker-compose可以在一个文件夹里把一主一从跑起来。先写docker-compose.yml:
version: "3.8" services: redis-master: image: redis:7.0 container_name: redis-master command: redis-server --requirepass Master123456 --appendonly yes ports: - "6379:6379" volumes: - ./master-data:/data redis-slave: image: redis:7.0 container_name: redis-slave command: redis-server --replicaof redis-master 6379 --masterauth Master123456 --requirepass Slave123456 --appendonly yes depends_on: - redis-master ports: - "6380:6379" volumes: - ./slave-data:/data这个编排里有几个细节要解释清楚:
- 从库的
--replicaof redis-master 6379用的是docker-compose网络内的服务名,不是IP。Compose会自动创建内网DNS,容器之间可以用服务名互访。 --masterauth是给从库连接主库时用的认证密码,它的值必须等于主库的--requirepass。- 从库自己也有
--requirepass,这是给客户端访问从库用的。主从之间的数据同步不会因为requirepass而中断,因为走的是masterauth通道。 - 如果你让客户端直接连从库做读操作,那需要一个从库自己的密码;如果只让从库在后台同步供主库故障切换用,密码也可以不设。
启动并验证:
docker compose up -d docker exec -it redis-slave redis-cli -a Slave123456 info replication重点看两行:role:slave和master_link_status:up。前者确认它确实是从库角色,后者确认主从链路是通的。再做个写入验证,在主库写入一个key,从库就能读到:
docker exec -it redis-master redis-cli -a Master123456 set hello world docker exec -it redis-slave redis-cli -a Slave123456 get hello从库返回world,说明复制链路正常。
6.4 主从不是终点,后面还差三样东西
主从解决了读扩展和基础数据冗余,但离"稳"还差三样东西。
第一是高可用。主库挂了,从库不会自动顶上,客户端还是会连那台死掉的主库。要自动故障切换,需要搭建Sentinel,或者直接用Redis Cluster。Sentinel的配置本质上就是三个角色:监控、通知、自动故障转移,但部署复杂度和调参细节,比主从复制又高一个量级。
第二是监控。生产环境Redis不是装完就完事了,内存、连接数、命中率、慢查询、复制延迟,这些指标必须落到监控系统里。redis-cli --stat和INFO命令只能用于现场排查,长期观测还是需要redis_exporter这类组件配合Prometheus。
第三是容量规划。maxmemory不设置,Redis会一直用系统的内存,直到触发OOM killer。涉及缓存淘汰策略,比如maxmemory-policy allkeys-lru,什么时候配、配多少,关系到缓存治理的稳定性。缓存穿透、击穿、雪崩这些话题,全都建立在一个配置合理、监控到位的Redis实例之上。
回到最初的问题:Ubuntu安装Redis,真正要装的不只是那个二进制文件,而是安装之前的规划、安装之后的配置、以及出问题后的排障能力。这套链路捋顺了,一个稳定的Redis实例就离你不远了。