1 wfd0807 2018-05-07 18:43:55 +08:00 ![]() 少见多怪 |
2 snal123 2018-05-07 19:02:44 +08:00 via iPhone 可能只是存了一点缓存吧 方便读取,重要的还是存在 mysql 里? |
3 eslizn 2018-05-07 19:11:15 +08:00 ![]() redis 本身就是持久化存储,没毛病的,性能也高。要说唯一的缺点就是管理和数据提取麻烦点 |
![]() | 4 rrfeng 2018-05-07 19:12:13 +08:00 via Android Redis 的持久化是不安全的。 要这么用为什么不直接上个 MongoDB ... |
![]() | 5 AltairT 2018-05-07 19:13:26 +08:00 via iPhone 赞同二楼,不知 po 主是怎么用 redis 的 |
![]() | 6 dltsgl 2018-05-07 19:19:43 +08:00 查询不方便吧,比如根据手机号查用户之类 |
![]() | 7 whatisnew 2018-05-07 19:21:19 +08:00 涉及到事务就悲催了 |
![]() | 8 cout2013mr 2018-05-07 19:23:24 +08:00 via Android 赞同二楼 |
![]() | 9 Finest 2018-05-07 19:26:05 +08:00 id 查询还好,O ( 1 ),问题是按条件筛选,每次都是 O ( N )吧 |
![]() | 10 kindjeff 2018-05-07 19:27:46 +08:00 via iPhone redis 不就是这么用的吗 |
![]() | 11 johnsneakers OP 尴尬了原来我才是非主流 |
12 |
![]() | 13 wizardforcel 2018-05-07 20:05:55 +08:00 via Android 我的话会申请个 mongodb 再这么玩 |
![]() | 14 quxiangxuanqxx 2018-05-07 22:48:03 +08:00 via Android 呃………缓存不是这样吗? redis 搞缓存这样用不对吗……… |
![]() | 15 wdlth 2018-05-07 22:53:20 +08:00 如果是用于缓存,没什么问题,取一部分信息进行缓存预热。 |
16 reself 2018-05-07 22:55:06 +08:00 via Android 不然呢?难道你把 session 放 MySQL ? |
![]() | 17 changnet 2018-05-07 22:59:52 +08:00 via Android redis 做缓存不是很正常吗。只是做持久化在稳定性,容灾,可维护性不如 mysql,很多工具不如 mysql。才 10000 数据,这个很少啊。 |
18 troywinter 2018-05-07 23:55:45 +08:00 看 value 的大小,value 过大的话,redis 在并发量高时的性能就是灾难,具体看阿里的 redis 编程规范。 |
![]() | 19 suit 2018-05-08 00:39:33 +08:00 刚学 redis 的时候试过只用 redis 做持久层写一个商城,然后碰到多对多的关联就懵逼了,而且一些逻辑上相关的 key 还得用另一个 hash 来记录,数量一多就很难管理 |
![]() | 20 johnsneakers OP @eslizn 我有点懵逼了, 虽然还没有上线, 但是把几十万用户信息存到一个 hash 里面是大家公认最好的做法吗? @Zzde @quxiangxuanqxx @reself @changnet 不是缓存,详见 append |
![]() | 21 Los 2018-05-08 01:15:59 +08:00 @johnsneakers 是的,这样做没有太大问题。你只是潜意识里信不过 redis 而已。。 |
![]() | 22 changwei 2018-05-08 01:24:03 +08:00 via Android hashtable 里面放一百万个 key 有什么不对吗? hashtable 的查找时间复杂度是 o ( 1 )的(当然排除 hash 冲突的情况),和数据量又无关,只要内存够大,你放一千万个也没什么问题啊。 |
![]() | 23 changwei 2018-05-08 01:28:19 +08:00 via Android @dltsgl 那就再做一个手机号到 uid 的 key-value 对呗! redis 建缓存就像 mysql 建索引的策略一样,哪个是索引项就对谁建缓存。 |
![]() | 24 kran 2018-05-08 08:30:09 +08:00 via iPhone ![]() |
![]() | 25 hareandlion 2018-05-08 08:40:54 +08:00 via Android 貌似很多人都觉得 Redis 不能做持久化存储 |
![]() | 26 realpg PRO |
27 owt5008137 2018-05-08 08:49:55 +08:00 via Android ![]() 不考虑 sharding 或者自己做 sharding 是可以这么做。 但是别听上面他们说的,你的做法是对的。现有的 redus 的 sharding 方案全是基于 key 的,所有的数据存一个 key 那就只能单点。而且一级 key 带 uid 这样二级还可以再分字段,可以实现只存脏数据字段和读取部分字段,能减少很多 redis 压力的。 |
28 agostop 2018-05-08 08:55:54 +08:00 赞同#27,等到数据量上来,需要切片的时候,你就发现,傻了…… 不过对于功能来讲,没什么问题。 |
![]() | 29 lepig 2018-05-08 09:09:37 +08:00 功能上没什么问题 只是分 key 方便写代码和管理 |
30 salamanderMH 2018-05-08 09:10:13 +08:00 全部存一个 key,这个还是不寻常的 |
![]() | 31 suyuanhxx 2018-05-08 09:32:16 +08:00 没什么太大问题,redis hash 结构-》 key field(hashkey) value,虽然是同一个 key,但是不同的 hashkey,没问题,但是这种方式不太优雅 |
![]() | 32 kiddult 2018-05-08 09:46:16 +08:00 这里面大部分人的用户只有几十几百么?一个 hash 放这么多内容,你是打算找死呢,还是想害死 redis 运维?这么大 key 线上要出事的,楼主的做法才明明是对的 |
![]() | 33 ryanking8215 2018-05-08 09:48:25 +08:00 记得哪里看到过,有公司(instagram ?)使用 key-value 方式存储觉得太占空间,咨询 redis 开发组后,改成 hash 方式存储,节约空间。 |
![]() | 34 ylcc 2018-05-08 09:54:30 +08:00 为什么这么多人觉得一个 key 存这么大的数据没问题啊,这么干肯定需要拆分一下啊。 |
36 windstill 2018-05-08 10:04:10 +08:00 ![]() 之前看过一篇 redis 优化的文章,其中说到一级 key 的数量不能太多。你那样一个用户一个 key,几百万个一级 key,会影响 redis 的读写效率。 不知道其他大神怎么看 |
37 g8287694 2018-05-08 10:12:01 +08:00 阿里的 redis 使用手册了解一下 |
38 eslizn 2018-05-08 10:13:25 +08:00 @johnsneakers 一个 hash key 里确实有问题,之前审题没注意,以为是一个用户一个 hash,里面存属性 |
39 mingzu 2018-05-08 10:14:01 +08:00 ![]() 看了上半段回复开始自我怀疑人生了.. 还好后半段回复又把我抓回来了。。 |
40 eslizn 2018-05-08 10:15:07 +08:00 @johnsneakers 因为一个 key 的话没办水平扩展,无法利用集群 |
41 Yinnfen 2018-05-08 10:18:49 +08:00 看懂了。。意思就是。hash 作为一张表用?社会社会。。 |
42 jyf 2018-05-08 10:20:20 +08:00 这样做其实挺好的 我记得 instgram 还是 flickr 曾经分享过一个心得 是把他们的数据从你那种方式转换成提问里这种方式 内存省了好多好多 另外你没想到这样清理方便么 |
![]() | 43 mentalidade 2018-05-08 10:29:01 +08:00 跟我这个很像,不过我不要哈希,就 key-value,/t/450596 |
![]() | 44 myyou 2018-05-08 10:30:48 +08:00 用 hash 据说可以让内存使用减小到是 string key 的 1/10,而且 hash 的查询速度也很快。现在的 redis 已经很稳定了,架构设计合理,作为很持久化使用,并没有什么不妥。 |
45 jyf 2018-05-08 10:31:25 +08:00 |
46 OneNian 2018-05-08 10:34:17 +08:00 via iPhone 居然有人觉得一个 hash 这样用很合理,持久化也很合理?……用过 redis 没? |
![]() | 48 tylerdurden 2018-05-08 10:39:11 +08:00 既然都是程序员,咱们数据说话好不好,来个对比呗,不要臆断可以么 |
![]() | 49 changnet 2018-05-08 10:43:32 +08:00 via Android @johnsneakers 没说这是最好的方案啊,具体业务不知道,你们项目成员经验也不知道,不好说。通常都是 redis 做缓存,后面 mysql 落地。一个 key 的问题,这个设计有点奇怪,一般都是分开的吧。 |
50 youxiachai 2018-05-08 10:45:55 +08:00 @changnet redis 其实也能做落地... 人家实践过.应该是信得过,redis 的落地 |
51 gotanaka4869 2018-05-08 10:48:40 +08:00 |
![]() | 52 changnet 2018-05-08 10:49:24 +08:00 via Android @youxiachai 是能做落地。但是实际操作起来团队的经验不够,运维的经验不够,容灾不如 mysql 成熟,不好做。还要考虑后续优化,维护啊。 |
53 youxiachai 2018-05-08 10:49:56 +08:00 |
![]() | 54 nooper 2018-05-08 10:50:23 +08:00 |
55 9684xtpa 2018-05-08 10:51:06 +08:00 不过如果是集群的话,这么做会导致热点 key,然后并发高的话,会有问题的 |
![]() | 56 imherer 2018-05-08 10:58:00 +08:00 这样做应该也没什么大问题吧 不过我的做法和你一样,也是一个 user 一个 key |
57 youxiachai 2018-05-08 10:58:48 +08:00 看了一下...instagram 那篇文章居然是 2011 年的.... 一些...大厂的博客..还是值得去翻翻啊.. |
58 youxiachai 2018-05-08 11:06:57 +08:00 @ylcc 其实..instagram .. 2011 年就分享过这样的操作了...... |
![]() | 59 darklowly 2018-05-08 11:08:01 +08:00 ![]() 假设按照 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 |
![]() | 60 jwdstefani 2018-05-08 11:10:16 +08:00 这种玩法 直接上 mongo 啊 |
![]() | 61 darklowly 2018-05-08 11:12:41 +08:00 同时注意几点 1 搞程序的严谨一点, 不要觉得自己没见过的,就不合理,就要喷一下。 2 适当的调查一下,或搜索一下就能解决的问题,不要拿来喷 3 标题党太严重,还是你自己真的十分大惊小怪? |
62 youxiachai 2018-05-08 11:19:54 +08:00 @darklowly 我觉得..应该是真的没见识过的吧... 毕竟 lz 还尝试.说服对方... |
![]() | 63 bk201 2018-05-08 11:22:30 +08:00 hash 只会在额定的要求范围内,才会以 ziplist 存储,当超过额定阈值后会转换成真正 hashtable 格式并重新存储。而 hashtable 的存储对于内存的使用不占优势 == 你是说这个问题嘛 |
![]() | 64 johnsneakers OP @darklowly 1. 你还挺会扣帽子的,我哪里喷了。不合理的设计提出来说怎么了? 2. 论坛不是讨论技术的地方? 设计上的东西发论坛来讨论怎么了? 又是一顶帽子? 3. 标题党? 我确实很惊讶。 你的分析也很有意思, 拿多个 key 存储方案和一个 key 存储方案来比容量。 |
![]() | 65 johnsneakers OP @youxiachai 确实没见识过,所以发到论坛求教一下 |
66 perssy 2018-05-08 11:28:18 +08:00 @youxiachai 这篇文章里写的也不是把所有 key 都放一个 hash 里吧,而是每个 hash 存 1000 条数据,超过这个数字的话 HSET 会有明显的 cpu 占用 |
![]() | 67 gouchaoer 2018-05-08 11:31:11 +08:00 我觉得 LZ 说的没错啊,redis 本质上是一个缓存,数据落地到数据库是理所当然的啊 最重要的是如果用户信息存到 redis 里面了,那么你只能根据用户 id 去存取而无法做查询操作,比如你要查询哪些用户今天登录过,redis 没法查询哦 另外推荐 mongo 的,这个场景有意义么? |
![]() | 68 hyq 2018-05-08 11:41:55 +08:00 即使楼主 append 了一下,还是有不少人没看明白。 |
![]() | 69 liu7833 2018-05-08 11:45:51 +08:00 ![]() 一个 hash key 存的话肯定是有问题的,容易造成 key 的热点,最终打垮一个节点 |
70 troywinter 2018-05-08 11:53:22 +08:00 那些说放到 hash 里合理的,你们写个性能测试看看,不用说千万并发,就 10 万的并发,你们看看 redis 的性能 |
![]() | 71 caixiexin 2018-05-08 11:53:30 +08:00 via Android 大 key 在 Redis 集群里是个隐患 |
![]() | 72 ytmsdy 2018-05-08 11:59:54 +08:00 结合具体的业务实际情况吧,如果业务上对用户信息需要高频读写,那这么搞也算是情有可原。 但是想了一圈,想不出来能有什么业务需要对用户信息高频读写的。 打个比方 Redis 类似于微粒贷,花呗等短期的消费贷款 mysql 类似于房贷 偶尔手头紧,来点消费贷缓解燃眉之急,没问题。 但是要是拿着消费贷去买房子那就有点嘬死了 |
![]() | 73 Waterchestnut 2018-05-08 12:01:42 +08:00 这种会有热 key 问题,节点会瘫痪,会报出 too many cluster redirections。。。。血的教训啊 |
![]() | 74 enenaaa 2018-05-08 12:04:59 +08:00 从主楼内容看,楼主语文堪忧 |
75 ty89 2018-05-08 12:11:07 +08:00 @ytmsdy 游戏业务里对用户数据读写操作是很频繁的,比如战斗中计算战力值,经验点数的增加减少,装备对战力的加成影响等等,一堆高频读写。 楼主少见多怪且蜜汁自信,新人总是会认为老项目里各种做法不合理,直到自己掉进坑里了才会发现原来这么做都是有原因的。 |
![]() | 76 darklowly 2018-05-08 12:14:04 +08:00 ![]() @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 里面,也不倾向于一定要分开放,具体问题具体分析。我只是想说两种方案都可以。 |
![]() | 77 clippit 2018-05-08 12:18:43 +08:00 ![]() 可以参考一下 https://redis.io/topics/memory-optimization 用 hash 存一堆 k-v 的用户信息是可以节约内存的,但是单个 hash 不能太大,需要手动分一分 |
78 youxiachai 2018-05-08 12:24:36 +08:00 @perssy 那文章是 3 亿用户..... 这里是个实践问题....而已 |
79 youxiachai 2018-05-08 12:26:25 +08:00 @perssy 打错是 3 亿图片信息... |
![]() | 80 ety001 2018-05-08 12:26:36 +08:00 我觉得得先把语文学好,完全没有看懂说的是什么意思。。。 |
![]() | 81 johnsneakers OP |
![]() | 82 jiangzhuo 2018-05-08 13:09:04 +08:00 100W 规模的级别这么用没啥问题吧 而且在实现某些需求的时候还更方便 比如说我要一次把这些用户数据全从 redis 里清掉 |
![]() | 83 johnsneakers OP @darklowly 谢谢你给我科普这些基础知识 |
![]() | 84 nooper 2018-05-08 13:23:29 +08:00 @youxiachai 我感觉是同一时间发的,居然你比我的快。 |
![]() | 85 jerryt 2018-05-08 13:41:49 +08:00 @Waterchestnut 同样遇到过, 真的肠子都悔青了 |
![]() | 86 keepfun 2018-05-08 13:51:34 +08:00 这么做是有点奇怪,但是也没啥特别的. 虽然我是第二种做法. |
87 perssy 2018-05-08 13:51:49 +08:00 @youxiachai 我想还是有点差别的,这贴里讨论的是两个问题: 1. 能否把用户信息保存在 redis 里 2. 能否把全部用户信息保存在一个 hash 中 从 append 来看,lz 纠结的是第二个问题,那么用这篇文章作为论据反驳就不适合了,因为就像文章中也提到的,一个 hash 中的 key 不建议超过 1000 个 |
![]() | 88 watzds 2018-05-08 14:00:43 +08:00 via Android 我初学 redis 的时候就发现这个问题了,当时是分开了,似乎一般情况两种都行,没深究 |
![]() | 89 luw2007 2018-05-08 14:06:04 +08:00 用户不到千万,单 key,或者单用户 key 都可以。 超过千万,单 key 是做不到的,单用户 key 要考虑 key 多问题。 |
![]() | 90 luw2007 2018-05-08 14:19:23 +08:00 在讨论一下关于效率的问题, 两者操作都是 O(1)。所以查询速度相差无几。 底层结构上单个 key-> hashtable,单用户 key-> hashtable,两者数据结构并无区别。 单个用户 key 查找 db.hashtable 命中返回。 单个 key 查找 db.hashtable 命中 再次查询 key.hashtable 命中返回。 多出来的一次查询操作基本可以忽略掉。 |
![]() | 91 shuax 2018-05-08 14:21:41 +08:00 基本操作,O(1)有什么问题?不然 hash 设计来干嘛的 |
92 youxiachai 2018-05-08 14:33:30 +08:00 @perssy 文章的例子是 3 亿信息规模....反过来说..1k 个 key 就能处理 3 亿信息... 你觉得..lz 提的几万的量..甚至百万.... 无论是 cpu 还是别的...就几十万甚至几百万的量.. 你想到这些是不是没考虑到实际? |
93 sampeng 2018-05-08 15:23:16 +08:00 原则上可以,但现实中不推荐使用。 优点: 1.足够快。不会蛋疼 io 问题。 2.其实逻辑和管理会复杂,其实是被关系型数据库惯坏了。算法足够 ok。结构很好的话其实没什么问题。而且会简化很多问题。如果对数据可用性不那么高,只用 redis 反而是简单可依赖的。所以具体问题具体分析 有两点问题: 1,内存问题。100 万用户放得下,500 万用户呢? 2,单点问题。如果是云类的主机,都有一定概率的当机。自己服务器就不用说了,冷不丁挂了怎么搞。还有服务器迁移的时候得把数据 flush 到硬盘上。确保所有数据都 flush 好了才能做。另外就算全部有持久化,加载的时候如果数据足够多。真的不是一会半会。你们能忍几分钟服务不可用的状态?。做分布式很不好搞,自行做 hash 和分片不是不可以,但都用了这么大一坨了,为何不直接在 mysql 中弄呢? |
![]() | 94 Felldeadbird 2018-05-08 15:23:53 +08:00 你同事的设计没毛病啊,楼主你的方案也合理。 就看哪边业务在实际 存取中,更贴合业务。 有时候依据某个值,只取 1 点数据,和取 1 个数据,连带获取大量数据的区别。 |
95 tikiet 2018-05-08 17:25:30 +08:00 标题配合头像太有误导性了 ;) |
96 daxiangxuezhang 2018-05-08 17:41:35 +08:00 看了标题以为是要分享什么 redis 新特性 |
97 daxiangxuezhang 2018-05-08 17:43:28 +08:00 存 hash 感觉也没什么太大的问题吧,一个 key 担心热点数据拖垮节点的话就多搞几个,keyName = user + mod(userId,n)就好了么~ |
98 Mirana 2018-05-08 18:19:19 +08:00 本身就是单线程的,hset 里所有的数据取出来用单独一个 key 并没有任何优化,反而污染了命名空间 |
![]() | 99 RorschachZZZ 2018-05-08 18:23:34 +08:00 我也是 string 存用户信息。这个 key 感觉太大了 |
100 xiadada 2018-05-08 19:13:52 +08:00 @daxiangxuezhang mod 的做法并没有压榨干存储空间, 应该用 / 法, user:213 user:233 提取出来一个 user:2 然后 里面是 13 和 33 |