johnsneakers
V2EX  ›  Redis

惊了 redis 还能这样玩??

  •  
  •   johnsneakers · May 7, 2018 via Android · 22351 views
    This topic created in 3101 days ago, the information mentioned may be changed or developed.
    接手新项目,那个程序把 hash 当 MySQL 来用,给我说他们以前项目都这样搞。具体是:所有玩家的个人信息放在 user 这个 key 里面,hset user 10000 用户个人信息 json。 第一次见这样玩的 ,我太菜了,怎么给对方说都不听。
    Supplement 1  ·  May 8, 2018
    看了一些人的回答我开始懵逼了。也可能是我没说清楚,这里的场景是做持久化只是会定时落地,也就是说有 100 万用户,那么这个 hash 里面的 key 就有 100 万个,线上来同时来几万人也都是操作这一个 key。
    难道我真的错了么,我一直的做法是一个 user 一个 key, 如: userInfo:{$uid}。
    111 replies  •  2018-05-10 11:06:55 +08:00
    1  2  
    ❮ ❯
    wfd0807
    wfd0807
    May 7, 2018❤️1
    1
    少见多怪
    snal123
    snal123
    May 7, 2018 via iPhone
    2
    可能只是存了一点缓存吧 方便读取,重要的还是存在 mysql 里?
    eslizn
    eslizn
    May 7, 2018❤️1
    3
    redis 本身就是持久化存储,没毛病的,性能也高。要说唯一的缺点就是管理和数据提取麻烦点
    rrfeng
    rrfeng
    May 7, 2018 via Android
    4
    Redis 的持久化是不安全的。
    要这么用为什么不直接上个 MongoDB ...
    AltairT
    AltairT
    May 7, 2018 via iPhone
    5
    赞同二楼,不知 po 主是怎么用 redis 的🧐
    dltsgl
    dltsgl
    May 7, 2018
    6
    查询不方便吧,比如根据手机号查用户之类
    whatisnew
    whatisnew
    May 7, 2018
    7
    涉及到事务就悲催了
    cout2013mr
    cout2013mr
    May 7, 2018 via Android
    8
    赞同二楼
    Finest
    Finest
    May 7, 2018
    9
    id 查询还好,O ( 1 ),问题是按条件筛选,每次都是 O ( N )吧
    kindjeff
    kindjeff
    May 7, 2018 via iPhone
    10
    redis 不就是这么用的吗
    johnsneakers
    johnsneakers
    OP
    May 7, 2018 via Android
    11
    尴尬了原来我才是非主流
    Zzde
    Zzde
    May 7, 2018 via iPhone
    12
    当缓存用不是很正常吗。
    我经常这样用.....
    wizardforcel
    wizardforcel
    May 7, 2018 via Android
    13
    我的话会申请个 mongodb 再这么玩😂😂
    quxiangxuanqxx
    quxiangxuanqxx
    May 7, 2018 via Android
    14
    呃………缓存不是这样吗? redis 搞缓存这样用不对吗………
    wdlth
    wdlth
    May 7, 2018
    15
    如果是用于缓存,没什么问题,取一部分信息进行缓存预热。
    reself
    reself
    May 7, 2018 via Android
    16
    不然呢?难道你把 session 放 MySQL ?
    changnet
    changnet
    May 7, 2018 via Android
    17
    redis 做缓存不是很正常吗。只是做持久化在稳定性,容灾,可维护性不如 mysql,很多工具不如 mysql。才 10000 数据,这个很少啊。
    troywinter
    troywinter
    May 7, 2018
    18
    看 value 的大小,value 过大的话,redis 在并发量高时的性能就是灾难,具体看阿里的 redis 编程规范。
    suit
    suit
    May 8, 2018
    19
    刚学 redis 的时候试过只用 redis 做持久层写一个商城,然后碰到多对多的关联就懵逼了,而且一些逻辑上相关的 key 还得用另一个 hash 来记录,数量一多就很难管理
    johnsneakers
    johnsneakers
    OP
    May 8, 2018
    20
    @eslizn 我有点懵逼了, 虽然还没有上线, 但是把几十万用户信息存到一个 hash 里面是大家公认最好的做法吗?


    @Zzde
    @quxiangxuanqxx
    @reself
    @changnet

    不是缓存,详见 append
    Los
    Los
    May 8, 2018
    21
    @johnsneakers 是的,这样做没有太大问题。你只是潜意识里信不过 redis 而已。。
    changwei
    changwei
    May 8, 2018 via Android
    22
    hashtable 里面放一百万个 key 有什么不对吗? hashtable 的查找时间复杂度是 o ( 1 )的(当然排除 hash 冲突的情况),和数据量又无关,只要内存够大,你放一千万个也没什么问题啊。
    changwei
    changwei
    May 8, 2018 via Android
    23
    @dltsgl 那就再做一个手机号到 uid 的 key-value 对呗! redis 建缓存就像 mysql 建索引的策略一样,哪个是索引项就对谁建缓存。
    hareandlion
    hareandlion
    May 8, 2018 via Android
    25
    貌似很多人都觉得 Redis 不能做持久化存储
    realpg
    realpg
    May 8, 2018
    26
    @hareandlion #25
    非实时持久啊
    对于很多项目 没法做主存储的
    owt5008137
    owt5008137
    May 8, 2018 via Android❤️1
    27
    不考虑 sharding 或者自己做 sharding 是可以这么做。

    但是别听上面他们说的,你的做法是对的。现有的 redus 的 sharding 方案全是基于 key 的,所有的数据存一个 key 那就只能单点。而且一级 key 带 uid 这样二级还可以再分字段,可以实现只存脏数据字段和读取部分字段,能减少很多 redis 压力的。
    agostop
    agostop
    May 8, 2018
    28
    赞同#27,等到数据量上来,需要切片的时候,你就发现,傻了……

    不过对于功能来讲,没什么问题。
    lepig
    lepig
    May 8, 2018
    29
    功能上没什么问题 只是分 key 方便写代码和管理
    salamanderMH
    salamanderMH
    May 8, 2018
    30
    全部存一个 key,这个还是不寻常的
    suyuanhxx
    suyuanhxx
    May 8, 2018
    31
    没什么太大问题,redis hash 结构-》 key field(hashkey) value,虽然是同一个 key,但是不同的 hashkey,没问题,但是这种方式不太优雅
    kiddult
    kiddult
    May 8, 2018
    32
    这里面大部分人的用户只有几十几百么?一个 hash 放这么多内容,你是打算找死呢,还是想害死 redis 运维?这么大 key 线上要出事的,楼主的做法才明明是对的
    ryanking8215
    ryanking8215
    May 8, 2018
    33
    记得哪里看到过,有公司(instagram ?)使用 key-value 方式存储觉得太占空间,咨询 redis 开发组后,改成 hash 方式存储,节约空间。
    ylcc
    ylcc
    May 8, 2018
    34
    为什么这么多人觉得一个 key 存这么大的数据没问题啊,这么干肯定需要拆分一下啊。
    ioth
    ioth
    May 8, 2018
    35
    @ylcc 基于什么理由?
    程序写多了,觉得什么都是天经地义,和社会脱节。
    windstill
    windstill
    May 8, 2018❤️1
    36
    之前看过一篇 redis 优化的文章,其中说到一级 key 的数量不能太多。你那样一个用户一个 key,几百万个一级 key,会影响 redis 的读写效率。

    不知道其他大神怎么看
    g8287694
    g8287694
    May 8, 2018
    37
    阿里的 redis 使用手册了解一下
    eslizn
    eslizn
    May 8, 2018
    38
    @johnsneakers 一个 hash key 里确实有问题,之前审题没注意,以为是一个用户一个 hash,里面存属性
    mingzu
    mingzu
    May 8, 2018❤️2
    39
    看了上半段回复开始自我怀疑人生了..

    还好后半段回复又把我抓回来了。。
    eslizn
    eslizn
    May 8, 2018
    40
    @johnsneakers 因为一个 key 的话没办水平扩展,无法利用集群
    Yinnfeng
    Yinnfeng
    May 8, 2018
    41
    看懂了。。意思就是。hash 作为一张表用?社会社会。。
    jyf
    jyf
    May 8, 2018
    42
    这样做其实挺好的 我记得 instgram 还是 flickr 曾经分享过一个心得 是把他们的数据从你那种方式转换成提问里这种方式 内存省了好多好多
    另外你没想到这样清理方便么
    mentalidade
    mentalidade
    May 8, 2018
    43
    跟我这个很像,不过我不要哈希,就 key-value,/t/450596
    myyou
    myyou
    May 8, 2018
    44
    用 hash 据说可以让内存使用减小到是 string key 的 1/10,而且 hash 的查询速度也很快。现在的 redis 已经很稳定了,架构设计合理,作为很持久化使用,并没有什么不妥。
    OneNian
    OneNian
    May 8, 2018 via iPhone
    46
    居然有人觉得一个 hash 这样用很合理,持久化也很合理?……用过 redis 没?
    ylcc
    ylcc
    May 8, 2018
    47
    @ioth 如果你能提出你的理由那是合理反驳,如果你不加最后一句,我会把你当个人,但是我现在只能当你是条狗
    tylerdurden
    tylerdurden
    May 8, 2018
    48
    既然都是程序员,咱们数据说话好不好,来个对比呗,不要臆断可以么
    changnet
    changnet
    May 8, 2018 via Android
    49
    @johnsneakers 没说这是最好的方案啊,具体业务不知道,你们项目成员经验也不知道,不好说。通常都是 redis 做缓存,后面 mysql 落地。一个 key 的问题,这个设计有点奇怪,一般都是分开的吧。
    youxiachai
    youxiachai
    May 8, 2018
    50
    @changnet redis 其实也能做落地...
    人家实践过.应该是信得过,redis 的落地
    changnet
    changnet
    May 8, 2018 via Android
    52
    @youxiachai 是能做落地。但是实际操作起来团队的经验不够,运维的经验不够,容灾不如 mysql 成熟,不好做。还要考虑后续优化,维护啊。
    9684xtpa
    9684xtpa
    May 8, 2018
    55
    不过如果是集群的话,这么做会导致热点 key,然后并发高的话,会有问题的
    imherer
    imherer
    May 8, 2018
    56
    这样做应该也没什么大问题吧
    不过我的做法和你一样,也是一个 user 一个 key
    youxiachai
    youxiachai
    May 8, 2018
    57
    看了一下...instagram 那篇文章居然是 2011 年的....
    一些...大厂的博客..还是值得去翻翻啊..
    youxiachai
    youxiachai
    May 8, 2018
    58
    @ylcc 其实..instagram .. 2011 年就分享过这样的操作了......
    darklowly
    darklowly
    May 8, 2018❤️1
    59
    假设按照
    users:id 的模式存储
    那么 id 为 10000 的用户的存储 key 是:
    users:10000,key 大概需要 11 个字节
    同时 id 为 10001 的用户的存储 key 是:
    users:10001,key 大概需要 11 个字节

    如果是按照 hash 来存储
    则两个用户,一共需要 len(users) + len(10000) + len(10001) = 5 + 5 + 5 = 15 个字节
    依此类推。


    @9684xtpa

    如果是集群的话,
    给 user 分片就可以了,例如 users_1,users_2
    jwdstefani
    jwdstefani
    May 8, 2018
    60
    这种玩法 直接上 mongo 啊
    darklowly
    darklowly
    May 8, 2018
    61
    同时注意几点

    1 搞程序的严谨一点, 不要觉得自己没见过的,就不合理,就要喷一下。
    2 适当的调查一下,或搜索一下就能解决的问题,不要拿来喷
    3 标题党太严重,还是你自己真的十分大惊小怪?
    youxiachai
    youxiachai
    May 8, 2018
    62
    @darklowly 我觉得..应该是真的没见识过的吧...
    毕竟 lz 还尝试.说服对方...
    bk201
    bk201
    May 8, 2018
    63
    hash 只会在额定的要求范围内,才会以 ziplist 存储,当超过额定阈值后会转换成真正 hashtable 格式并重新存储。而 hashtable 的存储对于内存的使用不占优势
    ==
    你是说这个问题嘛
    johnsneakers
    johnsneakers
    OP
    May 8, 2018
    64
    @darklowly
    1. 你还挺会扣帽子的,我哪里喷了。不合理的设计提出来说怎么了?
    2. 论坛不是讨论技术的地方? 设计上的东西发论坛来讨论怎么了? 又是一顶帽子?
    3. 标题党? 我确实很惊讶。

    你的分析也很有意思, 拿多个 key 存储方案和一个 key 存储方案来比容量。
    johnsneakers
    johnsneakers
    OP
    May 8, 2018
    65
    @youxiachai 确实没见识过,所以发到论坛求教一下
    perssy
    perssy
    May 8, 2018
    66
    @youxiachai 这篇文章里写的也不是把所有 key 都放一个 hash 里吧,而是每个 hash 存 1000 条数据,超过这个数字的话 HSET 会有明显的 cpu 占用
    gouchaoer
    gouchaoer
    May 8, 2018
    67
    我觉得 LZ 说的没错啊,redis 本质上是一个缓存,数据落地到数据库是理所当然的啊
    最重要的是如果用户信息存到 redis 里面了,那么你只能根据用户 id 去存取而无法做查询操作,比如你要查询哪些用户今天登录过,redis 没法查询哦

    另外推荐 mongo 的,这个场景有意义么?
    hyq
    hyq
    May 8, 2018
    68
    即使楼主 append 了一下,还是有不少人没看明白。
    liu7833
    liu7833
    May 8, 2018❤️1
    69
    一个 hash key 存的话肯定是有问题的,容易造成 key 的热点,最终打垮一个节点
    troywinter
    troywinter
    May 8, 2018
    70
    那些说放到 hash 里合理的,你们写个性能测试看看,不用说千万并发,就 10 万的并发,你们看看 redis 的性能
    caixiexin
    caixiexin
    May 8, 2018 via Android
    71
    大 key 在 Redis 集群里是个隐患
    ytmsdy
    ytmsdy
    May 8, 2018
    72
    结合具体的业务实际情况吧,如果业务上对用户信息需要高频读写,那这么搞也算是情有可原。
    但是想了一圈,想不出来能有什么业务需要对用户信息高频读写的。
    打个比方
    Redis 类似于微粒贷,花呗等短期的消费贷款
    mysql 类似于房贷
    偶尔手头紧,来点消费贷缓解燃眉之急,没问题。
    但是要是拿着消费贷去买房子那就有点嘬死了
    Waterchestnut
    Waterchestnut
    May 8, 2018
    73
    这种会有热 key 问题,节点会瘫痪,会报出 too many cluster redirections。。。。血的教训啊
    enenaaa
    enenaaa
    May 8, 2018
    74
    从主楼内容看,楼主语文堪忧
    ty89
    ty89
    May 8, 2018
    75
    @ytmsdy 游戏业务里对用户数据读写操作是很频繁的,比如战斗中计算战力值,经验点数的增加减少,装备对战力的加成影响等等,一堆高频读写。


    楼主少见多怪且蜜汁自信,新人总是会认为老项目里各种做法不合理,直到自己掉进坑里了才会发现原来这么做都是有原因的。
    darklowly
    darklowly
    May 8, 2018❤️4
    76
    @johnsneakers


    第一

    你的原话是( 第一次见这样玩的 ,我太菜了,怎么给对方说都不听)。

    注意这里的措辞

    第一次见这样玩的
    我太菜了
    怎么给对方说都不听。

    就算不是喷?也带着极大的负面情绪。

    第二

    技术类的问题,网络上有很多的资料,如果自己没见过的,不懂的,第一反应,应该是查资料,而不是惊叹,也不是到论坛上讨论。在你把所面对的技术问题本身搞清楚了,再来讨论比较好。附赠一篇文章给你( https://blog.csdn.net/danky/article/details/1370632 )

    第三

    在 redis 里面,本身就是一个大的 hashmap,然后 hashmap 包含很多的 key==>val,同时这里的 val 可能有多种类型。当 val 是 hashmap 的时候,他的数据结构本身和 redis 的大 haspmap,并没有太大的不同。

    获取一条数据的流程大概是:
    1 从大的 hashmap 拿到 user 集合的小 hashmap O(1)级别
    2 从小的 hashmap 拿到 user 的信息 O(1)级别

    你的想法是一步就能拿到的,为什么要两步? 性能损失了 50%?其实完整的过程是:
    1 发送命令给 redis
    2 从大的 hashmap 拿到 user 集合的小 hashmap O(1)级别
    3 从小的 hashmap 拿到 user 的信息 O(1)级别
    4 返回数据
    2 和 3 都是 O(1)级别, 相比 1 和 4 的时间,可能 5%都不到。那么性能是微乎其微的。

    第四

    我并不是倾向于把所有用户放到一个 key 里面,也不倾向于一定要分开放,具体问题具体分析。我只是想说两种方案都可以。
    clippit
    clippit
    May 8, 2018❤️1
    77
    可以参考一下 https://redis.io/topics/memory-optimization
    用 hash 存一堆 k-v 的用户信息是可以节约内存的,但是单个 hash 不能太大,需要手动分一分
    youxiachai
    youxiachai
    May 8, 2018
    78
    @perssy 那文章是 3 亿用户.....
    这里是个实践问题....而已
    youxiachai
    youxiachai
    May 8, 2018
    79
    @perssy 打错是 3 亿图片信息...
    ety001
    ety001
    May 8, 2018
    80
    我觉得得先把语文学好,完全没有看懂说的是什么意思。。。
    johnsneakers
    johnsneakers
    OP
    May 8, 2018 via Android
    81
    @ety001
    @enenaaa

    这个帖子开的不亏....发现很多人都没搞明白我在说什么,或者误解了我说的了...吃了没文化的亏
    jiangzhuo
    jiangzhuo
    May 8, 2018
    82
    100W 规模的级别这么用没啥问题吧
    而且在实现某些需求的时候还更方便 比如说我要一次把这些用户数据全从 redis 里清掉
    johnsneakers
    johnsneakers
    OP
    May 8, 2018
    83
    @darklowly 谢谢你给我科普这些基础知识
    nooper
    nooper
    May 8, 2018
    84
    @youxiachai 我感觉是同一时间发的,居然你比我的快。
    jerryt
    jerryt
    May 8, 2018
    85
    @Waterchestnut 同样遇到过, 真的肠子都悔青了
    keepfun
    keepfun
    May 8, 2018
    86
    这么做是有点奇怪,但是也没啥特别的.
    虽然我是第二种做法.
    perssy
    perssy
    May 8, 2018
    87
    @youxiachai 我想还是有点差别的,这贴里讨论的是两个问题:
    1. 能否把用户信息保存在 redis 里
    2. 能否把全部用户信息保存在一个 hash 中
    从 append 来看,lz 纠结的是第二个问题,那么用这篇文章作为论据反驳就不适合了,因为就像文章中也提到的,一个 hash 中的 key 不建议超过 1000 个
    watzds
    watzds
    May 8, 2018 via Android
    88
    我初学 redis 的时候就发现这个问题了,当时是分开了,似乎一般情况两种都行,没深究
    luw2007
    luw2007
    May 8, 2018
    89
    用户不到千万,单 key,或者单用户 key 都可以。
    超过千万,单 key 是做不到的,单用户 key 要考虑 key 多问题。
    luw2007
    luw2007
    May 8, 2018
    90
    在讨论一下关于效率的问题, 两者操作都是 O(1)。所以查询速度相差无几。
    底层结构上单个 key-> hashtable,单用户 key-> hashtable,两者数据结构并无区别。
    单个用户 key 查找 db.hashtable 命中返回。
    单个 key 查找 db.hashtable 命中 再次查询 key.hashtable 命中返回。
    多出来的一次查询操作基本可以忽略掉。
    momo1999
    momo1999
    May 8, 2018
    91
    基本操作,O(1)有什么问题?不然 hash 设计来干嘛的
    youxiachai
    youxiachai
    May 8, 2018
    92
    @perssy 文章的例子是 3 亿信息规模....反过来说..1k 个 key 就能处理 3 亿信息...
    你觉得..lz 提的几万的量..甚至百万....
    无论是 cpu 还是别的...就几十万甚至几百万的量..
    你想到这些是不是没考虑到实际?
    sampeng
    sampeng
    May 8, 2018
    93
    原则上可以,但现实中不推荐使用。
    优点:
    1.足够快。不会蛋疼 io 问题。
    2.其实逻辑和管理会复杂,其实是被关系型数据库惯坏了。算法足够 ok。结构很好的话其实没什么问题。而且会简化很多问题。如果对数据可用性不那么高,只用 redis 反而是简单可依赖的。所以具体问题具体分析

    有两点问题:
    1,内存问题。100 万用户放得下,500 万用户呢?
    2,单点问题。如果是云类的主机,都有一定概率的当机。自己服务器就不用说了,冷不丁挂了怎么搞。还有服务器迁移的时候得把数据 flush 到硬盘上。确保所有数据都 flush 好了才能做。另外就算全部有持久化,加载的时候如果数据足够多。真的不是一会半会。你们能忍几分钟服务不可用的状态?。做分布式很不好搞,自行做 hash 和分片不是不可以,但都用了这么大一坨了,为何不直接在 mysql 中弄呢?
    Felldeadbird
    Felldeadbird
    May 8, 2018
    94
    你同事的设计没毛病啊,楼主你的方案也合理。 就看哪边业务在实际 存取中,更贴合业务。
    有时候依据某个值,只取 1 点数据,和取 1 个数据,连带获取大量数据的区别。
    tikiet
    tikiet
    May 8, 2018
    95
    标题配合头像太有误导性了 ;)
    daxiangxuezhang
    daxiangxuezhang
    May 8, 2018
    96
    看了标题以为是要分享什么 redis 新特性
    daxiangxuezhang
    daxiangxuezhang
    May 8, 2018
    97
    存 hash 感觉也没什么太大的问题吧,一个 key 担心热点数据拖垮节点的话就多搞几个,keyName = user + mod(userId,n)就好了么~
    Mirana
    Mirana
    May 8, 2018
    98
    本身就是单线程的,hset 里所有的数据取出来用单独一个 key 并没有任何优化,反而污染了命名空间
    RorschachZZZ
    RorschachZZZ
    May 8, 2018
    99
    我也是 string 存用户信息。这个 key 感觉太大了
    xiadada
    xiadada
    May 8, 2018
    100
    @daxiangxuezhang mod 的做法并没有压榨干存储空间, 应该用 / 法, user:213 user:233 提取出来一个 user:2 然后 里面是 13 和 33
    1  2  
    ❮ ❯
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5882 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 226ms · UTC 02:29 · PVG 10:29 · LAX 18:29 · JFK 21:29
    ♥ Do have faith in what you're doing.