
Linux下装Redis这件事看起来就是下载、解压、make三步走但真正落到服务器上坑一个接一个系统源自带的版本老得掉渣、源码编译时gcc版本不对报错、配了systemd之后服务一直卡在activating、远程连接死活不通。我在不同发行版上把这些问题轮番踩了一遍今天重新整理一份可以直接照着抄的完整笔记目标是按标准流程把Redis 7编译安装好用systemd统一托管再把7.x版本新增的核心能力验证一遍最后把容易踩的坑一次性列清楚。这篇东西适合第一次在Linux云服务器上部署Redis的后端同学也适合运维想把手动安装流程规范化的场景。1. 安装前想清楚版本、环境与下载源1.1 为什么建议源码编译而非系统源直接安装很多发行版自带的软件源里其实有Redis比如CentOS 7自带的是3.2.xCentOS 8自带的是5.0.xUbuntu 20.04默认源里是5.0.7。这几个版本有一个共同问题太老了。5.0版本到现在虽然还能用但没有ACL权限体系、没有多线程I/O、也缺少RESP3协议更别说Redis 7才有的Functions、Sharded Pub/Sub这些能力。生产环境里如果还在用老版本一方面是功能跟不上另一方面是一些老版本在特定场景下存在已知的稳定性问题升级越拖越痛苦。有人会问能不能加第三方源直接装Redis 7部分发行版确实可以通过EPEL、Remi或一些社区源装到但第三方源的维护质量参差不齐有时候版本跟进不及时有时候又存在依赖冲突。我自己更倾向于一个确定性的方案从Redis官网下载源码包在目标机器上编译安装。这样版本完全可控、安装路径完全可控以后升级也好管理。编译安装的代价只是需要gcc、make这些基础工具链对Linux服务器来说基本是标配。1.2 环境检查与依赖准备编译Redis 7需要的基础工具不多gcc、make、pkg-config。想在编译后跑官方测试套件的话还需要tcl。不同系统的安装命令不一样CentOS/RHEL系列yum install -y gcc make tcl # 或者更省事直接安装开发工具组 yum groupinstall -y Development ToolsUbuntu/Debian系列apt update apt install -y build-essential tcl这里有一个非常容易被忽略的细节gcc版本。CentOS 7自带的gcc是4.8.5这个版本编译Redis 7.0或者7.2时可能会遇到问题。我在CentOS 7.9上试过编译7.0.x时能过但警告很多编译7.2.x时严格模式下会报错。如果你的生产环境是CentOS 7这种老系统建议先升级gccyum install -y centos-release-scl yum install -y devtoolset-9 scl enable devtoolset-9 bash新一点的系统比如Rocky Linux 9、Ubuntu 22.04/24.04自带的gcc版本足够新不需要这一步。装依赖之前可以先看一下系统信息cat /etc/os-release uname -a gcc --version顺便说一句make命令和内核版本也有关系如果编译时指定高并行度比如make -j8内存小的机器可能会出现内存不足导致编译失败这种情况把并行度降到make -j2或者直接make就好。1.3 下载Redis 7安装包的选择Redis官网的下载页面会列出当前稳定版本。以Redis 7为例常见的有7.0.x和7.2.x两个系列。7.0是2022年发布的稳定大版本7.2是后续的稳定分支。如果项目不是特别追求新特性建议选7.2.x系列的最新小版本如果团队更保守7.0.x也完全够用。这里我以7.2.4为例cd /usr/local/src wget https://download.redis.io/releases/redis-7.2.4.tar.gz国内服务器如果直接连官网下载慢可以用阿里云或华为云的开源镜像站搜索“redis”就能找到源码包的镜像地址下载速度会快很多。下载完成后建议核对一下文件的校验值官网会给出对应版本的SHA256防止下载过程损坏sha256sum redis-7.2.4.tar.gz2. 编译安装完整流程从下载到可运行2.1 解压与编译常用参数说明解压源码包并进入目录tar -zxvf redis-7.2.4.tar.gz cd redis-7.2.4接下来是编译。Redis的Makefile比较简单直接执行make就好建议带上-j参数并行编译加快速度make -j$(nproc)这里如果报错最常见的错误是找不到jemalloc头文件。Redis默认的内存分配器是jemalloc但系统中如果没有安装对应的开发包make的时候会提示“jemalloc.h: No such file or directory”。处理方法有两个# 方案一使用系统默认的libc分配器 make MALLOClibc # 方案二安装jemalloc开发包后再编译推荐 yum install -y jemalloc-devel # Debian/Ubuntu: apt install -y libjemalloc-dev make clean make -j$(nproc)为什么要推荐jemallocRedis是重度内存操作的程序大量小对象频繁申请和释放jemalloc在减少内存碎片方面比glibc的malloc表现更好。用libc分配器也能跑但长时间运行后内存碎片率可能会偏高。编译完成之后如果时间允许可以跑一下官方测试make testmake test需要系统里有tcl没装的话会提示找不到tclsh。测试套件会完整验证Redis各功能模块耗时几分钟第一次安装建议跑一遍能提前暴露很多潜在问题。2.2 安装目录规划与配置文件准备编译产物会生成在src目录下包括redis-server、redis-cli、redis-benchmark、redis-check-aof、redis-check-rdb等。直接用make install可以安装到系统路径但我习惯指定一个独立目录方便后续多版本切换和维护make install PREFIX/usr/local/redis执行完后Redis的可执行文件会安装到/usr/local/redis/bin目录。注意make install不会自动复制配置文件需要手动把源码包根目录下的redis.conf复制过去。同时我建议把数据目录、日志目录单独规划出来和生产环境的标准一致mkdir -p /usr/local/redis/etc /var/lib/redis /var/log/redis cp redis.conf /usr/local/redis/etc/redis.conf这样规划的好处很明显二进制、配置、数据、日志四者分离。以后升级版本时只需要替换bin目录配置和数据目录原封不动不用做额外迁移。日志和数据目录分离之后清理日志、备份数据也都不会互相干扰。为安全起见生产环境不要用root运行Redis单独创建一个系统用户useradd -r -s /sbin/nologin redis chown -R redis:redis /var/lib/redis /var/log/redis /usr/local/redis/etc/sbin/nologin这个shell能确保该用户无法交互登录即使进程被入侵攻击者也无法直接通过这个用户登进系统。2.3 配置环境变量让redis-cli直接可用如果不用环境变量每次执行Redis命令都要写全路径/usr/local/redis/bin/redis-cli非常麻烦。Linux下配置环境变量的标准做法是在/etc/profile.d/下新建一个脚本echo export PATH$PATH:/usr/local/redis/bin /etc/profile.d/redis.sh chmod 644 /etc/profile.d/redis.sh source /etc/profile.d/redis.sh之后重新登录或者source一下redis-cli、redis-server这些命令就能直接用了。验证一下redis-server --version输出版本号说明二进制文件安装成功且PATH配置生效。3. 配置文件与服务托管不会systemd等于白装3.1 redis.conf核心参数逐项解读Redis的配置文件在源码包根目录有一份默认版本但默认配置只适合本地开发生产环境必须逐项过一遍。我挑几个改动频率最高的参数说明配置项默认值建议值说明bind127.0.0.1 -::1127.0.0.1 或内网IP控制监听地址默认只允许本机访问port63796379默认端口除非有冲突否则不用改protected-modeyesyes保护模式配合bind和密码使用daemonizenono用systemd托管时必须保持nosupervisednosystemd配合systemd的Typenotify机制logfile空/var/log/redis/redis.log日志文件路径dir.//var/lib/redisRDB/AOF持久化文件目录requirepass空强密码访问密码生产环境必设maxmemory0根据机器内存最大内存限制0表示不限制maxmemory-policynoevictionallkeys-lru等内存达到上限后的淘汰策略appendonlynoyes是否开启AOF持久化逐项解释一下关键点。daemonize这个参数老教程基本都是“daemonize yes”因为以前习惯用nohup把redis-server放到后台。但用systemd管理服务时必须保持daemonize no否则systemd会认为进程没有正常启动或管理不了进程生命周期服务状态会是异常的。supervised systemd这个配置容易被忽略。它的作用是让Redis在启动完成后主动通知systemd“我已经准备好了”systemd那边配合Typenotify来接收消息。这两个必须配套使用后面我会单独说明如果配错会发生什么。maxmemory和maxmemory-policy是线上必须认真考虑的参数。如果不设maxmemoryRedis会一直吃内存直到操作系统OOM如果设了maxmemory但不设置合理的淘汰策略默认的noeviction会在内存满后直接拒绝写操作。缓存场景一般用allkeys-lru语义是所有key按照最近最少使用算法淘汰如果业务上允许多数数据过期也可以用volatile-lru只淘汰设了过期时间的key。appendonly建议生产环境开启。Redis默认只开RDB快照周期性保存极端情况下会丢失最后一次快照之后的数据。AOF是追加写日志每秒刷盘一次的配置下最多丢一秒数据。两个同时开的话Redis启动时会优先用AOF恢复数据安全性和恢复速度都能兼顾。3.2 使用systemd管理Redis写service文件前先确保配置文件和目录权限已经就位。然后创建/etc/systemd/system/redis.service[Unit] DescriptionRedis 7.2 server Afternetwork-online.target Wantsnetwork-online.target [Service] Typenotify ExecStart/usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf ExecReload/bin/kill -s HUP $MAINPID ExecStop/bin/kill -s QUIT $MAINPID Restartalways RestartSec3 Userredis Groupredis LimitNOFILE1024000 [Install] WantedBymulti-user.target几个关键配置我展开说一下。Typenotify是我踩过大坑的地方。Redis配置里如果没写supervised systemd进程启动后不会给systemd发通知而systemd的Typenotify会一直等通知直到超时然后服务显示启动失败。反过来如果配置里写了supervised systemd但service文件用的是默认的Typesimple虽然服务能起来但systemd无法准确感知Redis的就绪状态管理上会有偏差。所以这两个配置必须配套。LimitNOFILE1024000是文件描述符上限。Redis处理高并发连接时会打开大量文件描述符系统默认的1024远远不够如果不调大连接数一上来就会出现“Too many open files”错误。这个限制在systemd里通过LimitNOFILE设置作用是覆盖系统的ulimit限制。Restartalways和RestartSec3表示进程异常退出后3秒自动重启。Redis自身比较稳定但也会遇到OOM或者被误杀的情况这种自动化恢复在线上能省很多事。写完service文件后执行systemctl daemon-reload systemctl enable redis systemctl start redis systemctl status redis如果一切正常status输出会是active (running)。查看日志journalctl -u redis -f顺便说一句很多人问为什么要用systemd而不是直接在命令行敲redis-server这个人差别在于systemd接管了进程生命周期管理开机自启、崩溃重启、统一日志、统一停止重启操作运维上完全标准。以后这台机器上如果还跑其他服务管理方式都一致不用再记各种trick。3.3 防火墙、SELinux与远程访问控制服务起来之后如果是本机使用默认bind 127.0.0.1就够了。但更多时候需要让其他机器连过来比如应用服务器连Redis。这时要设置监听地址和放行端口。redis.conf里改动两处# 如果需要所有网卡都能访问 bind 0.0.0.0 # 或者只绑定内网IP bind 192.168.1.100注意一旦bind不是127.0.0.1就必须设置requirepass同时保持protected-mode yes。否则Redis端口暴露到外网扫描工具扫到后很快就会被入侵、写入恶意数据、甚至被当作跳板。这个不是危言耸听公网裸奔的Redis在扫描器眼里的价值极高。防火墙要放行6379端口firewall-cmd --permanent --add-port6379/tcp firewall-cmd --reload firewall-cmd --list-ports如果你用的是云服务器还要到云控制台的安全组规则里放行6379端口。这两层网络策略是叠加的缺一个都连不上。CentOS这类默认开启SELinux的系统还有一个隐藏难点。就算防火墙放行了端口SELinux如果没有对应的端口策略连接仍然会被拦截。表现为本机redis-cli连接正常远程telnet端口不通。先看SELinux状态getenforce如果输出Enforcing需要给Redis放行端口yum install -y policycoreutils-python-utils semanage port -a -t redis_port_t -p tcp 6379再强调一下遇到SELinux拦截时别一上来就setenforce 0那是关掉整个SELinux保护属于治标不治本。用semanage精准放行Redis端口才是正规做法。4. Redis 7新特性实测与基本玩法4.1 ACL账号权限从“一把密码锁”到细粒度授权Redis 6开始引入了ACLAccess Control ListRedis 7继续完善了这个体系。我不止一次见过生产环境里所有人共用一个密码、所有权限一把梭出问题根本不知道是谁操作的。ACL可以按业务创建独立账号只给最小权限。默认情况下Redis只有一个default用户配置里的requirepass等价于给default用户设置了密码。创建业务只读账号redis-cli -a 管理员密码 EOF ACL SETUSER app_read on app123 ~cache:* get mget exists ACL LIST ACL GETUSER app_read EOF这条ACL命令的意思是创建app_read用户密码app123只允许访问cache:前缀的key只允许执行get、mget、exists三个命令。效果立竿见影即使密码泄露攻击者也无法删除数据、无法执行flushall、无法访问非cache前缀的key。ACL真正的价值在于权限收敛和审计。生产环境可以给不同业务线建立不同用户缓存读写账号、报表只读账号、运维管理账号每个账号的命令范围、key范围、读写权限都明确。万一某个账号泄露影响范围可以控制在最小。4.2 Redis Functions把Lua脚本变成可复用的函数Redis 7发布时重点推的功能之一就是Redis Functions。之前写Lua脚本要么用EVAL每次把脚本内容传过去要么把脚本缓存在客户端管理起来很别扭。Redis Functions相当于服务端的“存储过程”脚本一次加载之后通过函数名直接调用还能跟随主从复制和集群同步。一个很常见的场景需要原子的“INCR EXPIRE”防止key永远不过期。新建一个mylib.lua文件#!lua namemylib local function incr_with_ttl(keys, args) local key keys[1] local ttl tonumber(args[1]) local v redis.call(INCR, key) if v 1 then redis.call(EXPIRE, key, ttl) end return v end redis.register_function(incr_with_ttl, incr_with_ttl)加载到Redisredis-cli -a 管理员密码 -x FUNCTION LOAD mylib.lua调用redis-cli -a 管理员密码 FCALL incr_with_ttl 1 mykey 60连续执行两次第一次返回1第二次返回2同时TTL mykey会显示60。这套机制做限流、计数器衰减、分布式锁续期都非常方便。函数库支持FUNCTION DUMP/RESTORE可以整体备份和迁移比手动管理一堆EVAL脚本干净太多。为什么推荐函数而不是直接EVAL一是代码复用同一个逻辑不需要每个客户端各存一份脚本二是升级管理函数整体加载版本可通过名字区分三是主从同步加载的函数会自动同步到从节点故障切换后逻辑不丢。在Redis 7环境里新项目建议优先用Functions。4.3 Sharded Pub/Sub分片发布订阅简单实验Redis 7在集群场景新增了Sharded Pub/Sub分片发布订阅相关的命令是SPUBLISH、SSUBSCRIBE、SUNSUBSCRIBE。传统的PUBLISH/SUBSCRIBE在集群模式下有个问题一条消息要广播到集群所有节点节点规模大了之后很浪费带宽。Sharded Pub/Sub将频道和某个slot绑定消息只会路由到该slot所在节点的订阅客户端大幅减少网络开销。单机环境一样可以体验这个功能开两个终端# 终端1 redis-cli SSUBSCRIBE shard_channel # 终端2 redis-cli SPUBLISH shard_channel hello sharded pubsub终端1会收到这条消息。如果项目里用到WebSocket推送、实时通知这类场景并且部署的是Redis Cluster用Sharded Pub/Sub会比传统发布订阅更高效。4.4 安装完成后的基本数据操作与验证Redis装好后至少要熟练操作五大数据类型。我每次给团队做环境验证都会用这几条命令过一遍redis-cli -a 密码 EOF # String缓存、计数器、会话 SET user:1:name tom GET user:1:name INCR page_view # Hash对象存储 HSET user:1 age 20 city beijing HGETALL user:1 # List消息队列、时间线 LPUSH task:queue job1 job2 job3 LRANGE task:queue 0 -1 # Set去重、标签、共同关注 SADD tag:redis linux database SMEMBERS tag:redis # ZSet排行榜、延时队列 ZADD rank:score 100 user_a 95 user_b ZRANGE rank:score 0 -1 WITHSCORES EOF验证版本和运行状态redis-cli -a 密码 INFO server redis-cli -a 密码 INFO memory redis-cli -a 密码 INFO statsINFO server里能看到redis_versionINFO memory里的used_memory是实际占用mem_fragmentation_ratio是内存碎片率这个值长期高于1.5说明碎片比较多得找原因INFO stats里的instantaneous_ops_per_sec表示瞬时QPS压测时可以观察。5. 常见问题与排查实录5.1 编译安装阶段的问题速查我把实际运维中遇到的高频问题整理成一张表方便直接对照现象原因解决办法make报错jemalloc.h找不到系统缺少jemalloc开发包make MALLOClibc或安装jemalloc-devel后重新makemake test报错找不到tclsh没装tclyum/apt install tcl老系统编译7.2报语法错误gcc版本太低如4.8.5用devtoolset升级gcc或换新系统make -j高并行度时编译失败内存不足降低并行度用make -j2或直接make启动时报TCP backlog警告内核somaxconn参数小于Redis的511sysctl -w net.core.somaxconn1024并写入/etc/sysctl.conf日志提示transparent huge page警告THP未被禁用echo never /sys/kernel/mm/transparent_hugepage/enabled并写入rc.local编译阶段最花时间的是gcc版本和jemalloc这两个问题建议在准备环境时就处理掉不要等到编译报错再折腾。5.2 启动与服务管理阶段的问题速查服务管理阶段最常见的问题就是systemd启动卡住。现象原因解决办法systemctl start redis后一直activating (start)Typenotify等待通知但Redis没发通知redis.conf里设置supervised systemd并保持daemonize no服务一会儿起来一会儿挂数据目录权限不对redis用户无法写dirchown -R redis:redis /var/lib/redis /var/log/redis重启后Redis没起来没执行enablesystemctl enable redis想改配置但不知道生效没有写错配置项用redis-cli CONFIG GET/REWRITE动态校验我之前在测试环境反复出现service状态卡在activating日志里什么都没有排查到最后就是配置里写了一个daemonize yessystemd一直在等一个永远等不到的通知。这个问题在官方文档里有说明但平时谁会逐字读文档还是踩坑记得最牢。5.3 连接与安全相关的问题速查远程连接不上按照下面的顺序一层层排查基本都能找到原因现象原因解决办法本机能连远程不行bind还绑定在127.0.0.1修改bind为内网IP或0.0.0.0报NOAUTH Authentication required设了密码但客户端没带redis-cli -a 密码或连接后执行AUTH密码正确但仍连不上protected-mode 无bind组合限制保持protected-mode yes设置bind和requirepass远程telnet端口不通防火墙或安全组没放行firewall-cmd添加6379/tcp检查云安全组防火墙放行后仍不通SELinux拦截semanage放行redis_port_t端口收到MISCONF Errors writing to the AOF file磁盘满或AOF写入失败检查磁盘空间、挂载权限安全相关的建议再重复一遍密码不要用弱口令不要图方便不设密码直接暴露公网。连接测试时别用redis-cli -a 密码这种把密码暴露在命令行历史里的做法用环境变量更安全export REDISCLI_AUTH你的密码 redis-cli ping写在最后的一点经验这套流程走完Redis 7已经能稳定跑在Linux上了。我个人实操后的几个习惯配置目录用Git管理每次改动都有记录启动后第一件事就是配ACL账号和强密码数据目录挂独立磁盘避免和根分区抢空间每月用redis-check-aof和redis-check-rdb做一次持久化文件体检。安装本身只是第一步真正考验功力的是运行期的监控、备份和权限治理。希望这篇笔记能让你少踩几个坑尤其是systemd托管和SELinux那两个地方知道原理就不会再被绕进去了。