Linux源码编译安装Redis:从依赖检查到systemd托管与调优
1. 先别急着敲安装命令三种装法先摆在桌面上比一比我见过太多人接手一台测试机之后的第一反应就是apt install redis-server三秒装完然后卡在配置到底在哪这个问题上半小时。现象很典型systemctl start redis能起来redis-cli能连上但你想改个maxmemory、想开 AOF、想换个数据目录翻遍/etc/redis/发现配置文件被发行版改得面目全非跟官网文档里的redis.conf完全对不上号。这就是选错安装路径带来的隐性成本——省下的三分钟后面要用几个小时找回来。装 Redis 这件事本身没有技术难度真正的分水岭在于你知道自己为什么选这条路吗。Linux 上部署 Redis 主流就三条路包管理器、源码编译、容器化。三者都能把服务跑起来但可控制的粒度、可迁移性、后续排错的难度完全不在一个量级。下面这张表是我自己总结的选型依据你可以直接拿去当决策参考。安装方式拿到的版本可控制粒度适合场景主要代价包管理器 apt/yum跟随发行版仓库通常落后 1-3 个大版本低配置文件被发行版定制临时验证、内网快速起服务版本旧、配置路径不统一源码编译官网最新稳定版自己说了算高路径、编译参数、配置全可控生产环境、需要指定版本、需要调优要装编译依赖首次耗时 5-15 分钟容器 Docker官镜像版本齐全切换成本极低中靠挂载配置和数据卷本地开发、多实例、主从演练需要理解数据卷与网络映射我的建议很直接如果你是要在一台长期存在的服务器上跑业务走源码编译如果只是本机做实验、或者想快速拉起一套主从来验证架构容器化性价比最高包管理器那条路我基本只在给别人演示什么叫版本落后的时候才用。还有一个很多人忽略的判断维度是卸载和升级成本。包管理器装的 Redis日后升级要看发行版仓库什么时候跟进源码编译装的我只需要下载新版本 tar 包make完替换掉bin目录配置和数据目录纹丝不动回滚也一样。容器化则把升级压缩成改一行镜像 tag代价是你要接受数据落在卷里这个事实。所以本文的实操主线走源码编译因为它能把安装这件事的每个环节都摊开给你看——依赖、编译、目录、配置、托管、验证。把源码这条路走通之后包管理器和容器那两条路你几乎不用学就会了因为坑都在同一个地方配置项的含义、持久化的取舍、内核参数的调整。2. 动手之前的地基检查依赖、目录与内核参数2.1 先把系统底细摸清楚上来就wget下载 tar 包是我最不建议的做法。Redis 官方源码在编译时会根据系统架构和内核版本决定一部分行为你至少要先确认三件事发行版和版本号、CPU 架构、可用的编译工具链。cat /etc/os-release uname -a nproc gcc -v make -vcat /etc/os-release决定你后面用apt还是yum/dnf装依赖uname -a告诉你架构是 x86_64 还是 aarch64这直接影响你能不能直接用别人编译好的二进制nproc决定你make -j后面填几编译 Redis 是纯 CPU 密集型任务核心数越多差距越明显4 核机器大概两分钟单核机器能拖到十分钟以上。gcc -v和make -v是硬门槛。如果这两条命令提示 command not found说明你的系统是个精简版很多云厂商的最小化镜像就是这样连编译器都不带。这种情况不用慌装依赖就行# Debian / Ubuntu 系 sudo apt update sudo apt install -y build-essential pkg-config tcl # RHEL / CentOS / Rocky / Alma 系 sudo yum install -y gcc gcc-c make pkgconfig tcl这里的tcl值得单独说一句。很多人装完依赖编译也通过了但在make test那一步报错翻了半天以为是 Redis 源码有问题其实是缺 tcl。Redis 的测试套件是用 tcl 写的生产环境你可以跳过make test但如果你想验证这份源码在这台机器上跑得正常跑一遍测试是最省心的方式。2.2 目录规划别让配置、数据、日志混在一起我踩过最难受的一个坑是早期把 Redis 装在/root/redis下面配置和数据全在一个目录里。后来服务器迁移我复制了目录过去结果带着旧的 RDB 文件和旧日志启动之后数据对不上排查了半天才发现是数据目录写死在配置里但配置没跟着改。从那之后我就固定了一套目录规范/usr/local/redis/bin # 可执行文件 /etc/redis/6379.conf # 配置文件一个实例一个文件 /data/redis/6379/ # 数据目录RDB、AOF /var/log/redis/ # 日志目录 /var/run/redis/ # pid 文件目录如果用 pidfile这套结构最大的好处是将来你要在一台机器上跑多个 Redis 实例时只需要复制一份配置改端口和目录剩下的逻辑一模一样。6379 是默认端口第二个实例用 6380配置文件名就叫6380.conf数据目录就叫/data/redis/6380/一眼就能对上运维的时候不会搞混。2.3 专用账号不要让 Redis 以 root 身份跑这一点被忽略的频率高得惊人。Redis 是网络服务监听端口、处理外部请求用 root 跑等于把整个系统的控制权暴露在一个网络进程上。正确做法是建一个没有登录 shell 的系统账号sudo groupadd -r redis sudo useradd -r -g redis -s /sbin/nologin -d /var/lib/redis redis sudo chown -R redis:redis /data/redis /var/log/redis-r表示创建系统账号-s /sbin/nologin表示这个账号不能登录系统只能用来跑服务。这三行命令看着琐碎但它是权限收敛的基础后面写 systemd 单元的时候直接指定Userredis就行。2.4 三个内核参数不调也能跑但会在高峰期咬你这三项属于不设置的时候一切正常流量一上来就出玄学问题的典型。第一项是vm.overcommit_memory。默认值是 0意思是内核在执行 fork 时会做启发式判断可能拒绝一部分内存分配请求。Redis 在开启 RDB 持久化时会 fork 子进程来做快照这个动作依赖写时复制机制如果 fork 被拒绝日志里会打印一句警告严重的时候直接导致持久化失败。echo vm.overcommit_memory 1 | sudo tee -a /etc/sysctl.conf sudo sysctl -p第二项是透明大页THP。开启状态下内核会把小内存页合并成 2MB 的大页日常业务没感觉但 Redis 的 fork 和内存回收延迟会明显变差官方文档里明确建议关闭。临时关闭一行命令就行持久化需要在 systemd 单元里补一行这个放在 3.5 节里一起写。第三项是net.core.somaxconn。它决定了监听队列的长度上限默认值在不少发行版里只有 128。当瞬时并发连接数超过这个值多余的连接会被内核直接丢弃客户端看到的就是莫名其妙的连接超时。改成 1024 起步配合 Redis 配置里的tcp-backlog一起用。echo net.core.somaxconn 1024 | sudo tee -a /etc/sysctl.conf sudo sysctl -p这三条命令加起来不到一分钟但它们解决的是为什么白天好好的晚上压测就崩这类最难查的问题。3. 源码编译安装的完整链路从下载到 systemd 托管3.1 下载与校验多花三十秒省掉两小时Redis 的源码包从官网的 releases 页面下载稳定版优先选偶数小版本号那种长期维护的。以 7.2 系列为例cd /usr/local/src sudo wget https://download.redis.io/releases/redis-7.2.5.tar.gz sudo wget https://download.redis.io/releases/redis-7.2.5.tar.gz.sha256 sha256sum -c redis-7.2.5.tar.gz.sha256最后一行输出OK才继续。这一步很多人觉得多余但下载过程中出现字节翻转、或者公司网络中间层做了缓存替换都会导致你编译出一个看起来能跑但行为诡异的二进制。校验通过之后你至少能确定后面所有问题的排查起点是干净的。提示如果目标机器不能直接访问外网就在能上网的机器上下载好 tar 包和 sha256 文件用 scp 传过去校验步骤同样要做。3.2 解压与源码目录速览sudo tar -zxvf redis-7.2.5.tar.gz -C /usr/local/src/ cd /usr/local/src/redis-7.2.5 ls解压出来之后你会看到几个关键文件src/是源码redis.conf是官方配置模板utils/里面有个install_server.sh是老式的初始化脚本sentinel.conf是哨兵配置tests/是测试套件。这里插一个真实遇到过的坑。如果你的 tar 包是从 Windows 环境拷过来的解压之后可能发现文件名里出现乱码甚至代码文件里的中文注释全变成问号。原因不是 Redis 的包有问题而是压缩工具用了 GBK 之类的编码去处理文件名而 Linux 默认按 UTF-8 解析。判断方法很简单看解压出来是不是有一堆redis-7.2.5/开头的文件权限异常。真遇到了在 Linux 上重新下载解压是最省事的方案不要试图手工修复编码。另外要注意 tar 包解压后的权限。tar -zxvf会保留包内的权限位正常情况下没有问题但如果你的umask被改过可能出现目录不可写。加一句sudo chown -R $(whoami):$(whoami) redis-7.2.5一劳永逸。3.3 编译与安装make后面的参数决定成败make -j$(nproc) make PREFIX/usr/local/redis install第一条命令编译第二条命令把产物安装到指定前缀下。-j$(nproc)是让 make 用满所有 CPU 核心并行编译这是纯收益没有副作用。如果你在 ARM 架构或者某些精简发行版上编译报错提示找不到 jemalloc那就加上内存分配器的指定参数make MALLOClibc -j$(nproc)Redis 默认使用 jemalloc 作为内存分配器因为它在频繁分配释放小块内存的场景下碎片率更低。但某些系统没有现成的 jemalloc 依赖强制用系统自带的 libc 分配器也能跑代价是长时间运行后内存碎片可能更明显。这是一个典型的知道取舍再选的场景不要看到报错就随便加参数。编译成功之后/usr/local/redis/bin下会出现这些可执行文件文件名作用redis-server服务端主程序redis-cli命令行客户端redis-sentinel哨兵软链接到 redis-serverredis-check-rdbRDB 文件检测修复工具redis-check-aofAOF 文件检测修复工具redis-benchmark压测工具其中redis-check-aof和redis-check-rdb我希望你永远用不上但一定要知道它们存在。AOF 文件写坏了、服务器异常断电导致 RDB 不完整这两个工具是最后的救命稻草。我曾经遇到过一台机器断电后 Redis 起不来日志说 AOF 文件截断用redis-check-aof --fix修复之后数据只丢了最后一条命令业务几乎无感。3.4 首次启动前台跑一遍看一眼日志安装完成之后不要急着做 systemd 托管先手动前台启动一次把日志直接在终端里看清楚。/usr/local/redis/bin/redis-server你会看到经典的 ASCII 图案和启动日志注意几行关键信息监听的端口、配置文件的加载路径、有没有警告。如果出现关于overcommit_memory、THP 或者tcp-backlog的黄色警告说明 2.4 节的内核参数你漏了回去补上。前台启动状态下另开一个终端执行/usr/local/redis/bin/redis-cli ping # 返回 PONG到这一步说明二进制本身没问题了CtrlC停掉进入托管配置。3.5 写 systemd 单元让服务真正系统化我在很长一段时间里用的是redis-server /path/to/conf 这种粗暴方式直到有一次服务器重启后服务没起来业务方半夜打电话过来。systemd 的价值不只是开机自启还包括崩溃自动重启、日志统一收集、资源限制这些能力。先把配置文件准备好sudo mkdir -p /etc/redis /data/redis/6379 /var/log/redis /var/run/redis sudo cp /usr/local/src/redis-7.2.5/redis.conf /etc/redis/6379.conf sudo chown -R redis:redis /data/redis /var/log/redis /var/run/redis然后创建/etc/systemd/system/redis-6379.service[Unit] DescriptionRedis 6379 In-Memory Data Store Afternetwork.target Wantsnetwork.target [Service] Typesimple Userredis Groupredis ExecStart/usr/local/redis/bin/redis-server /etc/redis/6379.conf --supervised systemd ExecStop/usr/local/redis/bin/redis-cli -p 6379 -a 你的密码 shutdown ExecStartPost/bin/sh -c echo never /sys/kernel/mm/transparent_hugepage/enabled Restartalways RestartSec3 LimitNOFILE100000 [Install] WantedBymulti-user.target几个细节需要解释。--supervised systemd是告诉 Redis 我是被 systemd 管着的这样它不会自己守护化日志也能正确交给 journaldExecStop用redis-cli shutdown而不是kill是为了让 Redis 有机会做一次优雅的持久化落盘ExecStartPost那行就是 2.4 节提到的 THP 关闭用 systemd 的原生方式实现不依赖 rc.localLimitNOFILE100000是文件描述符上限Redis 官方建议值就是 100000同时你还应该在/etc/security/limits.conf里补上对应的redis soft nofile 100000和redis hard nofile 100000。启用并启动sudo systemctl daemon-reload sudo systemctl enable --now redis-6379 sudo systemctl status redis-6379 sudo journalctl -u redis-6379 -n 50 --no-pagerenable --now一条命令完成开机自启和立即启动两件事。如果状态显示active (running)并且journalctl里没有 ERROR安装环节就算结束了。4. 装完只是起点让 Redis 具备上线资格的六项配置4.1 从官方模板到自己的配置改哪几项刚拷过来的/etc/redis/6379.conf有八百多行注释全改是不现实的。我的做法是先备份一份原始模板然后只动下面这些项其余保持默认。bind 127.0.0.1 -::1 protected-mode yes port 6379 daemonize no supervised systemd pidfile /var/run/redis/redis-6379.pid logfile /var/log/redis/redis-6379.log dir /data/redis/6379 requirepass 一个足够长的随机密码 maxmemory 2gb maxmemory-policy allkeys-lru appendonly yes appendfsync everysec逐项说一下背后的理由。bind默认只监听本地回环这是最安全的默认值只有当你的应用服务器和 Redis 不在同一台机器上时才需要改改之前务必先想清楚网络安全边界。protected-mode yes是一道兜底保险当没有设置密码且监听地址是通配的时候Redis 会拒绝外部连接并在日志里提示这个机制救过不少人。daemonize no配合supervised systemd是托管模式的正确组合如果你既写了daemonize yes又用 systemd 管理会看到服务启动成功但立刻变成 stopped 的诡异现象。maxmemory和maxmemory-policy是最需要根据业务确认的两项。不设maxmemoryRedis 会一直吃内存直到触发系统 OOM然后被内核杀掉日志里什么都没有只有一句Killed。设了上限但策略选错也会出问题纯缓存场景用allkeys-lru让所有键参与淘汰如果是混合存储了不能丢的数据就得用noeviction写满之后返回错误而不是静默丢数据。这两个选择的差别是丢缓存还是丢数据必须由业务方拍板。4.2 持久化RDB 与 AOF 不是二选一而是什么时候用哪个网上有个流传很广的说法是Redis 是缓存不需要持久化。这句话只在一种情况下成立你能接受缓存全部失效后回源数据库重建。但只要你的 Redis 承载了任何不可重建的数据比如分布式锁的状态、任务队列、计数器持久化就是必须的。RDB 是快照把某一时刻的全量数据写成一个二进制文件恢复速度快、文件体积小缺点是两次快照之间的数据会丢。AOF 是命令日志把每条写命令追加到文件里数据安全性高代价是文件更大、恢复更慢、需要定期重写。生产上我基本都用appendonly yes打底同时保留默认的 RDB 规则做冷备份。AOF 有三个关键参数值得单独调appendonly yes appendfsync everysec auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mbappendfsync有三个取值always每条命令都刷盘性能最差但几乎不丢数据everysec每秒刷一次最多丢一秒数据性能和安全性的平衡点是绝大多数场景的默认答案no交给操作系统决定性能最好但断电可能丢几十秒数据。这三个值的差异不是理论上的一点点实测中always的写入吞吐可能只有everysec的五分之一选之前先问自己能不能接受一秒的数据损失。4.3 连接数、内存与看不见的瓶颈除了maxmemory还有几项和并发相关的配置容易被忽略。timeout 300 tcp-keepalive 300 tcp-backlog 1024 maxclients 10000timeout 0是默认值意思是永不主动断开空闲连接。很多客户端连接池实现不严谨连接用完了不归还也不关闭日积月累连接数就顶到上限。设一个 300 秒的空闲超时能让这些僵尸连接自动被清理掉。tcp-backlog要和前面提到的net.core.somaxconn保持一致或更小否则内核层面的队列比 Redis 层短还是会在高峰期丢连接。maxclients受文件描述符限制你把它设成 20000 但系统ulimit只有 1024实际生效的还是 1024所以这两处必须一起改。4.4 安全边界密码之外还要做的事requirepass是必须的但它远远不够。Redis 的密码是明文传输的网络层面被抓包就没了所以永远不要把 Redis 直接暴露在公网。正确的做法是让它只监听内网地址用防火墙限制来源 IP。sudo firewall-cmd --permanent --add-rich-rulerule familyipv4 source address10.0.0.0/24 port port6379 protocoltcp accept sudo firewall-cmd --reload另一件必须做的事是禁用或重命名危险命令。FLUSHALL、FLUSHDB、KEYS、CONFIG这几个命令在误操作和恶意利用两个维度上都是重灾区。KEYS *在几十万键的实例上执行会阻塞主线程几秒钟直接引发线上雪崩所以我倾向于在生产配置里直接关掉它。rename-command KEYS rename-command FLUSHALL rename-command CONFIG CONFIG_9f3a2b如果确实需要用到改成随机后缀的名字只有知道名字的人才能调用。日常查键改用SCAN游标遍历它虽然不保证完整但不会长时间阻塞主线程。5. 报错自查手册编译、启动、连接三类问题的排查链路5.1 编译阶段报错先看依赖再看参数编译报错的现象很好认终端里一大片红字最后一行是make: *** [Makefile:xxx: all] Error 2。真正有用的信息在红字的最前面而不是最后一行。最常见的三类第一类是gcc: command not found或者make: command not found说明基础工具链没装回到 2.1 节装依赖就行。第二类是头文件找不到提示fatal error: xxx.h: No such file or directory常见于缺少pkg-config或者某个开发库。第三类是执行make test时报 tcl 相关错误这个不影响二进制本身装个 tcl 再重跑即可。还有一个隐蔽的坑是磁盘空间。编译过程需要几百 MB 的临时空间如果/usr/local/src所在分区快满了你会看到各种奇怪的写入失败。动手前执行一次df -h看一眼可用空间成本几秒钟。5.2 启动阶段报错日志永远是你的第一现场启动失败时很多人第一反应是反复执行systemctl start然后看systemctl status那一小段输出。信息量根本不够。正确的顺序是sudo journalctl -u redis-6379 -n 100 --no-pager sudo tail -n 100 /var/log/redis/redis-6379.log我按频率排一下遇到的启动问题。现象根因处理服务显示 active 但立刻变 inactive配置里daemonize yes和 systemd 冲突改成daemonize nosupervised systemd日志提示无法创建 pid 文件/var/run/redis目录权限或所有者不对chown redis:redis并确认目录存在提示Address already in use端口被占用ss -lntp | grep 6379找到占用进程启动即退出日志为空数据目录不可写Redis 启动时校验失败检查dir指向的目录权限提示 RDB 文件格式错误上次异常断电导致快照损坏用redis-check-rdb检测与修复注意如果日志文件是空的先确认你是不是把logfile写成空字符串了。配置里logfile 表示输出到标准输出被 systemd 接管后走 journald不再写文件。5.3 连接阶段报错三种错误对应三种完全不同的原因redis-cli -h 10.0.0.5 -p 6379 ping连不上时别急着改配置先看错误信息。Connection refused是 TCP 层面根本没通说明服务没在监听、或者监听的地址不包含你连的那个 IP、或者被防火墙拦了。按顺序排查systemctl status确认服务活着ss -lntp确认监听地址firewall-cmd --list-all确认规则放行。NOAUTH Authentication required说明服务通了但没带密码。加-a参数或者进交互式之后执行AUTH 你的密码。这里提醒一句命令行里带-a会把密码写进 shell 历史用redis-cli的交互模式输密码或者设置REDISCLI_AUTH环境变量更稳妥。DENIED Redis is running in protected mode是最容易让人困惑的一个。它出现的前提是没有设置密码、监听地址是通配的、并且 protected-mode 是开启的。Redis 在这种情况下会拒绝非本地连接。这是一个安全机制不是 bug说明你的配置处于没密码又对外开放的危险状态。正确的处理是设置密码并限制监听地址而不是把 protected-mode 关掉。6. 装好之后的验收命令手测、可视化工具与多实例6.1 用 redis-cli 走一遍真实读写服务起来了不等于能用。我习惯用一组命令做快速验收覆盖连接、写入、读取、过期、持久化信息这几个维度。redis-cli -p 6379 AUTH 你的密码 PING PONG SET user:1001 zhangsan EX 3600 OK TTL user:1001 (integer) 3598 GET user:1001 zhangsan INCR counter:page:view (integer) 1 INFO persistence DBSIZE CONFIG GET maxmemoryINFO persistence这一步重点看aof_enabled:1和rdb_last_bgsave_status:ok前者确认 AOF 打开后者确认最近一次快照成功。DBSIZE确认数据落在正确的库CONFIG GET maxmemory确认你改的配置真的生效了——这个动作很有必要我遇到过改了配置但没重启服务、然后对着不生效的参数排查半小时的情况。关于数据类型装完之后顺手把五种基础类型的用法过一遍是值得的。字符串用来做缓存和计数器哈希适合存对象列表适合队列集合和有序集合用来做去重和排行榜。这里不展开讲用法只说一个高频误区不要用字符串存整个 JSON 对象然后每次更新都整体覆盖这种写法在字段多、并发高的时候序列化开销和网络开销都很大用哈希存字段、只改变动的那一个是更经济的做法。既然说到序列化就顺带提一句客户端侧的事。用 Java 系客户端时默认的 JDK 序列化会把键写成带二进制前缀的一串乱码在命令行里KEYS出来完全看不懂跟其他语言的客户端也没法共享数据。统一换成字符串序列化器处理键、JSON 序列化器处理值是团队协作里必须提前约定好的规范否则后期跨语言对接会非常痛苦。6.2 可视化工具的选型什么时候该用什么时候不该用命令行足够强大但有些场景图形界面确实省事比如浏览键空间结构、查看大 key 分布、观察内存曲线。两类工具值得试一试。一类是官方出品的 RedisInsight跨平台功能比较全能做内存分析、慢查询展示和命令行面板结合使用。另一类是 Another Redis Desktop Manager轻量、启动快、连接配置管理方便适合同时维护多套环境的人。选择上我的标准很简单需要做性能分析和内存诊断就用前者只是日常查键改值就用后者。但有一条底线生产环境的可视化工具连接一定要走内网跳板并且用只读账号。图形工具最大的风险是误删右键一个 Delete 就没了命令行至少还有一次回车的时间给你反悔。6.3 顺手搭一个主从多实例的目录规划这下派上用场了单机跑通之后很多人的下一步就是验证主从复制。这时候前面那套一个实例一个配置、一个数据目录的规划就体现出价值了复制一份配置改端口、改 pidfile、改日志名、加一行replicaof就是一个从节点。# 6380.conf 里新增 port 6380 pidfile /var/run/redis/redis-6380.pid logfile /var/log/redis/redis-6380.log dir /data/redis/6380 replicaof 127.0.0.1 6379 masterauth 主节点密码启动之后在主节点执行INFO replication看到connected_slaves:1就算搭成了。如果你更倾向于用容器来做这件事思路完全一样只是把改配置文件换成映射不同的端口和数据卷docker run -v把宿主机的配置目录挂进容器即可切换成本极低适合反复演练。搭主从的过程中有个坑值得提前说从节点第一次连接主节点会做全量同步主节点会 fork 一个子进程生成 RDB 并发给从节点。如果主节点内存很大这个 fork 可能耗时几百毫秒甚至更久期间的写入延迟会明显上升。所以主从演练不要放在业务高峰期做也不要在内存已经吃满的实例上做。6.4 从装好了到用得住之间还差什么安装这件事本身从下载到 systemd 托管熟练之后半小时之内能全部搞定。但 Redis 真正的门槛从来不在安装而在装完之后缓存的过期策略怎么定、热点键怎么发现、内存碎片怎么监控、分布式锁的续期和误删怎么防、多级缓存的一致性怎么保证。这些问题没有一个能靠改配置解决它们需要你在真实的流量里观察和迭代。我个人的习惯是每装完一套 Redis就在监控里挂上四个指标内存使用率、命中率、连接数、慢查询数量。前两个看容量够不够后两个看有没有异常访问模式。这四个数字连续观察一周你对这套实例的脾性就基本摸清了后面出问题的时候也能第一时间判断是业务量涨了还是有人写了个KEYS *。装完就撒手不管等到出事再看日志那安装时省下的时间全都要还回去。