8.2 性能优化与安全加固 本节摘要:Redis 的性能优化大多不靠调参数,而靠纠正结构误用:选对类型、拆小键、避免阻塞命令。参数层的收益集中在内存分配器、内核透传与持久化调度三处。安全则是一张清单:网络、密码、权限、重命名危险命令,逐项核对。 性能:先纠结构,再谈参数 按收益从大到小排: 1. 键设计。一个 50 万 field 的 Hash 拆成 500 个千级小哈希(按 field 哈希取模分桶),HGETALL 变 HMGET 小批量,响应体积与单次耗时同时降一个量级——第 2 章"大键是事故源"的正向应用。 大键治理值得展开成完整过程。背景:巡检发现商品详情 Hash 平均三十万 field、最大九十万,HGETALL 慢日志常客;
本节摘要:Redis 的性能优化大多不靠调参数,而靠纠正结构误用:选对类型、拆小键、避免阻塞命令。参数层的收益集中在内存分配器、内核透传与持久化调度三处。安全则是一张清单:网络、密码、权限、重命名危险命令,逐项核对。
按收益从大到小排:
1. 键设计。一个 50 万 field 的 Hash 拆成 500 个千级小哈希(按 field 哈希取模分桶),HGETALL 变 HMGET 小批量,响应体积与单次耗时同时降一个量级——第 2 章"大键是事故源"的正向应用。
大键治理值得展开成完整过程。背景:巡检发现商品详情 Hash 平均三十万 field、最大九十万,HGETALL 慢日志常客;操作分四步走:
# 第一步:定量。抽样看真实体积与访问模式 > MEMORY USAGE product:8521 (integer) 58723456 # 单键约56MB > HLEN product:8521 (integer) 912340 # 第四步:验证后删旧键,用 UNLINK 而不是 DEL > UNLINK product:8521
解读:56MB 的键在主从同步时按整块传输、在淘汰时按整体考量、在过期时按一次性删除对待,三个环节全是放大器;拆成 256 桶后每桶两百多 KB,任何单桶操作都在毫秒内。变式:List、Set、ZSet 的拆法同理,分桶数按"单桶目标体积"倒推,不按经验拍脑袋。迁移期双写的成本要算——它是用一段时间的高峰写放大,换长期的稳定,值不值由键的访问频率决定。
2. 阻塞命令替换。KEYS 换 SCAN,SMEMBERS/HGETALL 换 SSCAN/HSCAN 分批,DEL 大集合换 UNLINK 异步释放,都在减少主线程的单次最长停顿。
3. pipeline 与连接池。批量场景把往返合并(第 1 章 RESP 的结论),配合连接池避免频繁建连。
4. 参数三件套。
# 内存分配器碎片整理(4.0+,内存吃紧时主动整理碎片) activedefrag yes # 内核尽快把连接交给监听进程,高连接数场景收益明显 tcp-keepalive 300 # 持久化错峰:见第6章,低峰定时手动重写 auto-aof-rewrite-percentage 200
活跃碎片整理开启前后的对比实验值得做一次:删掉大批键制造碎片(碎片率升到 1.6 以上),开启后观察碎片率在数小时内缓步回落到 1.2 附近,期间命令延迟略有抬升(整理本身要占少量主线程时间片)。由此得出它的适用画像:碎片率高、又无法安排重启的常驻实例;反过来,碎片率正常的实例开了只是白付整理税。参数上还能控制整理的力度与阈值,从默认起步、盯一周延迟曲线再调,是稳妥路径。

# ① 网络:只绑内网,绝不上公网 bind 10.0.0.11 protected-mode yes # ② 密码:强随机串,主从双端配置(第7章 masterauth) requirepass 强随机串 # ③ 权限:最小命令集,重命名危险命令(6.0前的主要手段) rename-command KEYS "" rename-command FLUSHALL "随机后缀_flushall" rename-command CONFIG "随机后缀_config" # 以普通用户身份跑服务,RDB与AOF文件权限600
6.0 起有 ACL 可以按用户分配命令白名单,比 rename-command 更体面,新版本优先用它。ACL 的最小可用配置长这样:
# 建一个只能读写业务键的用户,禁止管理与危险命令 > ACL SETUSER app on >App的强密码 ~app:* +get +set +del +hget +hset +expire OK > ACL LIST user app on #哈希后的密码 ~app:* +get +set +del +hget +hset +expire # 应用侧以 app 用户连接,键名被限制在 app 前缀内
这五行配置的含义:on 启用用户;尖号后是密码;波浪号限定可访问的键前缀;加号罗列放行的命令,没列的全部拒绝——哪怕拿到密码,也删不掉别的业务前缀的键、执行不了 FLUSHALL。给不同应用发不同用户,权限边界落到连接层,误操作与横向渗透的伤害半径同时被压住。清单之外还有两条纪律:不把 Redis 直接暴露给前端或第三方网络(历史上大量勒索事件就是公网裸奔加无密码实例被清空后写入勒索信息);CONFIG 命令收紧后,改配置走配置文件加重启或 ACL 授权通道,运维流程要相应调整。
现象:接口每约 5 分钟抖动一次,慢日志空。排查记录:
> LATENCY HISTORY fork 1724301000,218 # 每5分钟一次fork,每次约218毫秒 > CONFIG GET save save 300 100 # 每5分钟窗口正好吻合
结论:save 规则触发过频,fork 在大内存实例上停顿 200 多毫秒,主线程全程被卡。处理:save 窗口放宽、数据量收缩后 fork 耗时随页表缩小而降。慢日志为空不代表服务不卡——卡在事件层,要去看 LATENCY,这正是 8.1 两个工具的分工。
同类抖动还有两个近亲,排查思路一致:AOF 的 everysec 刷盘遇上慢盘,会在延迟曲线上刻出每秒一次的小锯齿,INFO persistence 的延迟刷盘计数会涨;异步释放大键(UNLINK 后的后台回收)在极端大键上也会造成内存释放的毛刺。三者共同点都是"周期性与持久化或后台任务对齐"——延迟曲线一出来先找周期,周期对上谁,谁就是嫌疑人。
💡 关键直觉:优化前先问"瓶颈在结构、命令、批量还是参数",四层各有一次出手的机会;跳层直改参数,是安慰剂式优化。