三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Redis 缓存雪崩把我搞了一周,我叛逃到 DragonflyDB 的血泪史(附避坑指南)

Redis 缓存雪崩把我搞了一周,我叛逃到 DragonflyDB 的血泪史(附避坑指南)

Redis 缓存雪崩把我搞了一周,我叛逃到 DragonflyDB 的血泪史(附避坑指南)

Redis 缓存雪崩把我搞了一周,我叛逃到 DragonflyDB 的血泪史(附避坑指南)

缓存工具咋选?我从 Redis 叛逃到 DragonflyDB 的血泪史。

听起来像是"换个数据库"这么简单,但真做起来,踩的坑比想象中多得多。


事情的起因

上个月,我们的一套安全告警分析系统出了大事。

凌晨三点,Redis 主节点内存打满,触发了 maxmemory 策略,大量缓存被驱逐。紧接着,所有请求直接穿透到 PostgreSQL——然后数据库扛不住,连接池爆了,整个系统雪崩。

我被电话叫醒,花了 40 分钟才恢复服务。第二天领导问我:"这个 Redis 能不能换掉?"

我嘴上说"我评估一下",心里想的是——换就换,谁怕谁。

为什么选 DragonflyDB

先说结论:Redis 本身没问题,是我们用得不对。但 DragonflyDB 确实解决了我们几个痛点:

痛点RedisDragonflyDB 内存效率存 1GB 数据实际占 1.5-2GB存 1GB 数据实际占 ~1.1GB 单线程限制6.0 后有多线程,但主命令还是单线程原生多线程,自动利用多核 持久化RDB 快照时 fork 子进程,大内存下会卡无 fork,快照不阻塞 兼容性—100% 兼容 Redis 协议

一句话总结:DragonflyDB 就是"内存更省、跑得更快、不用 fork"的 Redis 替代品

迁移过程:四步走

第一步:安装 DragonflyDB

# Docker 方式(推荐先试水)
docker run -d --name dragonfly \-p 6379:6379 \-v /data/dragonfly:/data \docker.dragonflydb.io/dragonflydb/dragonfly:latest# 如果要替换现有的 Redis,先停掉 Redis
# systemctl stop redis

第二步:验证兼容性

因为我们用的是 Python + redis-py,理论上不需要改代码。但还是要验证:

import redis# 连接 DragonflyDB(端口和 Redis 一样)
r = redis.Redis(host='localhost', port=6379, decode_responses=True)# 测试基础操作
r.set('test:key', 'hello')
print(r.get('test:key'))  # 输出: hello# 测试 Hash
r.hset('test:hash', mapping={'name': 'security-bot', 'version': '2.0'})
print(r.hgetall('test:hash'))# 测试有序集合(告警排名用)
r.zadd('test:alerts', {'alert:001': 95, 'alert:002': 80, 'alert:003': 99})
print(r.zrevrange('test:alerts', 0, -1, withscores=True))# 测试 Pipeline
pipe = r.pipeline()
for i in range(1000):pipe.set(f'bulk:{i}', f'value-{i}')
pipe.execute()
print(f"Bulk write done: {r.dbsize()} keys")

跑通了,一行代码没改。

第三步:数据迁移

这里有个坑——不能直接把 Redis 的 RDB 文件丢给 DragonflyDB 加载

虽然 DragonflyDB 支持加载 RDB 文件,但版本兼容性是个问题。我试了 Redis 7.0 的 RDB 文件,部分数据格式对不上。

最终方案是用 redis-cli 做在线迁移:

# 从 Redis 导出所有 key,导入到 DragonflyDB
redis-cli -h old-redis-host -p 6379 --rdb /tmp/dump.rdb# DragonflyDB 加载(测试发现大部分 key 能正常加载)
# 如果有报错,用下面的方式逐 key 迁移
redis-cli -h old-redis-host -p 6379 --scan | while read key; doredis-cli -h old-redis-host -p 6379 DUMP "$key" | \head -c -1 | \redis-cli -h localhost -p 6379 RESTORE "$key" 0
done

我们的数据量不大(约 50GB),迁移花了大约 2 小时。

第四步:切换流量

# 先把应用配置从 redis-host 改成 dragonfly-host
# 用环境变量控制,方便回滚
export REDIS_HOST=localhost
export REDIS_PORT=6379# 逐步灰度:先切 10% 流量观察
# (具体灰度方式取决于你的网关配置)

踩过的坑(重要!)

坑 1:内存占用初期比 Redis 高

刚导入数据后,DragonflyDB 的内存占用比 Redis 高了 30%。吓了一跳。后来发现是它在做后台压缩,等了 10 分钟就降下来了,最终比 Redis 低 40%。

坑 2:KEYS 命令行为不同

Redis 的 KEYS * 会阻塞主线程,DragonflyDB 不会——但它的返回顺序和 Redis 不一样。如果你的代码依赖 KEYS 的返回顺序(虽然不应该),迁移后会出问题。

# 替代方案:用 SCAN 代替 KEYS
redis-cli --scan --pattern "alert:*" | head -20

坑 3:Lua 脚本需要测试

DragonflyDB 支持大部分 Lua 脚本,但有些边缘 case(比如 redis.call('TIME') 的返回格式)有细微差异。我们的 3 个 Lua 脚本里有 1 个需要微调。

坑 4:监控工具要重新配

之前用的 redis-exporter 不认识 DragonflyDB 的 INFO 输出格式。换成 DragonflyDB 自带的 Prometheus exporter:

# prometheus.yml
scrape_configs:- job_name: 'dragonfly'static_configs:- targets: ['dragonfly-host:6379']metrics_path: /metrics

迁移后的效果

指标迁移前 (Redis)迁移后 (DragonflyDB)变化 内存占用48 GB29 GB**-40%** P99 延迟12 ms3 ms**-75%** QPS 上限~80,000~180,000**+125%** 快照耗时45 秒(阻塞)8 秒(不阻塞)**-82%**

我的建议

如果你的 Redis 内存超过 30GB、有多核 CPU 但 Redis 只用到一个核、或者被 RDB fork 卡过——值得试试 DragonflyDB。

如果你的 Redis 跑得好好的,数据量不大,别折腾。换数据库的迁移成本永远比你想的高。

选工具嘛,顺手最好。DragonflyDB 就是那把让你少操心内存、减少半夜被叫醒的好家伙。


关注「安全值班室」公众号

每天AI安全早报 + 实战攻防案例 + 网安学习路线连载

关注安全值班室
← 返回列表