外观
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 |
dir | RDB/AOF 落盘位置,默认是当前工作目录,不设会随启动方式漂移 |
logfile | 写文件而不是 stdout,避免 journald 被日志刷爆 |
maxmemory | 不设等于无上限,最终被 OOM killer 杀掉整个进程 |
maxmemory-policy | 默认 noeviction 是"写不进去报错",缓存场景几乎都该改成 allkeys-lru |
appendonly yes | RDB 会丢最后一次快照之后的数据,做队列/存储必须开 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是必须项。RedisBGSAVE会 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.targetbash
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 |