咨询一个 redis 穿透的问题,看看大佬有什么解决方案没有

2021-03-08 17:41:30 +08:00
 BinYang

背景:在被访问数据库中没有的数据时,此时会访问 db 。线上 90%的数据都是数据库没有的(业务场景限定)。此时为了解决缓存穿透的问题,引入了 redis 设置空值。此时导致的结果是(数据是 n x n )的。导致线上 redis 有 3 亿的空值 key 。

解决思考:如果使用布隆过滤器,受限制于不能删除元素限制。不能使用,有什么更好的解决方案吗?

8072 次点击
所在节点    Java
97 条回复
BinYang
2021-03-08 19:12:06 +08:00
@lucienhsu 场景,大概就是人和人的点对点关系。可以理解为微博的好友添加。
但是,大多数时候人和人不需要点对点关系。但因为一些业务上的需要,需要在接口返回中有一个内容就是是否和其他人存在点对点关系。此时会不停的去查库。因为不存在关系,redis 也命中不到。此时穿透到数据库。但是不能使用布隆过滤器(这个关系可能随时变化,布隆过滤器不支持随时的变更->多写的场景)。因此做的操作是,给 redis 放一个值为空的对象进来。来防止穿透到 db 。但是因为这个关系是 N X N 关系。比如,有 100W 用户,那就是 100W X 100W
这个数据量上限来说,是非常大的
Dganzh
2021-03-08 19:21:30 +08:00
过期时间太长了,24h 试试看
BinYang
2021-03-08 19:31:58 +08:00
@Dganzh 是的,当前会在下次版本发布时候,降低这个时间。但是也只能逐步降低。步子太大会扯到蛋。
linvon
2021-03-08 19:37:44 +08:00
@BinYang #21 这种场景应该存储我的好友有谁(或者说我与谁是好友),而不应该存储我与谁是不是好友吧,怎么会扩散到 n^2 的数据量呢,用户总不能把其他所有用户都关注了吧
vpsong
2021-03-08 19:40:29 +08:00
布隆过滤器只增不删,命中了布隆过滤器的再去 db 查,db 不会连那 10%的量都撑不住吧
yzbythesea
2021-03-08 19:41:11 +08:00
我觉得问题核心是你这 90% 的数据都没有,但是你却还要请求你这个服务去查他们的值,感觉很奇怪。。。Redis 空值我觉得更多是一个 Hack 。

为什么不考虑先搞个索引服务,来过滤掉这 90% 的请求吗?比如加些业务逻辑判断下这个请求为什么就不可能有值。
palmers
2021-03-08 19:46:24 +08:00
我觉得这种应该把 redis 当做 db 来做的,redis + db 双写, 所以 db 只是作为一个备份使用 兜底策略, 然后本地内存作为缓存使用 就是这中间的淘汰策略和缓存时间需要好好调一下
MajorAdam
2021-03-08 19:49:19 +08:00
9 楼的方案可以啊,没有就是没有,不会主动去 db 查,保证写入的时候同步到 redis
dnhzm
2021-03-08 19:59:58 +08:00
像 24 楼说的,存储已有关系到 redis 当中,然后使用 lua 脚本处理你的请求,返回是否存在对应关系
BinYang
2021-03-08 20:00:44 +08:00
@linvon 问题是缓存命中不到时,就会去 db 查。这个时候就大多数流量都会命中不到。所以去 db 查。就会导致大流量打入 db 。
BinYang
2021-03-08 20:02:50 +08:00
@yzbythesea 业务逻辑上是判断不出来两者是否有关系的,业务需求最后就是要查询这个人和其他人是否有关系。所以要去关系表查(实际上少数人有关系),此时。其他没有关系的人,因为 redis 命中不到关系数据就会一直打到 db 。此时为了解决这个问题,引入了 db 查询不到的情况下,设置一个 value 为 null 的值到 redis 中。此时就会导致 redis 有很多为 null 的对象(但是可能这个对象是热点对象)。比如有的人,总是被查是否和其他人有关系。
BinYang
2021-03-08 20:04:35 +08:00
目前还是比较支持 13 楼的答案,当前来说。

7 楼的方案问题,13 楼也做了答复。
young1lin
2021-03-08 20:11:40 +08:00
128G 的单个 Redis 实例?秀啊。返回一个 “null” 给 Redis,设置过期时间。
rrfeng
2021-03-08 20:34:25 +08:00
这个设计就有问题……对于此种简单关系表,直接查数据库并不会慢。我们之前用 MongoDB 抗几十亿关注关系查询,毫无压力。
rrfeng
2021-03-08 20:37:13 +08:00
MySQL 估计也没问题,专库专用,预先分表,加大内存即可。
luozic
2021-03-08 20:44:26 +08:00
firefox12
2021-03-08 21:08:20 +08:00
为什么存 n*n 这么大呢? 难道不应该一个人一个 hash 吗? 没有就去数据库里拿。查完就存在 redis 里 这样 1000 万 也只有 1000 万 hash table

你这样设计微博 12 亿注册用户 它的 redis 怎么搞?
xuboying
2021-03-08 22:19:18 +08:00
虽然没有这方面的具体业务经验,但也觉得 op 的设计应该先转化为一个论证过程。再落实到具体的代码。

比如数据库和缓存总是有个同步过程,为什么觉得 redis 命中空结果是 OK 的,也许此时数据库里已经有数据了?这个同步的过程是怎么实现的。为什么不能反过来,redis 的有数据就是数据库的有,没有就认为没有。。。
linvon
2021-03-08 22:26:43 +08:00
@BinYang 我的意思是存储设计不应该出现这种大量缓存缺失的情况
linvon
2021-03-08 22:36:54 +08:00
@luozic cuckoo filter 的删除也并不完美,会有误删率,并发上跟布隆一样,还是解决不了这个问题的痛点

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/759715

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX