ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Linux服务器上Redis安装全指南:从源码编译到systemd托管

Linux服务器上Redis安装全指南:从源码编译到systemd托管

说实话,如果目标只是“让 Redis 跑起来”,绝大多数 Linux 发行版上一条命令就够了:Ubuntu 上sudo apt install redis-server,CentOS 上sudo yum install redis。但我见过太多人这样装完,直接改两行配置就丢进生产环境,结果半夜被监控报警叫醒——要么是 Redis 连不上,要么内存直接打满,要么服务器重启后服务根本没起来。问题不在 Redis 本身,而在安装过程中绕过了太多本该确认的细节。

所以这篇文章不是教你怎么敲那一条命令,而是把“在 Linux 上安装 Redis”这条路的完整链路走一遍:动手前的环境确认、源码编译的完整过程、包管理器安装的取舍、redis.conf 里必须改的参数、用 systemd 做服务托管,以及装完之后的验证和排错。适合刚接触 Linux 服务器的新手,也适合已经能装、但没认真想过“为什么这么装”的人。

1. 动手前先摸清底细:你手头的 Linux 决定了安装方式

1.1 发行版与包管理器的第一道分水岭

Linux 不是铁板一块。同样是“装 Redis”,Debian/Ubuntu 系列用 apt,CentOS/RHEL/Rocky Linux 系列用 dnf 或 yum,Alpine 用 apk,openSUSE 用 zypper。包管理器不同,软件包名称、配置文件路径、systemd 服务文件的位置都可能不一样。

最典型的一个坑是 CentOS 默认源里没有redis-server这个包名,只有redis,而且通常要先启用 EPEL 源才有。Ubuntu 则正好相反,包名就是redis-server。如果你照着 CentOS 的教程在 Ubuntu 上搬运命令,第一步就会卡住。千万别小看这一步,我见过不止一个人在这上面浪费一整个下午。

所以动手之前,先花三十秒确认系统:

cat /etc/os-release uname -r getconf LONG_BIT

第一行告诉你发行版名称和版本号,第二行看内核版本,第三行确认系统是 64 位还是 32 位。Redis 官方对老旧 32 位系统的支持已经很弱,这种环境下与其折腾源码编译,不如直接换台 64 位机器更省时间。

1.2 编译工具链版本:源码安装前的隐性门槛

如果打算选择源码编译,gcc 和 make 的版本就是第一道坎。Redis 7.x 源码对编译器版本有隐性要求,拿一个 GCC 4.8 的老环境去编,大概率会在某个不显眼的地方报错。

检查方式很简单:

gcc --version make --version

正常来说 GCC 8 以上编译 Redis 7 系列没有压力。如果你手头是 CentOS 7 这种老发行版,默认 GCC 是 4.8,编译 Redis 6.x 都可能遇到 C 标准相关的报错。碰到这种情况,别急着硬怼编译器,要么换系统,要么用发行版自带的低版本 Redis,这是性价比更高的选择。

1.3 版本选择:不要闭眼装最新,也不要闭眼装仓库版

版本选择有几个务实原则。发行版仓库里的 Redis 通常比官方最新版落后一到两个大版本,比如某系统自带 6.0.x,而官方已经稳定在 7.x。仓库版的优势是“有人替你踩过兼容性的坑”,适合不想折腾的环境;官方最新版的优势是包含新特性和性能优化,比如 Redis 7 在内存碎片处理上的改进,对大规模缓存场景很有价值。

我个人的选择逻辑是:开发测试环境随便装,生产环境优先用官方 stable 版本,源码编译固定到一个具体的次版本号,而不是跟着最新小版本跑。这样方便复现问题,也方便团队统一维护。

2. 源码编译安装:为什么有人绕开包管理器也要自己编

2.1 编译安装的真实价值

有人会问:包管理器一把梭不香吗?为什么还要源码编译?答案是三点。

第一,版本可控。仓库里是什么版本不由你决定,官方发布新稳定版你也只能等发行版维护者打包。源码编译则可以把版本精确锁定,今天装的版本和昨天装的一样,线上出问题能稳定复现。

第二,目录可控。用 PREFIX 参数可以把二进制装到指定位置,多实例部署时各放各的目录,互不污染。

第三,学习价值。编译一次 Redis 成本不高,却能逼你把整个工具链跑通。之后编译 Nginx、编译其他 C 项目,都是同一套思路,一次学会终身受用。

2.2 编译环境的准备

在 Debian/Ubuntu 系列上,最小依赖是:

sudo apt update sudo apt install -y build-essential pkg-config tcl

build-essential包含 gcc、g++、make,pkg-config用于检测依赖库,tcl是运行make test用的。注意,tcl 不装也能编译通过,但跑不了测试。编译完不跑测试的风险,后面会专门讲。

在 CentOS/RHEL 系列上,对应命令是:

sudo yum groupinstall "Development Tools" sudo yum install -y tcl

如果不想用 root 编译,可以自建一个编译用户,这不是必需,但环境更干净。

2.3 下载、校验、编译、安装

从 Redis 官网下载页找稳定版 tarball,比如 redis-7.0.15.tar.gz,然后执行:

wget https://download.redis.io/releases/redis-7.0.15.tar.gz sha256sum redis-7.0.15.tar.gz tar xzf redis-7.0.15.tar.gz cd redis-7.0.15 make -j$(nproc)

这里有几个细节需要说明。wget之后一定要先比对sha256sum与官网给出的校验值,防止文件在传输过程中损坏或被替换。这个习惯非常重要,尤其是你经手服务器时,一步校验能省掉后面一堆莫名其妙的编译错误。-j$(nproc)让 make 用上机器全部核心,编译速度快很多。

编译完先确认src/redis-server存在,再执行安装:

sudo make install PREFIX=/usr/local/redis

PREFIX是可选项。不指定时,make install默认装到/usr/local/bin;指定后,会装到/usr/local/redis/bin。很多公司的一键部署脚本都会指定 PREFIX,主要是为了方便统一管理路径和后续版本回滚。装完之后,redis-server、redis-cli、redis-benchmark 等工具都会出现在这个 bin 目录下。

2.4 编译过程最容易踩的几个现场

我实际见过也帮别人排查过不少编译报错,最有代表性的是三类。

第一类:make 阶段报 jemalloc 相关错误。Redis 默认使用自带的内存分配器 jemalloc,个别老旧环境会配不上并报错。处理方式是显式指定 libc:

make MALLOC=libc

代价是失去 jemalloc 的碎片优化,但能让编译通过,适合临时验证环境。真上生产还是建议搞明白为什么 jemalloc 编译失败,通常跟内核版本或缺少头文件有关。

第二类:make test阶段报缺 tcl。报错提示通常是“You need tcl 8.5 or newer”。装好 tcl 再重新跑一遍即可。生产环境哪怕时间再紧,我也建议至少把make test过一遍——这能提前暴露大量运行时才可能出现的问题。

第三类:编译过程中磁盘满了或者 make 中断。调整好磁盘空间后,直接进入目录重新 make 就行,不需要重新解压整个包,因为编译产物是增量生成的。

还有个细节:编译完第一次启动前,把 tar 包和解压出来的目录留好,不要急着rm -rf。版本升级、出问题需要回看源码时,这份现场就是排查的依据。

3. 不折腾的路线:包管理器安装 Redis,以及它与编译安装的取舍

3.1 两条快速路径的区别

包管理器安装的最大优点就是快。Debian/Ubuntu 上:

sudo apt install -y redis-server

CentOS/RHEL 上:

sudo yum install -y epel-release sudo yum install -y redis

装完系统会自动创建 redis 用户、生成/etc/redis/redis.conf、注册redis-server.service,数据目录在/var/lib/redis,日志默认走/var/log/redis/redis.log。这一套目录规范是发行版维护者定好的,和源码编译默认都堆在/usr/local下的习惯完全不同。如果你习惯自己编译,切到包管理器后别凭经验去/usr/local/redis找东西,多半找不到。

3.2 包管理器隐藏的细节

包管理器装完,有一件事必须确认:服务是否真的在跑,以及配置是不是生产可用。Ubuntu 的 redis-server 包装完会把服务设为启用,但默认配置是bind 127.0.0.1、protected-mode yes,只允许本机访问。这其实是安全默认值,但很多人以为装完就能被远程应用连接,结果客户端连不上,就以为“Redis 坏了”。不是坏了,是默认安全策略在起作用。

另外,版本滞后是真的。某系统默认源里 Redis 是 6.0.16,官方 7.x 已经发了好久。对大多数 set/get、做缓存的需求来说 6.0 完全够用;但如果要使用新特性,比如 Redis 7 的 Function、更细粒度的内存碎片整理,就必须自己编译或添加维护者提供的第三方源。

3.3 三种安装方式的对比

对比维度包管理器安装源码编译安装容器方式
安装速度最快,一条命令较慢,依赖编译工具链快,依赖 Docker/Podman
版本自由度低,仓库版本滞后高,可精确指定中,取决于镜像标签
配置位置/etc/redis/redis.conf自己掌控挂载卷内配置
系统集成度高,自动注册 systemd需要手动写服务文件与宿主机隔离
适合场景快速验证、小规模使用生产环境、多实例部署容器化环境、研发机

表格看着清楚,但真实选择没那么泾渭分明。我的习惯是:开发机和临时验证用包管理器,真正要长期维护的环境用源码编译固定版本,容器化平台里则直接以镜像方式下发,根本不需要关心宿主机上的安装细节。

3.4 从包管理器迁移到自定义版本的注意点

如果你之前用 apt/yum 装过,后来决定换编译版,记住先停掉原服务,再小心处理数据目录。Ubuntu 上:

sudo systemctl stop redis-server sudo apt remove --purge redis-server

--purge会清掉配置和部分数据目录,如果想保留 RDB/AOF 数据,提前备份/var/lib/redis下的文件。我见过不止一次,因为卸载清库直接丢掉整份缓存数据——如果那里面是登录会话或商品库存,这个损失就不是一杯咖啡能解决的了。

4. redis.conf 核心配置:装完不调这几个参数等于白装

4.1 后台运行:daemonize 与 supervised 的正确姿势

这是第一次启动 Redis 最先遇到的问题。直接执行redis-server会默认前台运行,终端一关服务就没了。

老做法是在配置文件里写daemonize yes,让 Redis 自己 fork 到后台。但对被 systemd 托管的服务,推荐在配置文件里写:

supervised systemd daemonize no

这个组合的意思是:让 Redis 对接 systemd 的通知机制,由 systemd 来判断服务是否就绪。它比daemonize yes更可靠,因为 systemd 能拿到进程的真实状态,做崩溃拉起和开机自启都更顺畅。直接手动redis-server &是三者里最不推荐的做法,没有任何监督机制,进程死了都不知道。

4.2 安全三件套:bind、protected-mode、requirepass

默认情况下,Redis 只监听 127.0.0.1,也就是只能本机访问。要给局域网内其他服务器提供服务,需要改:

bind 0.0.0.0 protected-mode yes requirepass 你的强密码

这里要特别注意,bind 和 protected-mode 是配合工作的。protected-mode yes时,如果只 bind 了本机回环地址,Redis 认为自己处于安全状态,不需要密码;一旦你 bind 对外网卡或 0.0.0.0,Redis 会严格检查 requirepass。很多人在这里翻车:bind 改了 0.0.0.0 但没设密码,Redis 启动后拒绝一切请求,日志里写“Client sent AUTH, but no password is set”。

即使只在内网使用,密码也不建议省。内网扫描工具很容易发现开放 6379 的机器,没密码的 Redis 等于把数据直接交出去。Redis 6 之后还支持 ACL,可以用redis-cli ACL SETUSER给不同业务建独立账号,比全局 requirepass 更细粒度。生产环境一旦涉及多团队共用,ACL 几乎是必选项。

4.3 内存上限与持久化策略

不做限制的 Redis 会把内存吃光。设置 maxmemory 不是可选项,是必选项:

maxmemory 4gb maxmemory-policy allkeys-lru

单位可以是 512mb、4gb。maxmemory 建议设置为物理内存的 60%~80%,留出系统和其他进程的余量。如果整机只跑 Redis,可以到 80%;混跑业务服务就保守一点。maxmemory-policy常用的两种:allkeys-lru表示所有键都参与淘汰,适合纯缓存场景;noeviction表示内存到上限后写入直接报错,适合不能丢数据的队列场景。

持久化方面,默认 RDB 快照适合宕机恢复,但会丢最后一次快照之后的数据。需要更高可靠性就开启 AOF:

appendonly yes appendfsync everysec

appendfsync everysec是性能和安全的平衡点,每秒刷盘一次,最多丢一秒数据。写成always更安全但性能损耗明显,写成no就别指望崩溃恢复。这是标准的“你要哪一头”选择题,没有绝对正解,取决于业务对数据丢失的容忍度。

4.4 日志、目录与连接数

源码编译安装后,Redis 默认把日志打到标准输出、RDB 文件写到启动目录下,这对正式运行不友好。建议在配置文件统一指定:

logfile /var/log/redis/redis.log dir /var/lib/redis pidfile /var/run/redis/redis.pid

dir决定 RDB 和 AOF 文件的落盘位置,务必提前创建目录并确保运行用户有写入权限,否则启动时会出现“Can't open the log file”或持久化失败。连接数方面,默认maxclients 10000通常够用,但单机部署大量连接时,系统层可能会先报 "no file descriptors"。此时需要提高进程文件描述符上限,这个建议写进 systemd 服务文件,下一节具体说。

5. 用 systemd 把 Redis 管起来:开机自启与崩溃拉起

5.1 为什么不能直接 redis-server &

先给结论:任何正式环境,都不建议让 Redis 以裸后台进程的方式跑。原因很简单,redis-server &只是把进程丢到后台,机器重启后它不会自动回来,进程异常退出也没人知道,更别说做资源限制。

systemd 的价值在于三件事:开机自启、崩溃自动拉起、统一日志。这些都是生产环境的基础能力。包管理器安装的发行版已经帮你把redis-server.service写好了,源码编译安装则需要自己动手。

5.2 手写一个 redis.service 单元文件

新建/etc/systemd/system/redis.service,内容如下:

[Unit] Description=Redis Server After=network.target [Service] User=redis Group=redis Type=simple ExecStart=/usr/local/redis/bin/redis-server /etc/redis/redis.conf ExecReload=/bin/kill -s HUP $MAINPID Restart=on-failure RestartSec=5 LimitNOFILE=65535 ProtectSystem=full PrivateTmp=true [Install] WantedBy=multi-user.target

逐个解释关键项。

User和Group指向 redis 用户。用普通用户跑服务而不是 root,是安全底线。编译安装默认没有 redis 用户,先创建:

sudo useradd --system --user-group redis sudo mkdir -p /var/lib/redis /var/log/redis /etc/redis sudo chown -R redis:redis /var/lib/redis /var/log/redis

注意配置文件里dir指向的目录必须是 redis 用户有权限的目录,否则启动直接报错。

ExecStart指定了配置文件的绝对路径,Redis 会按配置文件里的supervised systemd设置决定自己是否前台运行。Type=simple表示 ExecStart 启动的进程就是主进程,这也是配合daemonize no使用的。

Restart=on-failure表示只在异常退出时自动拉起。RestartSec是重启间隔,避免进程反复崩溃时疯狂拉起。LimitNOFILE提高文件描述符上限,避免连接数增长时被内核卡住。ProtectSystem=full和PrivateTmp=true是 systemd 的沙箱选项,防止进程随意写系统目录,多一层保护。

5.3 内核层面的两个参数

除了服务文件,Redis 官方文档还建议检查两个内核参数,很多人装完 Redis 根本不知道它们的存在。

第一个是overcommit_memory。Redis 做数据持久化时依赖 fork 写时复制,如果系统内存偏紧,内核可能在 fork 时直接拒绝分配内存,导致后台保存失败。建议设为 1:

echo 'vm.overcommit_memory = 1' | sudo tee -a /etc/sysctl.conf sudo sysctl -p

第二个是 Transparent Huge Pages(THP)。THP 会增大 Redis 的延迟抖动,官方建议关闭:

echo 'never' | sudo tee /sys/kernel/mm/transparent_hugepage/enabled

注意第二条是运行时修改,重启后失效。要把关闭动作做成开机执行的脚本或 systemd 单元,否则每次重启还得手动来一遍。

5.4 启动、启用的标准流程

写完单元文件之后,执行:

sudo systemctl daemon-reload sudo systemctl enable --now redis sudo systemctl status redis

enable --now等于 enable 加 start 一步到位。status 输出里如果显示Active: active (running),说明服务起来了。之后机器重启也会自动拉起来。

排查时用 journalctl:

sudo journalctl -u redis -n 100

Redis 进程输出到标准输出的日志、报错都会汇总到这里,比翻文件方便得多。凡是 systemd 托管服务,日志第一站先来这里,别去猜。

6. 安装后的验证与现场排错:别让装完变成“看似成功”

6.1 用 redis-cli 走一遍基本验证

装完不验证等于白装。最基本的验证:

redis-cli ping

返回 PONG 说明服务在跑。设了密码就加-a:

redis-cli -a 你的密码 ping

注意-a会把密码留在 shell 历史里,安全做法是用环境变量:

export REDISCLI_AUTH=你的密码 redis-cli ping

然后跑一遍关键配置核对:

redis-cli INFO memory redis-cli CONFIG GET maxmemory redis-cli CONFIG GET appendonly

INFO memory里的used_memory_human可以直观看到当前占用,used_memory_peak_human是历史峰值。这两个数据之后配监控告警也用得上,值得记一下。

6.2 用 redis-benchmark 压一轮

Redis 自带压测工具 redis-benchmark,简单跑一轮:

redis-benchmark -t set,get -n 100000 -c 50

-t只测 set 和 get,-n是请求总数,-c是并发连接数。输出里重点看 "Requests per second" 字段,能对当前机器的性能基线有个大致判断。benchmark 主要压的是本机资源,结果只能做横向参考,别拿它当线上容量规划的绝对依据,更别拿它来和网上的跑分对比然后自我怀疑。

6.3 安装现场最常见的几个报错速查

我把这些年装 Redis 遇到的报错整理成一张速查表,按出现频率排序:

报错/现象可能原因处理方式
Could not create server TCP listening socket *:6379: bind: Address already in use6379 端口已被占用ss -lntp | grep 6379找到进程,停掉旧服务或改 port
Can't open the log file: Permission deniedlogfile 目录不存在或属主不对创建 /var/log/redis 并chown给 redis 用户
You must specify a password / AUTH requestedrequirepass 未设置但 protected-mode 生效给 requirepass 配密码,或客户端加密码
MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on diskdir 目录不可写、磁盘满查 dir 指向、磁盘空间,修好后CONFIG SET dir加BGSAVE
Warning: /proc/sys/vm/overcommit_memory is set to 0内核参数未调按 5.3 节设置vm.overcommit_memory = 1
Please use the same user for Redis and jemalloc配置里 user 参数与运行用户不一致修改 redis.conf 的 user 或 systemd 的 User

最后给一个排错顺序建议:先systemctl status redis看服务状态,再journalctl -u redis看日志,最后redis-cli ping做连通性测试。大多数问题都能在这条链路里定位,别一上来就怀疑配置改错了,更别随手删数据文件。日志里也有种情况是只给出一大段警告文字,比如 THP、overcommit 相关,它不是致命错误,但看到了就顺手按上面方法处理掉,能避免很多线上的诡异延迟和进程被杀问题。

最后说点我自己的习惯。生产环境装 Redis,我基本都走官方 stable 版本源码编译,固定到一个具体版本号,配置文件统一放/etc/redis/redis.conf,用 systemd 托管,数据目录独立,密码必须设,maxmemory 必须设。这套组合我维护了好几年,没有一次因为 Redis 没起来被半夜叫醒。还有个经验是:把 redis.conf 和 redis.service 文件都纳入配置管理,不要只靠本机文件。出问题的时候,能对比出“上一版配置到底改了什么”比什么都管用。多实例场景下,复制多个 systemd 单元文件配合不同端口和目录,6379、6380 各管一摊,数据互不干扰。装 Redis 本身不难,难的是把环境、配置、托管方式这些地基一次打对,这篇文章就是希望你把地基一次打好。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进