Redis 在 Linux 上的安装,几乎是后端入门的第一次"手感训练"——命令没几条,但每一步背后都藏着坑。我见过太多人照着某篇三年前的教程敲完make install,结果redis-cli死活连不上,日志里一行 protected-mode 的提示就把人卡住半天;也见过有人用包管理器两分钟装完,上线时才发现版本是 Redis 5.x,业务里用的 Stream 类型根本不认。
这篇东西不讲虚的,目标就一个:让你在一台干净的 Linux 机器上把 Redis 真正装起来、跑起来、并且能长期跑下去。源码编译、包管理器、容器这三条路线我都会给完整实操过程,不管你是刚背 Linux 常用命令的新手,还是要给生产环境做部署的老手,都能在里面找到对应阶段的细节——编译参数为什么这么选、redis.conf 里每一行的作用、systemd 托管文件怎么写、内存和持久化怎么配、以及各类报错现场到底是怎么修好的。
先提前说清楚一个前提:Redis 安装从来不是"敲三条命令"的事,而是"选版本、选安装位置、选启动方式、选安全策略"这一串决策的结果。下面按这个顺序拆。
1. 动手之前先把路线定下来
1.1 你到底要的是"能跑"还是"能长期跑"
这是最容易被跳过的一步。很多人上来就问"Redis 怎么装",但这个问题本身是残缺的——装在本机做开发调试,和装在生产服务器上扛流量,需求完全不一样。
开发环境要的是快:两分钟能起一个实例,改配置重启方便,数据丢了也无所谓。生产环境要的是稳:版本可控、配置可追溯、开机自启、内存有上限、持久化有策略、端口不裸奔。你如果拿开发环境那套"apt install完事"的思路去装生产库,后面一定会在某个凌晨三点被叫起来。
所以我的建议是先回答三个问题:这台机器是开发机还是服务器;你需要的 Redis 版本号是多少(业务依赖了什么特性);这台机器上还有没有别的东西要跑。三个问题回答完,路线基本自己就浮出来了。
1.2 源码编译安装:可控性最高,代价是编译阶段容易翻车
源码编译是我在服务器上最常用的方式,理由很直接:版本完全由我说了算,安装路径完全由我说了算,编译时可以按需开关 TLS、jemalloc 这些选项,将来升级也只需要换一个源码目录。
代价也很明确。第一是依赖问题,缺少 gcc、make、tcl 的时候编译直接中断;第二是 CentOS 7 这类老系统自带 gcc 4.8.5,编译 Redis 7 会因为 C11 标准支持不足报错,得先升级工具链;第三是编译过程吃内存,小内存机器上make被 OOM Killer 干掉的情况我遇到过不止一次。
不过这些坑都是一次性的,装通一遍之后你会对整个 Redis 的组成结构清楚很多。真正做运维或者做后端开发,我建议至少完整手动编译过一次。
1.3 包管理器安装的版本陷阱
apt install redis-server或者yum install redis,这是最快的路径,也是最容易埋雷的路径。发行版仓库为了稳定性,会把软件版本长期冻结在一个老版本上。Ubuntu 22.04 自带的 Redis 是 6.0.x 这个量级,Debian 12 大概是 7.0.x,而主线版本早就跑到 7.4 往上了。
这中间差的可不只是小版本号。Redis 6 引入了 ACL 和多线程 IO,Redis 7 引入了 Functions 和分片式 AOF 重写,如果你写的代码用了这些特性,而线上跑的是老版本,本地测试通过、上线直接报错,这种问题排查起来极其折磨人。
所以包管理器安装适合两种人:一种是本地随便跑跑的开发者,一种是明确知道自己只需要基础 KV 能力、且不想维护编译环境的团队。如果你属于这两种,用发行版仓库没问题,但至少要让仓库里是 Redis 6 以上。
1.4 容器化安装适合什么样的场景
Docker 跑 Redis 的体验确实舒服,一条docker run就完事,版本切换只要改镜像 tag,环境隔离干净,数据目录挂出来也不怕容器被删。现在很多团队的开发环境、CI 环境、甚至部分生产环境都在这么干。
但它有两个必须先想清楚的点。一是网络,容器内的 6379 和你宿主机的 6379 是两回事,端口映射没做好就会出现"容器明明起来了我却连不上"。二是持久化,容器一删数据就没,必须把/data挂载到宿主机目录,而且这个目录的权限要和容器内 redis 用户的 uid 对齐,否则会出现 AOF 写入失败这种诡异问题。
还有一个细节:官方镜像默认是不带配置文件启动的,用的是内置默认配置。你想改参数,要么挂载自己的配置文件,要么用--requirepass这类命令行参数。前者更规范,后面我会给出完整的挂载写法。
1.5 一张表帮你三分钟做决定
| 对比维度 | 源码编译安装 | 包管理器安装 | 容器化安装 |
|---|---|---|---|
| 版本可控性 | 完全可控,想装哪个装哪个 | 受发行版仓库限制 | 完全可控,改 tag 即可 |
| 首次安装耗时 | 10 到 30 分钟(含编译) | 2 到 5 分钟 | 3 到 5 分钟 |
| 依赖要求 | gcc、make、tcl、系统库 | 无额外依赖 | Docker 运行时 |
| 升级难度 | 换源码目录重新编译 | 一条命令升级 | 换镜像重启容器 |
| 配置灵活性 | 最高,编译期也能调 | 中等 | 高,但要走挂载 |
| 适合场景 | 生产服务器、需要特定版本 | 本地开发、基础需求 | 开发环境、CI、微服务配套 |
| 常见翻车点 | 编译报错、依赖缺失 | 版本过旧 | 端口映射、数据卷权限 |
我个人的习惯是:本机开发用包管理器或者容器,服务器上一律源码编译。这不是信仰问题,纯粹是出问题时定位成本更低——所有东西都在我指定的目录里,出了事看日志、看配置、看进程,一目了然。
2. 源码编译安装 Redis:从零到 systemd 托管
2.1 环境检查与编译依赖准备
第一步永远是确认机器状态。登上去先看三件事:系统版本、内存大小、以及到底能不能连外网下东西。
# 看系统版本和内核 cat /etc/os-release uname -r # 看内存,Redis 编译阶段建议至少 1GB 可用内存 free -h # 看 CPU 核数,决定后面 make -j 用几个线程 nproc # 看磁盘空间,编译加源码包建议留 2GB 以上 df -h /usr/local然后装依赖。Debian 系和 RedHat 系的包名不一样,我把两套都列出来。
Debian / Ubuntu 系:
sudo apt update sudo apt install -y build-essential tcl pkg-configCentOS / RHEL / Rocky / Alma 系:
sudo yum groupinstall -y "Development Tools" sudo yum install -y tcl tcl-devel这里解释一下为什么需要这几个东西。gcc和make是编译的基础,没有它们make会直接报cc: Command not found。tcl是 Redis 自带的测试套件make test需要的,虽然不做测试可以跳过,但既然装一次,顺手装上更省事。pkg-config主要在链接系统库的时候用得上。
提示:CentOS 7 用户请特别留意,系统自带 gcc 4.8.5 在编译 Redis 6 以上版本时会报
unrecognized command line option "-std=c11"之类的问题。这种情况要么升级 gcc,要么换用后面提到的make MALLOC=libc方式绕开部分编译路径,但这个绕法解决不了 C11 支持问题,最终还是得升级工具链。
2.2 下载源码包与完整性校验
我习惯把源码放在/usr/local/src下,这是比较传统的做法,和系统自带的软件目录结构一致,将来找东西方便。
cd /usr/local/src # 下载指定版本的源码包,版本号按需替换 wget https://download.redis.io/releases/redis-7.2.4.tar.gz # 如果服务器没装 wget,用 curl 也一样 # curl -O https://download.redis.io/releases/redis-7.2.4.tar.gz # 校验压缩包完整性 sha256sum redis-7.2.4.tar.gz下载页面上会给出对应版本的 SHA256 值,把sha256sum的输出和官网给的值逐位对比,一致才继续。这一步很多人觉得多余,但我确实遇到过下载中断导致压缩包不完整、解压到一半报错的情况,校验一下能省掉后面一堆莫名其妙的问题。
注意:如果服务器在受限网络环境里下载特别慢,可以在本地下载好再用 scp 传到服务器,效果是一样的。文件传输完成后同样要做一次 sha256 校验。
校验通过就可以解压了:
tar -zxvf redis-7.2.4.tar.gz cd redis-7.2.4 ls -l正常的话你会看到src、deps、utils、tests这些目录,以及顶层的README.md、redis.conf、Makefile。这里记住一件事:顶层那个redis.conf是配置模板,后面要复制到我们规划的目录里再用。
2.3 make 编译过程详解与参数选择
编译这一步是整个流程里最容易出问题的环节,所以我把参数说透。
# 进入源码目录 cd /usr/local/src/redis-7.2.4 # 先清理一遍,确保没有历史编译残留 make distclean # 带多核并行编译 make -j$(nproc)make distclean这一步看着多余,其实很有必要。如果你之前在这个目录编译过一次并失败了,残留的.o文件可能导致下次编译出现莫名其妙的链接错误,先清干净是成本最低的兜底动作。
-j$(nproc)是用上机器的所有 CPU 核心并行编译,能把编译时间从几分钟压到几十秒。
关于MALLOC参数。Redis 默认会使用自带的 jemalloc 内存分配器,需要编译deps/jemalloc这个子目录。这个子目录在某些环境下会编译失败,典型报错是找不到jemalloc/jemalloc.h。这种情况下有两个处理方式:
# 方式一:重新清理后再来一遍,很多时候是上次中断导致的残留问题 make distclean && make -j$(nproc) # 方式二:改用系统自带的 libc 分配器,绕开 jemalloc 编译 make MALLOC=libc方式二能解决问题,但代价是内存碎片管理能力会弱一些,高并发写入场景下更明显。所以我的建议是优先用方式一排查,实在绕不过去再选方式二。
关于BUILD_TLS。如果你的环境需要 TLS 加密连接(比如跨公网传输),编译时要显式开启:
make BUILD_TLS=yes这需要系统里已经装了 OpenSSL 开发库(libssl-dev或openssl-devel)。普通内网使用不需要开这个,开了反而增加配置复杂度。
编译成功的话,最后会看到一句Hint: It's a good idea to run 'make test' ;)。想验证的话可以跑make test,这一步会花几分钟,做的是功能自测。生产环境我一般不会在服务器上跑完整测试,因为耗时且吃资源,但如果你是在本地搭建学习环境,跑一遍很有价值。
2.4 安装目录规划与 make install
编译产物都在src目录下,比如src/redis-server、src/redis-cli。直接跑也能跑,但那样管理起来太乱。标准做法是用PREFIX参数把可执行文件装到统一目录。
# 指定安装前缀,可执行文件会落到 /usr/local/redis/bin make PREFIX=/usr/local/redis install执行完看一下目录:
ls -l /usr/local/redis/bin正常会看到redis-server、redis-cli、redis-benchmark、redis-check-aof、redis-check-rdb、redis-sentinel这几个文件。每个的用途简单说一下:redis-server是服务端主程序;redis-cli是命令行客户端,日常用得最多;redis-benchmark是压测工具;redis-check-aof和redis-check-rdb是持久化文件的修复校验工具,出故障时能救命;redis-sentinel是哨兵,做高可用时用。
接着把配置和数据目录建起来。我一般分三个目录:配置、数据、日志。
mkdir -p /usr/local/redis/conf mkdir -p /usr/local/redis/data mkdir -p /usr/local/redis/logs # 从源码目录复制配置模板 cp /usr/local/src/redis-7.2.4/redis.conf /usr/local/redis/conf/ # 建一个专用账号跑 Redis,避免用 root 启动 sudo useradd -r -s /sbin/nologin redis # 把目录属主改掉 sudo chown -R redis:redis /usr/local/redis注意:千万不要用 root 身份长期运行 Redis。一旦 Redis 出现漏洞被利用,攻击者拿到的就是 root shell。创建独立系统账号是最基本的一道防线,成本几乎为零。
2.5 redis.conf 关键参数逐条拆解
配置文件是这个环节的核心,我挑必须改的和必须懂的说。
vim /usr/local/redis/conf/redis.conf网络与访问控制部分:
# 监听地址。只允许本机访问就写 127.0.0.1 # 需要被同网段其他机器访问,写内网 IP,不要写 0.0.0.0 bind 127.0.0.1 # 保护模式。默认 yes,在没有密码且没有 bind 的情况下会拒绝外部连接 protected-mode yes # 端口 port 6379 # TCP 连接队列长度,配合内核 somaxconn 调整 tcp-backlog 511 # 客户端空闲超时,0 表示不断开 timeout 0 # TCP 心跳,建议保留 tcp-keepalive 300bind和protected-mode这两个是最容易出问题的组合。很多人为了图方便把bind改成0.0.0.0,把protected-mode改成no,然后还设了个弱密码——这等于把数据库直接挂在公网上。6379 端口是被扫描最多的端口之一,我强烈建议只监听内网地址,配合防火墙做白名单。
进程与日志部分:
# 是否后台运行。用 systemd 托管时设为 no daemonize no # 让 Redis 以 systemd 模式运行,交给 systemd 接管主进程 supervised systemd # pid 文件位置 pidfile /var/run/redis_6379.pid # 日志级别:debug / verbose / notice / warning loglevel notice # 日志文件,空字符串表示输出到标准输出 logfile "/usr/local/redis/logs/redis.log" # 数据库数量,默认 16 个 databases 16这里有个关键点值得展开:daemonize和supervised的搭配。如果你手动敲命令启动、想让 Redis 在后台跑,那就daemonize yes。但如果用 systemd 托管,正确做法是daemonize no加supervised systemd,让 systemd 直接持有主进程。否则会出现 systemd 认为服务"启动失败"但进程其实在跑,或者 stop 的时候杀不干净这种问题。这是新手很容易踩的坑。
持久化部分:
# RDB 快照策略:900 秒内至少 1 次写入就存盘 save 900 1 save 300 10 save 60 10000 # 快照失败时是否停止写入,建议 yes,能及时暴露磁盘问题 stop-writes-on-bgsave-error yes # 快照文件是否压缩 rdbcompression yes # 快照文件名 dbfilename dump.rdb # 工作目录,RDB 和 AOF 都放这 dir /usr/local/redis/data # 开启 AOF 持久化 appendonly yes # AOF 刷盘策略:everysec 每秒一次,性能与安全的平衡点 appendfsync everysec # AOF 重写条件 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mbRDB 和 AOF 的区别我用一个类比说明:RDB 像定期给数据库拍照片,文件小、恢复快,但两次拍照之间宕机会丢数据;AOF 像记账本,每次写操作都记一笔,丢掉的数据极少,但文件会越来越大,需要通过重写来瘦身。生产环境我的经验是两个都开,用 AOF 保数据完整性,用 RDB 做备份和快速恢复。
内存与淘汰策略部分:
# 最大内存,按机器实际内存的 60% 到 70% 设置 maxmemory 2gb # 淘汰策略:内存满了之后怎么处理 maxmemory-policy allkeys-lru # LRU 采样精度,越大越精确但越耗 CPU maxmemory-samples 5淘汰策略的选择逻辑:如果你的 Redis 是纯缓存,所有 key 都可以丢,用allkeys-lru;如果有一部分 key 是必须长期保留的,就用volatile-lru,只淘汰设置了过期时间的那部分。noeviction是默认值,意思是内存满了直接报错拒绝写入,用在"数据绝对不能丢"的场景,但要做好写入失败的兜底。
安全部分:
# 访问密码,强烈建议设置,且要足够长 requirepass 你的高强度密码 # 危险命令重命名或禁用 rename-command FLUSHALL "" rename-command FLUSHDB "" rename-command KEYS "" rename-command CONFIG "CONFIG_8f2a1c"禁用FLUSHALL和FLUSHDB是因为这两个命令会清空整个库,误操作一次就是生产事故。禁用KEYS是因为它会阻塞主线程遍历所有 key,线上执行一次可能导致几秒的服务中断,替代方案是用SCAN。CONFIG重命名是为了防止有人远程改配置。
改完配置记得检查一遍语法,然后启动:
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf2.6 用 systemd 托管 Redis 并设置开机自启
手动启动的进程一关终端就没了,也不方便管理。正规做法是写一个 systemd 服务单元。
sudo vim /etc/systemd/system/redis.service内容如下:
[Unit] Description=Redis In-Memory Data Store Documentation=https://redis.io/documentation After=network.target network-online.target Wants=network-online.target [Service] Type=notify User=redis Group=redis RuntimeDirectory=redis RuntimeDirectoryMode=0755 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf ExecStop=/usr/local/redis/bin/redis-cli -a 你的密码 shutdown Restart=always RestartSec=5 LimitNOFILE=65535 [Install] WantedBy=multi-user.target几个字段解释一下。Type=notify配合配置里的supervised systemd使用,让 systemd 能准确知道 Redis 什么时候真正准备好了。Restart=always保证进程意外挂掉后自动拉起。LimitNOFILE=65535是文件描述符上限,Redis 官方文档明确建议调高,默认的 1024 在高并发连接下会直接报 "too many open files"。
生效并启动:
sudo systemctl daemon-reload sudo systemctl enable redis sudo systemctl start redis sudo systemctl status redis看到active (running)就对了。如果显示失败,用journalctl -u redis -n 50 --no-pager看最近 50 行日志,报错信息通常很直白。
2.7 安装结果验证:从 ping 到五大数据类型
最后一步是确认它真的能用,而不只是"进程起来了"。
# 看版本 /usr/local/redis/bin/redis-server -v /usr/local/redis/bin/redis-cli -v # 连接并测试 redis-cli -h 127.0.0.1 -p 6379 -a 你的密码 --no-auth-warning ping返回PONG就说明连接链路通了。--no-auth-warning是关掉那个"用命令行传密码不安全"的提示,仅用于测试,脚本里不要这么写。
接着把这五种基础数据类型各跑一遍,既验证安装,也顺便熟悉命令:
# 字符串 String SET user:1:name "tom" GET user:1:name # 列表 List LPUSH task:queue "task1" "task2" "task3" LRANGE task:queue 0 -1 # 哈希 Hash HSET user:1 name "tom" age 28 city "hangzhou" HGETALL user:1 # 集合 Set SADD article:1:tags "linux" "redis" "backend" SMEMBERS article:1:tags # 有序集合 ZSet ZADD rank:score 100 "tom" 92 "jerry" 85 "spike" ZRANGE rank:score 0 -1 WITHSCORES五种类型各有各的适用场景:String 做缓存和计数器,List 做消息队列,Hash 存对象,Set 做去重和交并集,ZSet 做排行榜。装完之后自己动手跑一遍,比看十篇文档都管用。
3. 两条捷径:包管理器与容器安装的完整实操
3.1 Ubuntu/Debian 用 apt 安装
基础安装简单到不像话:
sudo apt update sudo apt install -y redis-server sudo systemctl enable redis-server sudo systemctl start redis-server redis-cli ping装完之后几个关键路径记一下:配置文件在/etc/redis/redis.conf,数据目录在/var/lib/redis,日志在/var/log/redis/。改配置改/etc/redis/redis.conf,改完sudo systemctl restart redis-server生效。
如果嫌仓库里的版本太老,可以换官方源:
# 导入官方 GPG 公钥 curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg # 添加官方仓库 echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list # 更新并安装 sudo apt update sudo apt install -y redis这样装到的就是 Redis 官方当前稳定版,比发行版自带的新不少。装完后包名从redis-server变成了redis,systemd 服务名也跟着变,用systemctl status redis-server查状态,这是很多人换源后会懵一下的地方。
3.2 CentOS/RHEL 用 yum/dnf 安装
# 先装 EPEL 扩展仓库 sudo yum install -y epel-release # 安装 Redis sudo yum install -y redis # 启动并设置开机自启 sudo systemctl enable redis sudo systemctl start redis redis-cli pingCentOS 系的配置文件在/etc/redis.conf(注意不是/etc/redis/redis.conf,路径和 Debian 系不一样)。RHEL 8 以上系统yum其实就是dnf的软链,命令可以直接通用。
整体流程不复杂,但依赖第三方仓库,用之前建议先确认一下要装的版本。yum info redis能看到仓库里提供的版本号和来源。
3.3 Docker 跑一个生产可用的 Redis 实例
容器方式看着简单,但要配得像样,还是得挂配置文件和数据卷。
# 拉镜像,指定具体版本,不要用 latest docker pull redis:7.2.4 # 建宿主机目录 mkdir -p /data/redis/conf mkdir -p /data/redis/data # 从官方镜像里拷一份配置模板出来 docker run --rm redis:7.2.4 cat /usr/local/etc/redis/redis.conf > /data/redis/conf/redis.conf # 按需修改配置,至少改这三项 # daemonize no # bind 0.0.0.0 (容器内需要监听所有地址,外部访问靠端口映射控制) # dir /data vim /data/redis/conf/redis.conf # 启动容器 docker run -d \ --name redis \ --restart always \ -p 127.0.0.1:6379:6379 \ -v /data/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf \ -v /data/redis/data:/data \ redis:7.2.4 \ redis-server /usr/local/etc/redis/redis.conf几个细节必须说清楚。端口映射我写的是127.0.0.1:6379:6379,意思是只在宿主机本地监听,外部机器连不上,这是最安全的做法,需要外部访问时再改成内网 IP。--restart always保证容器随 Docker 服务自动拉起。数据卷必须挂/data,否则容器重建数据就没了。最后一行指定了配置文件路径,不写的话 Redis 会用内置默认配置启动。
注意:挂载配置文件时,宿主机上的文件必须已经存在,否则 Docker 会把它当成目录创建,导致容器启动报错。这是个非常经典的坑。
3.4 顺手把主从复制搭起来
单机部署之后,很多时候下一步就是主从。原理很简单:从节点连上主节点,同步全量数据,之后持续接收增量。配置上只需要在从节点的配置文件里加一行:
# 在从节点的 redis.conf 中 replicaof 主节点IP 6379 # 如果主节点设置了密码,从节点必须配上,否则同步会失败 masterauth 主节点密码改完重启从节点,然后用redis-cli info replication查看状态。主节点上会看到connected_slaves:1,从节点上会看到master_link_status:up。如果显示down,八成是masterauth没配对,或者防火墙拦了 6379 端口。
主从搭起来之后,读请求可以分摊到从节点,同时也具备了一定的容灾能力(虽然还需要哨兵做故障自动切换)。
3.5 三种安装方式横向对比
| 项目 | 源码编译 | 包管理器 | Docker |
|---|---|---|---|
| 配置文件位置 | 自定义,如 /usr/local/redis/conf | /etc/redis/redis.conf | 挂载到宿主机指定目录 |
| 数据目录 | 自定义,如 /usr/local/redis/data | /var/lib/redis | 容器内 /data,挂载出来 |
| 服务管理 | 手写 systemd unit | 安装时自带 | docker restart 策略 |
| 升级方式 | 重新编译安装 | 包管理器升级 | 换镜像 tag |
| 排查便利性 | 高,所有路径都在掌控内 | 中 | 依赖 docker logs |
| 隔离性 | 差,和系统共享环境 | 差 | 好 |
4. 装完之后必须做的四件事
4.1 安全加固:密码只是第一步
很多人的安全认知停留在"设个密码就完事",实际上这只是最低门槛。我按优先级列几条。
第一,永远不要监听公网。bind写内网地址,配合防火墙白名单。Redis 在没有任何防护的情况下暴露公网,被植入挖矿程序的案例多到数不清。
第二,密码要够长。8 位以下的密码在离线爆破面前撑不了多久。用 32 位随机字符串,存在配置文件的权限要设成 600。
chmod 600 /usr/local/redis/conf/redis.conf chown redis:redis /usr/local/redis/conf/redis.conf第三,用 ACL 做细粒度权限。Redis 6 以后支持 ACL,可以给不同的应用分配不同账号,限制能访问的 key 前缀和能执行的命令。这是比单一密码更合理的做法:
# 创建一个只能读 app1 前缀 key 的账号 ACL SETUSER app1_read on >强密码 ~app1:* +@read # 查看现有账号 ACL LIST第四,考虑改端口。这个措施只能减少被扫描命中的概率,属于"降低噪音"级别的防护,不能替代密码和防火墙,但成本低,顺手做一下没坏处。
4.2 RDB 与 AOF:持久化怎么选怎么配
持久化配置直接决定宕机后你会丢多少数据。我把两种方式的特性列一下。
| 维度 | RDB | AOF |
|---|---|---|
| 文件形式 | 二进制快照 | 追加写日志 |
| 文件大小 | 小,压缩后更小 | 大,需要定期重写 |
| 恢复速度 | 快 | 相对慢 |
| 数据丢失风险 | 可能丢几分钟 | 最多丢 1 秒 |
| 对性能影响 | 子进程 fork,瞬间内存翻倍 | 每写一次有刷盘开销 |
| 适合场景 | 备份、灾备 | 数据可靠性要求高 |
我的实际配置通常是两个都开:RDB 用来做定期备份,AOF 用来保证数据不丢。同时要注意maxmemory的设置不能太激进,因为 RDB 存盘时fork子进程需要额外的内存空间,如果maxmemory设成了物理内存的 90%,存盘时极有可能触发 OOM,导致 Redis 被杀掉。
Redis 7 的 AOF 采用了多文件机制,会生成appendonly.aof.1.base.rdb这样的基础文件加上增量文件,这个目录不要手动去动,需要修复时用redis-check-aof工具。
4.3 内存上限与淘汰策略
maxmemory不设的话,Redis 会一直吃内存直到把机器吃爆。我的一般原则是单实例不超过物理内存的 60% 到 70%。如果开了 RDB 持久化,再往下压一点,给 fork 留出空间。
淘汰策略一共 8 种,常用的就是表格里这几个:
| 策略 | 含义 | 适用场景 |
|---|---|---|
| noeviction | 内存满时拒绝写入并报错 | 数据不能丢的场景 |
| allkeys-lru | 所有 key 中淘汰最久未使用的 | 纯缓存场景 |
| allkeys-lfu | 所有 key 中淘汰访问频率最低的 | 有明显冷热数据的缓存 |
| volatile-lru | 只从设了过期时间的 key 里淘汰 | 冷热数据混存 |
| volatile-ttl | 优先淘汰快要过期的 key | 数据有明确生命周期的场景 |
| allkeys-random | 随机淘汰 | 访问分布均匀的场景 |
LFU 是 Redis 4 引入的,比 LRU 更适合有明显热点分布的场景。比如商品详情缓存,少量热门商品被频繁访问,LRU 反而可能把这些热点挤掉,LFU 就不会。
线上环境调整内存参数有个技巧:不要直接改配置文件重启,用CONFIG SET动态调整,然后CONFIG REWRITE写回配置文件。这样不会中断服务。
4.4 可视化工具与日常运维命令
命令行用熟了其实比图形界面效率高,但有个可视化工具排查问题时确实直观。Redis Desktop Manager 是最早出名的那个,不过后来转为商业版了。现在更推荐Another Redis Desktop Manager,开源免费、跨平台、支持集群和哨兵,连上去能直接看到 key 的分布和内存占用情况。
装的时候注意一点:客户端工具连接的是 Redis 的服务地址和端口,不是装 Redis 那台机器本身,需要保证网络可达、端口开放、密码正确。
日常运维我常用这几条命令:
# 实时查看 Redis 每秒执行的命令,排查问题非常有价值 redis-cli -a 密码 --no-auth-warning monitor # 查看整体信息,重点看 used_memory、connected_clients、keyspace redis-cli -a 密码 --no-auth-warning info # 只看内存相关 redis-cli -a 密码 --no-auth-warning info memory # 查看慢查询日志 redis-cli -a 密码 --no-auth-warning slowlog get 10 # 查看当前连接数 redis-cli -a 密码 --no-auth-warning client listmonitor命令在线上慎用,它会输出所有执行的命令,高 QPS 场景下自己就成了性能瓶颈。排查问题时短时间开一下,看完了立刻 Ctrl+C 退出。
慢查询日志的阈值默认是 10 毫秒,可以用CONFIG SET slowlog-log-slower-than 5000调整成 5 毫秒。生产环境我一般设成 5 到 10 毫秒,能覆盖大部分需要关注的操作。
5. 踩坑实录:安装 Redis 最常见的报错与排查
5.1 编译阶段:gcc、jemalloc、make 中断
报错一:make: cc: Command not found
原因就是没装编译器。Debian 系装build-essential,RedHat 系装Development Tools组。装完gcc --version确认一下。
报错二:fatal error: jemalloc/jemalloc.h: No such file or directory
这是最经典的报错,出现在编译deps/jemalloc的时候。绝大多数情况下是上次编译中断留下的残留文件导致的,处理方式是彻底清理再重来:
make distclean make -j$(nproc)如果反复失败,检查一下是不是deps/jemalloc目录本身不完整,重新解压一遍源码包试试。实在不行用make MALLOC=libc绕开。
报错三:cc1: error: unrecognized command line option "-std=c11"
gcc 版本太老,典型出现在 CentOS 7 上编译 Redis 6 以上版本。升级工具链是唯一稳妥的解法。可以用 Software Collections 装新版 gcc,或者直接换一个系统版本较新的机器。
报错四:make跑到一半被 killed
这是内存不足被 OOM Killer 杀了。两种处理:加内存,或者临时加 swap。编译 Redis 单个核心大概需要 500MB 到 1GB 内存,多核并行会放大这个需求。这种情况改用make单线程编译能缓解,但时间会明显变长。
报错五:You need tcl 8.5 or newer in order to run the Redis test
这个只在跑make test时报,不影响安装。想解决就装 tcl。
5.2 启动阶段:配置不生效、端口占用、权限拒绝
问题一:改了配置文件但启动后行为没变
最常见的原因是指定了配置文件但路径写错了,Redis 直接用了内置默认配置启动,而且它不会主动告诉你。启动时一定要看日志输出,如果看到类似"使用默认配置"的提示,就是路径问题。另一个可能是重复的配置项,后面的覆盖了前面的,用grep -n 参数名 配置文件检查一下有没有重复。
问题二:Could not create server TCP listening socket *:6379: bind: Address already in use
端口被占了。先查是谁占的:
ss -lntp | grep 6379 # 或者 lsof -i:6379如果是之前启动的 Redis 残留进程,kill掉再启动。如果是别的程序,改 Redis 端口或者停掉对方。
问题三:Permission denied写入日志或数据文件失败
目录属主不对。检查一下 Redis 运行用户和目录属主是否一致:
ls -ld /usr/local/redis/data /usr/local/redis/logs # 修正 chown -R redis:redis /usr/local/redis用 root 启动过 Redis 之后,数据目录里的文件属主会变成 root,之后再切换成 redis 用户启动就会报这个错。这也再次说明不要用 root 启动。
问题四:systemd 显示启动失败但进程实际在跑
daemonize设成了yes,导致 Redis 自己 fork 到后台,systemd 追踪的父进程退出了,就认为服务失败。改成daemonize no加supervised systemd即可。
5.3 连接阶段:Connection refused / NOAUTH / 超时
Could not connect to Redis at 127.0.0.1:6379: Connection refused
三种可能:服务没启动、端口写错了、bind配的地址不包含你连接的地址。先systemctl status redis看进程状态,再ss -lntp | grep redis看实际监听的地址和端口。
NOAUTH Authentication required
服务端设了密码,客户端没传。加-a 密码就行。注意在脚本里不要直接把密码写在命令行,用环境变量或者配置文件更安全。
DENIED Redis is running in protected mode
这是protected-mode在起作用。当bind没配或者配的是通配地址、同时没设密码时,Redis 会拒绝来自非本机的连接。解决方式有两个:要么老老实实设密码,要么明确配置bind到内网地址。不要图省事直接把protected-mode关掉。
连接超时,一点反应都没有
大概率是防火墙。CentOS 系用firewall-cmd --list-all看规则,Debian 系用ufw status。需要放行的话:
# firewall-cmd sudo firewall-cmd --permanent --add-port=6379/tcp sudo firewall-cmd --reload # ufw sudo ufw allow from 内网网段 to any port 6379注意:放行端口时尽量限定来源网段,别用
allow 6379这种全放开的写法。
5.4 常见问题速查表
| 现象 | 最可能的原因 | 快速定位命令 | 处理方式 |
|---|---|---|---|
| make 报 cc 找不到 | 未装编译工具链 | gcc --version | 安装 build-essential 或 Development Tools |
| 找不到 jemalloc.h | 编译残留 | ls deps/jemalloc | make distclean后重编译 |
| make 中途被杀 | 内存不足 | dmesg | tail -20 | 加内存或加 swap,改单线程编译 |
| 启动报端口占用 | 已有实例在跑 | ss -lntp | grep 6379 | 杀掉残留进程或改端口 |
| 改配置没生效 | 配置路径写错或项重复 | grep -n 参数 配置 | 修正路径,清理重复项 |
| systemd 状态失败但进程在跑 | daemonize 与 supervised 冲突 | journalctl -u redis -n 30 | 改 daemonize no + supervised systemd |
| 连接被拒绝 | 服务未启动或 bind 不匹配 | ss -lntp | grep redis | 启动服务,调整 bind |
| 提示 NOAUTH | 客户端未传密码 | 无 | 加 -a 参数或改配置 |
| 提示 protected mode | 无密码且监听通配地址 | 无 | 设密码并绑定内网地址 |
| 日志写入失败 | 目录属主不对 | ls -ld 数据目录 | chown 成 redis 用户 |
| 从节点同步不上 | masterauth 缺失 | info replication | 从节点配置 masterauth |
| AOF 文件异常大 | 未及时重写 | info persistence | 调整重写阈值或手动 bgrewriteaof |
这张表我建议存下来,出问题的时候按顺序对照,能省下大量翻文档的时间。多数报错的根因都在这十几条里。
最后分享一个我自己的习惯:每次装完 Redis,第一件事不是急着写业务代码,而是把redis-cli info的完整输出存一份到文件里,标注好日期和版本号。这个基线文件在将来排查性能问题时价值极高——你能清楚知道正常状态下连接数是多少、内存占用是多少、命中率是多少。没有基线,所有"这个数字正常吗"的疑问都只能靠猜。
另外关于版本,我的经验是不要盲目追新,也不要长期停留在老版本。跟着官方的稳定分支走,比主线落后一到两个小版本是比较舒服的位置,既有足够的新特性,也避开了刚发布时的潜在问题。升级前一定要在测试环境把 AOF 和 RDB 文件做完整体验,从新版本回退到旧版本时持久化文件的兼容性是有坑的。