Redis 分词拆分存储,大佬们有没有好的解决方案

2019-03-14 16:38:14 +08:00
 yaoweber

应用场景: 一篇文章会被切分成很多片,每一片都会有一个 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 内容到了服务器进行剪裁后在塞回去。效率极差。

各位有什么更好的方案吗?

10471 次点击
所在节点    Redis
14 条回复
whileFalse
2019-03-14 16:51:20 +08:00
key = hashid/timestamp, value = (timestamp,pageid)
whileFalse
2019-03-14 16:51:59 +08:00
然后为每个 key 单独设置过期时间。
whileFalse
2019-03-14 16:54:44 +08:00
或者,如果本身 hash_id 重复概率不高的话(比如 99%的 key 都只有一个元素),直接为每个 hash_id 设置过期时间。为已有 key 追加内容时刷新过期时间。这样绝大部分的 key 可以在 30 天后过期。

如果 hash_id 重复概率高,说明这个 id 太短了。
knightdf
2019-03-14 17:45:55 +08:00
直接处理 dump 出来的 rdb 文件,参考 redis 的存储格式
besttime
2019-03-14 17:58:12 +08:00
使用 ssdb 替换 redis
yaoweber
2019-03-14 18:28:14 +08:00
@knightdf 不能够停机啊
yaoweber
2019-03-14 18:30:47 +08:00
@whileFalse 这个 hashid 不能除以 timestamp,因为我们会根据 hashid 查询所有的 pageid。
justfly
2019-03-14 18:37:13 +08:00
rdb 离线分析删除 key。

如果还能再撑 30 天吗,能的话直接开新的实例,新的写新实例,并加上 30 天过期,30 天一过直接干掉旧的实例。
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 测试一下吧.
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 去删除即可。
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 做缓存。
br00k
2019-03-14 22:01:44 +08:00
这个设计是不是有问题😂,redis 这样迟早都会被玩坏。如果为了提升性能为啥不考虑静态化。走 CDN 速度快多了。也同可以同步到 es 来处理。
yc8332
2019-03-15 09:19:15 +08:00
这个好像没有必要用 redis。。。看起来纯静态化的东西,访问量不大,自己做静态化一下,访问量大的话走下 CDN。。。非要 redis,那就是设置过期时间了。。
yaoweber
2019-03-15 19:25:05 +08:00
@justfly 不能哈

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/544630

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX