CentOS 7.5源码编译Redis 6.0.1完整指南

发布时间:2026/10/19 9:17:01
CentOS 7.5源码编译Redis 6.0.1完整指南
前阵子要在一批 CentOS 7.5 的老机器上统一部署缓存业务方态度很明确就要 Redis 6.0.1。我一开始想偷懒直接yum install redis结果拉出来的版本是 3.2.12ACL、新版集群管理这些能力全是空的去官方下载预编译二进制放到 CentOS 7.5 上又经常被 glibc 版本卡住。来回折腾之后发现在 CentOS 7.5 / RHEL 7.x 环境里编译安装 Redis 6.0.1反而是最可控、最不依赖外部条件的方式。这篇文章把我完整跑通的命令、参数和踩过的坑全写出来照着抄基本能一次过。1. 为什么绕不开编译安装这条路1.1 仓库里的版本和预编译包都卡在哪CentOS 7 的默认软件仓库里Redis 停留在 3.2.12。这个版本不是不能用但和 6.0.1 的差距实在太明显6.0 引入了 ACL 用户权限体系可以对不同客户端做精细化权限控制引入了多线程 I/O虽然默认不开但给了你优化空间RESP3 协议也是从这代开始支持的。业务方如果是冲着这些能力来的3.2.12 基本没法交差。有人会说那装 EPEL 仓库试试EPEL 在 CentOS 7 上确实能提供更新的 Redis但版本依然停留在 5.x 左右而且升级节奏不受你控制想精确锁定 6.0.1 这个版本号很难。再看官方下载站里的预编译二进制。官方多数情况下会针对较新的发行版来编译拿回 CentOS 7.5 这种老系统上经常会遇到类似GLIBC_2.18 not found的报错。说到底CentOS 7.5 的 glibc 版本偏旧官方二进制没有义务向下兼容到这么老的运行库。这种情况下自己拿源码编译反而是最干净的出路。1.2 哪些场景适合走编译路线如果你遇到下面这几种情况编译安装基本是唯一合理选择需要精确锁定某个版本比如 6.0.1不跟随发行版仓库的随意变动需要把安装目录放到自定义路径下方便多版本共存或离线打包分发想通过编译参数开启特定模块比如 TLS 支持服务器不能连外网需要在内网离线环境用源码包落地上线。编译安装也能让你对安装过程完全可控知道每一步做了什么。对生产环境来说可控比省事更重要。所以环境准备上第一个要解决的不是 Redis 本身有什么依赖而是编译器。2. 环境准备CentOS 7.5 的第一道坎是 gcc不是 Redis2.1 默认 gcc 4.8.5 编译 Redis 6.x 为什么会直接挂CentOS 7.5 自带的 gcc 是 4.8.5。这个版本发布得很早对 C11 标准的支持并不完整而 Redis 6.x 源码里大量使用了 C11 的原子操作类型_Atomic和相关头文件。直接用它编译 Redis 6.0.1你很可能会在server.c或者其他核心文件里看到类似_Atomic未定义、stdatomic.h找不到的报错。我见过不少新手栽在这里源码包解压好make一跑满屏报错然后开始怀疑是不是 Redis 源码有问题甚至去网上搜各种奇怪的“补丁”。其实原因很简单就是编译器太老。注意不要去动系统的 glibc。网络上有一些文章为了编译新软件会叫你升级系统基础运行库这在 CentOS 7.5 上风险极高极有可能把整个系统的动态库依赖搞崩。正确的思路是用 Red Hat 系的 SCL 软件集单独装一个新版 gcc编译完就完事不污染系统自身。2.2 用 devtoolset-9 把编译器切到 gcc 9在 CentOS 7.5 上我推荐使用 devtoolset-9它提供的是 gcc 9.x 系列编译 Redis 6.0.1 足够用了。安装命令如下yum install -y centos-release-scl yum install -y devtoolset-9 scl enable devtoolset-9 bash gcc --versionscl enable devtoolset-9 bash这条命令的意思是在当前 shell 会话里临时把 devtoolset-9 的 bin 目录加到 PATH 前面。跑完gcc --version如果看到 gcc 9.x就说明切换成功。这里有个特别容易忽略的细节SCL 的切换只对当前终端会话有效。如果你开两个 SSH 窗口一个窗口scl enable之后开始编译另一个窗口没切直接用旧的 gcc那你第二个窗口编译必然报错。更隐蔽的场景是你用脚本或 CI 工具跑编译脚本里没激活 SCL 环境编译一样会失败。我习惯在~/.bashrc末尾加上一行source /opt/rh/devtoolset-9/enable这样新开的终端会话会自动带上 gcc 9。如果你担心影响其他编译任务那就只在编译时执行scl enable devtoolset-9 bash用完退出终端即可。2.3 顺手准备的系统依赖与目录规划编译 Redis 6.0.1 本身不依赖太多东西但如果你后面想跑make test就需要 tcl官方测试框架依赖它。建议提前装好yum install -y tcl另一个可选依赖是 openssl-devel。Redis 6.0.1 支持 TLS如果你打算启用加密传输需要这个头文件库暂时用不上也可以跳过。目录规划上我不建议把 Redis 安装到/usr/local/bin这种全局目录了事。更好的做法是使用带版本号的独立目录方便日后升级切换mkdir -p /usr/local/redis-6.0.1/bin mkdir -p /usr/local/redis-6.0.1/etc数据目录和日志目录建议独立放在系统数据区mkdir -p /var/lib/redis mkdir -p /var/log/redis目录建好之后先放着等创建了 redis 用户再一起调整权限。环境准备好了下面去拿源码包。3. 源码下载、编译、安装我把每条命令都拆开讲3.1 下载官方源码包并做 SHA256 校验源码包一定要从官方渠道下载Redis 官方下载页对应地址如下cd /usr/local/src wget https://download.redis.io/releases/redis-6.0.1.tar.gz下载完成后不要急着解压先做校验。官方页面会给出对应文件的 SHA256 值你在本机用sha256sum算一遍再和官方列出的值比对sha256sum redis-6.0.1.tar.gz这一步很多人会跳过。说实话如果只是内网自己用跳过可能也没事但如果是生产环境部署源码包被下载源掉包的风险虽然低后果却不可控。多花十秒钟买个心安。校验没问题再解压tar xzf redis-6.0.1.tar.gz cd redis-6.0.13.2 make 与 MALLOClibc为什么必须认识这个参数Redis 的源码没有 configure 脚本它和经典的 autotools 流程不一样不需要./configure make make install三步走。Redis 的 Makefile 自带依赖检查和构建逻辑你进入源码目录后直接make就能编译。但这里有一个很关键的参数MALLOC。Redis 默认使用自己内置的 jemalloc 内存分配器这是为了在高并发场景下减少内存碎片、提高分配效率。但问题在于Redis 6.0.1 自带的 jemalloc 在 CentOS 7.5 配合 gcc 9 的环境下偶尔会出现编译失败或运行期异常。最典型的现象就是卡在zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory。所以我在这类老系统上执行 make 时习惯直接指定使用系统的 libc 分配器make -j$(nproc) MALLOClibc-j$(nproc)表示用 CPU 核心数并行编译。如果服务器内存不大比如只有 2GB却是个 8 核机器并行编译可能会把内存吃满导致 OOM。这种情况建议保守一点手动限制并发数make -j2 MALLOClibc用MALLOClibc会不会损失很多性能对绝大多数应用来说差异远没有想象中大。jemalloc 的优势主要体现在长时间运行、高并发、内存分配频繁的场景如果内存碎片率本身不严重libc 分配器完全够用。我曾在一台 2C4G 的虚拟机上分别跑过日常业务 QPS 基本看不出差别。这一点后面验证章节也会提到。3.3 make install PREFIX 与重新编译的坑make distclean编译本身过程比较安静跑完没有报错之后建议做一次官方测试make testmake test需要 tcl 环境前面已经装好。测试会跑一段时间看到类似\o/ All tests passed without errors!的输出才算完整通过。这一步很多教程会略过但我建议至少在新环境第一次编译时跑一遍它能提前暴露出运行时问题而不是等你把 Redis 部署上去之后才发现进程起不来。测试通过后执行安装指定 PREFIX 路径make install PREFIX/usr/local/redis-6.0.1这个命令会把redis-server、redis-cli、redis-sentinel、redis-benchmark、redis-check-aof、redis-check-rdb等二进制复制到/usr/local/redis-6.0.1/bin目录下。你可以验证一下ls -l /usr/local/redis-6.0.1/bin /usr/local/redis-6.0.1/bin/redis-server --version到这里二进制就算装好了。这里必须提醒一个坑如果你在编译过程中改变了参数比如之前用默认 malloc 编译到一半现在想换成MALLOClibc或者在切换 gcc 版本之后重新编译一定要先执行make distcleanmake distclean会把之前的编译产物全部清掉强制全量重新编译。不要小看这一步。Makefile 的增量编译逻辑有时候不会重编所有文件新旧对象文件混在一起链接阶段就会出现各种诡异错误比如找不到符号、重复定义、版本不匹配。我踩过一次之后凡是改动编译参数或换了编译器都先make distclean再说。3.4 编译完成后的文件布局建议二进制已经放到/usr/local/redis-6.0.1/bin接下来把源码包里的配置文件复制到之前规划好的目录cp /usr/local/src/redis-6.0.1/redis.conf /etc/redis/redis.conf cp /usr/local/src/redis-6.0.1/sentinel.conf /etc/redis/sentinel.conf记住一个原则源码目录里的东西是“一次性构建产物”别在里面直接改配置运行。配置归/etc/redis数据归/var/lib/redis日志归/var/log/redis二进制归/usr/local/redis-6.0.1/bin。各司其职升级时也好处理。二进制到位了真正的运行环境也得同步准备。4. redis.conf 关键参数配置保姆级不等于什么都默认4.1 daemonize、supervised 与 systemd 的三角关系这个部分特别容易踩坑先说清楚。很多旧教程会让你把daemonize yes配上让 Redis 自己后台化。但在用 systemd 管理的生产环境里我建议把它设为no再用 systemd 配合supervised systemd来托管进程。为什么systemd 的Typenotify模式要求进程启动后主动向 systemd 发送“我准备好了”的通知。如果 Redis 自己先fork到后台父进程退出systemd 就很难精确掌握服务的就绪状态容易出现“systemctl start 返回了但实际还没有完全就绪”的尴尬局面。所以我的配置做法是daemonize no supervised systemd这样 Redis 以前台进程方式运行由 systemd 通过sd_notify机制来感知它的状态服务启停的反馈非常明确。4.2 bind、protected-mode 和密码配置配置文件里的bind和protected-mode必须一起看不然容易懵。默认情况下Redis 只监听127.0.0.1这是最安全的姿势。如果只有本机应用需要访问保持默认即可。如果有多台内网服务器要连这台 Redis就把bind改成内网 IP 和回环地址比如bind 127.0.0.1 192.168.10.20protected-mode yes的含义是当 Redis 没有配置密码、且监听地址不是仅限回环地址时它会拒绝外部连接。如果你既改了 bind 又开了 protected-mode但忘了设密码外部客户端会被直接拒绝这是保护机制在起作用不是故障。密码配置上老版本用requirepassRedis 6.0.1 虽然支持 ACL但最简单的方式依然是requirepass 你的强密码如果你要用 6.0.1 的 ACL可以单独在配置里定义用户user default on nopass ~* all user legacy on 你的强密码 ~* all不过 ACL 那套对新手来说入门成本更高初期用requirepass完全够。还有一种场景需要警惕如果把 3.x 老项目的客户端直接迁移到 6.0.1老客户端可能不认识 ACL 相关配置用requirepass反而是最兼容的方案。4.3 内存、RDB/AOF 和慢日志设置maxmemory这个参数我建议一定要显式配置否则 Redis 可能把整台机器内存吃满。具体值取决于你的业务形态纯缓存场景可以设置物理内存的 70% 左右配合maxmemory-policy allkeys-lru内存满了自动淘汰最久未使用的 key数据不可丢失的场景设置一个保守值并且maxmemory-policy noeviction内存满了直接拒绝写入保留数据完整性。持久化方面默认的 RDB 快照机制建议保留同时按需开启 AOFappendonly yes appendfsync everysecappendfsync everysec是性能和安全的平衡点每秒钟刷一次磁盘崩溃最多丢一秒数据。不建议用always写性能下降非常明显。慢日志也是运维排查问题时的利器slowlog-log-slower-than 10000 slowlog-max-len 128前者表示超过 10 毫秒的命令会被记录后者表示最多保留多少条慢日志。另外如果想让 Redis 更安全可以重命名危险命令rename-command FLUSHALL rename-command FLUSHDB rename-command CONFIG 但注意这么做的同时你的监控脚本、备份脚本里如果有调用CONFIG的命令会直接失效。改之前先确认一下业务脚本里有没有用到这些命令。配置改完还不能直接裸跑得让系统来接管它的生命周期。5. 把 Redis 6.0.1 交给 systemd 托管以及我实测的坑5.1 创建 redis 用户与服务目录Redis 的生产环境管理我几乎不用 root 直接跑服务而是创建一个专用账号最小化权限useradd -r -s /sbin/nologin redis-r表示创建系统账号-s /sbin/nologin表示禁止登录。然后调整之前建好的目录属主chown -R redis:redis /var/lib/redis chown -R redis:redis /var/log/redis chown -R redis:redis /usr/local/redis-6.0.1最后一项是让 redis 用户能读取二进制目录。如果之后做磁盘扩容或者数据归档也要保证新目录属主是 redis。5.2 systemd unit 文件的正确写法和 RuntimeDirectory 报错CentOS 7.5 内置的 systemd 版本偏老对较新版本新增的一些指令支持不完整。我在网上看到很多高版本系统的 unit 模板里面会用RuntimeDirectoryredis让 systemd 在/run下自动创建属主为 redis 的目录。这个写法在 CentOS 7 的 systemd 219 上能不能用取决于具体系统版本和 systemd 小版本有时候会直接报Unknown lvalue RuntimeDirectory in section Service。所以我在 CentOS 7.5 上的做法是不依赖RuntimeDirectory手工把需要用的运行目录建好mkdir -p /var/run/redis chown redis:redis /var/run/redis然后在 unit 文件里用/var/run/redis作为运行目录。我的 unit 文件放在/etc/systemd/system/redis.service内容如下[Unit] DescriptionRedis 6.0.1 server Afternetwork.target [Service] Userredis Groupredis Typenotify ExecStart/usr/local/redis-6.0.1/bin/redis-server /etc/redis/redis.conf ExecReload/bin/kill -s HUP $MAINPID TimeoutStopSec30 Restarton-failure RestartSec5 LimitNOFILE65535 PrivateTmptrue [Install] WantedBymulti-user.target注意这里Typenotify和配置文件里的supervised systemd、daemonize no是配套的。如果redis.conf里你写成了daemonize yes服务启动时 systemd 很可能报启动超时或者状态判定不准。写好 unit 后执行systemctl daemon-reload systemctl enable redis systemctl start redis systemctl status redis如果一切正常你会看到Active: active (running)。5.3 启动时可能出现的内核参数警告服务能起来不代表日志里干干净净。Redis 启动时经常在内核层面给出两类警告一类是内存 overcommit一类是 TCP backlog。vm.overcommit_memory默认值在 CentOS 7 里可能是 0。Redis 做 RDB 快照或者主从全量同步时需要 fork 子进程内核的内存分配策略在 overcommit 为 0 的情况下可能因为“虚拟内存承诺过量”而拒绝 fork导致后台保存失败。官方建议设置为 1echo vm.overcommit_memory 1 /etc/sysctl.conf sysctl -p另一条是 TCP backlogRedis 默认监听队列长度是 511但如果你系统的net.core.somaxconn只有 128Redis 的队列长度会被强制压到 128高并发情况下表现为连接排队甚至丢连接echo net.core.somaxconn 1024 /etc/sysctl.conf sysctl -p还有一个隐蔽问题是透明大页 THP。如果 Redis 日志里出现WARNING you have Transparent Huge Pages (THP) support enabled in your kernel建议临时关闭echo never /sys/kernel/mm/transparent_hugepage/enabledTHP 在 Redis fork 子进程做写时复制时会显著增加内存页分配延迟可能造成延迟尖刺。不过这个设置不是持久化的重启后需要重新执行所以通常配合 systemd service 片段或 rc.local 来做。5.4 防火墙与 SELinux 的补刀服务跑起来了但你从另一台机器用redis-cli -h 你的IP ping却连不上第一反应别急着怀疑 Redis 配置先看防火墙和 SELinux。CentOS 7.5 默认开着 firewalld放行端口firewall-cmd --permanent --add-port6379/tcp firewall-cmd --reload如果防火墙已经放行还是连不上再看 SELinux 有没有拦。SELinux 默认 enforcing 状态下自定义的 Redis 监听端口如果没有对应策略连接会被直接拒绝。可以查一下journalctl -u redis或ausearch -m avc。解决办法是给端口加上 redis 类型标签yum install -y policycoreutils-python semanage port -a -t redis_port_t -p tcp 6379如果端口已经存在把-a换成-m修改。不建议为了省事直接setenforce 0那相当于把整个系统的安全机制关掉了隐患太大。服务起来了不代表就没有暗坑验证要跟上。6. 安装后的验证从 redis-cli ping 到 benchmark 数据6.1 服务启动与基本验证命令先确认服务状态systemctl status redis再用客户端做一次最基本的连通性测试redis-cli ping如果你配置了requirepass直接redis-cli ping会得到NOAUTH Authentication required。正确的做法是用环境变量传密码避免密码出现在命令行历史里export REDISCLI_AUTH你的强密码 redis-cli ping输出PONG就说明 Redis 核心服务和认证都没问题。接着看服务器信息redis-cli info server重点看redis_version是否显示 6.0.1以及tcp_port是否和配置一致。再看内存和客户端连接redis-cli info memory redis-cli info clientsused_memory_rss和used_memory的比值可以初步判断内存碎片情况。如果比值长期偏高比如超过 1.5说明内存碎片严重这时候 jemalloc 的优势才会体现出来。6.2 redis-benchmark 怎么读结果安装目录自带redis-benchmark可以快速给服务做个压力摸底/usr/local/redis-6.0.1/bin/redis-benchmark -t set,get,incr,lpush -n 100000 -c 50 -r 1000000参数含义-t指定要测的命令集-n是每个命令的请求总数-c是并发客户端数-r表示使用随机 key避免把所有操作压到同一个 key 上造成误导。我拿一台 2C4G 的虚拟机跑出来的典型结果大概是 SET 100000 requests completed in 0.83 seconds 50 parallel clients ... Requests per second: 120481.93get 通常会比 set 高一点lpush 和 incr 也都在十万级别。如果你看到某个命令的 QPS 明显偏低先检查是不是 key 冲突严重或者网络延迟异常不要立刻怀疑 Redis 性能。另外benchmark 结果只能作为这台机器上的参考值不能直接当容量规划依据生产环境还要结合真实命令分布和键大小来评估。6.3 日志确认和后续升级的注意点启动完成后养成看日志的习惯tail -f /var/log/redis/redis.log正常启动日志应该只包含基础信息比如版本号、监听地址、配置加载路径。如果看到 5.3 节提到的 warning顺手把内核参数优化掉。这里再多说一点升级和回滚的维护习惯。编译安装最怕升级时把旧目录直接覆盖一旦新版本有问题你想回滚都找不回原样。正确做法是保留版本目录比如这次装在/usr/local/redis-6.0.1之后升级新版本时装到/usr/local/redis-6.0.2然后通过软链切换ln -s /usr/local/redis-6.0.1 /usr/local/redisunit 文件里的ExecStart写成/usr/local/redis/bin/redis-server。升级时停服务、改软链、启服务整个过程秒级完成出问题也能立刻切回旧目录。这个习惯帮我避免过好几次线上事故值得保留。安装过程中最值得反思的其实不是命令本身而是对老系统兼容性的敬畏。千万别为了省事去动系统的 glibc 或全局 gcc用 SCL 做工具链隔离是最稳妥的方案。我也见过有人编译到一半发现内存不够改小并发数之后不清理旧对象直接重编最后被各种莫名其妙的链接错误折磨白白浪费几个小时。遇到这种情况先make distclean再重新编译基本都能解决。生产服务器上的部署慢一点没关系重要的是每一步都可控、可回滚、可解释。