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

2021 年 3 月 8 日
 BinYang

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

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

8652 次点击
所在节点    Java
97 条回复
xiangbohua
2021 年 3 月 9 日
@HanLi2021 具体场景可以类比一下么?没遇到过这种场景
linxb
2021 年 3 月 9 日
用 Hash 类型试一下?一个 Hash 可以存储 40 多亿键值对,内存占用比 key-value 小很多
pipi32167
2021 年 3 月 9 日
直觉是个 X-Y problem
FaceBug
2021 年 3 月 9 日
@Aidenboss

我一开始思路也是用方案 1,即用 set 来存储,我实验了下

set 、setex 、sAdd 、zAdd 几种方案

以 100 万条 UID 为例

string+过期时间:就是楼主现在用的,key 为 UID,value 为 null,设置过期时间,内存占用 122M

string:内存占用 92M,但不能自动设置过期时间

sadd:根据 uid%10,分为 10 个 set (如果每个 UID 一个 set 占用会更大),占用 76M,缺点是无法知道 uid 是什么时候插入的

zadd:同 sadd,score 设为 timestamp 为 115M,优点是可以手工删除到期的 uid
securityCoding
2021 年 3 月 9 日
布隆过滤器明显可以用啊,它的误差率表示:如果返回不存在则一定不存在,返回存在则可能存在。
先用一个专门的 redis 集群挡住 90%的无效流量,剩下的应该就可以处理了。
dqzcwxb
2021 年 3 月 9 日
没人考虑过 Caffeine 吗
guijianshi01
2021 年 3 月 9 日
1. 缩短空缓存时间
2. 过滤器内没有清除已经删除数据影响不大,导致写入部分空幻存
3. 定时刷新过滤器
4. 加内存,除非性能要求很高,否则不推荐直接将 redis 当做库,全量拉到 redis 里,两个同步成本稍高,具体更具自己业务确定
FaceBug
2021 年 3 月 9 日
另外问一下
A-B 和 B-A,是视为两条关系,还是一条关系

如果不存在单向关注,都是互关这种逻辑

其实可以只存 UIDA-UIDB 一种情况就行了
NUT
2021 年 3 月 9 日
如果 qps 要求不高可以使用 360 的 pika 等 基于 rocksdb 的 redis 变种实现。
这些中间件都是经过验证的。 甚至 pika 可以前面加一个 codis 作为 proxy

另外数据肯定要分冷热。 冷数据还有一个逐渐变冷的过程。

其实题主就是来平衡成本和性能的。 大家抓核心。 楼主你说对吧。
Aidenboss
2021 年 3 月 9 日
@FaceBug 赞。目前看内存消耗不高。
BinYang
2021 年 3 月 9 日
@FaceBug 算作 2 条数据
FaceBug
2021 年 3 月 9 日
@BinYang 你可以先排序一下,永远把小的放在前面,大的放后面,这样不就可以减少(最多) 50%的 key 么
xuletter2021
2021 年 3 月 9 日
@HanLi2021 赞同 79 楼的做法,但逻辑顺序可以,先查询布隆过滤器,布隆过滤器根据业务周期性更新,结果是不存在直接返回,存在再去查 DB 或 redis,这样先拦截 90%的流量,后面的流量具体看 DB 是否能抗住,实在不行分库分表的做法也可以,这样整体方案简单;如果不能可以用 redis 缓存下大部分的流量,但需要同步 DB 中的数据到 redis,一种方式是双写,复杂度高,一种是只写 DB,使用自动同步工具同步 DB 中的数据到 redis,稍微简单。但这些都引入了额外的复杂性。其实还是倾向只用布隆过滤器和 DB 分库分表,实现方案简单。
tghoul
2021 年 3 月 10 日
@no1xsyzy (User, User) -> Bool 这种方案有什么缺点吗?
no1xsyzy
2021 年 3 月 10 日
@tghoul 楼主的问题就是这种方案的巨大缺陷。
数据库可以存 Friend(User, User) ,封装到业务层 Model 就是 User -> User[]
当然这里默认了稀疏
rylei
2021 年 3 月 10 日
感觉就是用户关注的业务,这样正常来说只需要存储用户的关注列表即可。100W 也就是 100W 个 hash
rylei
2021 年 3 月 10 日
#37 楼方案是可以的

对于#57 查询两个人是不是好友,直接查询两次 redis, 或者用 lua 脚本一次将数据取回即可

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

https://study.congcong.us/t/759715

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

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

© 2021 V2EX