架构设计笔记_11_关键模式_缓存
2009年7月 北京灵山
缓存是我们优化系统最常用的一种手段,不要一出现性能问题就开始考虑分布式,微服务,分库分表等等,看起来高大上的说起来炸耳朵的名词,试想一下你的缓存用好了吗?SQL优化了没有?
Runnf的问题在于读大于写,QPS是83328,完全从数据库查询,会导致数据库服务器压力大,通过缓存可以解决此问题,数据写库后要同步一份到缓存,具体业务场景是,产生的用户动态数据,因为用户动态数据时效性没有那么高,可以有延时,还有就是跑步记录的主要轨迹数据,特别是在查看运动记录详情时需要查看到轨迹数据的详细信息,以上2个场景的数据都是一次形成后,很少会进行修改的,所有放在缓存中比较合适。目前Redis官网给出的QPS数据是10万。
缓存的使用场景
对于大量更新不频繁的热点数据,甚至系统启动后很难再更新的数据,这种情况就需要放入缓存,一次读入随时使用。热点数据的特点就是读取量很大,更新不频繁,比如新浪微博的热搜,比如Runnf的动态等。上千万粉丝的明星发一条微博,会产生千万条select语句查询数据库,数据库肯定会招架不住。
对于业务大表,虽然不是热点数据,也可以通过缓存来缓解数据库的读取压力。比如商品详情页这种,对于大型电商系统,商品详情页集成了多方面的综合数据总体展现,不可能每次都查多张表,但是这种场景必须要有一个安全的缓存数据更新和淘汰机制,保证没有脏数据的产生。比如商品的分页数据,当商品数据巨大时,通过缓存把分页数据缓存起来。
缓存的问题
缓存数据不存在,这种情况理论上是正常的,不存在就去数据库里面查询,然后在缓存起来,但是不正常的是,如果恶意的发起大量的不存在数据的查询,就会拖垮后台的数据库,这种情况,可以通过返回空,然后缓存起来,就保证下次不再直接访问数据库了。(穿透问题)
缓存数据构建时耗时较长,当有大量请求过来时,如果发现缓存没有就查询数据库,然后开始同时生成缓存数据,那么也会导致后台的服务压力较大,即同时访问存储系统,使得存储系统性能下降,同时会影响其他业务逻辑,这种情况的关键点在于构建缓存数据的这段代码逻辑,可以通过加锁的方式解决,每次只有一个线程可以生产缓存,其他只能等待。单体结构服务这种方式可以解决,但是如果是分布式系统,应用实例并不知道其他实例都在访问存储系统,就需要分布式锁来保证大家步调一致。另外一种方案就是通过后台定时更新缓存机制,业务逻辑代码不更新缓存,缓存失效后业务代码直接返回空即可,后台更新缓存逻辑会更加设定的时间间隔进行更新缓存。(雪崩问题)
Runnf的缓存机制实现了用户动态数据和跑步轨迹数据的缓存,同时结合Redis的数据结构,可以缓存当前用户的动态页的前几页动态数据,就是其关注的所有好友的动态数据汇总,根据时间线进行展示。如果Runnf增加一个发现功能,同理可以借助Redis的缓存功能将有价值的用户动态一次呈现在发现页中。
以上,Runnf中我们在使用缓存时,使用到的就是通过缓存存储业务大表数据,即用户动态数据,和热点数据,即发现页的热点数据。而对于缓存的问题,我们在关键缓存构建代码上加上锁机制,保证不会出现雪崩问题,结合我们的用户量,无状态的服务器同时进行缓存重建逻辑也不会达到雪崩的状态,所以无需使用分布式锁机制。同样,会通过返回空来防止缓存穿透问题。