
前两天陪一个刚转运维的朋友装Redis他在网上翻了一堆教程照着敲完make启动后用redis-cli ping死活连不上卡了一下午。打电话过来一问装的是 Redis 7.2系统里 gcc 还是 4.8启动报错一大堆最后发现进程压根没起来。这件事我在生产环境也见过不少次。Linux 安装 Redis 本身不难真正难的是装完之后那堆看不见的坑编译环境、jemalloc 分配器、保护模式、systemd 托管、防火墙、可视化客户端连接。这篇我就把从零开始装 Redis 的完整路径翻一遍从版本选择、编译安装、配置调优、服务化、安全策略到远程连接一次讲透。1. 安装前先想清楚三件事版本、环境、装法1.1 版本选择别一上来就追最新很多人在官网看到最新稳定版就直接下完全没考虑自己的 Linux 发行版和编译工具链。Redis 官网目前的稳定线有 6.2.x、7.0.x、7.2.x各版本之间有明显的性能和功能差异但并不是越新越适合你。我个人的建议是生产环境选发布超过半年的稳定版本。6.2 属于保守稳重型兼容性好网上资料最多踩坑成本最低7.0 引入了 Redis Functions、更完善的自动故障转移能力和跨版本数据迁移工具性能也有实打实的提升7.2 是最新稳定线新功能多但对编译环境和内核版本的要求更高。如果你用的是 CentOS 7 这种老系统默认 gcc 4.8.5 编译 Redis 7.x 基本都会报错要么升级 gcc要么老老实实装 6.2。版本选择的另一个关键是避开 RC 和 M 开头的非稳定版。有人图新鲜装了个 RC 版线上跑了两个月才发现一个内存泄漏想回退又要折腾数据迁移。我的习惯是装之前先到官网的 releases 页面看一眼发布日期超过三个月到半年的稳定小版本才值得用。1.2 环境准备先把编译家底摸清楚在下载源码之前先把操作系统的家底摸一遍。用这几条命令查cat /etc/os-release gcc --version make --version rpm -qa | grep tcl # Debian/Ubuntu 用 dpkg -l | grep tclRedis 是 C 语言写的源码编译需要 gcc、make、以及运行测试用的 tcl。CentOS/RHEL 系安装编译环境yum install -y gcc tcl makeDebian/Ubuntu 系apt update apt install -y build-essential tcl注意build-essential这个包会一次性装好 gcc、g、make 等一堆基础工具比单独装省心。tcl 很多人会漏掉它只在make test阶段用到不装的话测试跑不起来。生产环境我建议至少把make test完整跑一遍它能提前暴露 glibc 版本不兼容、缺库、原子操作不支持这类运行期问题。如果你用的是老旧的 CentOS 7 又非要编译 Redis 7.x可以这样把 gcc 升级到 8 以上yum install -y centos-release-scl yum install -y devtoolset-8 scl enable devtoolset-8 bash执行完之后当前 shell 里的 gcc 就变 8 了。但要注意这只是在当前会话生效关掉终端就恢复原样所以编译要在同一个会话窗口里做完。1.3 三种安装方式怎么选不是只有源码编译这一条路很多教程上来就让你源码编译但实际场景里这不是唯一选择。我自己用下来的对比是这样的安装方式优点缺点适用场景源码编译版本精确可控、可指定编译参数、性能最优编译耗时长、依赖要自己搞定、卸载不干净生产环境、需要定制编译参数的场景yum/apt 仓库安装命令一条搞定、自带 systemd 服务文件、卸载方便版本取决于发行版仓库通常偏旧快速部署、测试环境、不太在乎版本Docker 容器拉镜像即用、无编译烦恼、环境隔离网络和端口映射有学习成本、数据卷要手动挂本地开发、快速验证、多实例隔离Docker 方式尤其适合快速体验主从。一条命令起一个主库一个从库再配个哨兵几分钟就能搭出一套高可用环境这点后面第 6 节我会再提。但如果公司内部有等保或合规要求追求对系统底层的完全掌控源码编译依然是生产环境更稳妥的选择。我个人推荐的路线是生产环境用源码编译测试环境用系统仓库或 Docker。这样既能保证线上版本的稳定可控又不浪费测试环境搭建的时间。2. 源码编译安装把每一步拆开讲透2.1 下载官网慢的时候换国内镜像选定版本之后去官网下载对应源码包。以 6.2.14 为例cd /usr/local/src wget https://download.redis.io/releases/redis-6.2.14.tar.gz tar xzf redis-6.2.14.tar.gz这里有个很现实的坑download.redis.io在国内的下载速度经常惨不忍睹几十兆的包能下载半小时。碰到这种情况别死磕直接用国内镜像源。清华源的地址是wget https://mirrors.tuna.tsinghua.edu.cn/redis/releases/redis-6.2.14.tar.gz阿里云镜像也可以配置方式类似。解压之后建议把目录挪到一个统一的位置我习惯放/usr/local/src/redis-6.2.14方便以后查看版本和源码。注意目录的属主和管理权限如果你后面要用 redis 用户运行服务编译阶段可以用普通用户编译避免用 root 编译然后把一堆 root 属主的文件留给 redis 用户后面各种权限问题接踵而至。2.2 编译make 和 make install 之间的细节进入源码目录直接 makecd redis-6.2.14 makeRedis 默认使用 jemalloc 内存分配器这是官方推荐选项在内存碎片化处理上比 glibc 自带的 malloc 好不少。但如果你系统里没有 jemalloc 开发库或者版本太老编译会在zmalloc.h上报找不到jemalloc/jemalloc.h。这时候可以退回到 libc 分配器make MALLOClibc为什么官方默认要用 jemalloc简单说Redis 这种频繁分配小块内存的应用最容易出现内存碎片jemalloc 能明显降低碎片率。但它在老系统上编译很容易出问题所以我的建议是先试试默认的 jemalloc报错再回退到MALLOClibc。两种模式运行效果差别没那么大至少比编译不过去强。编译完成后检查核心文件是否生成ls -l src/redis-server src/redis-cli然后强烈建议跑一遍测试make test这步会花几分钟但能发现底层系统不兼容的问题。测试过程会打印大量 PASS 信息看到\o All tests passed without errors就说明环境没问题。编译完别急着用先安装到指定目录。我习惯装到/usr/local/redis而不是系统默认的/usr/local/bin这样整个 Redis 的文件聚在一起卸载时直接删目录就行不会污染系统路径make install PREFIX/usr/local/redis装完后目录结构长这样/usr/local/redis/ ├── bin/ │ ├── redis-benchmark │ ├── redis-check-aof │ ├── redis-check-rdb │ ├── redis-cli │ ├── redis-sentinel │ └── redis-server注意PREFIX是安装前缀不是执行路径。很多人以为指定了 PREFIX 之后可执行文件会直接出现在这个目录实际上它会在 PREFIX 下再建一个bin目录。2.3 三大编译报错与排查我把这些年编译 Redis 遇到最多的问题整理成一张表报错特征根因解决办法bash: gcc: command not found系统没装编译工具链yum install -y gcc或apt install -y build-essentialfatal error: jemalloc/jemalloc.h: No such file or directory缺少 jemalloc 开发库安装 jemalloc-devel 或make MALLOClibc编译过程中出现undefined reference to __sync_add_and_fetch_8之类的原子操作报错系统 gcc 版本太老不支持新版本 Redis 需要的原子操作或 C11 特性用 SCL 升级 gcc或换成 Redis 6.2 老版本you need tcl 8.5 or newer in order to run the Redis test运行 make test 但没装 tcl安装 tcl然后重新make test最高频的还是 gcc 版本问题。Redis 7.x 对编译器的要求明显提高了CentOS 7 的 gcc 4.8.5 在 2020 年之后的 C 项目里经常连编译期语法检查都过不去别浪费时间找源码报错的原因直接升级 gcc 或者降 Redis 版本。3. redis.conf 配置详解装完不代表能用3.1 后台运行模式与日志输出安装完成之后的第一个动作是处理配置文件。Redis 默认是前台运行的你终端一关或者按一下 CtrlC进程就没了。要让它后台常驻核心配置是daemonize。编译生成的默认配置在源码目录下的redis.conf先把它复制到标准位置mkdir -p /etc/redis cp /usr/local/src/redis-6.2.14/redis.conf /etc/redis/redis.conf改这几个参数daemonize yes pidfile /var/run/redis_6379.pid logfile /var/log/redis/redis.log dir /var/lib/redisdaemonize yes让 Redis 启动后 fork 一个子进程在后台跑pidfile记录主进程 PID停服务时靠它清场logfile指定日志路径日志目录要提前建好并给足权限否则启动时根本起不来dir是持久化文件的工作目录RDB 和 AOF 文件都会写在这里。新手最容易忽略的就是logfile。默认情况下这个值是空的Redis 后台运行时日志直接丢到标准输出你什么都看不到。出了问题连排查入口都没有一定要先建好日志目录mkdir -p /var/log/redis /var/lib/redis chown -R redis:redis /var/log/redis /var/lib/redis关于权限多说一句后面如果用 systemd 托管并以 redis 用户运行日志目录和持久化目录的属主必须是 redis否则启动时写不了文件直接退出。这种坑不是看报错能立刻反应过来的因为它可能只报一句Cant open the log file很多人还以为是日志路径写错了。3.2 网络绑定与保护模式为什么外面连不上装完 Redis你想从自己的电脑上用可视化工具连上去输入 IP 和端口等了半天连接超时或者直接拒绝然后开始怀疑网络、怀疑防火墙——最后一个排查到 Redis 配置。这几乎是每个人都会遇到的事。问题出在三处bind、protected-mode和requirepass。默认配置是这样的bind 127.0.0.1 -::1 protected-mode yesbind 127.0.0.1的意思是 Redis 只监听本机回环地址外部机器的连接请求从 TCP 层面就被拒掉了。要允许局域网访问可以改成bind 0.0.0.0但只改 bind 还不够。当protected-mode yes且你没有设置密码、又监听了非回环地址时Redis 会拒绝所有外部 IP 的连接。这是 Redis 从 3.2 开始引入的保护机制防止你在公网裸奔。正确的远程访问配置是组合拳bind 0.0.0.0 protected-mode yes requirepass your-strong-password设置requirepass之后protected-mode 就不再拦截了因为已经有访问控制的凭证了。但注意protected-mode yes这个选项我建议保留它在你哪天忘记设置密码时能作为最后一道保险挡住外部访问。这里要特别提醒一句网上有些教程是让你直接protected-mode no的如果你只是在内网测试环境玩玩倒无所谓但凡是能接触到公网的机器千万别这么干。没设密码的 Redis 暴露在公网上等于把数据库送给别人轻则数据被删勒索重则被写入恶意代码利用系统漏洞进一步入侵。Redis 的服务端口一旦被扫描到且没有认证后果非常直接。3.3 持久化RDB 和 AOF 到底开不开Redis 默认是内存数据库不配置持久化的话一断电所有数据全部清零。默认配置里 RDB 快照是开了的save 3600 1 300 100 60 10000这个含义是3600 秒内至少改 1 个 key、300 秒内至少改 100 个 key、60 秒内至少改 10000 个 key满足任一条件就生成一次快照。RDB 文件恢复快、体积小但两次快照之间的数据会丢。AOF 默认是关的它记录每次写操作恢复时逐条重放。生产环境我的配置习惯是appendonly yes appendfsync everysec appendfilename appendonly.aofappendfsync everysec表示每秒把缓冲区的写操作同步到磁盘兼顾性能和安全性最多丢一秒的数据。Redis 7.x 默认开了 AOF 文件里嵌 RDB 头的混合持久化模式恢复速度比纯 AOF 快很多这点不用你额外配保持默认即可。关于持久化还有一个面试高频题RDB 和 AOF 同时开启时会怎么恢复答案是以 AOF 为准因为 AOF 数据更完整。这个知识点很多教程讲得云里雾里但你在配置里同时开了两种模式理解恢复优先级就是实际运维中的刚需。4. 启动、验证与服务化让 Redis 成为系统的正式成员4.1 三种启动方式的区别配置改完之后启动 Redis 有三种常见方式很多人搞不清差别第一种直接前台跑/usr/local/redis/bin/redis-server /etc/redis/redis.conf --daemonize no适合临时调试CtrlC 就停。第二种是把daemonize yes配置写好后台 fork 一个进程跑这种方式适合手动管理的场景。第三种是用 systemd 托管让操作系统负责进程的启动、停止、崩溃重启和开机自启。我强烈建议生产环境直接用 systemd原因很简单Restarton-failure能自动拉起崩溃的进程systemctl enable能开机自启不用再写一堆自启动脚本。但这里有一个很容易踩坑的细节如果用 systemd 托管daemonize一定要设为no。因为 systemd 管理进程的生命周期需要直接监控主进程如果 Redis 自己 fork 到后台systemd 会认为主进程已经退出然后报Main process exited, codekilled这类错误甚至把你的服务标记为 failed。4.2 编写 redis.service 服务文件在/etc/systemd/system/redis.service写入以下内容[Unit] DescriptionRedis Server Afternetwork.target [Service] Typesimple ExecStart/usr/local/redis/bin/redis-server /etc/redis/redis.conf ExecStop/bin/kill -TERM $MAINPID Restarton-failure Userredis Groupredis RuntimeDirectoryredis LimitNOFILE65535 PrivateTmptrue [Install] WantedBymulti-user.target这里几个参数值得展开讲Typesimple配合daemonize no是最稳的组合。进程不 forksystemd 直接跟踪它。有些老教程里写Typeforking加PIDFile那是给daemonize yes用的两者不能混搭。Userredis和Groupredis要求系统里先建好这个用户useradd -r -s /sbin/nologin redis-r表示创建系统用户-s /sbin/nologin禁止这个用户登录 Shell它只用来运行 Redis 进程减少被攻破后的危害面。LimitNOFILE65535很重要。Redis 作为缓存和队列服务在高并发场景下会同时打开大量 TCP 连接和文件描述符默认的 1024 上限在连接数一多就会报Too many open files。我见过一个生产事故Redis 压测时突然大量报错最后排查就是文件描述符上限太低加上这一行之后立刻解决了。RuntimeDirectoryredis会在/run下自动创建名为redis的临时目录权限会自动归属 redis 用户pid 文件放在这里有地方可写。写完服务文件后执行systemctl daemon-reload systemctl start redis systemctl status redis systemctl enable redis如果服务状态显示Active: active (running)说明 systemd 托管成功。以后重启机器Redis 会自动跟着起来。4.3 验证安装成功的标准动作服务起来了怎么判断是真的好了很多人redis-cli进去看到提示符就算成功了其实有几个更靠谱的验证动作。第一步基础连通性/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379 ping返回PONG是最基本的。第二步看内存和连接数/usr/local/redis/bin/redis-cli info memory | head -20 /usr/local/redis/bin/redis-cli info clients重点看used_memory、connected_clients这几个指标。第三步验证持久化是否工作/usr/local/redis/bin/redis-cli info persistence看rdb_last_save_time和aof_enabled的状态。第四步可以简单压一下/usr/local/redis/bin/redis-benchmark -t set,get -n 100000 -c 50在 50 个并发连接、10 万次请求的情况下本地跑出 8 万以上的 QPS 属于正常水平。如果压测时出现大量失败连接优先检查LimitNOFILE和内核参数net.core.somaxconn。5. 安全加固与远程连接别让 Redis 裸奔5.1 密码、ACL 与高危命令处理requirepass是密码认证的最基础配置但 Redis 6.0 之后的 ACL访问控制列表功能更精细可以按用户、命令、key 分别授权强烈建议用起来。在redis.conf里配置 ACL 的方式有两种一种是直接在配置文件里写user指令一种是新增aclfile /etc/redis/users.acl并单独维护用户文件。我倾向于后者结构更清晰。以一个只允许操作cache:前缀 key 的用户为例user worker on worker_password ~cache:* all -key -flushall -flushdb这个用户能用所有命令但只能操作cache:开头的 key并且不能执行FLUSHALL和FLUSHDB。这把连接层的权限收得非常紧即使密码泄露攻击者能造成的影响也被限制在一个小范围内。高危命令的处理是另一个重点。FLUSHALL、FLUSHDB、EVAL、KEYS这几个命令在大部分业务场景里用不到建议重命名或者直接禁用rename-command FLUSHALL rename-command FLUSHDB rename-command KEYS 把命令名改成空字符串等于禁用。但禁用KEYS要谨慎因为很多旧版运维脚本会拿它统计 key 数量改成用SCAN命令替代。生产环境执行KEYS会阻塞 Redis 事件循环key 一多整个服务秒级卡顿这也是线上禁它的原因。防火墙层面的配合不能少。如果系统开启了 firewalldfirewall-cmd --permanent --add-port6379/tcp firewall-cmd --reloadUbuntu 上用 ufwufw allow 6379/tcp还有一个运维习惯值得养成如果是纯内网 Redis最好直接bind内网网段别用0.0.0.0。比如bind 192.168.10.15让它只监听内网 IP外界连端口扫描都扫不到这是最小暴露面的做法。5.2 可视化客户端从 redis-cli 到桌面管理器命令行用redis-cli是基本功但日常排查和开发调试图形化客户端更高效。目前我用得最多的是 Another Redis Desktop Manager开源免费跨平台支持不错。早期 Another Redis Desktop Manager 的中文支持不稳定近几个版本明显改善了。比较经典的 Redis Desktop Manager 这个名字也经常在教程里出现它的社区版功能够用但老版本有些连接兼容性问题遇到连不上的情况可能是客户端版本太老导致的。图形化客户端连接配置基本上就四个字段主机地址、端口默认 6379、密码和你配置的requirepass一致、数据库编号默认 0。如果 Redis 部署在服务器上而你在本地开发机最稳妥的连接方式是 SSH 隧道——把本地端口转发到服务器的 6379ssh -L 6379:127.0.0.1:6379 userserver-ip -N然后客户端直接连127.0.0.1:6379就行远程 Redis 完全不需要对公网暴露端口。这是运维里最常用的安全做法数据也是加密传输的比直接把 Redis 端口暴露到公网安全得多。5.3 连接不上的排查五步法遇到 Redis 连不上不要慌按顺序排查每一步对应的现象都是不一样的。第一步看进程ps -ef | grep redis-server没有进程检查日志/var/log/redis/redis.log常见的启动失败原因有权限不足、配置文件语法错误、端口被占用。第二步看端口监听ss -lntp | grep 6379如果发现127.0.0.1:6379而不是0.0.0.0:6379说明 bind 没改对外部连不上是必然的。第三步看防火墙规则firewall-cmd --list-all iptables -L -n -v端口没有放行的表现通常是客户端连接超时不是立即拒绝。第四步看 Redis 配置里protected-mode和bind的组合是否允许来自你所在网段的访问。第五步确认密码没错输错密码的报错特征是NOAUTH Authentication required或WRONGPASS invalid username-password pair说明网络通了只是在认证环节失败了。这套流程走完十个连接问题九个人都能解决。剩下的那一个通常就是你自己的客户端工具版本太老换最新版客户端再试。6. 装完之后的进阶路从单机到缓存治理与高可用6.1 maxmemory 与淘汰策略做缓存治理的第一道闸门很多人装完 Redis 直接用完全不设置maxmemory这在生产环境是隐患。默认情况下只要操作系统内存够用Redis 就会一直往里面写直到把内存吃满触发系统 OOM Kill 或者开始大量使用 swap性能断崖式下跌。做缓存治理的第一件事是给 Redis 定一个内存上限maxmemory 512mb maxmemory-policy allkeys-lruallkeys-lru表示当内存到达上限后优先淘汰最近最少使用的 key。这个策略适合纯缓存场景。如果你的 Redis 里既有可以丢弃的缓存数据又有绝对不能丢的重要数据那就分开实例部署或者用volatile-lru只淘汰设置了过期时间的 key。这里多说一句 LFU 和 LRU 的区别。LRU 按多久没访问淘汰LFU 按访问频率淘汰。Redis 4.0 之后maxmemory-policy支持allkeys-lfu。如果业务是一天只访问一次但每次访问都很关键的共享数据LRU 容易把它误淘汰掉LFU 更合适。这两个策略没有绝对的好坏关键看你数据的访问分布。6.2 主从复制与哨兵高可用的地基单机 Redis 挂了缓存雪崩的后果大家应该都听过。主从复制是走向高可用的一步配置其实不复杂。假设主库 IP 是 192.168.10.10从库机器上在redis.conf里加replicaof 192.168.10.10 6379 replica-read-only yes重启从库后主库的数据会自动同步过来。在主库上执行info replication看到role:master并且有slave0列表说明主从关系已经建立。这里注意老版本配置项叫slaveofRedis 5.0 之后改成了replicaof如果照抄老教程配置会发现从库根本没生效。主从解决的是数据冗余但主库挂了之后从库不会自动顶上。要实现自动故障转移需要加一层哨兵Sentinel。哨兵的配置单独用一个文件sentinel monitor mymaster 192.168.10.10 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 100002表示两个哨兵都认为主库不可达时才触发切换避免单个哨兵误判。哨兵模式能实现主库宕机后自动提升某个从库为新主库客户端连接也会自动切换到新主库。如果一开始就规划了这套架构用 Docker 起 Redis 主从加哨兵是最快的验证方式几个配置文件挂载上去几分钟就能练熟整套流程。6.3 分布式锁对部署形态的要求热词里经常出现Redis 分布式锁这个场景和单机安装强相关。Redis 的 SET NX EX 命令是实现分布式锁最经典的方式但很多人都忽略了部署形态对锁安全性的影响如果 Redis 是单机部署主库宕机触发主从切换时原本持有的锁可能因为还没同步到从库而丢失产生锁失效的安全问题。所以做分布式锁扶持业务之前先回头审视一下部署形态是不是主从加哨兵min-replicas-to-write是否配置了持久化策略是否用的 AOF everysec。安装阶段多花一点时间把高可用和持久化底座打好后面写锁逻辑时才不会隔三差五出线上问题。另外分布式锁对连接池和超时配置也很敏感。客户端连接池太小高并发抢锁时会大量直接拒绝命令超时设得太短临时网络抖动就会误判锁获取失败超时设得太长服务又可能出现堆积。装完 Redis 之后用redis-benchmark简单压一下本地环境提前摸清这台机器单实例能扛多大并发再做客户端参数设计会靠谱很多。最后说一个我自己一直保留的习惯装完 Redis 的第一件事不是看版本号而是依次执行redis-cli ping、info persistence、info replication确认网络、持久化、主从状态全部正常再去调整业务参数。这套检查流水线走熟了一次装 Redis 十分钟内可以完成。希望你按这篇文章操作完也能把这些坑提前绕过去。