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

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

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

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

8082 次点击
所在节点    Java
97 条回复
BinYang
2021-03-09 09:54:46 +08:00
@wangluofansi 确实,可能之前的思路上是有问题的。这个是历史问题,暂时来说,还不可能推翻重来。肯定是在当前的基础上看怎么能优化出来使用先。
BinYang
2021-03-09 09:55:26 +08:00
@luozic 好的,去了解一下。感谢建议
fengpan567
2021-03-09 10:05:44 +08:00
布隆过滤器,value 为 null 的过期时间可以短一些。或者考虑上 elasticsearch 吗(
AxEqaq
2021-03-09 10:42:20 +08:00
搭个分布式 redis,redis 接入 mysql binlog 或 canal,让 redis 做全量 mysql 数据的同步

这是电商厂各种商品系统的标配策略
如果内存成本太高,可以换成 ssd
pangleon
2021-03-09 10:43:58 +08:00
我说一个没人提的吧,社交关系这种可以用图数据库,NEO4J,NEBULA 等。
保持图数据库和数据库的同步即可。但这会引入额外的复杂度和成本。
考虑到你们目前的数据量并不大。。。没必要这么折腾。
但是如果是搞社交的图数据库会有更多应用场景在你们那。
wuqingdzx
2021-03-09 10:45:42 +08:00
@BinYang 老哥思维不要局限了.

可以有个 Buffer 的布隆过滤器

假如布隆过滤器重建的粒度是每小时一次.
用一个异步任务每个整点前重建一个带有下一个时间段标识的布隆过滤器.
业务上使用布隆过滤器的时候按当前所处的小时选择对应的布隆过滤器.

例如现在时间 10 点 37 分, 你用的是 bloomfilter_0 .
到了 10 点 55 分, 11 % 2 = 1, 异步任务重建一个 bloomfilter_1.你到了 11:00 以后进来的请求就用的是 bloomfilter_1 了.
到了 11 点 55 分, 12 % 2 = 0, 异步任务重建一个 bloomfilter_0.你到了 12:00 以后进来的请求就用的是 bloomfilter_0 了. 以此类推
iseki
2021-03-09 10:50:42 +08:00
布隆过滤器定时重建就可以吧,本来就是一个有假阳性的东西,删除元素什么的不存在的
BinYang
2021-03-09 11:26:58 +08:00
@wuqingdzx 定时重建的话,还是会在某个时间段内,关系是保持久的关系。这种不实时的话。业务上是不能接受的吧。个人理解,勿喷。
wuqingdzx
2021-03-09 11:44:23 +08:00
@BinYang 不太明白对你的实时性影响是什么.
布隆过滤器在这里是减少你大量的空值 key.
首先你的每个有效的 key 写入了布隆过滤器.布隆过滤器存储的是你可能有效的值,反过来说布隆过滤器没命中,那么这个 key 或者说 这个关系一定不存在,就没有必要再查 mysql 了

你的关系还是在 redis 和 mysql 里. 你的关系直接查 redis 缓存.查不到才走布隆过滤器.
布隆过滤器不存在,那 db 一定是不存在的.(按你 9:1 的比例,这足以挡掉 8 成以上的无效请求了)
布隆过滤器存在,那你就查 db 是不是真的存在,真的存在就继续 redis 缓存一下,不存在继续写入 redis 空值 key. (注意这部分请求很少,因为你大量的有效 key 已经命中 redis 直接返回了.)
tolza
2021-03-09 11:53:28 +08:00
订阅 mysql 的 binlog,做主动变更 redis 中的缓存。相当于全量缓存了 db
daijialong
2021-03-09 11:58:29 +08:00
感觉设计有问题
BigR
2021-03-09 12:27:09 +08:00
这种数据一定要放在服务器上查询么,可以把个人的已有的点对点信息放到每一个终端呀。每次操作同步到终端。验证的时候可以在终端验证。担心数据不一致,可在验证的时候,去服务器上请求当前的点对点信息。
15190049162
2021-03-09 13:28:40 +08:00
我想知道为什么会查出大量的不存在的好友关系...这是什么业务场景
freeminder
2021-03-09 13:42:36 +08:00
布隆过滤器存数据库有的,命中了才去 DB 二次验证也行吧。这种情况下的 BF 就是只加不减了
zhgg0
2021-03-09 14:00:10 +08:00
没看明白定时重建布隆过滤器为啥不能解决问题。就算删除比较频繁,布隆过滤器也能挡住绝大多数无效请求。
布隆过滤器里面存在就去查 redis 、db,如果最终发现不存在就缓存空值,缓存时间可以设为布隆过滤器重建时间。
这样 redis 中的空值极限情况最多只有一个重建时间里删除的数量。
azhi
2021-03-09 15:07:10 +08:00
觉得你设置空值 key 的逻辑,有点别扭,这不就是不论是否命中都只查 redis 了,既然这样,我觉得可以不设置空值 key,缓存无法命中的时候也不用查库了,证明没有好友关系
no1xsyzy
2021-03-09 15:09:07 +08:00
数据库
你是搞了个 (User, User) -> Bool 的查询吗?
不要这样,你应该写个 User -> User[]
yc8332
2021-03-09 16:03:55 +08:00
90%没有,那为什么不把数据库里的设置到缓存。都不用去查数据库,而是数据库主动更新到缓存。
HanLi2021
2021-03-09 16:19:56 +08:00
我们业务有类似场景,推荐用布隆过滤器,支持实时

1 实时修改的数据(新增 /删除),使用 Redis 缓存(过期时间大于布隆过滤器重建一次的时间就好了,比如 1 小时 )
2 全量数据使用布隆过滤器,对于 3 亿的数据,内存只需要大概十几 MB,可以定时重建(比如每 30 分钟一次)。
3 穿透布隆的再加上临时缓存,比如 GUAVA 等包装下 DB 查询

判断逻辑

if (Redis 中 key 存在)
return Redis value

if 布隆不存在
return false
else

return guavaCache.get(key)
xiangbohua
2021-03-09 16:20:37 +08:00
来个数据预热?
我的理解里面 3 亿空值难道很多吗?
缓存很多时候是解决速度问题,如果压力不高就让他穿呗,如果压力很大,那就来个数据预热?
有一点不太明白,你来个空值的 key 的话能解决问题吗?
逻辑上会不会反会 null 而出现逻辑错误呢

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

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

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

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

© 2021 V2EX