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

如何取出大数据量的 redis hash 结构的数据并遍历导出?

  •  
  •   tanteng ·
    tanteng · 2016-03-01 12:04:56 +08:00 · 28119 次点击
    这是一个创建于 3174 天前的主题,其中的信息可能已经有所发展或是发生改变。

    redis hgetall

    如图,存了一个 hash 结构的数据, key 是用户名, value 是这个用户的一些信息,这个 hash 结构的数据会增长,最后数据量可能非常大。

    假如用 hgetall 一次取出所有数据,然后去遍历导出,大数据的情况可能会: 1.影响其他 redis 的操作 2.内存溢出

    需求是把这个 hash 结构的数据导出,比如导出到数据表或者 excel 文件。

    有什么好的技术实现方法?谢谢!(程序语言 PHP , JAVA , Python 都可以)

    26 条回复    2016-04-14 18:55:06 +08:00
    yuankui
        1
    yuankui  
       2016-03-01 12:48:15 +08:00   ❤️ 1
    一定是设计出了问题
    soli
        2
    soli  
       2016-03-01 13:00:09 +08:00   ❤️ 2
    你需要的是 HSCAN : http://redisdoc.com/hash/hscan.html
    tanteng
        3
    tanteng  
    OP
       2016-03-01 13:05:28 +08:00
    @yuankui 那像这种一开始没有记录到数据库,直接存到 redis 的数据,如何导出呢
    Jaylee
        4
    Jaylee  
       2016-03-01 13:07:26 +08:00   ❤️ 1
    先 keys * 取所有 key , 然后遍历
    tanteng
        5
    tanteng  
    OP
       2016-03-01 13:10:56 +08:00
    @Jaylee 先 hkeys key ,然后根据这个 key 去遍历取 hash 的数据?? 1.这个 keys 可能非常大有没有影响 2.这样会大大增加操作 redis 的次数,是不是问题
    Jaylee
        6
    Jaylee  
       2016-03-01 13:28:38 +08:00   ❤️ 1
    @tanteng 1, 没有影响 2.不是问题
    zhs227
        7
    zhs227  
       2016-03-01 13:37:34 +08:00   ❤️ 1
    @tanteng Redis 官方原来有个加密的功能,但是官方说你们不应该太相信这个功能,因为 Redis 的存取速度太快了,破解起来飞起。

    http://redis.io/commands/AUTH

    Note: because of the high performance nature of Redis, it is possible to try a lot of passwords in parallel in very short time, so make sure to generate a strong and very long password so that this attack is infeasible.

    高速存取是 Redis 的优势,操作次数根本不是问题。
    kingddc314
        8
    kingddc314  
       2016-03-01 13:41:17 +08:00
    可以使用 redis 内的 lua 脚本进行处理
    EVAL script numkeys key [key ...] arg [arg ...]
    kingddc314
        9
    kingddc314  
       2016-03-01 13:43:20 +08:00   ❤️ 1
    可能理解错了楼主的意思,同 2L ,你需要的应该是 HSCAN 进行遍历
    tanteng
        10
    tanteng  
    OP
       2016-03-01 14:13:25 +08:00
    @kingddc314 hscan 只支持 2.8 以上版本
    ynztyl10
        11
    ynztyl10  
       2016-03-01 14:28:55 +08:00
    keys * 确认没问题?不要误导。。
    fwrq41251
        12
    fwrq41251  
       2016-03-01 14:33:21 +08:00
    像这种情况一般还会有个 set 存所有用户的用户名吧。这样直接取这个 set,再根据 key 遍历就好了。
    zts1993
        13
    zts1993  
       2016-03-01 14:40:42 +08:00
    hscan 啊。。。。。
    tanteng
        14
    tanteng  
    OP
       2016-03-01 15:47:26 +08:00
    @fwrq41251 并没有
    rubytek
        15
    rubytek  
       2016-03-01 17:30:01 +08:00
    @tanteng 是说设计成自带一个 Key 的集合啊。
    tanteng
        16
    tanteng  
    OP
       2016-03-01 17:33:49 +08:00
    从集合中取出所有用户 id ,和从 hash 中通过 hkeys 取,有什么不同吗
    tanteng
        17
    tanteng  
    OP
       2016-03-01 17:33:58 +08:00
    @rubytek 从集合中取出所有用户 id ,和从 hash 中通过 hkeys 取,有什么不同吗
    neoblackcap
        18
    neoblackcap  
       2016-03-01 18:02:52 +08:00   ❤️ 1
    @tanteng 一个是全部读到你 Client 端的内存里面,在 Client 端以一个数据结构或者对象的形式存在。一个只是一个迭代器。
    简单而言,内存消耗不一样。
    soli
        19
    soli  
       2016-03-01 18:14:55 +08:00   ❤️ 1
    KEYS 、 HGETALL 等命令应禁止在生产环境使用。看官方文档,都有非常显眼的警告。
    tanteng
        20
    tanteng  
    OP
       2016-03-01 18:32:42 +08:00
    @neoblackcap 这个明白,但是要 2.8 才支持 hscan
    tanteng
        21
    tanteng  
    OP
       2016-03-01 18:33:04 +08:00
    @soli 看来不能用这种方式
    solaro
        22
    solaro  
       2016-03-09 11:16:35 +08:00
    @Jaylee 你这种做法就是要坑死楼主的, keys * 在生产环境里我都是禁用的,量大的时候秒蹦你缓存你信不信,执行一次得卡上 N 秒或者 N 十秒
    tanteng
        23
    tanteng  
    OP
       2016-03-09 11:18:16 +08:00
    @solaro 还没着手做这个,用 hscan 是否可行?
    solaro
        24
    solaro  
       2016-03-09 11:22:23 +08:00
    如果是我,我会这么做:
    1.一个 hash , hash-key :uid, hash-value:zsetid_uid
    2.一个 zset, id:uid ,value : user info
    各种好判断, hash 效率高,单量小, zset 可以用来分页,分段取出
    甚至你存储的时候可以做 shard
    solaro
        25
    solaro  
       2016-03-09 11:23:36 +08:00
    如果 hash 丢了,重建结构简单,
    如果 zset 丢了,重建,也不难。
    当然,你那个 hash 其实从业务上来说是最简单的
    abc123ccc
        26
    abc123ccc  
       2016-04-14 18:55:06 +08:00
    @tanteng 建议:
    方案 1 、凌晨某个点,一次 hgetall 把 key 写入到队列当中,这样你的队列与 hash 就能保持一致了,以后取数据就相当的容易。因为 list 里的值就为 hash 的 key 。但可以告诉你的是:一次性读入大量的数据,整个网站都会很慢。

    方案 2 、如果你的 hash 的 key 是有规律的,那就写个程序往 list 里赛吧,定时定量跑。跑完为止。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1036 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:15 · PVG 03:15 · LAX 11:15 · JFK 14:15
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.