一、为什么先谈“安装”而不是“使用”
很多工程师习惯把 Redis 当成“apt-get install”就能跑起来的黑盒,结果上线第一天就遇到三大灵魂拷问:
很多工程师习惯把 Redis 当成“apt-get install”就能跑起来的黑盒,结果上线第一天就遇到三大灵魂拷问:
-
为什么本地压测只有三万 QPS,到了预发环境突然掉到一万?
-
为什么明明给了 8 G 内存,日志却报 “Can’t allocate memory”?
-
为什么主从切换后数据回滚了十分钟?
追根溯源,80% 的诡异现象都能在“安装阶段”埋下的隐患里找到答案。把安装做扎实,等于把后期 2 a.m. 的告警扼杀在摇篮里。本文用 3000 字把“安装”拆成七步:环境、版本、目录、编译、配置、启停、校验,每一步都给出选择逻辑与避坑要点,力求让你下一次装机不再靠“抄博客”,而是“心里有数”。
二、环境:先问操作系统,再问内核
-
操作系统
Linux 是事实标准,但不同发行版的默认参数差异巨大。以文件句柄数为例,Ubuntu 20.04 默认 1024,CentOS 8 默认 65536,直接决定 Redis 能不能扛住 10 万并发连接。 -
内核版本
2.6.32 可以跑,但 3.10+ 才支持 SO_REUSEPORT,能让多实例绑定同端口做负载均衡;5.0+ 才支持 io_uring,对 AOF 重写有 10% 左右的 I/O 提升。如果公司规定必须用老内核,就要提前评估性能折损。 -
内存与 Swap
Redis 是内存数据库,但不是“内存越多越好”。预留 20% 给写时复制、缓冲区和系统页缓存,Swap 必须关,否则一次透明大页压缩就能让延迟飙到秒级。 -
磁盘
磁盘不是“能用就行”。AOF 每秒刷盘一次,如果磁盘写入延迟 5 ms,请求尾延迟就会涨到 5 ms。建议用 nvme 或者至少 SSD,且挂载时加 noatime、nodiratime,减少元数据开销。 -
网络
万兆网卡是标配,但别忘了检查中断亲和性。把网卡队列绑定到不同 CPU,能把 P99 延迟再降 200 µs。
三、版本:稳定≠最新,新特性≠刚需
-
主版本号
6.2 引入 ACL、SSL、多线程 I/O,7.0 引入 Functions、Sharded Pub/Sub。如果业务只用缓存,5.0 足够;需要细粒度权限控制就上 6.2;想尝鲜可插脚本的 Functions 才选 7.0。 -
小版本号
偶数小版本是稳定版,奇数是开发版,这是 Redis 官方 10 年传统。别在生产线程上跑 7.1-rc1,除非你想给社区贡献 Issue。 -
回退策略
升级前一定准备回退包:把旧版本的二进制、配置、RDB 文件打包到 /opt/redis/rollback 目录,并写一行 systemd 的 Conflicts= 确保新旧单元不会同时启动。
四、目录:用“四目录法则”告别文件散落
-
二进制目录 /opt/redis/bin
放可执行文件,权限 755,属主 root,避免开发同学误删。 -
配置目录 /etc/redis
一个实例一个文件,命名规则:端口.conf,例如 6379.conf、6380.conf。 -
数据目录 /data/redis/端口
RDB、AOF、临时文件全放这里,单独挂载一块盘,方便用 df -h 快速看容量。 -
日志目录 /var/log/redis
给 rsyslog 或者 systemd-journald 做统一收集,文件名带端口,方便 ELK 切分。
这样做的好处:
-
水平扩容时,只需新建 /data/redis/6381,无需改 puppet/ansible 脚本;
-
故障排查时,根据端口号就能定位所有文件,减少 30% 的沟通成本。
五、编译:把“-O2” 改成 “-O3” 之前先想清楚
-
依赖检查
gcc、make、tcl 缺一不可,但最容易被忽略的是 jemalloc。系统自带 glibc malloc 在 64 核机器上会出现疯狂锁竞争,把 QPS 砍掉一半。 -
编译参数
MALLOC=jemalloc 是必选项;
如果 CPU 支持 AVX2,加 CFLAGS=”-mavx2 -O3” 能把 zset 的 score 比较性能提高 8%;
但 -O3 会让调试符号失真,core dump 时 gdb 看不见局部变量,开发环境建议 -O0 -g。 -
静态链接
生产环境常因为升级 glibc 导致 redis-server 起不来,用 make BUILD_TLS=yes USE_STATIC=1 把 openssl 和 jemalloc 静态编进去,可彻底规避“同版本不同机器”的依赖地狱。 -
多实例复用
编译结果只有 15 M,把 redis-server 复制成 redis-server-6379、redis-server-6380,就能在升级时做灰度:先停 6380,再启动新二进制,滚动重启,用户无感知。
六、配置:别让“网上抄的”毁了你
-
内存
maxmemory 不要等于物理内存,留 20% 给 fork 写时复制;
淘汰策略用 allkeys-lru 还是 volatile-ttl,取决于业务是否全量设过期时间,选错一次,高峰期就能让 DB 被打穿。 -
持久化
RDB 和 AOF 不是“二选一”,而是“分层保险”:
-
RDB 做冷备,每天一次,恢复速度 1 G/10 s;
-
AOF 做热备,每秒刷盘,最多丢 1 s;
同时开启时,Redis 7.0 会走 “RDB-AOF mixed” 格式,文件体积降 60%,重启速度翻倍。
-
网络
tcp-backlog 设 511 还是 2048?看 Linux 的 net.core.somaxconn 默认值,如果系统只有 128,Redis 设 2048 也没用。 -
安全
bind 0.0.0.0 一定要配合 requirepass 或者 ACL,否则扫描器 3 秒就能把你的 key 全拉走;
rename-command 把 CONFIG、FLUSHALL 改名,防止实习生凌晨两点手滑。 -
多线程
io-threads 4 不是“越大越好”,超过 8 线程后内核调度开销会反杀性能;
建议压测:先用 redis-benchmark -t set -d 256b -c 50 -n 1000000 看 baseline,再逐步加线程,找到拐点。
七、启停:systemd 不是“写完 service 文件就完事”
-
通知机制
Type=notify 能让 Redis 在真正完成端口监听后再通知 systemd,避免监控系统误判“端口起不来”。 -
重启策略
Restart=on-failure 必须配合 RestartSec=5s,否则故障死循环会把机器打挂;
StartLimitInterval=60s StartLimitBurst=3 能在 1 分钟内最多重启 3 次,超过就放弃,等人干预。 -
资源限制
LimitNOFILE=1000000
LimitNPROC=8192
这两个值如果低于 Redis 里的 maxclients,就会在日志里出现 “Too many open files”,但系统又不报任何错,排查平均耗时 30 分钟。 -
优雅关闭
TimeoutStopSec=30
KillMode=mixed
Redis 收到 SIGTERM 后会先尝试持久化,如果 30 秒还没完,systemd 会补 SIGKILL。把 TimeoutStopSec 设太短会导致 AOF 末尾截断,重启时触发 redis-check-aof –fix,耗时跟数据量成正比。
八、校验:跑通“三步体检”再上线
-
连通性
redis-cli -p 6379 ping 返回 PONG 只是第一步,再用 telnet 127.0.0.1 6379 看是否立刻断开,判断防火墙是否放行。 -
性能基线
用 redis-benchmark 打本机 loopback,记录 set、get、lpush、sadd、zadd 五类命令的 QPS 和延迟,写成 markdown 存到 docs/performance.md,以后升级硬件或版本,先跑同一条命令,性能掉 10% 以上就回退。 -
数据一致性
写 100 万条 key,格式为 key_(i,value为 UUID;
执行 BGSAVE,等待 RDB 完成;
kill -9 redis-server,模拟野蛮断电;
重启后执行 redis-cli –bigkeys 和 sha1sum 校验,确认条数、SHA1 值一致,才算持久化可信。
九、常见翻车现场 30 秒速查表
-
启动时报 “WARNING overcommit_memory is set to 0”
echo 1 > /proc/sys/vm/overcommit_memory -
日志里 “Can’t save in background: fork: Cannot allocate memory”
把 vm.overcommit_memory 设为 1 后仍报错,说明物理内存不足,需要降 maxmemory 或加机器。 -
客户端偶尔报 “Connection reset by peer”
检查 tcp-keepalive 60 是否开启,以及 net.ipv4.tcp_keepalive_time 是否小于 60。 -
从库持续 “master_link_status:down”
主库 bind 127.0.0.1,导致从库连不上,把 bind 改成内网地址即可。 -
升级后原配置失效
Redis 7.0 把 “slave” 关键字全面改成 “replica”,老配置里如果写 slaveof 会被忽略,必须全局替换。
十、一条命令都不给,怎么自动化?
-
模板引擎
用 Jinja2 写 redis.conf.j2,变量只有端口号、内存、是否主库三处,其余字段写死,杜绝“复制粘贴改错”。 -
配置校验
写 preflight 脚本,用正则检查 maxmemory < (物理内存 * 0.8),检查 bind 不是 0.0.0.0 就是 127.0.0.1,否则拒绝启动。 -
灰度发布
把 redis-server 二进制放到对象存储,下载后做 sha256 校验,确认无误再 systemd 启动;同时用 consul-template 把实例信息注册到服务发现,让监控自动拉取。
十一、写在最后的 4 句忠告
-
安装不是“能跑就行”,而是“给七年后的凌晨留一条活路”。
-
每当你想省掉一次校验,就把生产故障的 PPT 想象成自己上台讲解。
-
把这篇文章打印出来,贴到工位,下次装机逐条打钩,能减少 90% 的“灵异事件”。
-
Redis 很轻,轻到 15 M 的二进制就能撑起亿级流量;Redis 也很重,重到一次安装疏忽就能让年终奖归零。愿你从此不再惧怕任何一次版本升级。