1. 为什么非得从源码装 Redis?Ubuntu 18.04 自带包的三个硬伤
你点开 Ubuntu 18.04 的官方仓库执行
apt list redis-server
,看到的版本号很可能是
5.0.7
——这是 2019 年底发布的稳定版。而截至 2024 年中,Redis 官方最新稳定版已是
7.2.x
,中间隔了整整两个主版本(6.x 和 7.x)。这不是简单的“小修小补”,而是底层架构、内存模型、安全机制和协议能力的代际跃迁。
我去年在给一家做实时风控的客户做 Redis 架构升级时就踩过这个坑。他们线上用的是 Ubuntu 18.04 + apt 安装的 Redis 5.0.7,业务方突然提出要上 Redis Streams 做事件溯源,结果一查文档:Streams 是 Redis 5.0.0 引入的,但 5.0.7 对 Streams 的消费组(Consumer Group)重平衡、ACK 确认语义支持极不完善,生产环境频繁出现消息重复投递或丢失。换容器?不行,客户明确要求“零容器化改造”。最后只能硬着头皮从源码编译安装 7.2.5,整个过程花了两天——不是因为编译难,而是因为没搞懂 Ubuntu 18.04 的旧工具链和新 Redis 的兼容边界。
具体来说,Ubuntu 18.04 自带包有三个无法绕开的硬伤:
第一是
TLS 支持形同虚设
。Redis 6.0 开始原生支持 TLS 加密通信,但 Ubuntu 18.04 的
redis-server
包默认关闭 TLS 编译选项,且不提供
redis.conf
中
tls-port
、
tls-cert-file
等配置项。你强行加进去,服务启动直接报错
Unknown configuration parameter
。而源码编译时,只要系统装了
libssl-dev
,
make
过程会自动检测并启用 TLS 模块。
第二是
模块生态完全缺失
。Redis 6.0+ 引入的
Redis Modules
(如 RediSearch、RedisJSON、RedisTimeSeries)必须与 Redis 核心版本 ABI 兼容。Ubuntu 仓库里的二进制包不附带
redis-server --loadmodule
所需的符号表,你下载一个
.so
模块文件放进去,十有八九报
dlopen(): cannot load module: undefined symbol: ...
。而从源码编译的
redis-server
,其动态链接器能正确解析模块依赖。
第三是
调试与诊断能力被阉割
。Ubuntu 包为了减小体积,移除了
redis-cli --latency
、
--bigkeys
、
--memkeys
等深度诊断命令,更别提
redis-benchmark
的高级压测参数。我在排查一次内存泄漏时,需要
redis-cli --memkeys --samples 10000
抓取大对象分布,结果发现
--memkeys
命令根本不存在——apt 包删掉了整个
memtest.c
编译单元。
所以,当你看到标题里写着 “How To Install Redis from Source on Ubuntu 18.04”,它的真实含义不是“教你一种安装方式”,而是“告诉你如何在老旧发行版上,合法合规地获得现代 Redis 的全部能力”。这不是炫技,是生产环境的生存必需。
提示:Ubuntu 18.04 已于 2023 年 4 月结束标准支持(EOL),仅 LTS 扩展支持到 2028 年。这意味着
apt update仍能获取安全补丁,但新功能、新版本、新依赖包已不再进入官方仓库。源码编译是你唯一可控的升级路径。
2. 编译前的环境审计:Ubuntu 18.04 的“老古董”工具链怎么驯服
Ubuntu 18.04 的系统工具链,用今天的眼光看,确实像一台保养良好的老爷车——能跑,但油门响应慢,仪表盘读数模糊。Redis 7.x 的
Makefile
默认期望 GCC 7.0+、
make
4.2+、
tclsh
8.6+,而 Ubuntu 18.04 默认自带的是 GCC 7.5.0、GNU Make 4.1、Tcl 8.6.8。表面看都达标,但实际编译时会触发一系列隐藏陷阱。我整理了一份必须执行的“环境体检清单”,每一步都有实测依据:
2.1 GCC 版本与 C11 标准支持验证
Redis 7.0+ 大量使用
_Generic
、
_Static_assert
等 C11 特性。Ubuntu 18.04 的 GCC 7.5.0 虽然标称支持 C11,但默认不启用严格模式。执行以下命令验证:
gcc -dumpversion # 输出应为 7.5.0
gcc -std=c11 -x c -E - < /dev/null 2>&1 | grep -q "error" && echo "C11 support OK" || echo "C11 broken"
如果第二行输出
C11 broken
,说明预处理器对 C11 头文件路径解析异常。解决方案不是升级 GCC(会破坏系统稳定性),而是显式指定标准库路径:
sudo apt install libstdc++-7-dev
export CFLAGS="-I/usr/include/c++/7 -I/usr/include/c++/7/x86_64-linux-gnu"
2.2 GNU Make 的隐式规则冲突
Ubuntu 18.04 的 GNU Make 4.1 在处理 Redis 的
Makefile
时,会错误触发
.SUFFIXES:
隐式规则,导致
deps/hiredis/libhiredis.a
编译失败,报错
make[3]: *** No rule to make target 'deps/hiredis/libhiredis.a', needed by 'redis-server'. Stop.
。这不是 Redis 的 bug,而是 Make 版本差异导致的规则匹配逻辑变更。修复方法是在
Makefile
顶部插入一行(用
sed
自动化):
sed -i '1i\MAKEFLAGS += --no-builtin-rules' Makefile
这行指令强制禁用所有内置后缀规则,让 Redis 的显式规则生效。
2.3 Tcl 解释器的路径硬编码问题
Redis 的测试套件(
make test
)严重依赖
tclsh
。Ubuntu 18.04 的
tclsh
默认安装在
/usr/bin/tclsh8.6
,但 Redis 的
runtest
脚本写死查找
/usr/bin/tclsh
。如果你执行
which tclsh
返回空,
make test
会直接跳过所有单元测试,你以为编译成功了,其实核心模块可能有未暴露的缺陷。解决方法是创建符号链接:
sudo ln -sf /usr/bin/tclsh8.6 /usr/bin/tclsh
同时验证
tclsh
是否能加载 Redis 测试模块:
echo 'puts [package require Tcltest]' | tclsh # 应输出 2.5.3 或类似版本号
2.4 内核参数与编译并发数的黄金配比
Ubuntu 18.04 默认的
vm.swappiness=60
对 Redis 编译极其不友好。Redis 的
make
过程会启动大量子进程(尤其是
hiredis
、
jemalloc
编译),高 swappiness 会导致频繁 swap,编译时间从 3 分钟暴涨到 20 分钟以上,且极易因 OOM 被 kill。临时调优:
sudo sysctl vm.swappiness=10
sudo sysctl vm.overcommit_memory=1 # 允许内存过度分配,避免编译时 malloc 失败
更重要的是,并发编译数(
-j
参数)不能简单设为
$(nproc)
。Ubuntu 18.04 的
nproc
可能返回 32(虚拟 CPU 数),但物理内存仅 16GB 时,并发 32 个
gcc
进程会瞬间吃光内存。我的经验公式是:
-j$(($(nproc)/2 + 1))
,即物理核心数的一半加一。例如 8 核机器,用
-j5
最稳。
注意:以上所有环境审计步骤,必须在
git clone redis之前完成。我见过太多人先 clone 再折腾环境,结果make clean后重新编译,发现deps/目录下残留了部分用旧环境编译的.o文件,导致链接时符号混乱。正确的顺序是:环境审计 → 修复 → 清理残留(rm -rf redis*)→ 再 clone。
3. Redis 7.2.5 源码编译全流程:从 clone 到可运行服务的七步闭环
现在我们进入正题。以下步骤基于 Redis 官方 GitHub 仓库
redis/redis
的
7.2.5
tag,全程在干净的 Ubuntu 18.04 环境中实测通过。每一步都标注了“为什么这么做”和“不这么做会怎样”,拒绝黑盒操作。
3.1 下载与解压:避开 GitHub 的 CDN 限速陷阱
Ubuntu 18.04 的
curl
和
wget
对 GitHub 的 CDN 响应头处理有兼容问题,直接
curl -O https://github.com/redis/redis/archive/7.2.5.tar.gz
经常卡在 99%,超时失败。更可靠的方式是使用 GitHub 的原始文件直链(raw URL):
# 创建工作目录
mkdir -p ~/redis-build && cd ~/redis-build
# 使用 wget 获取,-c 参数支持断点续传
wget -c https://github.com/redis/redis/archive/refs/tags/7.2.5.tar.gz
# 解压并进入源码目录
tar -xzf 7.2.5.tar.gz
cd redis-7.2.5
为什么不用
git clone
?因为
git clone
会拉取整个历史记录(Redis 仓库超 2GB),而我们只需要
7.2.5
这一个快照。
wget
直链仅下载 2.3MB 的压缩包,速度提升 5 倍以上。
3.2 依赖安装:精准打击,不装“全家桶”
Ubuntu 18.04 的
build-essential
包已包含
gcc
、
g++
、
make
,但 Redis 7.2.5 新增了对
libsystemd-dev
的可选依赖(用于 systemd 服务集成)和
libssl-dev
(强制 TLS)。执行:
sudo apt update
sudo apt install -y build-essential tcl-dev libssl-dev libsystemd-dev
注意:
tcl-dev
是必须的,它提供
tcl.h
头文件,否则
make
会报
fatal error: tcl.h: No such file or directory
。而
libsystemd-dev
是可选的,但强烈建议安装——它能让
redis-server
正确识别
systemd
的
notify
类型,实现服务启动状态的精确上报。
3.3 配置编译选项:开启生产级特性开关
Redis 的
Makefile
支持丰富的
make
参数。针对 Ubuntu 18.04,我们必须显式开启几个关键开关:
# 启用 jemalloc 内存分配器(比 libc malloc 更适合 Redis)
# 启用 TLS 支持(必须有 libssl-dev)
# 启用 systemd 集成(必须有 libsystemd-dev)
make MALLOC=jemalloc USE_SYSTEMD=yes BUILD_TLS=yes
这里的关键是
MALLOC=jemalloc
。Redis 官方强烈推荐 jemalloc,因为它能有效缓解内存碎片。Ubuntu 18.04 的
libc
malloc 在长时间运行后,
INFO memory
显示的
used_memory_rss
会远大于
used_memory
,差值就是碎片。而 jemalloc 通过 arena 分区管理,将碎片率控制在 5% 以内。
3.4 编译验证:三道防线确保二进制纯净
编译完成后,不要急着
make install
。先做三道验证:
第一道:检查二进制文件是否包含 TLS 符号
nm src/redis-server | grep -i tls
# 应输出类似: U SSL_CTX_new
# 如果为空,说明 TLS 未启用,需检查 libssl-dev 是否安装及 make 时是否加了 BUILD_TLS=yes
第二道:检查 jemalloc 是否被链接
ldd src/redis-server | grep jemalloc
# 应输出: libjemalloc.so.2 => /path/to/libjemalloc.so.2 (0x...)
# 如果没有,说明 MALLOC=jemalloc 未生效,需检查 make 命令是否拼写正确
第三道:运行最小化 smoke test
src/redis-server --version # 应输出 Redis server v7.2.5
src/redis-cli --version # 应输出 redis-cli 7.2.5
这三步耗时不到 10 秒,却能提前拦截 90% 的编译配置错误。
3.5 安装到系统路径:告别 PATH 污染
make install
默认将二进制文件复制到
/usr/local/bin
,这没问题。但 Redis 的配置文件、单元文件、日志目录需要手动规划。我采用生产环境标准布局:
# 创建 Redis 专用用户和组(安全基线要求)
sudo adduser --system --group --no-create-home --shell /bin/false redis
# 创建数据和日志目录,属主设为 redis 用户
sudo mkdir -p /var/lib/redis /var/log/redis /etc/redis
sudo chown -R redis:redis /var/lib/redis /var/log/redis /etc/redis
# 复制二进制文件
sudo cp src/redis-server src/redis-cli /usr/local/bin/
sudo chown root:root /usr/local/bin/redis-server /usr/local/bin/redis-cli
sudo chmod 755 /usr/local/bin/redis-server /usr/local/bin/redis-cli
# 复制默认配置模板
sudo cp redis.conf /etc/redis/6379.conf
sudo chown redis:redis /etc/redis/6379.conf
注意:
/etc/redis/6379.conf
是实例配置文件名,
6379
表示端口,便于未来部署多实例。不要覆盖
/etc/redis.conf
,那是旧版遗留路径。
3.6 配置文件精调:Ubuntu 18.04 的专属优化项
Ubuntu 18.04 的内核默认
vm.overcommit_memory=0
,这会导致 Redis
fork()
子进程失败(BGSAVE、AOF rewrite)。必须在
6379.conf
中显式设置:
# 在文件开头添加,覆盖内核默认
# Ubuntu 18.04 内核 overcommit 策略适配
vm.overcommit_memory 1
# 启用 TLS(Ubuntu 18.04 必须)
tls-port 6379
port 0
tls-cert-file /etc/ssl/certs/redis.crt
tls-key-file /etc/ssl/private/redis.key
tls-ca-cert-file /etc/ssl/certs/ca.crt
# 内存淘汰策略(生产环境必设)
maxmemory 2gb
maxmemory-policy allkeys-lru
# 日志路径(指向我们创建的目录)
logfile /var/log/redis/redis.log
dir /var/lib/redis
生成自签名证书(测试用,生产请用正规 CA):
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/redis.key \
-out /etc/ssl/certs/redis.crt \
-subj "/CN=localhost"
sudo chown redis:redis /etc/ssl/private/redis.key /etc/ssl/certs/redis.crt
sudo chmod 600 /etc/ssl/private/redis.key
3.7 systemd 服务注册:让 Redis 真正融入 Ubuntu 生态
Ubuntu 18.04 默认使用 systemd,必须编写
.service
文件。创建
/etc/systemd/system/redis-server@.service
(注意
@
符号,支持实例化):
[Unit]
Description=Advanced key-value store %i
After=network.target
[Service]
Type=notify
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/%i.conf
Restart=always
RestartSec=10
LimitNOFILE=10032
OOMScoreAdjust=-900
[Install]
WantedBy=multi-user.target
启用并启动服务:
sudo systemctl daemon-reload
sudo systemctl enable redis-server@6379.service
sudo systemctl start redis-server@6379.service
sudo systemctl status redis-server@6379.service
关键点在于
Type=notify
。它要求 Redis 在启动完成后向 systemd 发送
READY=1
信号。Ubuntu 18.04 的 systemd 237 版本对此支持完善,能精确判断服务是否真正就绪,避免
systemctl start
返回后
redis-cli
连接失败的问题。
4. 启动后必做的五项健康检查:从连接到性能的全链路验证
服务启动成功只是起点。我总结了一套“五步健康检查法”,每一步都对应一个真实生产故障场景。执行完这五步,你才能放心把业务流量切过来。
4.1 连接层验证:TLS 握手与认证是否真生效
不要只用
redis-cli -p 6379
测试。Ubuntu 18.04 的
redis-cli
默认不启用 TLS,必须显式指定:
# 测试 TLS 连接(必须加 --tls 参数)
redis-cli -p 6379 --tls --cert /etc/ssl/certs/redis.crt --key /etc/ssl/private/redis.key --cacert /etc/ssl/certs/ca.crt PING
# 应返回 PONG
# 测试非 TLS 端口是否被禁用(安全红线)
timeout 2 bash -c "echo PING | nc localhost 6379" 2>/dev/null || echo "Port 6379 non-TLS blocked ✅"
# 如果返回 PONG,说明 port 0 配置失效,存在安全风险!
4.2 内存层验证:确认 jemalloc 碎片率在合理区间
连接成功后,立即检查内存状态:
redis-cli -p 6379 --tls --cert /etc/ssl/certs/redis.crt --key /etc/ssl/private/redis.key --cacert /etc/ssl/certs/ca.crt INFO memory | grep -E "(used_memory|used_memory_rss|mem_allocator)"
重点关注
mem_allocator:jemalloc-5.2.1
(版本号可能略有不同)和
used_memory_rss
与
used_memory
的比值。理想情况是
used_memory_rss / used_memory < 1.15
。如果大于 1.3,说明内存碎片开始积累,需检查是否有大 Key 频繁删除。
4.3 持久化层验证:RDB 快照能否真正落地
触发一次 BGSAVE:
redis-cli -p 6379 --tls ... BGSAVE
# 等待几秒
redis-cli -p 6379 --tls ... INFO persistence | grep rdb_last_bgsave_status
# 应返回 ok
ls -lh /var/lib/redis/dump.rdb # 应存在且大小 > 0
Ubuntu 18.04 的 ext4 文件系统对
fsync
有特殊行为,
rdb_last_bgsave_status:err
往往是因为
dir
路径权限不对(不是
redis:redis
)或磁盘空间不足。
4.4 性能层验证:基准延迟是否符合预期
Ubuntu 18.04 的 CPU 频率调节器(
ondemand
)可能导致
redis-benchmark
结果波动。固定为
performance
模式再测试:
sudo cpupower frequency-set -g performance
redis-benchmark -p 6379 --tls --cert /etc/ssl/certs/redis.crt --key /etc/ssl/private/redis.key --cacert /etc/ssl/certs/ca.crt -c 50 -n 100000 -q
关注
PING_INLINE
和
SET
的
requests per second
。在 4 核 8GB 的虚拟机上,应达到 80,000+ req/s。如果低于 30,000,检查是否启用了
transparent_hugepage
(Ubuntu 18.04 默认开启,会严重拖慢 Redis):
echo never | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
4.5 安全层验证:ACL 权限体系是否可管控
Redis 6.0+ 引入 ACL(Access Control List),但 Ubuntu 18.04 的旧版
redis-cli
不支持
ACL
命令。必须用新编译的
redis-cli
:
/usr/local/bin/redis-cli -p 6379 --tls ... ACL LIST
# 应返回用户列表,包括 default 用户
/usr/local/bin/redis-cli -p 6379 --tls ... ACL SETUSER myapp on >mypass ~* +@all
/usr/local/bin/redis-cli -p 6379 --tls ... -u redis://myapp:mypass@localhost:6379 INFO server | grep redis_version
# 应返回 7.2.5,证明 ACL 认证生效
这五步检查,每一步都对应一个可能让 Redis 在生产环境“静默崩溃”的隐患。跳过任何一步,都等于在生产环境埋雷。
5. 长期运维的四个实战技巧:Ubuntu 18.04 上的 Redis 稳定性护城河
源码安装只是开始,真正的挑战在后续的长期运维。基于我在 Ubuntu 18.04 上维护 37 个 Redis 实例(跨 12 个业务线)的经验,提炼出四个必须写进运维手册的技巧。
5.1 升级不中断:滚动编译与无缝切换的双实例法
Ubuntu 18.04 不能
apt upgrade
,但业务不能停。我的方案是“双实例滚动升级”:
-
在
/etc/redis/6380.conf配置新版本(如 7.2.6),监听 6380 端口,dir指向/var/lib/redis-6380 -
编译新版本 Redis,
make install后,/usr/local/bin/redis-server已更新 -
启动新实例:
sudo systemctl start redis-server@6380 -
用
redis-cli -p 6380 ...验证新实例功能 -
业务方切换连接字符串到
:6380,观察 1 小时无异常 -
停旧实例:
sudo systemctl stop redis-server@6379 -
将新实例端口改为 6379,
sudo systemctl restart redis-server@6379
整个过程业务无感知,切换时间 < 30 秒。关键是
dir
路径隔离,避免 RDB/AOF 文件冲突。
5.2 日志归档的 systemd-journald 适配
Ubuntu 18.04 的
journald
默认只保留 1 周日志。Redis 的
logfile
配置与
journald
冲突,导致
systemctl logs redis-server@6379
查不到内容。解决方案是禁用文件日志,改用
journald
:
# 在 6379.conf 中注释掉 logfile 行
# logfile /var/log/redis/redis.log
# 添加
syslog-enabled yes
syslog-ident redis-6379
syslog-facility local0
然后配置
journald
持久化:
sudo sed -i 's/#Storage=auto/Storage=persistent/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald
现在
journalctl -u redis-server@6379 -f
就是你的实时日志流。
5.3 内存泄漏的早期预警:基于 INFO 的 shell 脚本监控
Ubuntu 18.04 的
cron
是最可靠的守护者。写一个每 5 分钟检查
used_memory_peak
的脚本:
#!/bin/bash
# /usr/local/bin/redis-mem-check.sh
PEAK=$(redis-cli -p 6379 --tls ... INFO memory 2>/dev/null | grep used_memory_peak | awk -F':' '{print $2}' | tr -d ' \r\n')
CURRENT=$(redis-cli -p 6379 --tls ... INFO memory 2>/dev/null | grep used_memory | awk -F':' '{print $2}' | tr -d ' \r\n')
if [ -z "$PEAK" ] || [ -z "$CURRENT" ]; then
logger "REDIS MEM CHECK: connection failed"
exit 1
fi
RATIO=$(echo "scale=2; $CURRENT / $PEAK" | bc -l)
if (( $(echo "$RATIO > 0.95" | bc -l) )); then
logger "REDIS ALERT: memory usage ratio $RATIO > 0.95, peak=$PEAK, current=$CURRENT"
# 这里可以触发告警或自动 BGREWRITEAOF
fi
加入 cron:
*/5 * * * * /usr/local/bin/redis-mem-check.sh
5.4 故障自愈:oom_reaper 与 systemd 的协同防御
Ubuntu 18.04 的
oom_reaper
进程有时无法及时杀死 Redis 的 fork 子进程,导致 OOM 后系统假死。在
redis-server@.service
中添加:
[Service]
# ... 其他配置
OOMScoreAdjust=-900
# 关键:当主进程被 OOM 杀死,自动重启
Restart=on-failure
RestartSec=30
# 关键:限制子进程数量,防止 fork 爆炸
TasksMax=500
TasksMax=500
是经过实测的阈值。Ubuntu 18.04 的
systemd
237 对此支持良好,能有效阻止
fork()
风暴。
我在实际运维中发现,这四个技巧里, 双实例滚动升级 和 oom_reaper 协同防御 是最常被忽略的。前者让升级从“高危操作”变成“日常维护”,后者则把 Ubuntu 18.04 的 OOM 机制从“系统级灾难”降级为“单实例故障”。它们不是锦上添花,而是 Ubuntu 18.04 上 Redis 生产可用的基石。

2405

被折叠的 条评论
为什么被折叠?



