Skip to content

安装与配置

Redis 部署涉及的环节:版本来源选什么、目录怎么规划、配置文件里每个参数在控制什么、systemd 怎么接管、监听地址绑在哪里、密码和 ACL 怎么设、以及几个 Linux 内核参数为什么要跟着调。

一、部署方式的选择

方式适合什么场景
系统包(yum/apt)测试环境、快速验证
源码编译需要固定版本、自定义编译选项
二进制包离线环境、标准化批量部署
容器开发测试、K8s 环境

一批 Redis 实例的安装来源统一很重要。一部分用包安装、一部分手工编译,排查时配置路径、启动参数、升级记录的查找方式都不一样,故障时容易手忙脚乱。

二、系统包安装

RHEL / Rocky / CentOS:

bash
yum install -y redis
systemctl enable --now redis
redis-cli ping    # 返回 PONG 表示正常

Debian / Ubuntu:

bash
apt update
apt install -y redis-server
systemctl enable --now redis-server
redis-cli ping

不同发行版的服务名和配置文件路径不同。RHEL 系服务名通常是 redis,配置文件在 /etc/redis.conf;Debian 系服务名通常是 redis-server,配置文件在 /etc/redis/redis.conf。不确定时用 systemctl list-unit-files | grep -i redis 查实际的服务名,用 rpm -ql redisdpkg -L redis-server 看包里的文件列表。

三、源码编译

源码编译适合需要固定版本、统一目录规划的场景:

bash
# 编译依赖
yum groupinstall -y "Development Tools"
yum install -y jemalloc-devel    # Redis 默认使用 jemalloc 内存分配器

# 编译安装
tar -xf redis-7.x.x.tar.gz
cd redis-7.x.x
make -j"$(nproc)"                # 用多核并行编译
make PREFIX=/usr/local/redis install

创建运行用户和数据目录:

bash
groupadd redis
useradd -r -g redis -s /sbin/nologin redis

mkdir -p /etc/redis /data/redis /var/log/redis
chown -R redis:redis /data/redis /var/log/redis

复制配置文件:

bash
cp redis.conf /etc/redis/6379.conf

源码编译后最容易漏的不是编译本身,而是 systemd unit、目录权限和配置文件路径。命令能跑不等于服务已纳入系统管理——重启后会不会自动拉起、日志写到哪、数据存到哪,这些都要在 systemd 和配置文件里明确。

四、systemd unit

自定义 unit 示例(/etc/systemd/system/redis-6379.service):

ini
[Unit]
Description=Redis Server 6379
After=network.target

[Service]
Type=notify
User=redis
Group=redis
ExecStart=/usr/local/redis/bin/redis-server /etc/redis/6379.conf --supervised systemd
ExecStop=/usr/local/redis/bin/redis-cli -p 6379 shutdown
Restart=on-failure
RestartSec=5
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

几个字段的作用:

字段做什么
Type=notifyRedis 通过 systemd 协议通知启动完成,systemd 能准确知道服务是否真正就绪
--supervised systemd告诉 Redis 自己在 systemd 下运行,与之配合
ExecStopredis-cli shutdown 正常退出,而不是直接杀进程——给 Redis 时间做最后的持久化
LimitNOFILE提高可打开文件数上限,连接数多时不会因 fd 不够拒绝新连接
Restart=on-failure异常退出后自动拉起,RestartSec=5 表示间隔 5 秒再尝试

启用:

bash
systemctl daemon-reload
systemctl enable --now redis-6379
systemctl status redis-6379 --no-pager

五、配置文件分解

一份单机基础配置 6379.conf

conf
# 监听——同时绑本机和内网地址,不要暴露到公网网卡
bind 127.0.0.1 192.168.10.11
port 6379
protected-mode yes

# 进程管理——systemd 下用 notify,不用后台守护模式
daemonize no
supervised systemd
pidfile /run/redis_6379.pid

# 数据目录——RDB、AOF、Redis 7 多文件 AOF 的 appendonlydir 都在这个目录下
dir /data/redis
dbfilename dump.rdb

# 日志
logfile /var/log/redis/redis-6379.log
loglevel notice

# RDB 自动快照触发条件
save 900 1       # 900 秒内至少 1 次写操作
save 300 10      # 300 秒内至少 10 次写操作
save 60 10000    # 60 秒内至少 10000 次写操作

# AOF 持久化
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec

# 内存上限和淘汰策略
maxmemory 2gb
maxmemory-policy allkeys-lru

各配置的细节:

  • bind:不是"允许谁连我",而是"我在哪些地址上监听"。不写 bind 或 bind 0.0.0.0 表示所有网卡都监听,如果机器有公网 IP,Redis 就暴露到了公网。
  • protected-mode:当没有设置密码且 bind 的不是只有 127.0.0.1 时,protected-mode 会阻止外部连接。它是一个安全兜底,但不替代密码和网络隔离。
  • dir:这是最容易在排查时忽略的配置。RDB 文件、AOF 文件、Redis 7 之后的多文件 AOF 目录 appendonlydir 都以 dir 为基准。如果 dir 指到了默认路径(比如源码编译时的当前目录),备份、磁盘监控、恢复操作都可能找错地方。
  • save:RDB 自动触发的条件。多个规则是"或"的关系——任意一条满足就触发 BGSAVE。规则太少可能导致备份间隔过长,规则太密集可能导致 BGSAVE 频繁消耗 CPU 和 IO。
  • appendfsync everysec:每秒刷一次 AOF 到磁盘。比 always(每条命令都刷)性能好很多,比 no(交给 OS 决定)数据安全。everysec 最多丢 1 秒的数据。

六、密码和 ACL

Redis 6 之前只能用 requirepass 设一个全局密码。Redis 6 开始引入了 ACL,可以创建多个用户,各自拥有不同的密码、可操作的 key 模式和可执行的命令集合。

简单单用户模式(兼容旧版):

conf
requirepass strong_password_here

ACL 模式——关闭危险的 default 用户,创建应用账号和只读账号:

conf
user default off
user app on >app_password ~app:* +get +set +del +expire
user readonly on >readonly_password ~* +get +mget +exists +ttl

ACL 规则语法:

片段含义
user default off关闭无密码的默认用户
on启用该用户
>password设置密码
~app:*限制只能访问匹配该模式的 key
+get允许执行的命令

ACL 的价值在于拆分权限——应用账号、只读监控账号、运维管理账号各用各的。所有程序共用一个高权限密码,出问题时查不出是谁发的危险命令。ACL 还支持 ACL LOG 查看被拒绝的命令,方便排查权限配置是否过紧。

七、内存上限和淘汰策略

conf
maxmemory 2gb
maxmemory-policy allkeys-lru

淘汰策略的选择取决于 Redis 里存的是什么数据:

策略行为适用场景
noeviction内存满后写入直接报错不能接受数据丢失的纯存储场景
allkeys-lru在所有 key 中淘汰最近最少使用的纯缓存,所有 key 都可以丢
volatile-lru只淘汰设了过期时间的 key,LRU 排序缓存和永久数据混合
allkeys-random所有 key 中随机淘汰缓存,且访问模式均匀
volatile-ttl只淘汰设了过期时间的 key,TTL 短的优先希望优先保留长 TTL 的数据

缓存型实例选 allkeys-lru 最常见——内存满了就踢掉不常用的。如果 Redis 里既有缓存又有持久化状态数据(比如计数器、配置),volatile-lru 更安全,因为没设过期时间的 key 不会被淘汰。但关键前提是:永久数据确实没设过期时间,而缓存都设了。这个约定如果没在团队里统一,volatile-lru 的保护就形同虚设。

八、连接数和文件句柄

conf
maxclients 10000

Redis 的连接数受 maxclients 和系统文件句柄的双重限制。实际能建立的连接数是两者中较小的。文件句柄不够时,即使 maxclients 设得很大,新连接也会被拒绝。

检查限制:

bash
ulimit -n                                 # 当前 shell 的文件句柄限制
systemctl show redis-6379 -p LimitNOFILE  # systemd unit 里设的限制

应用连接池过大时,Redis 里会堆积很多 Sleep 状态的空闲连接。排查时看 CLIENT LIST 中的 ageidle 字段能区分长连接和短连接风暴。

九、Linux 内核参数

有几个内核参数不直接属于 Redis 配置,但会影响 Redis 的 fork、连接队列和延迟。

vm.overcommit_memory——Redis 在 BGSAVE 或 AOF rewrite 时会 fork 子进程。fork 瞬间,OS 需要为子进程预留与父进程同样大小的虚拟内存(尽管大部分是共享的,不会实际分配物理页)。如果 overcommit 策略太保守,大内存实例的 fork 可能直接被拒绝:

conf
# /etc/sysctl.d/99-redis.conf
vm.overcommit_memory = 1   # 允许 overcommit,fork 子进程时不会因虚拟内存不足失败

net.core.somaxconn——Redis 的 tcp-backlog 配置受这个内核参数的上限约束。高并发场景下连接队列太小会导致新连接被拒绝:

conf
net.core.somaxconn = 1024

加载 sysctl 配置:

bash
sysctl --system

Transparent Huge Pages (THP)——Redis 延迟排查里经常看到 THP 的身影。THP 会尝试动态分配和合并大页内存,这个过程可能导致 Redis 出现不规律的延迟抖动。Redis 日志里如果看到 "WARNING you have Transparent Huge Pages (THP) support enabled in your kernel",就是在提醒这件事。

临时关闭:

bash
echo never > /sys/kernel/mm/transparent_hugepage/enabled

但重启后失效。长期配置要写到系统启动脚本或内核参数管理里。实例迁移到新机器后,THP 状态经常被遗漏,导致"同样的 Redis 配置,新机器上就是有延迟毛刺"。

十、启动后的检查清单

部署完成后,不只是看 systemctl status 有没有绿:

bash
systemctl status redis-6379 --no-pager   # systemd 认为服务是否正常
redis-cli -p 6379 PING                    # Redis 能否响应
redis-cli -p 6379 INFO server             # 版本、运行时长
redis-cli -p 6379 INFO persistence        # RDB/AOF 加载状态
redis-cli -p 6379 CONFIG GET dir          # 数据目录是否指向预期路径
redis-cli -p 6379 CONFIG GET maxmemory    # 内存上限是否生效

CONFIG GET dir 要特别留意——Redis 跑起来但 dir 指向了默认路径(比如启动时所在目录),后续备份脚本取错路径、磁盘告警看错分区,问题就难查了。同样,maxmemory 如果没设或还是 0(不限制),Redis 会把内存用到系统极限然后被 OOM killer 杀掉。

十一、常见启动问题

现象常见原因先看什么
服务启动失败配置语法错、目录权限不对journalctl -u redis-6379 -n 100
端口已被占用旧实例没停、端口被其他进程使用ss -lntp | grep 6379
远端连不上bind 只绑了 127.0.0.1、防火墙拦截、安全组ss -lntp 确认监听地址
NOAUTH 错误设了密码但客户端没传客户端配置加密码或 -a 参数
fork 失败内存不够、overcommit 太保守、实例太大Redis 日志、INFO persistence
写入失败磁盘满、dir 目录不可写、内存满df -h、Redis 日志、INFO memory

Redis 日志里通常会直接写出配置错误、RDB/AOF 加载失败、端口绑定失败和权限问题。启动失败时,Redis 日志比 systemd 状态信息更具体——后者只知道"进程退出了",前者会写"为什么退出"。