缓存如何实现高性能

缓存如何实现高并发

redis和memcached的区别

  • redis拥有更多的数据结构和丰富的数据操作
  • redis内存利用率高于memcache
  • redis是单线程,memcache是多线程,在存储大量数据的情况下,redis的速度比memcache差一些
  • memcache没有原生的集群模式,redis官方支持redis cluster集群模式

    用缓存可能出现的问题

  • 数据不一致

  • 缓存雪崩
  • 缓存穿透
  • 缓存并发竞争

    当查询缓存报错,如何提高可用性?

    缓存可以极大提高查询性能,但是缓存数据丢失和缓存不可用不能影响应用的正常工作。因此,一般情况下,如果缓存出现异常,需要手动捕获这个异常,并且记录日志,然后从数据库查询数据返回给用户,而不是导致业务不可用

    如何避免缓存”穿透”的问题

    缓存穿透,是指查询一个一定不存在的数据,由于缓存是不命中时被动写,并且出于容错考虑,如果从db查不到数据则不写入缓存,这个将导致这个不存在的数据每次都需要请求db查询,失去了缓存的意义。
    如何解决
    方案一:缓存空对象
    当从db查询数据为空时,我们仍然将这个空结果进行缓存,具体的值需要使用特数据的标识,能和真正缓存的数据区分开。另外,需要设置较短的过期时间,一般建议不要超过五分钟
    方案二:bloomfilter 布隆过滤器
    在缓存服务的基础上,构建BloomFilter数据结构,在bloomfilter中存储对应的key是否存在,如果存在,说明该key对应的值不为空

    如何避免缓存”雪崩”的问题*使用golang如何实现本地缓存?

    缓存雪崩,是指缓存由于某些原因无法提供服务(如:缓存挂掉了),所有请求全部到达DB中,导致DB负荷大增,最终导致雪崩一样的挂掉。
    如何解决
    方案一:缓存高可用
    通过搭建缓存高可用,避免缓存挂掉无法提供服务的情况,从而降低出现缓存雪崩的情况。假设我们使用redis作为缓存,则可以使用redis sentinel或redis cluster实现高可用
    方案二:本地缓存
    如果使用本地缓存时,即使分布式缓存挂了,也可以将db查询的结果缓存到本地,避免后续请求全部到达DB中。*

    如何避免缓存”击穿”的问题

    缓存击穿,是指某个极度”热点“数据在某个时间点过期时,恰好在这个时间对这个key有大量的并发请求过来,这些请求发现缓存过期一般都会从db加载数据并回设到缓存,但这个时候大量并发请求可能会瞬间压垮DB
    如何解决:对于一些设置了过期时间的key,如果这些key可能会在某个时间点被高并发访问,是一种”热点“数据。这个时候,需要考虑这个问题:
    方案一:使用互斥锁。请求发现缓存不存在后,去查询DB前,使用分布式锁,保证只有一个线程去查询DB,并更新到缓存。
    方案二:手动过期,缓存上不设置过期时间,功能上将过期时间存在key对应的value中,方案如下
    1.获取缓存。通过value的过期时间,判断是否过期。如果未过期,则直接返回;如果已过期,继续向下执行
    2.通过一个后台的异步线程进行缓存的构建,也就是”手动“过期。通过后台的异步线程,保证有且只有一个线程访问db
    3.同时,虽然value已经过期,但还是直接返回。通过这样的方式,保证服务的可用性,虽然损失了一些时效性
    区别
    和缓存“穿透”的区别在于,这个key存在对应值
    和缓存“雪崩”的区别在于,缓存雪崩针对某个一个key,而缓存击穿是很多个key

    什么是缓存预热,如何实现缓存预热

    在刚启动的缓存系统中,如果缓存中没有任何数据,如果依靠用户请求的方式重建缓存数据,那么对数据库的压力非常大,而且系统的性能开销也是巨大。
    此时,最好的策略是启动时就把热点数据加载好。这样,用户请求时,直接读取的就是缓存的数据,而无需去读取db重建缓存数据。举个例子,热门或推荐的商品,需要提前预热到缓存中。
    如何实现:
    数据量不大时,在项目启动的时候自动进行初始化。
    数据量大时,写脚本或者在管理页面手动点击,预热对应的数据到缓存中。

    缓存数据的淘汰策略有哪些*自带了哪些失效策略

    除了缓存服务器自带的缓存自动失效策略之外,我们还可以根据业务的需求进行自定义的“手动”缓存淘汰,常见的策略有两种:
    1.定期去清理过期的缓存
    2.当有用户请求过来时,再判断这个请求用到的缓存是否过期,过期的话,就去底层系统得到数据来更新缓存
    第一种的缺点是维护大量缓存的key比较麻烦。
    第二种的缺点是每次用户请求都要判断缓存是否失效,逻辑相对复杂
    具体使用哪种方案,需要根据场景权衡。