Linux、Ubuntu 运维与日常维护
本章从后端开发和日常运维的角度介绍 Redis:如何在 Ubuntu 上安装、Node.js 代码更新时是否需要重启 Redis,以及工作中常用的检查、排障、备份和维护操作。
1. 先区分两个独立进程
一个使用 Redis 的 Node.js 系统至少包含两个独立部分:
Node.js 应用进程
|
| TCP / TLS
v
Redis 服务端进程
- Node.js 应用运行你的 TypeScript/JavaScript 业务代码。
- Redis 服务端保存数据并执行 Redis 命令。
redisnpm 包只是 Node.js 客户端,不是 Redis 服务端。
两者可以在同一台服务器,也可以部署在不同服务器或容器中。重启其中一个,通常不要求同时重启另一个。
2. 在 Ubuntu 上安装 Redis
方式一:使用 Ubuntu 自带软件源
这种方式最简单,适合本地学习和对版本要求不高的环境:
sudo apt update
sudo apt install redis-server
Ubuntu 自带仓库中的 Redis 版本可能落后于 Redis 官方最新稳定版。安装前可以查看候选版本:
apt-cache policy redis-server
方式二:使用 Redis 官方 APT 软件源
需要较新稳定版本时,可以使用 Redis 官方软件源:
sudo apt-get update
sudo apt-get install -y lsb-release curl gpg
curl -fsSL https://packages.redis.io/gpg \
| sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" \
| sudo tee /etc/apt/sources.list.d/redis.list
sudo apt-get update
sudo apt-get install redis
软件源配置可能随 Redis 官方发布方式变化。用于生产环境前,应再核对官方安装页面,而不是永久复制一份旧命令。
启动并设置开机启动
Ubuntu 软件包常见的 systemd 服务名是 redis-server:
sudo systemctl enable --now redis-server
查看状态:
sudo systemctl status redis-server
如果系统提示找不到该单元,可以查看实际服务名:
systemctl list-unit-files | grep redis
验证安装
redis-cli PING
预期结果:
PONG
查看版本:
redis-server --version
redis-cli INFO server
3. Ubuntu 上的常见目录
不同安装方式可能略有区别,Ubuntu 软件包通常使用:
| 内容 | 常见位置 |
|---|---|
| 主配置文件 | /etc/redis/redis.conf |
| 数据目录 | /var/lib/redis |
| 传统日志文件 | /var/log/redis/redis-server.log |
| systemd 日志 | journalctl -u redis-server |
| 服务账号 | redis |
不要仅凭表格修改文件,应先确认当前实例的真实配置:
redis-cli CONFIG GET dir
redis-cli CONFIG GET dbfilename
redis-cli CONFIG GET appendonly
查看服务启动参数:
systemctl cat redis-server
4. 最基本的安全配置
不要直接暴露到公网
Redis 应只允许可信应用网络访问。单机应用最简单的配置是只监听本机:
bind 127.0.0.1 ::1
protected-mode yes
如果 Node.js 和 Redis 位于不同服务器,应绑定内网地址,并同时配置:
- 云安全组或防火墙白名单。
- Redis ACL 用户与最小命令权限。
- 跨不可信网络时使用 TLS。
- 禁止公网
0.0.0.0:6379任意访问。
查看监听地址:
sudo ss -lntp | grep 6379
修改配置后的正确流程
编辑前先备份:
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
sudoedit /etc/redis/redis.conf
然后检查并重启:
sudo systemctl restart redis-server
sudo systemctl status redis-server
redis-cli PING
生产环境不要直接重启。应先确认持久化状态、业务低峰、应用降级能力,以及是否由 Sentinel/Cluster 提供故障转移。
5. Node.js 代码更新时是否要重启 Redis
通常不需要。
更新以下内容时,只需要重新部署或重启 Node.js 应用:
- 路由、业务逻辑或 TypeScript 代码。
- Node-Redis 调用方式。
- 缓存读写逻辑。
- Worker 处理函数。
package.json中的应用依赖。
Redis 是独立服务,不会加载 Node.js 源码。Node.js 重启后会重新建立 Redis 连接,Redis 服务端可以继续运行。
更新 Node.js 代码
|
+-- 重启 Node.js:通常需要
|
+-- 重启 Redis:通常不需要
哪些情况需要重启 Redis
- 修改了必须重启才能生效的
redis.conf配置。 - 升级 Redis 服务端版本。
- 修改 systemd 启动参数、运行用户或资源限制。
- 更换某些 TLS 证书或网络配置。
- Redis 进程异常,并且无法通过其他方式恢复。
- 服务器维护或操作系统重启。
部分 Redis 配置支持 CONFIG SET 动态修改,但运行时修改不一定会写回配置文件。日常运维应以受版本控制或配置管理系统管理的正式配置为准,避免“当前进程有效,重启后丢失”。
Node.js 更新仍可能影响 Redis 数据兼容性
虽然不用重启 Redis,但新旧代码可能使用不同的键名或数据格式。例如旧代码保存:
{"id":42,"name":"Alice"}
新代码却期待:
{"id":42,"profile":{"name":"Alice"}}
安全做法包括:
- 使用带版本的键,例如
nloop:v2:user:42。 - 部署期间兼容读取旧格式。
- 对缓存直接删除并让应用重建,而不是手工批量修改。
- 对会话、队列等不可随意删除的数据设计正式迁移方案。
- 滚动部署时确保新旧应用版本可以短时间共同工作。
6. Node.js 应用的常见重启方式
具体命令取决于部署方式。
systemd:
sudo systemctl restart nloop
sudo systemctl status nloop
journalctl -u nloop -n 100 --no-pager
PM2:
pm2 restart nloop
pm2 logs nloop
Docker Compose:
docker compose up -d --build app
docker compose logs --tail=100 app
这些命令应该只重建或重启应用服务,不要顺手执行 docker compose down -v。-v 可能删除 Redis 数据卷。
Node.js 进程退出前应调用 client.close(),停止接收新请求并等待正在执行的请求完成。部署平台也要提供足够的终止宽限时间。
7. 高频状态检查
查看 Redis 是否运行
sudo systemctl is-active redis-server
redis-cli PING
systemctl 只能说明进程状态,PING 能进一步说明 Redis 可以响应命令。
查看服务日志
sudo journalctl -u redis-server -n 100 --no-pager
sudo journalctl -u redis-server -f
-n 100:查看最近 100 行。-f:持续跟踪新日志,排障结束后按Ctrl+C退出。
查看总体信息
redis-cli INFO
redis-cli INFO server
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO stats
redis-cli INFO persistence
redis-cli INFO replication
常关注:
connected_clients:当前连接数。blocked_clients:正在等待阻塞命令的客户端数。used_memory、used_memory_rss:Redis 使用内存和进程常驻内存。mem_fragmentation_ratio:内存碎片比例,只能结合实际内存一起判断。evicted_keys:因为内存策略被淘汰的键数量。expired_keys:自然过期的键数量。keyspace_hits、keyspace_misses:缓存命中和未命中累计值。rdb_last_bgsave_status、aof_last_bgrewrite_status:持久化任务状态。master_link_status:副本与主节点的连接状态。
8. 高频键操作
查看键数量
redis-cli DBSIZE
redis-cli INFO keyspace
DBSIZE 返回当前逻辑数据库的键数量,但不能说明键占用了多少内存。
查找键
生产环境避免:
redis-cli KEYS '*'
使用增量扫描:
redis-cli --scan --pattern 'nloop:user:*'
键很多时,即使 SCAN 不会像 KEYS 一次阻塞全部键空间,扫描本身仍会消耗 CPU 和网络,应避开高峰并限制后续处理速度。
查看键类型、TTL 和内存
redis-cli TYPE 'nloop:user:42'
redis-cli TTL 'nloop:user:42'
redis-cli PTTL 'nloop:user:42'
redis-cli MEMORY USAGE 'nloop:user:42'
redis-cli OBJECT ENCODING 'nloop:user:42'
TTL 常见返回值:
- 正数:剩余过期时间。
-1:键存在,但没有过期时间。-2:键不存在。
设置或补充过期时间
redis-cli EXPIRE 'nloop:user:42' 300
redis-cli PERSIST 'nloop:user:42'
PERSIST 会移除 TTL,使键永久存在。生产操作前必须确认这符合业务要求。
删除键
redis-cli UNLINK 'nloop:user:42'
UNLINK 将键从键空间移除,并异步回收值占用的内存,删除大键时通常比同步 DEL 更稳妥。
删除前先确认环境、数据库编号和完整键名。不要把模糊匹配结果未经审核直接批量传给删除命令。
9. 检查大键和内存
抽样寻找大键
redis-cli --bigkeys
--bigkeys 会扫描键空间,并按数据类型报告较大的键。它关注的是元素数量或字符串大小,不是完整的内存诊断。
某些 Redis CLI 版本还支持:
redis-cli --memkeys
在大型生产实例运行全库扫描前,应评估耗时和负载,优先在副本或低峰期执行。
查看内存上限和淘汰策略
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy
作为普通缓存时,可以按业务选择合适淘汰策略。BullMQ 等队列数据所在 Redis 官方要求使用 noeviction,不能让队列内部键被随意淘汰。
常见内存增长原因
- 缓存键没有 TTL。
- TTL 设置过长。
- 完成或失败的队列任务没有清理。
- List、Set、Hash 持续追加,没有上限。
- 单个值过大。
- 客户端不断创建新键名,形成高基数数据。
- AOF rewrite 或 fork 期间短时内存压力增加。
10. 慢命令与延迟排查
Slow Log
查看最近的慢命令:
redis-cli SLOWLOG LEN
redis-cli SLOWLOG GET 20
慢日志记录的是 Redis 服务端执行命令的时间,通常不包含客户端排队、网络传输和 Node.js 事件循环等待时间。
查看阈值:
redis-cli CONFIG GET slowlog-log-slower-than
redis-cli CONFIG GET slowlog-max-len
不要为了排查临时把阈值改得极低后长期保留。
延迟诊断
redis-cli --latency
redis-cli LATENCY DOCTOR
redis-cli LATENCY LATEST
如果延迟监控没有启用,LATENCY DOCTOR 会提示没有可分析的数据。是否调整 latency-monitor-threshold 应由运维人员结合生产负载决定,不要为了临时排障永久开启过细采样。
延迟升高时依次检查:
- 是否存在
KEYS、大范围集合读取或长 Lua 脚本。 - 是否正在生成 RDB、重写 AOF 或发生主从同步。
- CPU 是否被其他进程抢占。
- 是否发生内存交换(swap)。
- Node.js 到 Redis 的网络是否异常。
- 客户端是否串行执行了大量命令。
11. 客户端连接排查
查看连接统计
redis-cli INFO clients
redis-cli CLIENT LIST
CLIENT LIST 可能输出客户端地址、名称、空闲时间、当前数据库和正在执行的命令。生产实例连接很多时输出较大,应谨慎使用和保存。
Node-Redis 可以设置客户端名称,便于识别:
const client = createClient({
url: process.env.REDIS_URL,
name: "nloop-api",
});
不同服务使用不同名称,例如:
nloop-api
nloop-worker
nloop-scheduler
不要用 CLIENT KILL 随意清理看不懂的连接。应先确认客户端身份和影响范围。
12. 持久化与备份
查看持久化状态
redis-cli INFO persistence
redis-cli LASTSAVE
手动触发后台 RDB 快照:
redis-cli BGSAVE
不要在生产环境使用前台阻塞式 SAVE。BGSAVE 会 fork 子进程,在大实例和内存紧张时仍可能造成延迟和额外内存压力。
导出 RDB
Redis CLI 支持通过复制协议生成 RDB 文件:
redis-cli --rdb /safe-backup/redis-$(date +%F-%H%M%S).rdb
备份文件应保存到独立磁盘或对象存储,并限制读取权限。只创建备份但从不测试恢复,不能算可靠备份。
恢复前的基本原则
- 在隔离环境验证备份可读取。
- 明确恢复会覆盖哪个实例和哪个时间点的数据。
- 停止写入或切换流量,避免恢复期间继续产生新数据。
- 备份当前实例,再执行覆盖操作。
- 生产恢复应遵循部署方式对应的正式流程;托管 Redis 通常应使用平台快照功能。
不要直接覆盖运行中 Redis 正在使用的 RDB 或 AOF 文件。
13. 安全重启 Redis 的检查流程
单机 Redis 重启会产生服务不可用时间。建议按以下顺序操作:
- 确认本次操作确实需要重启 Redis,而不只是重启 Node.js。
- 查看
INFO persistence,确认后台保存或 AOF 重写没有异常。 - 确认备份或平台快照可用。
- 检查当前连接数、阻塞客户端和业务高峰情况。
- 通知相关服务负责人,并确认应用会重连或降级。
- 修改配置后再次检查文件内容和权限。
- 执行重启。
- 立即检查状态、日志、
PING、内存、持久化和复制状态。 - 验证 Node.js 应用已经恢复读写。
命令示例:
sudo systemctl restart redis-server
sudo systemctl status redis-server
sudo journalctl -u redis-server -n 100 --no-pager
redis-cli PING
redis-cli INFO persistence
redis-cli INFO replication
Sentinel、Cluster 或托管 Redis 应使用对应的故障转移和维护流程,不能把单机重启步骤机械套用到集群。
14. 高风险命令清单
以下命令可能造成数据丢失、长时间阻塞或大范围影响:
FLUSHALL
FLUSHDB
KEYS *
CONFIG SET
CONFIG REWRITE
DEBUG
SHUTDOWN
SAVE
CLIENT KILL
MIGRATE
REPLICAOF
CLUSTER ...
这不表示它们永远不能用,而是使用前必须明确:
- 当前连接的是开发、测试还是生产环境。
- 当前选中的数据库编号。
- 命令影响单个键、单个数据库还是整个实例。
- 是否有备份、审批和回滚方案。
- 是否会阻塞 Redis 主线程。
建议为普通应用 ACL 用户移除管理类和危险命令权限。
15. 日常巡检清单
每天或通过监控持续检查
- Redis 实例和端口是否正常。
- 命令错误率、超时率和 P95/P99 延迟。
- 内存使用率和距离
maxmemory的余量。 evicted_keys是否持续增长。- 连接数、阻塞客户端数是否异常。
- 缓存命中率是否突然下降。
- RDB/AOF 最近一次执行是否成功。
- 主从复制链路是否正常。
- 磁盘容量是否足够保存 AOF、RDB 和日志。
每周或定期检查
- 大键、无 TTL 缓存键和增长异常的数据结构。
- Slow Log 和延迟事件。
- 备份是否按计划生成。
- 在隔离环境进行恢复演练。
- Redis 和 Node-Redis 是否存在需要处理的安全更新。
- 应用键命名和清理策略是否仍符合业务。
16. 常见故障快速判断
Node.js 报 ECONNREFUSED
- Redis 没有运行。
- 主机或端口写错。
- Redis 只绑定本地地址,但应用在另一台机器。
- 防火墙或容器网络不通。
Node.js 报认证错误
- 用户名或密码不正确。
- ACL 用户被禁用。
- 应用仍使用旧密钥。
- 连接 URL 特殊字符没有正确编码。
Redis 可以 PING,但业务很慢
PING 只证明简单命令可以响应。继续检查 Slow Log、大键、网络、CPU、持久化、命令并发和应用事件循环。
Redis 重启后部分键消失
- 键本来有 TTL。
- RDB 快照尚未包含最近写入。
- AOF 未启用、未成功同步或恢复失败。
- 应用连接到了错误实例或数据库编号。
- Redis 使用了会淘汰键的内存策略。
17. 一份最小维护命令速查表
# 服务状态
sudo systemctl status redis-server
redis-cli PING
# 日志
sudo journalctl -u redis-server -n 100 --no-pager
# 版本和基本状态
redis-cli INFO server
redis-cli INFO clients
redis-cli INFO memory
redis-cli INFO persistence
redis-cli INFO replication
# 键空间
redis-cli DBSIZE
redis-cli --scan --pattern 'nloop:*'
redis-cli TYPE 'nloop:key'
redis-cli TTL 'nloop:key'
redis-cli MEMORY USAGE 'nloop:key'
# 慢命令与延迟
redis-cli SLOWLOG GET 20
redis-cli LATENCY DOCTOR
# 内存配置
redis-cli CONFIG GET maxmemory
redis-cli CONFIG GET maxmemory-policy
# 后台快照
redis-cli BGSAVE
redis-cli LASTSAVE
如果 Redis 启用了 ACL、TLS 或不是本机实例,应通过安全方式提供连接参数。不要把密码直接写进 Shell 历史、脚本仓库或工单截图。