Redis 安装部署与生产配置基线实战

不少团队的 Redis 是「下载解压直接跑」上线的:默认配置不设密码、监听所有网卡,日志里 overcommit 与 THP 的警告挂了几个月也没人管。单机 Redis 本身不难装,难的是把生产基线一次配对。本文以 Redis 7.x 为例,从源码编译安装开始,逐项过一遍 systemd 托管与 redis.conf 的关键配置,最后给出上线自检清单。哨兵高可用与内存调优站内另有专篇,本文不展开。

问题与适用环境

默认配置直接用于生产,典型风险有四个:一是 bind 未收敛又没有密码,端口一旦暴露到公网极易遭遇未授权访问;二是 fork 做持久化时受内核 overcommit 策略影响,内存紧张时 RDB 保存与 AOF 重写可能失败;三是透明大页(THP)让 fork 的写时复制代价成倍放大,带来延迟毛刺与内存膨胀;四是进程文件句柄上限不足,连接数上来后 accept 失败。本文适用于单机或主从架构中的单个节点,环境为 Rocky Linux 9 / Ubuntu 22.04、Redis 7.2、systemd 托管;示例主机名 redis-01、内网地址 192.0.2.10,文中口令均以 <强密码> 占位。所谓「配置基线」,就是一份可以逐项打勾的最小完备清单:每一项都对应一类真实出过事的故障模式,先都配对,再谈业务调优。

前置条件

  • 具有 root 或 sudo 权限的账号,主机已配好静态内网地址与主机名。
  • 可访问外网下载源码,或已将安装包上传到 /usr/local/src。
  • 规划好 6379 端口的放行范围:只对应用服务器网段开放,绝不对公网开放。
  • 数据目录所在分区预留充足空间,一般不低于 maxmemory 的 2 倍。

一、源码编译安装

Redis 对编译环境要求不高,但要注意装上 systemd 开发库并打开 USE_SYSTEMD,这样后面 systemd 的 Type=notify 才能收到 Redis 的就绪通知;BUILD_TLS 仅在需要 TLS 连接时再加。

# Rocky / RHEL 系
dnf install -y gcc make tcl systemd-devel
# Ubuntu / Debian 系
apt install -y build-essential tcl libsystemd-dev

cd /usr/local/src
wget https://download.redis.io/releases/redis-7.2.5.tar.gz
tar xf redis-7.2.5.tar.gz
cd redis-7.2.5
make -j"$(nproc)" USE_SYSTEMD=yes
make install
redis-server --version

make install 默认把 redis-server、redis-cli 等二进制装到 /usr/local/bin,最后能打印出版本号即编译安装成功。

二、运行用户与目录规划

不要用 root 跑 Redis。创建专用系统用户,并按「配置 / 数据 / 日志」三分目录落地:

useradd -r -s /sbin/nologin -d /var/lib/redis redis
install -d -o redis -g redis -m 0750 /etc/redis /var/lib/redis /var/log/redis
cp /usr/local/src/redis-7.2.5/redis.conf /etc/redis/redis.conf
chown redis:redis /etc/redis/redis.conf
chmod 0640 /etc/redis/redis.conf

其中 /var/lib/redis 是数据目录,后面配置项 dir 指向它,建议挂在独立数据盘上;配置文件里有明文口令,权限收紧到 0640。

三、redis.conf 生产基线

1. 网络与访问控制

bind 127.0.0.1 -::1 192.0.2.10
protected-mode yes
port 6379
requirepass <强密码>
tcp-backlog 511
tcp-keepalive 300

逐项说明:bind 只写实际要监听的地址(本机回环加内网业务地址),不要留空,更不要图省事写 0.0.0.0;protected-mode 是兜底保护——当没有设置密码、又绑定了非回环地址时,它只允许本机连接,基线里保留 yes;requirepass 设置强口令是硬性要求(Redis 6 起还可用 ACL 做细粒度授权,单机基线先把默认口令落实);tcp-backlog 是待连接队列长度,它能否真正生效还取决于内核 somaxconn 不小于它,见第四节。两个细节别漏:bind 里 -::1 前面的减号表示「地址不存在时忽略」,避免没开 IPv6 的主机因绑定失败起不来;口令只写进配置文件和应用的连接串,不要出现在命令行、脚本与工单里,redis-cli 带 -a 时口令还会进入进程列表与 shell 历史,生产环境更推荐用环境变量 REDISCLI_AUTH 传入口令。

2. 进程托管方式

daemonize no
supervised auto
pidfile /run/redis/redis.pid
logfile /var/log/redis/redis.log

交给 systemd 托管时,daemonize 必须为 no,让 Redis 保持前台进程,systemd 才能正确跟踪其状态并在异常退出时重启;supervised auto 会自动识别运行环境,在 systemd 下(且编译时开启了 USE_SYSTEMD)于就绪时发出通知信号。logfile 写绝对路径,不要保留默认空值把日志打到无人收集的标准输出。

3. 数据目录

dir /var/lib/redis
dbfilename dump.rdb

dir 同时决定 RDB 与 AOF 文件的落盘路径,必须指向规划好的独立数据目录,不要留用默认的启动目录——把数据写进系统盘根分区,写满时拖垮的是整台主机。还要给这个分区留监控告警:RDB 文件约为内存数据的压缩后体积,AOF 重写期间会短时占用额外一份空间,磁盘使用率超过八成就要扩容。本文只要求路径与权限正确,持久化的具体策略参数按业务另行评估。

4. 内存上限入口

maxmemory 2gb
maxmemory-policy noeviction

maxmemory 是生产必设项:不设上限时 Redis 会持续吃内存,最终被系统 OOM Kill。数值按「主机内存减去系统与页缓存预留」规划,例如 4 GB 内存的主机可设 2gb。还要留出 fork 的余量:做 RDB 或 AOF 重写时,子进程与父进程靠写时复制共享内存页,写入越频繁,被复制的页越多,极端情况下需要接近一倍于数据量的空闲内存,所以 maxmemory 永远不要贴着物理内存上限设。淘汰策略这里只点入口:纯缓存场景选 allkeys-lru,把 Redis 当存储用则选 noeviction(写满直接报错,避免静默丢数据);具体的内存调优见站内《Redis 内存优化》一篇。

四、内核参数

三项内核设置决定 fork 的成败与连接队列是否生效,改完务必持久化:

cat > /etc/sysctl.d/99-redis.conf <<'EOF'
vm.overcommit_memory = 1
net.core.somaxconn = 65535
EOF
sysctl -p /etc/sysctl.d/99-redis.conf

# 关闭透明大页 THP(即时生效部分)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

vm.overcommit_memory=1 表示允许内存过量分配,保证大内存实例在 bgsave、AOF 重写 fork 子进程时不因策略被拒绝。THP 的 sysfs 写法重启后会失效,持久化二选一:给内核启动参数加 transparent_hugepage=never(Rocky 系可用 grubby --update-kernel=ALL --args="transparent_hugepage=never"),或写一个开机执行的 systemd oneshot 服务写回这两个文件。改完可以查 /proc/meminfo 里的 AnonHugePages,应当降到 0 或接近 0;ss 输出里监听队列的 Send-Q 显示为 511,则说明 backlog 与 somaxconn 已经对齐。

五、systemd 托管

新建 /etc/systemd/system/redis.service:

[Unit]
Description=Redis 7 In-Memory Data Store
After=network.target

[Service]
Type=notify
User=redis
Group=redis
WorkingDirectory=/var/lib/redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
RuntimeDirectory=redis
LimitNOFILE=65535
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

三个关键点:Type=notify 与配置里的 supervised auto 相对应;RuntimeDirectory=redis 会在 /run 下创建属主为 redis 的目录,供 pidfile 使用;LimitNOFILE 必须大于等于 maxclients + 32(maxclients 默认 10000,即至少 10032),否则启动日志会报警、高并发下新连接被拒,这里直接给 65535。另外不要写 ExecStop 去调 redis-cli shutdown:收到 SIGTERM 时 Redis 会自行完成落盘退出,而带口令时用 CLI 停服反而容易失败。

systemctl daemon-reload
systemctl enable --now redis

验证

$ systemctl is-active redis
active
$ ss -lntp | grep 6379
LISTEN 0 511 192.0.2.10:6379 0.0.0.0:* users:(("redis-server",pid=1234,fd=8))
$ redis-cli -a '<强密码>' ping
PONG
$ redis-cli -a '<强密码>' CONFIG GET maxmemory supervised
1) "maxmemory"
2) "2147483648"
3) "supervised"
4) "systemd"

再手动执行一次 redis-cli -a '<强密码>' BGSAVE,确认 /var/lib/redis 下生成 dump.rdb 且日志无报错,这一步同时验证了数据目录权限与 fork 路径都通。最后检查启动日志 /var/log/redis/redis.log,确认没有 overcommit、THP、backlog、文件句柄四类 WARNING——只要还有警告,就说明第四、五节里有某项没有真正生效。

常见问题

  • 服务启动后立刻退出,日志报 Permission denied:多半是数据或日志目录属主不是 redis,按第二节重新 chown。
  • 日志警告 TCP backlog of 511 cannot be enforced:somaxconn 小于 tcp-backlog,按第四节调大并重启服务。
  • 日志警告 overcommit_memory is set to 0,提示后台保存可能失败:sysctl 未生效或被其他配置文件覆盖,检查 /etc/sysctl.d/ 下的加载顺序。
  • 日志警告 THP support enabled:只做了即时关闭没做持久化,重启后恢复;或只改了 enabled 没改 defrag,两处都要设为 never。
  • 日志提示当前文件句柄上限低于 maxclients + 32:LimitNOFILE 没改,或改完后忘了执行 daemon-reload。
  • 本机 ping 正常但应用服务器连不上:依次查 bind 是否包含业务地址、防火墙是否放行 6379、口令是否一致;切忌为了「连上」就改成 bind 0.0.0.0 并去掉密码。
  • 用 CONFIG SET 在线改的参数,重启后又恢复了:CONFIG SET 只改内存中的运行值,不会自动写回文件。基线参数必须同步写进 redis.conf,或改完后执行 CONFIG REWRITE 落盘,否则重启、故障切换后配置回退,问题还会重演。

配置自检清单

  • bind 只监听回环与内网业务地址,protected-mode 为 yes。
  • requirepass 已设强口令,6379 未对公网开放,配置文件权限为 0640。
  • daemonize 为 no,supervised 与 Type=notify 对应,服务已设开机自启。
  • dir 指向 /var/lib/redis,属主 redis、权限 0750,位于独立数据分区。
  • maxmemory 已按主机内存设上限,淘汰策略与实际用途相符。
  • vm.overcommit_memory=1 已持久化;THP 的 enabled 与 defrag 均为 never 且重启不失效。
  • net.core.somaxconn 不小于 tcp-backlog;LimitNOFILE 不小于 maxclients + 32。
  • redis-cli ping 返回 PONG,启动日志无四类警告。

小结

单机 Redis 的生产基线可以浓缩成一句话:编译时打开 systemd 支持,用专用用户与三分目录规范落地,redis.conf 收敛监听与口令、设好内存上限,内核层关掉 THP、打开 overcommit,再用 somaxconn 与 LimitNOFILE 把连接能力兜住。按文中顺序做完并逐项对照自检清单打勾,就是一台可以放心交付的单机 Redis;在此之上再做高可用与内存调优,可继续阅读站内《Redis 哨兵高可用》与《Redis 内存优化》两篇。

发表回复

后才能评论