Skip to content

Redis 7 源码安装与 systemd 托管 ​

包管理器装的 Redis 版本老、配置散在 /etc/redis/ 各处,且开机自启行为各发行版不一致。生产建议源码装 + 自己写 unit,目录、配置、日志、数据四件事全在自己手里。

前置:编译器版本 ​

Redis 7.x 要求 GCC 8 以上,CentOS 7 自带的 4.8 会编译失败。

bash
gcc --version

输出:

text
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)

解释:看到这个版本就必须先装 devtoolset,否则 make 会在 server.c 报 C11 语法错误。Rocky 8/9、Ubuntu 20.04+ 自带 GCC 8+ 可跳过。

bash
# CentOS 7
yum install -y centos-release-scl && yum install -y devtoolset-11-gcc devtoolset-11-gcc-c++
scl enable devtoolset-11 bash          # 进入临时高版本环境,注意别只 source 不生效

# Rocky / Alma / Ubuntu 22 只需装基础工具
yum install -y gcc make                # 或 apt install -y build-essential

一、编译安装 ​

bash
cd /usr/local/src
wget https://download.redis.io/releases/redis-7.2.5.tar.gz
tar zxf redis-7.2.5.tar.gz && cd redis-7.2.5

make -j"$(nproc)" BUILD_TLS=yes MALLOC=libc
make install PREFIX=/usr/local/redis-7.2.5

输出(结尾几行):

text
    INSTALL redis-server
    INSTALL redis-benchmark
    INSTALL redis-cli
    INSTALL redis-sentinel

解释:

  • -j$(nproc) 按核数并行编译,单核要 3 分钟以上。
  • BUILD_TLS=yes 需要 openssl-devel;不需要 TLS 就删掉这个参数,否则会报 openssl/ssl.h: No such file。
  • MALLOC=libc 避免 jemalloc 在部分 ARM/容器环境下的编译问题;x86 物理机可以去掉这行用默认 jemalloc(内存占用更低)。
  • PREFIX 指定安装根,不要装进 /usr/local 裸目录,否则卸载时不知道删了哪些文件。

建一个版本无关的软链,方便以后升级:

bash
ln -sfn /usr/local/redis-7.2.5 /usr/local/redis

二、目录规范 ​

用途路径
程序/usr/local/redis/bin/
配置/etc/redis/6379.conf
数据/var/lib/redis/6379/
日志/var/log/redis/
运行时/run/redis/(systemd 自动建)
bash
mkdir -p /etc/redis /var/lib/redis/6379 /var/log/redis
useradd -r -s /sbin/nologin redis
chown -R redis:redis /var/lib/redis /var/log/redis
cp /usr/local/src/redis-7.2.5/redis.conf /etc/redis/6379.conf

解释:useradd -r 建系统账号(无家目录、不进 /home),-s /sbin/nologin 让它无法登录。Redis 不该以 root 跑。

三、改配置:只动这十项 ​

bash
cd /etc/redis
cp 6379.conf 6379.conf.orig                      # 留一份原厂配置做对照

sed -i 's|^bind .*|bind 0.0.0.0|' 6379.conf
sed -i 's|^protected-mode yes|protected-mode no|' 6379.conf
sed -i 's|^port 6379|port 6379|' 6379.conf
sed -i 's|^daemonize yes|daemonize no|' 6379.conf
sed -i 's|^# supervised no|supervised systemd|' 6379.conf
sed -i 's|^dir .*|dir /var/lib/redis/6379|' 6379.conf
sed -i 's|^logfile ""|logfile /var/log/redis/6379.log|' 6379.conf
sed -i 's|^# requirepass foobared|requirepass 换成你的强密码|' 6379.conf
sed -i 's|^# maxmemory .*|maxmemory 2gb|' 6379.conf
sed -i 's|^# maxmemory-policy noeviction|maxmemory-policy allkeys-lru|' 6379.conf
sed -i 's|^appendonly no|appendonly yes|' 6379.conf

解释(这几项每个都对应一类事故):

配置为什么这么改
daemonize no交给 systemd 管进程,自己 fork 会让 systemd 误判退出
supervised systemd让 Redis 用 sd_notify 报告"就绪",Type=notify 才生效
protected-mode no关了密码时的裸奔保护;设了 requirepass 才建议关,否则保持 yes
dirRDB/AOF 落盘位置,默认是当前工作目录,不设会随启动方式漂移
logfile写文件而不是 stdout,避免 journald 被日志刷爆
maxmemory不设等于无上限,最终被 OOM killer 杀掉整个进程
maxmemory-policy默认 noeviction 是"写不进去报错",缓存场景几乎都该改成 allkeys-lru
appendonly yesRDB 会丢最后一次快照之后的数据,做队列/存储必须开 AOF

bind 0.0.0.0 + 弱密码 = 被挖矿

公网机器上 bind 0.0.0.0 且 requirepass 简单(或没设),几小时内就会被扫描器写入计划任务挖矿。三选一必须做到:只监听内网网卡、设强密码、或用防火墙限制来源 IP。"改端口"不算防护。

四、内核参数 ​

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

# 关闭透明大页(THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled

输出:

text
vm.overcommit_memory = 1
net.core.somaxconn = 1024
always madvise [never]

解释:

  • overcommit_memory=1 是必须项。Redis BGSAVE 会 fork 子进程,默认策略下内核可能拒绝这次 fork,日志里就是 Can't save in background: fork: Cannot allocate memory。
  • somaxconn 太小会让新连接被丢弃,Redis 启动时会直接告警。
  • THP 会造成延迟毛刺,Redis 启动日志里那句 Transparent huge pages function is enabled 就是在提醒这事。

THP 要永久关闭得写进 grub 或 systemd unit 的 ExecStartPre。

五、systemd 单元 ​

ini
# /etc/systemd/system/redis-6379.service
[Unit]
Description=Redis In-Memory Data Store (port 6379)
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
ExecStartPre=/bin/chown -R redis:redis /var/lib/redis/6379 /var/log/redis
ExecStart=/usr/local/redis/bin/redis-server /etc/redis/6379.conf
ExecStop=/usr/local/redis/bin/redis-cli -a 换成你的强密码 shutdown nosave
Restart=always
RestartSec=3
LimitNOFILE=65535
OOMScoreAdjust=-900

[Install]
WantedBy=multi-user.target
bash
systemctl daemon-reload
systemctl enable --now redis-6379
systemctl status redis-6379 --no-pager

输出:

text
● redis-6379.service - Redis In-Memory Data Store (port 6379)
     Loaded: loaded (/etc/systemd/system/redis-6379.service; enabled; vendor preset: disabled)
     Active: active (running) since Tue 2026-10-27 16:52:04 CST; 3s ago
   Main PID: 21874 (redis-server)
     Status: "Ready to accept connections"
      Tasks: 6 (limit: 100000)
     Memory: 11.2M

解释:

  • Type=notify + 配置里的 supervised systemd 是一对,缺一不可;只改一边会出现"服务显示 active 但其实还没就绪"。
  • Main PID 直接是 redis-server 而不是 1,说明 daemonize no 生效了。
  • Status: "Ready to accept connections" 是 Redis 主动上报的,systemctl restart 后看到这行才算真起来。
  • OOMScoreAdjust=-900 让内核在内存紧张时优先杀别的进程,保护 Redis。
  • ExecStop 带 -a 才能优雅关(设了密码时);不加会 NOAUTH,然后 systemd 等超时后 SIGKILL,AOF 可能不完整。

密码写进 unit 文件会泄露

systemctl cat redis-6379 任何有权限的人都能看到明文密码。规范做法是用 EnvironmentFile=/etc/redis/6379.pass 配合 --requirepass "$(REDIS_PASS)",并把该文件权限设成 600、属主 redis。

六、验证 ​

bash
/usr/local/redis/bin/redis-cli -a '你的密码' -p 6379 ping
/usr/local/redis/bin/redis-cli -a '你的密码' info server | head -8
ss -lntp | grep 6379

输出:

text
PONG
# Server
redis_version:7.2.5
redis_mode:standalone
os:Linux 5.14.0 x86_64
tcp_port:6379
uptime_in_seconds:42

LISTEN 0  1024  0.0.0.0:6379  0.0.0.0:*  users:(("redis-server",pid=21874,fd=8))

解释:redis_mode:standalone 确认是单机模式;SendBuffer 那列 1024 是 somaxconn 生效后的监听队列;users:(...) 里的 pid 与 systemctl status 一致,说明进程归 systemd 管而不是自己 fork 出去的野进程。

七、日常运维命令 ​

bash
systemctl restart redis-6379
journalctl -u redis-6379 -f                          # 跟踪启动类日志
tail -f /var/log/redis/6379.log                      # 跟踪运行日志

redis-cli -a '密码' info memory | grep -E 'used_memory_human|maxmemory_human|mem_fragmentation_ratio'
redis-cli -a '密码' dbsize
redis-cli -a '密码' --bigkeys                        # 扫大 key
redis-cli -a '密码' slowlog get 10                   # 最近慢命令
redis-cli -a '密码' client list | head
redis-cli -a '密码' bgsave                           # 手动落一次 RDB
redis-cli -a '密码' config get maxmemory-policy      # 确认运行时配置
redis-cli -a '密码' config set maxmemory-policy allkeys-lru   # 热改(记得写回配置文件)

热改不持久

config set 只改运行时,重启就回滚。改完确认有效要补一句 redis-cli config rewrite,把当前运行时配置写回 6379.conf。

八、踩过的坑 ​

现象根因处置
启动即退出,日志空daemonize yes 与 systemd 冲突改成 no,由 systemd 管
systemctl restart 后连接全断没配 supervised systemd,就绪状态误判两处一起改
fork: Cannot allocate memory没设 overcommit_memory=1见第四节
内存一直涨到被 OOM 杀没设 maxmemory,或 key 无过期时间设上限 + 淘汰策略
重启后数据没了dir 是临时目录,或没开 AOF固定 dir + appendonly yes
远程连不上但本机 PONG云安全组没放通,或 bind 只监听 127.0.0.1查安全组,再查 ss -lntp