外观
从12s卡顿到零抖动:短视频Redis大key治理全实战
短视频业务Redis大key的问题背景
在短视频业务高速增长期,我们团队曾遇到过典型的大key故障:核心的用户收藏、点赞列表采用单SET结构存储,当头部用户收藏视频量突破1.2万条时,单key体积超过12MB,高峰期全量拉取收藏列表的接口平均耗时飙升至12s,同时大key的扩容同步直接阻塞Redis主进程近3s,触发全链路缓存超时,影响超过30%的用户访问。 这类大key在短视频场景下几乎是必然出现的:头部达人的作品点赞列表、重度用户的历史观看记录、热门话题的参与用户集合,只要业务没有做分片设计,运行半年以上必然会出现体积超过10MB的大key,轻则拖慢接口耗时,重则引发主从同步中断、缓存雪崩等线上事故。
三类大key治理方案实测对比
我们团队先后对比了行业内三类主流的大key处理方案,最终选择了业务无侵入的代理层分片方案: 第一种是客户端硬编码拆分方案:直接修改业务代码,对大key进行取模分片,优势是不需要额外引入组件,劣势是侵入性极强,短视频业务的历史存量接口超过20个都依赖旧的大key结构,全量改造成本超过20人日,很容易引入逻辑bug。 第二种是Redis集群原生自动分片方案:把单机版Redis迁移到Redis Cluster集群,依靠集群的hash槽自动拆分大key,优势是不需要改业务逻辑,劣势是迁移过程需要全量同步数据,短视频业务缓存数据量超过2TB,迁移窗口至少需要4小时,停机成本极高。 第三种是代理层自动识别+分片+双写迁移方案:在缓存代理层新增大key识别规则,对命中阈值的大key自动做分片拆分,通过双写机制完成平滑迁移,全程业务代码零改动,我们实测整个治理过程耗时不到2人日,完全没有影响线上用户。
全流程实操步骤与可运行代码示例
整个落地流程分为自动识别、分片拆分、平滑迁移三个环节,所有命令都可以直接在测试环境运行验证。
1. 大key自动识别落地
我们没有采用线上高峰期扫描的方案,而是结合离线RDB分析+低峰期抽样校验的方式,100%覆盖所有存量大key:
redis
# 凌晨低峰期执行抽样扫描,每处理100个key休眠100ms避免阻塞主进程
redis-cli -h 10.0.1.12 -p 6379 --bigkeys -i 0.1
# 针对短视频用户收藏场景的SET类型key做抽样统计
SCARD user:fav:10086
# 输出示例:(integer) 12689 代表单用户收藏1.2万条,超过预设1万条的大key阈值我们还在缓存代理层新增了实时大key上报规则:当单个命令返回的value体积超过1MB时,自动上报到监控平台,实时发现新增的大key,不需要等定时扫描才能感知。
2. 分片拆分数据结构改造
针对短视频场景的SET类型大key,我们采用按用户ID取模的分片拆分规则,把原来的单key拆成32个分片,完全兼容原有SET的所有操作:
redis
# 拆分后的分片key规则:user:fav:{uid}:{shard_idx},按视频ID取模定位分片
SADD user:fav:10086:7 789456 789457 789458
# 分页查询时遍历对应分片,用SSCAN指定返回20条数据
SSCAN user:fav:10086:7 0 COUNT 20拆分后单个分片的元素数量最多不会超过400条,单key体积不到50KB,完全不会出现大key阻塞问题,我们实测拆分后收藏列表接口的平均耗时从12s降到了180ms。
3. 双写机制平滑无感知迁移
为了避免迁移过程丢数据,我们采用了灰度双写的迁移方案:第一阶段所有新写入的收藏数据,同时写入旧大key和新分片结构;第二阶段读请求优先走新分片,当新分片返回的数据量不足分页要求时,再补查旧大key补齐数据;第三阶段观察7天,当旧大key的访问量降到0之后,再分批删除旧大key的存量数据,全程业务用户完全感知不到迁移过程。
大key治理避坑总结
我们在整个落地过程中踩了不少线上故障的坑,总结出3条可直接复用的实践注意事项: 第一,绝对不能在业务高峰期执行大key扫描操作。我们第一次排查问题时在下午3点高峰期跑了redis-cli --bigkeys命令,直接导致Redis主进程阻塞2s,所有请求超时,触发了P1级告警,修正方案是扫描时必须加-i 0.1参数,每处理100个key休眠100ms,或者直接把RDB文件下载到离线服务器做全量大key分析,完全不影响线上实例。 第二,绝对不能直接用DEL命令删除体积超过10MB的大key。我们第一次清理旧大key时直接执行DEL命令,一个存储了12万条元素的SET直接阻塞Redis主进程1.5s,导致上千个请求超时,正确的做法是用SCAN命令分批遍历元素,每次批量删除100条元素,直到整个大key被清空,全程不会出现长时间阻塞。 第三,短视频场景下拆分大key不要做跨分片全量排序。最初我们拆分收藏列表后,为了按时间排序,每次分页都拉取所有32个分片的全量数据到业务内存排序,直接导致接口OOM,正确的做法是把SET替换成ZSET有序集合,写入时把视频的收藏时间作为score,每个分片内部天然按时间排序,分页时只需要查询对应分片的指定范围数据,不需要跨分片全量拉取。 经过整套流程的治理,我们短视频业务的大key占比从之前的1.2%降到了0,缓存接口的平均耗时稳定在200ms以内,连续6个月没有出现过大key引发的线上故障。
免责声明
本工具与文章内容仅用于学习测试场景,优化建议仅供参考,请勿直接用于生产环境,由此产生的风险自行承担。