应用场景: 一篇文章会被切分成很多片,每一片都会有一个 hash_id,然后安装下面的格式存储进 redis 里面: key=hash_id value={(timestamp,pageid)}
由于其他文章也可能会出现分片一样的场景,也就是 hash_id 会一致。所以我们采用的是字符串追加。结构变成: key=hash_id value={(timestamp1,pageid1),(timestamp2,pageid2)...(timestampN,pageidN)}
现在遇到的问题是: 目前 redis 已经到达 100G,我们要进行瘦身,将 30 天以前的分词,也就是(timestamp1,pageid1)符合条件的给移除。但是现在的操作是将 redis 的 value 拿下来,在本地操作,非常慢,相当于拿 100G 内容到了服务器进行剪裁后在塞回去。效率极差。
各位有什么更好的方案吗?
1
whileFalse 2019-03-14 16:51:20 +08:00
key = hashid/timestamp, value = (timestamp,pageid)
|
2
whileFalse 2019-03-14 16:51:59 +08:00
然后为每个 key 单独设置过期时间。
|
3
whileFalse 2019-03-14 16:54:44 +08:00
或者,如果本身 hash_id 重复概率不高的话(比如 99%的 key 都只有一个元素),直接为每个 hash_id 设置过期时间。为已有 key 追加内容时刷新过期时间。这样绝大部分的 key 可以在 30 天后过期。
如果 hash_id 重复概率高,说明这个 id 太短了。 |
4
knightdf 2019-03-14 17:45:55 +08:00
直接处理 dump 出来的 rdb 文件,参考 redis 的存储格式
|
5
besttime 2019-03-14 17:58:12 +08:00
使用 ssdb 替换 redis
|
7
yaoweber OP @whileFalse 这个 hashid 不能除以 timestamp,因为我们会根据 hashid 查询所有的 pageid。
|
8
justfly 2019-03-14 18:37:13 +08:00
rdb 离线分析删除 key。
如果还能再撑 30 天吗,能的话直接开新的实例,新的写新实例,并加上 30 天过期,30 天一过直接干掉旧的实例。 |
9
monsterxx03 2019-03-14 19:00:49 +08:00
试试看用 https://github.com/CodisLabs/redis-port
它是把自己伪装成一个 redis slave, 从 master 那边把数据 dump 过来, 解析过后写到 slave. 可以试试把数据恢复的部分改一下, 把你不需要的 key 过滤掉, 这样应该就能不停机迁移到新的 redis 了. 粗略看下, 改下 doRestoreDBEntry 和 doRestoreAoflog 这两个函数就行了. 不过你这 100 好大了,找台 slave 测试一下吧. |
10
keakon 2019-03-14 19:10:40 +08:00
感觉你这个需求可以试试 redisearch。
另一个方案如下: value 存字符串会比存整数占用更多内存,可以拆分成 2 个 key,分别存 timestamp 和 pageid。 而每个 page 的所有分词其实都是相同的 timestamp,所以其中一个 key 可以改为 pageid 和 timestamp 的映射关系。 再用一个 key 做倒排索引,存储每个 page 的 hash_id。用 timestamp 过滤出过期的 pageid,然后去倒排索引找出对应的 hash_id 去删除即可。 |
11
johnk 2019-03-14 20:14:01 +08:00
最好使用 redis 的过期策略进行处理,如果 timestamp 不是业务上需要的参数,则可以不存。
key := <hash-id>:<page-id> 127.0.0.1:6379> set hash_id_1:page1 0 EX 10 OK 127.0.0.1:6379> set hash_id_1:page2 0 EX 10 OK 127.0.0.1:6379> set hash_id_1:page3 0 EX 10 OK 127.0.0.1:6379> keys hash_id_1:* 1) "hash_id_1:page3" 2) "hash_id_1:page1" 3) "hash_id_1:page2" # after a while 127.0.0.1:6379> keys hash_id_1:* 1) "hash_id_1:page3" 2) "hash_id_1:page2" 如果业务需要 timestamp,也可以作为 key 的一部分,但是会占用存储空间 key := <hash-id>:<page-id>:<timestamp> 或 key := <hash-id>:<timestamp>:<page-id> 看你有哪种排序需求。 redis 是单线程模型,若 keys 操作性能不满足需求,可以使用 scan。 数据量实在多的情况下,应该考虑冷热数据分开存储,用 HBase/Cassendra/ES 等基于磁盘的分布式数据库做存储,用 redis 做缓存。 |
12
br00k 2019-03-14 22:01:44 +08:00 via iPhone
这个设计是不是有问题😂,redis 这样迟早都会被玩坏。如果为了提升性能为啥不考虑静态化。走 CDN 速度快多了。也同可以同步到 es 来处理。
|
13
yc8332 2019-03-15 09:19:15 +08:00
这个好像没有必要用 redis。。。看起来纯静态化的东西,访问量不大,自己做静态化一下,访问量大的话走下 CDN。。。非要 redis,那就是设置过期时间了。。
|