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

关于 redis 的储存问题。

  •  1
     
  •   mandy0119 · 2018-04-08 16:42:55 +08:00 · 6157 次点击
    这是一个创建于 2425 天前的主题,其中的信息可能已经有所发展或是发生改变。

    有很大量用户信息,需要放进缓存中。

    	方法 1:每个用户一个 key,单独存放。
    	
    	方法 2:所有用户存入一个 key,类型为 hash。使用时取出此 hash,再操作。
    

    目前有点拿不准该用哪一种效率高一些,资源利用率高一些。

    	讨论:数据量 N 大于何值时,方法效率最高。
    
    	讨论:何种场景,使用方法 1/2 比较合适。
    

    对 redis 理解不深,求大佬们解疑。

    第 1 条附言  ·  2018-04-08 18:57:50 +08:00
    感谢各位的解惑。我在这总结一下:
    总体来说,方法 1 更优。
    方法 1:
    优点:1. 粒度更细;
    2. 避免很多后期优化问题,一步到位;
    3. 避免很多方法 2 存在的问题(不重复罗列)。
    缺点:1. 做好 key 的回收机制;
    2. 内存使用率略低于方法 2 ;
    3. 同类型数据的 key 在 redis 中非常分散

    方法 2:
    优点:1. 内存使用率高(当 value 为 int 会被压缩,甚至可以压缩到 1/10 ) from #21
    2. 相对 而言较适合长期储存用户
    3. 千级数据以下优势较明显
    缺点:1. 所有数据保存在一个 key 中,单 key 长度不可控,在集群中优化困难;
    2. 方法 1 中不同用户可以被存在集群不同机器内;
    3. 单个 key 安全性差,崩了就全完了;
    4. 单 key 数据过大,传输耗时也存在问题;

    从时间性能以及安全性来看,都是方法 1 比较好。
    另感谢#5 给出的链接 http://carlosfu.iteye.com/blog/2254572
    里面是美团的解决方案

    方法 3:
    将所有用户进行分段( all/100 ), 然后利用方法 2 储存。
    分段方法就不赘述了,可以通过 userid 等。内存利用率非常可观。
    26 条回复    2018-04-09 01:40:51 +08:00
    Immortal
        1
    Immortal  
       2018-04-08 16:47:26 +08:00
    具体没测试过,单纯从以前看过的 redis 的优化文章来看
    方法 2 资源(内存)利用率高很多,方法 1 中虽然是 kv 结构,但是就算是最简单的 kv,对于 redis 的数据结构也有很多额外数据
    undefinedMe
        2
    undefinedMe  
       2018-04-08 16:52:20 +08:00
    方法一
    defunct9
        3
    defunct9  
       2018-04-08 16:56:36 +08:00
    方法二
    rrfeng
        4
    rrfeng  
       2018-04-08 16:59:39 +08:00 via Android
    任何情况下都应该用 1
    单 key 太大是一个非常大的隐患
    micean
        5
    micean  
       2018-04-08 16:59:53 +08:00   ❤️ 4
    lastpass
        6
    lastpass  
       2018-04-08 17:02:38 +08:00 via Android   ❤️ 1
    方法一吧。毕竟你这是不是大量用户,而是很大量用户。
    用方法二,取所有用户这个数据,仅仅是数据传输都要一定的时间。
    jelinet
        7
    jelinet  
       2018-04-08 17:04:14 +08:00
    方法 1 吧。
    lastpass
        8
    lastpass  
       2018-04-08 17:05:18 +08:00 via Android   ❤️ 1
    而且,用方法二,你对用户信息的增删改等操作也很麻烦。容易出错。而且方法二将所有鸡蛋放在同一个篮子里。一旦这个数据发生点意外情况。你所有用户数据全部 gg。
    xomix
        9
    xomix  
       2018-04-08 17:07:24 +08:00   ❤️ 1
    数据量在千级以下的时候方法 2 都是比较优秀的,当数据量超过千的级别,你获取全部用户信息的 value 传输都是个大问题。

    千级别以下我觉得基本上也用不上这些缓存了,你随便写个文本库都可以对应,所以你就不要想方法 2 了。
    nowgoo
        10
    nowgoo  
       2018-04-08 17:13:22 +08:00   ❤️ 1
    方案一。
    1. 可制定细粒度的缓存过期策略,更灵活。
    2. 用 mget/mset 读写。
    3. 如果每个 value 的长度都差不多,内存利用率应该还可以的。实在不行启用压缩嘛。
    myyou
        11
    myyou  
       2018-04-08 17:13:26 +08:00   ❤️ 1
    方法二效率最高,可用在长期缓存用户信息(只在用户更新用户信息时更新 hash field 的 value )
    方法一虽然内存使用率低,但是可以设置过期时间,对比不常登录用户可以避免占用内存

    方法一和二除了能对每个用户设置过期时间,其实没什么区别
    myyou
        12
    myyou  
       2018-04-08 17:14:52 +08:00
    @myyou 说错了,方法一内存占用更高
    Immortal
        13
    Immortal  
       2018-04-08 17:15:03 +08:00   ❤️ 1
    再多说一句 具体还得看你的 value 大小 这个也比较关键
    yang2yang
        14
    yang2yang  
       2018-04-08 17:43:22 +08:00   ❤️ 1
    用方法一吧,方法二导致 value 变大,会导致速度变慢的,内存利用率不是关键吧,一般都考虑时间吧?
    tusj
        15
    tusj  
       2018-04-08 17:53:54 +08:00
    方法 1 吧。
    R18
        16
    R18  
       2018-04-08 17:58:38 +08:00 via Android
    自己做下测试?
    tusj
        17
    tusj  
       2018-04-08 17:59:05 +08:00   ❤️ 1
    方法一好。
    因为如果以后要上 redis 集群的话,这些 key 可以分散到不同的主机以分摊压力。
    如果用方法二,所有数据都在一个 key 下,出现单点性能问题的话,就算上 redis 集群也没用。
    R18
        18
    R18  
       2018-04-08 17:59:27 +08:00 via Android
    如果使用方案一,如果用户真的很大,请设置 key 的自动过期或者回收机制
    hustlibraco
        19
    hustlibraco  
       2018-04-08 18:00:20 +08:00   ❤️ 1
    方法 1 可用,方法 2 数据量上来了不可控。
    在少量数据规模的时候方法二确实利用更高效,但是一般情况下不需要这么节省 redis 资源,方法一的扩展性更好,控制粒度也更细,一开始就用方法一没有后顾之忧
    catinred
        20
    catinred  
       2018-04-08 18:01:17 +08:00   ❤️ 1
    要单独对部分用户设置过期时间 那就方法 1
    要是单个用户的数据量比较小 例如几 K,那就方法 2
    主要还是看业务场景
    无论哪种方法,都尽量避免取所有用户数据。
    monsterxx03
        21
    monsterxx03  
       2018-04-08 18:01:46 +08:00   ❤️ 1
    从业务上看,用方法一.

    hash 的确能减少内存使用, 但有些前提. 因为 size 小于阈值的 hash 内部会用 ziplist 实现,如果 value 是 int,还会用特殊算法进行压缩,极端情况下内存占用可以减少到 1/10, 相关配置: hash-max-ziplist-entries, hash-max-ziplist-value


    https://redis.io/topics/memory-optimization
    banksiae
        22
    banksiae  
       2018-04-08 18:07:23 +08:00   ❤️ 1
    方法 1, 但是 key 的规则要定义清除,以免滥用
    单 key 值过大的话,如果要导入到 codis 集群,会遇到大小限制问题
    WinMain
        23
    WinMain  
       2018-04-08 18:41:19 +08:00   ❤️ 1
    还有折中的方法,对用户 id 取模后作为 key 来分桶,哈哈,个人之见,没试过。
    生产线上用的还是一个用户 id 一个 key,因为即使是有几十个亿的用户量,也不是把所有 id 的相关信息放入 redis,要不然就失去了作为缓存这个出发点了,每天最多也就是亿级的活跃用户,这个对于 redis 集群来说,都是小 ks。
    MeteorCat
        24
    MeteorCat  
       2018-04-08 19:06:18 +08:00 via Android
    看存储之后是否要频繁更新,我们游戏架构是 MYSQL 存储基本充值数额等外部信息,NoSQL 做游戏库,人物角色信息用 Hash 表保存便于读写和单独取出;但是如果仅仅做缓存,根据 key 找到用户信息不做大修改,我感觉直接 key-value 就行了
    wplct
        25
    wplct  
       2018-04-08 21:25:44 +08:00
    方法 1.未来可以直接上集群。
    qi1070445109
        26
    qi1070445109  
       2018-04-09 01:40:51 +08:00 via Android
    请教一下,如果用来做布隆过滤器呢?大家怎么选择? 目前是方法二。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5419 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 32ms · UTC 05:50 · PVG 13:50 · LAX 21:50 · JFK 00:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.