ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Redis启动方式详解:前台、后台守护进程与systemd实践

Redis启动方式详解:前台、后台守护进程与systemd实践 生产环境里装过 Redis 的朋友都会有同感这玩意儿本身是个 C 写的轻量级内存数据库装起来不复杂可真正让你纠结的往往是“装完之后怎么启动”。前台启动一关终端就断后台启动忘了加配置文件就黑屏挂起想做成开机自启又发现 service 文件和 Redis 自身的守护进程模式相互打架。这篇文章把我自己从下载编译到三种启动方式完整跑通的经历全盘写下来包括每个坑是怎么踩的、日志输出长什么样、最后如何优雅关闭希望能帮你少走几趟弯路。1. 环境准备、版本选择与编译安装1.1 我的实验环境与版本取舍先说测试机环境CentOS 7.9内核 3.10配了 2 核 4G 内存没有外网访问生产库的需求纯做本地安装验证。生产上我用过 Redis 5.x、6.0 和 7.0 系列这里拿 redis-7.0.14 做演示因为 7.x 在配置文件结构、ACL 权限模型、以及默认的启动行为上都比 6.x 更接近当前新项目的落地习惯。为什么不是 8.x8.0 虽然已经在有些场景里崭露头角但很多企业还在做评估网上教程也大多是老语法。而且 7.0 系列的安装步骤、配置项、启动行为放到 6.2 和 8.0 之间都有很强的通用性。如果你们线上还在用 6.0跟着本文操作也基本没有障碍最多把版本号替换一下。版本选择这件事我的态度一直是能上 STABLE 就上 STABLE别追 beta 功能稳定压倒一切。1.2 下载 Redis 源码包的三个途径Redis 官方源码包的下载地址是 https://download.redis.io/releases/ 你可以在浏览器里直接访问选好版本后右键复制链接。Linux 服务器上最省事的方式是用命令行下载cd /usr/local/src wget https://download.redis.io/releases/redis-7.0.14.tar.gz如果你所在的网络访问官方下载源很慢可以考虑国内镜像或者 GitHub Releases。GitHub 的方式是wget https://github.com/redis/redis/archive/refs/tags/7.0.14.tar.gz但注意 GitHub 拉下来的压缩包解压后的目录名可能带redis-7.0.14前缀结构和官方一致不影响编译。另外还有不少教程喜欢用yum install redis或apt install redis直接装这种方式安装速度快不用自己编译但包管理器源里的版本通常滞后期间可能缺少你想要的新特性也不方便自定义安装目录。我个人的习惯是测试环境用包管理器没问题生产环境一律源码编译版本和参数完全可控。下载完了先校验大小或者解压验证避免下到一半的残包。解压命令tar xzf redis-7.0.14.tar.gz cd redis-7.0.141.3 编译安装的完整命令与踩坑点Redis 是 C 写的编译依赖 gcc。CentOS 上先装基础编译工具yum install -y gcc make tcl接着进入源码目录执行编译这一步很多人只记得make忽略了 tcl。tcl 不是编译期的硬依赖但你后面如果想跑make test做自测没有 tcl 就会直接报You need tcl 8.5 or newer的错误。生产环境里make test可以省本地测试我还是推荐跑一遍能提前暴露很多运行时环境问题。make MALLOClibc这里有个小知识点Redis 默认使用 jemalloc 作为内存分配器如果你服务器上的 gcc 版本偏老或者源码目录之前被中断过产生过残留编译时经常报zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory。遇到这个错误要么先清理重新编译要么直接用make MALLOClibc换成系统 libc 的 malloc。生产环境如果对性能没有极致要求libc 完全够用。编译完成后我习惯指定安装目录而不是直接make install把二进制散落在/usr/local/bin。我通常装到/usr/local/redis下这样卸载和升级都干净make install PREFIX/usr/local/redis到这里三个核心二进制就位了redis-server服务主程序redis-cli命令行客户端redis-sentinel哨兵模式的主程序高可用部署时用安装完成后把源码目录里的redis.conf复制到/usr/local/redis/下作为日常使用的配置模板cp /usr/local/src/redis-7.0.14/redis.conf /usr/local/redis/redis.conf这一步很多人会忽略直接在命令行参数里写一堆--daemonize yes最终导致配置文件重复加载覆盖、行为不可控。我强烈建议启动之前先固化一份配置文件后面不管是改端口、开持久化还是设置密码都在这份文件上操作再配合版本控制管理变更历史。2. 动手启动之前redis.conf 这些参数必须心里有数2.1 配置文件在哪、怎么读注释Redis 的配置文件和很多服务不一样它不是“缺省值就够用”的因为默认配置面向的是本机开发场景bind 只监听了 127.0.0.1保护模式开着持久化可能不符合业务预期。所以启动之前一定要打开 redis.conf 看一遍重点是看哪些参数被注释掉、哪些参数是默认生效的。配置文件里每一行通常都是参数名 参数值的格式例如port 6379 bind 127.0.0.1 -::1 protected-mode yes daemonize no读这个文件的时候注意Redis 的配置参数命名风格和很多服务不同它用的是小写单词形式比如appendonly、save、requirepass。别和 MySQL 的my.cnf搞混。配置文件里 # 开头的都是注释一个参数如果被注释掉表示当前使用的是该参数的内置默认值。2.2 决定启动方式的关键参数daemonize整个启动方式的话题里最核心的就是daemonize参数。这个参数控制 Redis 是“前台运行”还是“后台守护进程运行”。daemonize no表示前台运行启动后当前终端会被 Redis 的日志输出占住你可以直观看到启动过程的所有日志但终端一旦关闭或者按 CtrlC 结束进程Redis 就停了。daemonize yes表示以守护进程方式运行Redis 启动后父进程退出子进程在后台托管日志会写入配置的 logfile 文件终端可以继续用。在 Redis 7.x 版本中配置文件里的默认值是daemonize no。这其实是官方的一种引导信号他们更希望你用 systemd 或者 supervisor 这类进程管理器来托管 Redis而不是靠守护进程模式“裸奔”。不过现实中大量 Linux 服务器并没有给 Redis 单独建 systemd service开发测试机上daemonize yes依然是最主流、最省事的后台启动方式。2.3 其它一启动就会影响成败的参数除了 daemonize还有几个参数是你启动 Redis 后立刻就会感受到存在感的port默认 6379。如果端口被占用Redis 直接启动失败日志里会打印Address already in use。bind默认127.0.0.1 -::1只允许本机连。想允许其他机器访问就得改成0.0.0.0或指定内网 IP同时也要关注保护模式。protected-mode默认yes。这个参数和 bind 配合生效如果你没有配置密码也没有把 bind 设置成非本地回环地址Redis 会拒绝外部机器的连接请求。很多新手后台启动成功了局域网其他机器连不上十有八九就是这个原因。logfile默认是空的日志打到标准输出。如果你设置了daemonize yes却不配 logfile日志将从终端消失出了问题你都不知道为什么。我习惯配成/var/log/redis/redis.log或者退一步也至少有logfile /usr/local/redis/redis.log。dir持久化文件的保存目录默认是启动时的当前目录。这非常坑因为用 systemd 启动的话当前目录通常不是你想保存 RDB/AOF 的位置。我会显式设置成/var/lib/redis。appendonly是否开启 AOF 持久化。虽然和启动本身无关但如果突然重启后数据没恢复你会第一时间怀疑启动方式实际上多半是持久化没配。requirepass设置访问密码。Redis 7.x 里还可以用 ACL 用户管理但配置密码哪怕只是一个测试环境密码也能避免 Redis 暴露到外网后被恶意攻击。提示bind和protected-mode这两个参数组合最常见的恶果是——本机redis-cli ping通局域网连不通。排查时用redis-cli -h 服务器IP -p 6379 ping测试如果提示DENIED Redis is running in protected mode基本就是这两个参数的问题。3. 三种启动方式详解从简单到生产级3.1 前台启动一条命令跑起来只能用于测试前台启动是最简单的启动方式在任意目录直接执行/usr/local/redis/bin/redis-server或者带上显式配置/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf第二种写法更标准因为你可以把 daemonize、端口、密码、持久化参数都提前配置好。这时如果配置文件里daemonize noRedis 就会牢牢占据当前终端不断打印运行日志。启动成功后你会看到类似这样的一段输出Running modestandalone, port6379. Server initialized ... Ready to accept connections tcp当你看到Ready to accept connections这一行说明 Redis 已经就绪。前台启动模式下按下 CtrlC 可以直接停止 Redis。这种方式的优点是你对启动细节一目了然任何错误都会立刻显示在眼前非常适合刚接触 Redis 时验证配置是否正确。缺点也很明显终端一关服务就停而且在这种模式下你没法继续做其他操作除非另开 SSH 会话。所以结论很简单——只用来做测试和验证生产环境永远不要用。3.2 后台守护进程启动最常用的日常方式后台启动本质上就是借助 Redis 自身的daemonize能力把进程转到后台运行。操作方法有两种一种是启动时加命令行参数/usr/local/redis/bin/redis-server --daemonize yes还有一种是我更推荐的——改配置文件。把 redis.conf 里的daemonize no改成daemonize yes同时设置好 logfile然后用配置文件启动/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf这时终端会正常返回提示符Redis 已经在后台跑起来了。怎么确认它真的起来了两条命令ps -ef | grep redis-server netstat -tlnp | grep 6379如果进程和端口都在再顺手验证一下连通性/usr/local/redis/bin/redis-cli ping返回 PONG 就说明一切正常。后台启动模式下停止服务有两种方式一是用 Redis 自带的 shutdown 命令优雅关闭/usr/local/redis/bin/redis-cli shutdown二是直接 kill 进程。但除非服务真的僵死我都建议用 shutdown 而不是 kill因为 shutdown 会先执行持久化收尾动作减少数据丢失风险。注意使用redis-cli shutdown时如果配置了 requirepass就需要加上密码redis-cli -a 你的密码 shutdown。否则会提示NOAUTH Authentication required。3.3 systemd 服务启动生产环境的高阶选择如果这台服务器需要长期跑 Redis并且重启机器后希望 Redis 自己跟着起来那就得用 systemd 托管了。用 systemd 管理 Redis 最大的好处是开机自启、崩溃自动拉起、日志统一交给 journald 管理运维排查起来比翻 Redis 自己的 logfile 舒服得多。我实际操作的时候在/etc/systemd/system/redis.service写了一个服务单元文件内容如下[Unit] DescriptionRedis In-Memory Data Store Afternetwork.target [Service] Typeforking ExecStart/usr/local/redis/bin/redis-server /usr/local/redis/redis.conf ExecStop/usr/local/redis/bin/redis-cli -a 你的密码 shutdown ExecReload/bin/kill -s HUP $MAINPID Restartalways Userredis Groupredis [Install] WantedBymulti-user.target这里的 Type 选择有讲究。我配的是Typeforking因为 redis.conf 里daemonize yesRedis 启动时父进程会 fork 出子进程父进程退出。如果你配成Typesimplesystemd 就会把 Redis 的前台主进程当成服务主进程来跟踪但 Redis 自己变成守护进程退出了systemd 会误以为服务启动失败。另一种更贴近“官方推荐”的做法是把 redis.conf 里daemonize nosystemd 用Typesimple直接托管前台进程这样 systemd 对进程的生命周期控制更严格。两种模式我都实际跑过。如果你喜欢把 Redis 日志统一交给 systemd 管理那推荐第二种也就是 Typesimple daemonize no如果你希望 Redis 的日志依然写自己的 logfile同时保留 systemd 的开机自启那 Typeforking daemonize yes 也没问题。这里没有绝对的对错关键是类别要和配置文件保持一致。写完 service 文件后依次执行systemctl daemon-reload systemctl enable redis systemctl start redis systemctl status redissystemctl enable redis是为了生成开机自启软链接systemctl start redis是立即启动。status 输出里能看到Active: active (running)就说明没问题。日常的管理命令也很统一systemctl status redis systemctl restart redis systemctl stop redis3.4 三种启动方式怎么选一张表说清楚启动方式配置要点优点缺点适用场景前台启动daemonize no直接 redis-server日志直观调试方便终端关闭即停止占用终端第一次验证配置、快速测试后台守护进程daemonize yes配合 logfile简单高效不依赖管理工具进程管理靠手动无自启日常开发机、临时测试服务器systemd 服务systemd service 文件统一托管开机自启、崩溃自动拉起、日志统一配置相对复杂需要理解 Type 语义生产环境、长期运行、需要重启自恢复实际选型时我的建议是本地开发或者临时验证用第二种线上只要是 7 天 × 24 小时跑的直接第三种。别觉得 systemd 配置复杂这种复杂度换来的可靠性和运维便利是实实在在的。4. 启动后的连接验证与日常运维命令4.1 redis-cli 验证服务的四板斧启动成功不代表配置完全符合预期验证是必不可少的一步。我最常用的验证命令依次是redis-cli ping返回 PONG说明服务在监听且能正常响应最简单的心跳请求。接下来看基本信息redis-cli info server这个命令会打印 Redis 的版本号、进程 ID、运行模式、端口、TCP 连接数等信息。适合确认当前跑的到底是哪个版本以及是不是误加载了错误的配置文件。再看CONFIG GET用来检查你在配置文件里设的参数是否真正生效redis-cli config get daemonize redis-cli config get requirepass redis-cli config get maxmemory这个比info更直接因为可以一次性确认多个你关心的配置项。最后打开监控模式观察实时命令执行redis-cli monitor正常连接后任何客户端执行的命令都会实时打印出来。这个命令在生产环境上慎用它会增加 Redis 的 CPU 负担但在测试环境排查“某个 key 到底被谁改掉了”非常有用。4.2 进程、端口、日志三件套排查服务启动后我习惯从进程、端口、日志三个维度确认运行状态。进程看的是 Redis 是否存在以及归属哪个用户ps -ef | grep redis这里要留意进程的属主。如果 systemd 用的是 redis 用户启动进程显示redis而手动启动的往往是root。出于安全考虑生产环境用普通用户运行 Redis 更稳妥。端口看的是实际监听地址netstat -tlnp | grep 6379 ss -tlnp | grep 6379新版系统里 ss 已经替代了 netstat两者输出差不多。重点看 Local Address 这一列127.0.0.1:6379表示只监听本机0.0.0.0:6379或内网IP:6379才表示允许外部连接。日志是最后一道保险。后台启动模式下日志文件地址在 config 里的 logfile 配置决定如果用了 systemd可以直接用journalctl -u redis -f实时滚动查看服务日志。日志里出现Ready to accept connections说明正常出现Can’t bind address、Address already in use那就是启动阶段的问题。4.3 优雅关闭 Redis 的正确姿势关闭这件事很多人随手kill -9这是最粗暴也最危险的方式。Redis 在关闭时可能还在做 RDB 快照持久化kill -9会直接打断这个过程极端情况下会造成数据丢失。正确的开源姿势是redis-cli shutdown这个命令本身做了什么事呢它会先停掉所有客户端连接然后根据配置决定是否执行一次持久化保存最后退出进程。如果你给 Redis 设置了密码别忘加-a参数。如果是 systemd 托管关闭就是一条systemctl stop redissystemd 内部会执行 service 文件里的 ExecStop 指定的命令也就是 redis-cli shutdown。这里有个小坑如果 redis.conf 里设置了密码而 ExecStop 里没有带上-a密码systemctl stop 就会卡住或失败。我遇到过这个坑当时 systemctl stop 等了很久没反应排查发现是密码校验卡住了。所以上面 service 文件里我特意写了-a 你的密码就是这个原因。5. 高频踩坑实录与排查技巧5.1 编译阶段的两个拦路虎编译阶段最常见的两个报错一个是zmalloc.h: No such file一个是/bin/sh: cc: command not found。第一个我在前面提过是 jemalloc 和 gcc 版本兼容问题解决办法就是make clean后重新make MALLOClibc。第二个其实是没装 gccCentOS 上执行yum install -y gccDebian/Ubuntu 则是apt install -y build-essential装完 gcc 再重新 make 就能过。别小看这种基础错误很多新手卡在编译这步半天找不到头绪实际上就是编译工具链没装全。5.2 启动时常见的两个系统级警告Redis 启动时经常打印几个警告它们不会阻止进程启动但会埋下性能隐患。最典型的是这两个第一个是 overcommit_memoryWARNING Memory overcommit must be enabled without strict mode. Your Redis instance will eventually refuse to write to disk...原因是系统vm.overcommit_memory默认是 0Redis 在做 fork 子进程保存 RDB 时可能因为内存申请模式限制而出现问题。临时修复echo 1 /proc/sys/vm/overcommit_memory持久化配置写在/etc/sysctl.conf里vm.overcommit_memory 1执行sysctl -p让配置生效。第二个是 THPtransparent huge pagesWARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis.Redis 官方建议关掉透明大页因为 THP 的内存分配特性和 Redis 的大量小对象读写模式不搭。临时关闭echo never /sys/kernel/mm/transparent_hugepage/enabled开机持久化则把配置写入/etc/rc.local并确保该文件有执行权限。这些警告在开发机上可能感觉不到但在高并发或者大 key 写入时影响会被放大建议初始化时就处理掉。5.3 后台启动成功却连不上的原因后台启动成功后本机redis-cli ping是 PONG但局域网里其他机器连不上这个问题的排查思路是有顺序的首先看 Redis 监听地址。如果bind 127.0.0.1外部机器当然连不上。修改 bind 为服务器内网 IP 或0.0.0.0同时确认 protected-mode 状态。这里有个细节Redis 的 protected-mode 只有在“没有配置 bind 非回环地址”和“没有配置密码”时才生效。也就是说你只要设置了密码protected-mode 基本不会干涉外部连接。然后看防火墙。CentOS 7 默认 firewalld 开着6379 端口默认不放行firewall-cmd --permanent --add-port6379/tcp firewall-cmd --reloadDebian/Ubuntu 上有 ufw 的话就ufw allow 6379/tcp。最后再用 telnet 或者 nc 从外部主机探一下端口通不通nc -vz 服务器IP 6379注意有些人改了 bind 和防火墙还是连不上回头一看Redis 日志里反复出现Possible SECURITY ATTACK detected这其实是 Redis 在提示“有很多未授权连接被拒绝了”说明你的 protected-mode 或者密码策略已经生效。这个时候不是 Redis 出了问题而是你的客户端连接参数没带密码。5.4 systemd 服务启动失败排查步骤systemd 启动失败时第一时间看状态systemctl status redis我最常遇到的失败原因按概率排序redis 用户不存在、redis.conf 路径写错、daemonize 与 Type 不匹配、数据目录权限不对。redis 用户不存在的情况因为我在 service 文件里写了Userredis但系统里并没有这个用户systemd 会直接启动失败。提前创建用户useradd -r -s /sbin/nologin redis mkdir -p /var/lib/redis /var/log/redis chown -R redis:redis /var/lib/redis /var/log/redis路径写错的迹象是 journalctl 里出现Cant open the log file或者Cant open the config file。检查路径时务必用绝对路径不要写~/redis.conf这种带相对概念的路径。Type 和 daemonize 不匹配的症状更隐蔽systemctl start redis执行后命令返回了但systemctl status redis显示inactive (dead)或failed。这种时候把 redis.conf 里的 daemonize 改成 yes 配合 Typeforking或者 daemonize no 配合 Typesimple 就能解决。5.5 端口冲突与安全组问题最后说一个部署到云服务器时的高频问题本机一切正常但公网 IP 就是连不上 Redis。排除掉 bind 和 protected-mode 之后八成是云厂商的安全组规则没放行 6379 端口。这个不在 Linux 系统层面能看到得去云控制台的安全组里手动加一条入方向规则。我有一次排查了半小时最后发现是安全组只放行了 80 和 443。还有一个和端口相关的坑就是 Redis 占用了 6379 但这个端口同时被别的服务占用。用lsof -i:6379或者ss -tlnp | grep 6379看进程是谁如果被别的程序占用要么改 Redis 端口要么处理冲突进程。提示端口层面的排查永远是先看本机监听再看防火墙最后查安全组。顺序反了容易做无用功。我个人在实际操作中最深的体会是Redis 启动方式的“坑”其实不在启动命令本身而在配置文件的支微末节——daemonize 和 systemd Type 的匹配、bind 和 protected-mode 的组合逻辑、logfile 和 dir 是否规范。如果能把 redis.conf 里这几个参数吃透手动启动、守护进程启动、systemd 启动之间的差异就瞬间清晰了。最后再分享一个小技巧每次改完配置文件先用redis-server /path/to/redis.conf前台方式跑一下确认日志没有 ERROR 再切换成真正的后台或者 systemd 启动这样能过滤掉大部分低级配置问题比你直接 restart 服务看日志要高效得多。
返回列表