缓存架构设计

为什么要做缓存

  • 加速访问

大部分应用核心业务是围绕着数据来的,如果出现数据库访问速度的瓶颈,通常依靠数据库本身的做法是增加索引、分表。
如果选择增加索引,会带来写入速度慢、增加死锁风险的问题;如果选择分表,则会增加业务系统的复杂性,而且对于跨表统计查询等操作来说是雪上加霜;
除了上面的两种方式,访问数据前如果可以在内存中得到结果,那么就不去访问数据库,毫无疑问,这快得多!

  • 保护数据库

传统数据库承压能力是非常差的,这是因为访问数据库中的数据会带来磁盘io(除非你使用索引覆盖查询),如果大量的请求堆积在数据库访问上,数据库或者我们的应用可能直接无法提供服务。
缓存的出现可以让我们避开磁盘操作,直接在内存中得到数据,数据库的功能就变成了持久化和为缓存提供数据。

缓存存在的问题

  • 需要占用内存

并非所有的数据都适合缓存,即使它是数据库中的。
数据库中的大字段,如果数据库中的某张表存在一个较大的列,那就得考虑是不是要缓存它了,或者缓存时额外的过滤掉这些列,大字段往往不需要频繁的查询。
访问不那么频繁的数据,如果数据的访问数据库足以支撑,没必要加一层缓存,如果统计压力非常大,应该做的是预统计或者分表。

  • 数据一致性

保证缓存中的数据和数据库中的一致是缓存设计最优先考虑的内容。相对于正确性速度往往没有那么重要,因为访问缓存的数据是非常快的,额外的做一些工作保证一致性是非常必要的。

  • 雪崩问题

如果使用懒加载的缓存,在某一个时刻大量的请求用到了未加载的数据,会导致压力给到数据库;
如果为了保险起见,我们给缓存增加一个过期时间,过期时间过于密集的话,大量缓存同时过期的时刻就会去访问数据库刷新这些缓存,压力又打到了数据库;

  • 穿透问题

访问缓存中不存在的数据将会访问数据库加载缓存,但是如果数据库中依然不存在呢?那就会每次都去数据库中确认这条数据不存在,这样的请求如果是密集的,也会把压力给到数据库;

缓存的设计

  • 一个小数据库表

直接整张表都放到缓存中即可,这种表往往是不怎么更新的,做好缓存一致性每次写操作刷新全部缓存即可。
写操作增加事务,事务开启前把缓存标记为过时。
设计队列(可以直接使用公平锁来实现),先入先出,避免数据库读的同时写操作事务未提交造成过期数据加载到缓存;同时也保证多个读写请求的顺序正确;

  • 写不频繁,读频繁

最经典的缓存使用场景。
同样的使用事务、队列来保证数据的正确性;只不过这种场景往往本身应用是分布式的,要把队列替换成分布式队列或者分布式锁(redisson是个不错的选择);如果采用队列要充分考虑队列的性能是否足够,容量是否足够,比如说来自同一个服务的大量的请求堆积在队列中出现了请求倾斜,就得考虑是不是负债均衡有问题,考虑负债均衡算法的合理性;还可以通过其他方式优化,比如读请求入队前检查队列中如果不存在写请求,直接查就可以了不用入队;
解决雪崩问题,把缓存的有效期加盐,避免大量缓存同一时间过期;还可以通过热数据预热来避免该场景的出现;
解决穿透问题,如果数据不存在,也给它缓存下来,但是过期时间设置的要小一些,避免被攻击爆内存;或者是前置检查,比如缓存中存储最大的id和最小的id,如果要查询的数据不在这个范围内,显然是没有的;

  • 写频繁,读不频繁

不建议使用缓存,代价太大,大量的cpu、内存资源消耗在维护缓存上。

  • 写频繁、读频繁

这种数据真的存在吗,如果真的存在,考虑不使用传统数据库,直接上内存数据库是不是更好些,如果实时性要求不高,大数据量的情况下考虑使用hbase这种库。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值