V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yaoweber
V2EX  ›  Redis

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

  •  
  •   yaoweber · 2019-03-14 16:38:14 +08:00 · 10510 次点击
    这是一个创建于 2116 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

    如果还能再撑 30 天吗,能的话直接开新的实例,新的写新实例,并加上 30 天过期,30 天一过直接干掉旧的实例。
    monsterxx03
        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 测试一下吧.
    keakon
        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 去删除即可。
    johnk
        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 做缓存。
    br00k
        12
    br00k  
       2019-03-14 22:01:44 +08:00 via iPhone
    这个设计是不是有问题😂,redis 这样迟早都会被玩坏。如果为了提升性能为啥不考虑静态化。走 CDN 速度快多了。也同可以同步到 es 来处理。
    yc8332
        13
    yc8332  
       2019-03-15 09:19:15 +08:00
    这个好像没有必要用 redis。。。看起来纯静态化的东西,访问量不大,自己做静态化一下,访问量大的话走下 CDN。。。非要 redis,那就是设置过期时间了。。
    yaoweber
        14
    yaoweber  
    OP
       2019-03-15 19:25:05 +08:00
    @justfly 不能哈
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2399 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 16:00 · PVG 00:00 · LAX 08:00 · JFK 11:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.