故事的开头是由短时间内大量的请求指向MySQL开始的

故事的开头是由短时间内大量的请求指向MySQL开始的。
request
response
老铁帮我查一下
没毛病
Client
Server
MySQL
当业务量到达一定数量级以后,常见的操作会将经常被客户端访问的数据(即热门数据)放在缓存中,这样可以解决两个问题
request
request
request
老铁帮我查一下
老铁我有点扛不住了
Client1
Server
Client2
Client3
MySQL
  • 一定程度上降低了服务端的压力,即MySQL服务器的压力
  • 一定程度上增加了用户体验,用户在访问的时候感觉速度更快了
request
request
request
老铁帮我查一下
嗖嗖的
这个我这没有
老铁你缓存下
Client1
Server
Client2
Client3
Redis
MySQL
但即使这样的操作也无法避免请求的数据在缓存中找不到最终指向MySQL的问题(即缓存穿透)
所谓缓存穿透就是指大量的请求绕过了缓存直接打向服务器的情形,那么都有 哪些常见具体场景呢?
1、一条热门数据失效了,由于请求的客户端有点多,短时间内给数据库服务器造成了过大压力
解决方案:
  • 1、数据永不过期(大部分场景下不建议这么做)
  • 2、加互斥锁
什么是互斥锁,举个简单的栗子
公共厕所,小张、小王和小李同时闹肚子,都憋得不行了
上厕所
上厕所
上厕所
小张
厕所
小王
小李
此时的厕所承受了它本不该承受的压力,在不考虑伦理道德的情况下,会出现3个人同时上厕所的情况,对应到服务器可能就是服务器宕机或者瘫痪
为了解决这个问题,厕所管理员老赵在厕所上加了把锁,有人进去的时候就会先锁门
上厕所
来了老弟
上厕所
上厕所
小张
小王
小李
厕所
从此厕所又恢复了往日的生机
对于服务器来说就是下图
有锁吗哥?
拿去用
有锁吗哥?
不好意思有人了
老铁帮我查一下
没毛病
Request1
Lock
Request2
MySQL
用MySQL实现就是专门用一张表来记录锁(肯定不会这么做对不对,太麻烦)
有锁就会出现死锁,啥是死锁呢?
还是以上厕所距离,小张上厕所太使劲晕在里面了,一直不出来,外面的人也进不去,哎呀急死了,厕所的生态再一次受到了挑战。
哎呀头晕
醒醒老弟
哥你快出来吧,不行了
哥我也不行了
小张
小王
小李
厕所
在服务端处理中就是有个请求长期霸占锁,导致其他的请求无法处理只能等待,这样下去可能会出现很多问题(内存泄漏啊什么的)。
MySQL没有TTL(time to live)这样的操作,处理死锁很麻烦并且时间长会产生大量无用的数据需要定期清理。
来吧Redis,设置一个TTL会自动失效的锁,这个自动失效就像厕所管理员老赵,在锁发生异常没有释放的时候及时出来解决问题。
哎呀头晕
醒醒老弟
哥你快出来吧,不行了
哥我也不行了
我来修锁了不要慌
小张
小王
小李
厕所
老赵
但这样依然还有问题,锁的过期时间多少合适呢?
  • 长了,一个请求已经被处理完了,其他请求还在等待呢。就像厕所里的人已经上完了但就在那玩手机不出来
  • 短了,请求还在处理中,但由于锁过期了其他请求也开始被处理了。就像厕所里本来有个人,哎呀我说不下去了。
这个度很难拿捏,要根据每个项目具体业务去分析。
2、此时有个黑客专门专门来请求一些不存在的数据(比如id=-1这种),按照我们之前的设计,查了一次以后就会把id=-1的数据缓存起来,再来就是查缓存了,是的没错。但是黑客之所以是黑客就是因为他没有这么简单,黑客会对id进行随机(-1~-200000这种随便来一堆),那缓存里就会存在大量的无用数据,后果很严重。
解决方案:
  • 1、把所有有效的数据id都放在缓存里,查之前先校验id存不存在(数据量不大确实可以)
  • 2、布隆过滤器
布隆过滤器的原理是布隆算法,啥是布隆算法呢?
搞一个二进制数组(里面存0和1的那种),有个查询过来了,把id哈希算法搞一下,看看结果在数组里的哪个位置,如果这个位置存储的是1代表这个id可能存在,如果位置存储的是0代表这个id一定不存在。
文字太苍白,画图
id= 187
布隆过滤器
一致性哈希
结果3
二进制数组(实际上比这个长很多)
0101111100
可以看到这个数组地址3也就是第四格是1,也就表示id为187的数据是可能存在的
为啥是可能存在的呢?因为哈希算法存在哈希碰撞,简单地说就是可能有个id=345431的数据哈希算法算出了刚好也是3,就把数组第四格的位置存为了1,此时id=187不幸被命中了。
但如果id=187一致性哈希的结果是0,也就是指向二进制数组第一个格子,即结果是0就代表id=187一定不存在
因为哈希碰撞问题的存在,布隆过滤器是有错误率的,为了保证这个错误率在一个可控可接受的范围内,可以增加哈希算法的个数,就下图这个样儿
id= 187
布隆过滤器
哈希算法1
结果3
哈希算法2
结果9
哈希算法3
结果7
如果在二进制数组中找到了0那么这个id一定不存在,还有就是增加二进制数组的长度,也能降低错误率
但是哈希算法的数量和二进制数组的长度都不是越多越好的,也要控制在一个合理的范围内,具体由业务量来决定
3、缓存雪崩
啥是缓存雪崩呢,就是大量的数据在同一个时间一起失效了,导致大量的请求涌向MySQL
解决方案:
  • 1、数据永不过期(大部分场景下不建议这么做)
  • 2、随机数据过期时间
最后总结一下
1、缓存雪崩和缓存击穿是缓存穿透的两种具体表现
  • 一条数据绕过缓存指向数据库是缓存击穿
  • 多条数据绕过缓存指向数据库是缓存雪崩
2、锁
  • 避免死锁
  • 注意锁的失效时间
3、布隆过滤器
  • 合理设置哈希算法数量
  • 合理设置二进制数组长度
4、来个图

在这里插入图片描述

5、最后再啰嗦一下
  • 程序设计实现一定要和实际的业务场景匹配,没啥数据量就不要搞这么多有的没的,实现和维护都是要成本的
  • 文中的解决方案也不一定是最优的,比如分布式锁可以基于zookeeper实现,布隆过滤器不好用也可以使用布谷鸟过滤器
  • 感谢阅读
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值