ARTICLE DETAIL

资讯详情

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

macOS下Redis开机自启与后台运行完整指南

macOS下Redis开机自启与后台运行完整指南 我前阵子在一台全新的 MacBook 上从头装 Redis目标很明确装好之后让它安安静静在后台跑重启电脑也不用管开机自动起。本来以为就是brew install redis一条命令的事结果一路趟过去发现涉及的东西比想象中多——Homebrew 的服务管理、Redis 自身的守护进程配置、macOS 的 launchd 启动机制、plist 文件的写法任何一环没对上结果就是“装上了但没法用”或者“现在能用但重启就废”。这篇文章我就把这套流程完整拆开讲包括我一开始偷懒直接brew services start redis之后遇到的各种问题以及最后用手写 plist 接管开机自启的完整过程。如果你也是 macOS 用户想要一个开机自启、后台稳定运行的 Redis这篇文章可以直接照抄。1. 装之前的准备工作Homebrew 与命令行环境1.1 为什么要用 Homebrew 装 Redis而不是源码编译我见过不少人一上来就wgetRedis 源码包然后make、make install一条龙。这路子不能说错但在 macOS 上属于给自己找麻烦。源码编译的 Redis 默认只提供redis-server和redis-cli这些二进制配置文件、日志目录、数据目录、launchd 启动脚本全都要自己手动安排。而 Homebrew 的 redis 公式把这些都处理好了装完就有完整的目录结构、默认配置甚至自带了homebrew.mxcl.redis.plist这个现成的自启动配置模板。简单说Homebrew 装 Redis 能让你把精力放在“怎么让它开机自启”上而不是浪费在“编译报错缺依赖”“装完了连配置文件在哪都不知道”这种无关紧要的事情上。1.2 安装 Xcode Command Line Tools 与 Homebrew在 macOS 上装 Homebrew前提是系统里有 Xcode Command Line Tools它包含 git、clang 这些编译器工具链。装起来很简单打开终端执行xcode-select --install系统会弹窗让你确认等几分钟下载安装完就行。注意这一步依赖网络而且有时候会卡在“正在下载”很久多等一会别频繁取消重试。装完 Command Line Tools 之后再装 Homebrew。这里推荐用国内镜像源因为官方源在国内环境下经常慢到怀疑人生。我这边实测中科大源比较稳定/bin/bash -c $(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)如果你需要换镜像源装完之后执行cd $(brew --repo) git remote set-url origin https://mirrors.ustc.edu.cn/brew.gitIntel 和 Apple Silicon 的 Homebrew 默认安装路径不一样这直接影响后续 Redis 配置文件的路径。Apple Silicon 的 Mac 上 Homebrew 装在/opt/homebrewIntel 的装在/usr/local。我这台是 M 系列芯片所以后面出现的路径都以/opt/homebrew为准Intel 用户把路径换一下就行。1.3 用 brew install 安装 Redis 并验证准备工作做完之后安装本身反而最简单brew install redis这个过程会自动安装依赖比如openssl、pkg-config这些。装完看一眼版本号确认一下redis-server --version redis-cli --version我这边装完显示的是 Redis 7.x版本号不用太纠结只要是 6.x 以上本文的所有操作都适用。到这里 Redis 已经装好了但此刻它还只是个“装了但没跑”的状态。真正花时间的是接下来这部分怎么改配置、怎么后台跑、怎么开机自启。2. Redis 配置文件从默认值到可后台运行2.1 配置文件的默认位置与初次修改Homebrew 装的 Redis配置文件路径是Apple Silicon/opt/homebrew/etc/redis.confIntel/usr/local/etc/redis.conf用brew info redis也能看到这个路径。第一次打开这个文件你可能会被里面的注释量吓到密密麻麻全是英文注释。别慌绝大多数配置保持默认就行我们需要动的就那几个关键项。在动手之前推荐先备份一份原始配置cp /opt/homebrew/etc/redis.conf /opt/homebrew/etc/redis.conf.bak这个习惯我保持了很多年。改配置改到一半发现改坏了直接cp回来就能还原比靠记忆恢复靠谱得多。2.2 daemonize、logfile、requirepass 等关键项Redis 默认是前台启动的也就是说终端窗口一关Redis 就跟着退出。要让 Redis 自己跑到后台去需要改daemonize这个配置项。找到配置文件中这行daemonize no改成daemonize yes这个配置的意思很直白——让 Redis 以守护进程方式运行。改完这个之后redis-server /opt/homebrew/etc/redis.conf启动后终端会立刻回到命令提示符但 Redis 已经在后台跑着了。但这只是第一步。如果你想让 Redis 在系统启动时自动运行光靠daemonize yes是不够的因为daemonize yes只是让 Redis 脱离终端并没有告诉 macOS“开机时启动它”。所以很多教程里只改这一项然后告诉你“已经后台启动了”其实只答对了一半。后面我会专门讲 launchd 的部分那才是开机自启的正解。接着看日志配置。默认情况下 Redis 的日志输出到 stdout也就是终端。但既然要后台运行日志必须写到文件里否则以后排查问题什么都看不到。找到# logfile 改成logfile /opt/homebrew/var/log/redis.log注意这个目录是 Homebrew 装 Redis 时自动创建好的你不需要手动mkdir。如果你用了自定义路径必须先确保目录存在否则 Redis 启动会报错。密码这块如果 Redis 只在本机用可以暂时不开。但如果你的 Mac 在局域网内或者你打算用可视化工具远程连接建议设置一个强密码# requirepass foobared改成requirepass 你的强密码设置了密码之后用redis-cli连接时需要执行AUTH 你的密码才能操作这个别忘。我见过好几个人配好了密码结果过了几天自己忘了连不上还以为 Redis 挂了最后一看是密码问题。2.3 持久化配置影响RDB、AOF后台运行和开机自启其实还牵扯到一个隐藏问题数据持久化。先解释一下 Redis 的两种持久化机制RDB定时把内存中的数据快照写入磁盘默认开启文件叫dump.rdbAOF把每一条写命令追加到日志文件重启时重放命令恢复数据默认关闭对于开发机来说RDB 默认配置基本够用。但如果你的 Redis 里放了一些不想丢的临时数据建议顺手把 AOF 打开appendonly yesAOF 文件的默认位置同样在/opt/homebrew/var/db/redis/下。这个配置不直接影响“后台启动”和“开机自启”这两个主题但如果你开机自启配好了重启之后发现 Redis 里啥都没了那大概率是持久化没配好。所以我把这条一并列出来避免你走了前面的路最后栽在这个坑里。改完配置之后可以用redis-server /opt/homebrew/etc/redis.conf前台启动一次看看有没有报错。没有报错再 CtrlC 停掉继续下一步。如果你已经看到Ready to accept connections这行日志说明配置没问题。3. 后台启动的各种姿势与实测对比3.1 前台启动与 redis-server 路径确认先明确一个概念macOS 上装完 Redis 之后有两个地方可以执行redis-server/opt/homebrew/bin/redis-server/opt/homebrew/opt/redis/bin/redis-server两者基本一样/opt/homebrew/opt/redis/bin可以理解成 Homebrew 里的“内部链接”而/opt/homebrew/bin是暴露给用户的公开命令。直接用redis-server就行因为/opt/homebrew/bin已经在 PATH 里了。用下面的命令做一次配置校验redis-server /opt/homebrew/etc/redis.conf如果配置正确启动日志里能看到端口默认 6379在监听。这是最原始的启动方式放在这里只是为了验证配置。验证完直接 CtrlC 停掉因为接下来要聊的才是真正“后台化”的方案。3.2 用或 nohup 手动后台运行的局限很多人第一反应是既然前端启动会占住终端那我加个让它后台运行不就行了比如这样redis-server /opt/homebrew/etc/redis.conf 这确实能让 Redis 在当前终端会话存活期间在后台跑终端关闭之后进程还活着。但问题是这种方式本质上是“手动起了一个孤儿进程”管理起来很别扭。你想停的时候得先ps aux | grep redis找到 PID再kill PID完全是手工操作。nohup稍微好一点能让进程在终端退出后继续运行nohup redis-server /opt/homebrew/etc/redis.conf /opt/homebrew/var/log/redis-nohup.log 21 但它仍然没有解决“开机自启”的问题。macOS 开机之后不会因为你之前跑过一个nohup命令就自动拉起 Redis。你每次重启电脑都得手动执行一遍。这显然不符合“开机、后台启动”这六个字的要求。3.3 brew services 方式最省事的后台方案Homebrew 为每个装了服务的公式都封装了一个brew services命令用起来很简单brew services start redis执行完之后Homebrew 会把 Redis 注册进 launchd然后立即启动它。查看运行状态brew services list输出里会看到 Redis 这一行是started。这个方案的优点是省事、干净而且 Homebrew 自动帮你处理了 launchd 的 plist 注册重启电脑之后 Redis 会自动起来也算实现了开机自启。但我实际用过一段时间之后发现brew services方案有几个不舒服的地方Redis 的日志、错误输出等都由 launchd 统一管理排查问题时要到/opt/homebrew/var/log/redis.log或者launchctl error里去翻对不熟悉 launchd 的人来说黑盒感很强。一旦 Redis 启动失败brew services list里只显示error但你不知道具体错误原因得自己去看日志。如果你想用非默认端口、非默认配置路径brew services对自定义参数的支持比较弱。所以brew services适合“我就想让它跑起来”的场景。但如果你跟我一样想搞明白 macOS 到底是怎么把 Redis 拉起来的、想完全掌控启动参数和日志行为建议自己写 plist 文件。这是下一章的内容。3.4 为什么手动 daemonize 不推荐作为唯一方案这里必须把daemonize yes和“真正的后台服务”区分开。前面改过daemonize yes之后用命令redis-server /opt/homebrew/etc/redis.confRedis 确实会在后台运行终端也不会被占用。但问题在于这个进程是当前用户手动拉起的它和“登录会话”绑定在一起。你的 Mac 重启之后这个进程就没了你也不会看到一个“开机自动后台运行”的 Redis。更隐蔽的问题在于一旦 Redis 进程崩溃退出没有任何机制把它重新拉起来。而 launchd 的 plist 里可以配置KeepAlive进程退出后自动重启。同样是“后台运行”一个是裸奔一个是带保险绳性质完全不同。所以我把建议放在这里daemonize yes这个配置可以开但开了之后不要依赖它来实现“开机自启”。开机自启要用 launchd这是 macOS 的官方机制也是唯一靠谱的方案。4. 开机自启动的完整配置launchd 与 plist 文件4.1 launchd 的工作原理先搞清楚 launchd 是个什么东西。简单说它就是 macOS 的“开机管家”系统启动时会读入一堆 plist 配置按配置决定启动哪些服务、怎么启动、进程挂了要不要拉起。launchd 的 plist 文件有两个存放目录~/Library/LaunchAgents/当前用户登录后加载适用于用户级服务/Library/LaunchAgents/所有用户登录后加载需要 sudo 权限/Library/LaunchDaemons/系统级守护进程不需要用户登录就会启动适用于后端服务对于 Redis 这种本机开发用的服务放在用户级的~/Library/LaunchAgents/就够了。但有一个前提你 Mac 开机后需要有用户登录进入桌面LaunchAgent 才会被加载。如果你设置了自动登录或者你本人就是唯一的用户这完全没问题。如果你是开着 Mac 当服务器用、平时根本不登录图形界面那就应该考虑 LaunchDaemon。后者的 plist 写法和运行权限完全不同这篇文章以 LaunchAgent 为主因为大多数开发者都是这个场景。Homebrew 的brew services命令本质也是帮你生成一个 plist 并放进~/Library/LaunchAgents/。4.2 创建 plist 文件一步步写清每个字段下面这个 plist 是我在实际使用中逐渐调整出来的相比 Homebrew 默认生成的版本可读性更好参数也更明确?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyLabel/key stringcom.redis.server/string keyProgramArguments/key array string/opt/homebrew/bin/redis-server/string string/opt/homebrew/etc/redis.conf/string /array keyRunAtLoad/key true/ keyKeepAlive/key true/ keyStandardOutPath/key string/opt/homebrew/var/log/redis.stdout.log/string keyStandardErrorPath/key string/opt/homebrew/var/log/redis.stderr.log/string /dict /plist把这段内容保存到~/Library/LaunchAgents/com.redis.server.plist。逐个字段说清楚是什么意思Label服务的唯一标识必须和文件名com.redis.server一致。不一致会导致launchctl load报错。ProgramArguments要执行的命令和参数。第一个元素是程序路径后面的元素是传给它的参数。这里就是让redis-server读redis.conf启动。RunAtLoad设置为true表示加载这个 plist 时立即执行一次启动。这是“开机后自动启动”的关键。KeepAlive设置为true表示如果 Redis 进程意外退出launchd 会自动重新拉起。相当于带了一个守护进程。StandardOutPath和StandardErrorPath把 stdout 和 stderr 重定向到日志文件这样以后排查问题有据可查。有几点要注意如果你用了daemonize yesRedis 会自己 fork 到后台然后 launchd 会发现当初启动的那个“前台进程”已经退出了。此时KeepAlive的逻辑会跟 Redis 的守护进程化行为产生冲突。因此用 launchd 管理时推荐把daemonize改成no。因为 launchd 本身就负责管理后台生命周期Redis 不需要再自己 daemonize。这是一个非常容易踩的坑我折腾了快一个小时才反应过来。plist 文件对格式要求严格标签必须配对。写完建议用下面的命令校验plutil -lint ~/Library/LaunchAgents/com.redis.server.plist如果输出OK说明格式没问题。如果输出错误会告诉你具体哪一行有问题。4.3 launchctl 加载与验证plist 写完之后真正的加载命令如下launchctl load ~/Library/LaunchAgents/com.redis.server.plist老版 macOS 上这条命令正常但新版 macOS尤其是 Ventura 之后会提示load已废弃建议用bootstrap。保险起见我给出两种launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.redis.server.plist其中gui/$(id -u)表示当前用户的 GUI 会话域。这条命令在 Apple Silicon 的 macOS 上实测有效。查看服务是否加载成功launchctl list | grep redis如果看到类似PID Status Label的输出并且有进程 ID说明 Redis 已经被 launchd 管理起来了。也可以再用redis-cli ping验证一下 Redis 实际工作状态正常会返回PONG。如果要卸载服务用launchctl bootout gui/$(id -u)/com.redis.server听说过unload的老命令也没问题一样能用。但新系统下建议用bootout更符合 launchd 的新式管理语义。4.4 修改配置后的重载流程launchd 和 Redis 的配置都存在一个“改了配置不会立即生效”的问题。实际调优的时候经常要改 redis.conf 里的某个参数然后希望 Redis 用新配置重启。正确的流程是# 1. 卸载服务 launchctl bootout gui/$(id -u)/com.redis.server # 2. 重新加载服务 launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.redis.server.plist这一步做完launchd 会杀掉旧的 redis-server 进程然后用新配置重新拉起一个。整个过程就是两条命令的事不用手动去killPID。另外launchctl命令不会自己去读 Redis 的配置文件所以改了redis.conf之后直接launchctl bootstrap是无效的必须先bootout再bootstrap。这个顺序搞反了新配置不会生效而且 Redis 会继续用旧配置跑排查问题时容易被误导。5. 实测中遇到的坑与排查思路5.1 端口被占用启动失败的头号嫌疑我一开始装完直接启动 redis-server结果报错Could not create server TCP listening socket *:6379: bind: Address already in use这个提示的原因很明确6379 端口已经有进程占用了。最典型的场景是之前手动启动过一个 Redis但没人记得它还在后台跑着。排查命令lsof -i :6379如果看到有redis-server进程占用说明之前启动的 Redis 还在。用下面的命令停掉它redis-cli shutdown如果 Redis 设置了密码需要redis-cli -a 你的密码 shutdown停掉之后再验证lsof -i :6379没有任何输出说明端口已经释放了。然后重新走一遍launchctl bootstrap流程即可。5.2 plist 加载不生效的排查链路如果你执行完launchctl list | grep redis看不到任何输出按下面的链路排查第一确认文件路径和文件名。~/Library/LaunchAgents/com.redis.server.plist这个文件必须存放在 LaunchAgents 目录下文件名必须和Label一致。不一致launchd 静默忽略。第二检查 plist 格式。用plutil -lint校验任何括号不配对、标签写错都会导致加载失败。第三查看 launchd 的错误信息。比较常见的是launchctl error如果输出了错误码可以launchctl print gui/$(id -u)/com.redis.server查看这个服务的详细信息。注意print命令是排查 launchd 问题的神器里面能看到程序路径、参数、运行状态、退出原因等比盲猜有效得多。第四确认 redis.conf 中daemonize是no。如果你之前改成了yeslaunchd 启动 Redis 后Redis 自己把自己 fork 到后台初始前台进程正常退出。在 launchd 眼里这个服务“启动完了然后立即退出了”如果KeepAlive没开服务就直接变 inactive 了开了则会反复重启。这个问题在日志里看起来像“启动、退出、启动、退出”的死循环。排查时看/opt/homebrew/var/log/redis.stderr.log就能发现端倪。5.3 开机自启生效但 redis-cli 连不上还有一次比较有意思重启电脑后 Redis 确实在跑但redis-cli ping报连接拒绝用lsof -i :6379也没看到监听。查了半天发现是 macOS 的LocalHost网络服务在重启后稍微慢了一点launchd 在 Redis 需要监听的网络栈就绪之前就已经把它拉起来了导致 Redis 执行bind失败。处理方案有两个方案一在redis.conf里把bind 127.0.0.1显式写出来不要让 Redis 去监听所有网卡*减少网络栈依赖。方案二在 plist 里加一个延迟启动的机制。launchd 本身没有直接的 “sleep N 秒再启动” 字段但可以在ProgramArguments里包一层 shellkeyProgramArguments/key array string/bin/bash/string string-c/string stringsleep 5 /opt/homebrew/bin/redis-server /opt/homebrew/etc/redis.conf/string /array这样 launchd 拉起服务后会先睡 5 秒再启动 Redis给网络栈留出时间。这种方式不够优雅但实测能解决大部分“开机太早导致绑定失败”的问题。等 Redis 自己稳定运行之后可以再把 sleep 去掉。5.4 日志的查看方法与持久化验证日常维护 Redis 最常用的日志路径Redis 运行日志/opt/homebrew/var/log/redis.loglaunchd stdout/opt/homebrew/var/log/redis.stdout.loglaunchd stderr/opt/homebrew/var/log/redis.stderr.log排查问题时按顺序看这三个文件。如果 Redis 没起来先看 stderrstderr 里没有有效信息再看 redis.log。日志文件不存在说明 Redis 很可能根本没被启动或者启动参数有问题。持久化方面设置appendonly yes之后重启机器连 Redis 验证一下redis-cli 127.0.0.1:6379 SET testkey hello OK 127.0.0.1:6379 SAVE OK 127.0.0.1:6379 SHUTDOWN然后重新启动 Redis再GET testkey如果返回hello说明持久化验证通过。这一条配置看似跟“开机自启”无关实际是“开机自启后 Redis 数据还在不在”的关键保障。5.5 关于可视化工具和连接测试的补充Redis 跑起来之后很多人喜欢用可视化工具看一眼。相关热词里也出现了 Redis Desktop Manager目前这个工具的社区版已经更名为 RedisInsight官方推出的版本功能比较完整。如果只是想看 key 列表、内存占用这些基础信息用redis-cli完全够用如果确实需要 GUI下载 RedisInsight 即可。连接时注意填127.0.0.1:6379如果你在 redis.conf 里设置了密码需要填 AUTH 密码。连接不上时优先检查 Redis 是否监听、密码是否配置正确、网络栈是否正常这三个点不要一上来就怀疑工具坏了。如果你平时在 Linux 服务器上习惯用的systemctl命令在 macOS 上不存在。这和本文讨论的 launchd 机制是两套东西不要把两者的概念混在一起。最后再分享一个我个人的习惯我会在~/.zshrc里加一个别名方便快速查看 Redis 状态alias redis-statuslaunchctl list | grep redis redis-cli ping每次开机之后敲一下redis-status能同时确认 launchd 服务和 Redis 本身都正常一行命令搞定。这个项目做完之后我的 Redis 已经连续跑了一个多月没出过任何问题中间经历了多次重启。配置一次后面真的就省心了。
返回列表