Skip to content

Latest commit

 

History

History
52 lines (41 loc) · 3.58 KB

缓存.md

File metadata and controls

52 lines (41 loc) · 3.58 KB

缓存 cache

Cache Aside Pattern

缓存+数据库读写的模式

  • 读数据:先查缓存,不过不存在,查数据库,并更新缓存。
  • 更新数据:先更新数据库,再删除缓存。

    1 . 直接删除就行,不要更新缓存。缓存的数据可能是数据库取出后需要进行业务整合的,应该在查数据的时候再做此操作,提高更新性能。
    还有可能此数据更新比较频繁,更新了10次,却只查了2次。那么如果你每次更新数据的时候都重新更新缓存,则非常浪费资源。hibernate的lazy加载有点类似,只要需要的时候才去加载。
    2 . 顺序不应颠倒。在高并发下可能会发生缓存了旧数据的情况,导致数据不一致。 一个更新操作过来后,如果先删除缓存,在执行更新数据库逻辑时,另一个线程来查询,发现缓存没数据,去数据库取出了还未更新的旧数据,然后放置缓存,就发生了数据不一致问题。

缓存穿透

大多情况下缓存key是以ID为基础设置的,那么黑客故意删除他的一条数据,并记住这个ID,或者使用任意方式查询一个不存在的ID,比如,自增ID,使用负数取查询等等。那么他使用这个ID去查数据,缓存为空,导致查数据库,还是空,缓存不更新,那么他每次请求都能穿透缓存进入数据库。导致所有流量全部打入数据库,导致数据库重压甚至奔溃。
当然整体的系统设计还会加上API网关进行限流,熔断,黑名单,参数合法验证等保护措施,不一致压垮,但必定还是会受到影响。
解决方案:

  • BloomFilter,BitMap
  • 对查询出来为空的数据也设置缓存。设置一个常量,标志是空数据,并设置过期时间,在未过期之前,不用担心被穿透的问题。这种方法非常简单,高效,但存在一棒子打死全部的问题,缓存的过期时间设置也是非常难判断,时间短导致穿透次数的增加,数据库压力的增加;时间长,可能会影响正常数据的查询。所以还是推荐上面的那种解决方案。

Redis

数据结构

  • 基本数据类型:字符串String、字典Hash、列表List、集合Set、有序集合SortedSet
  • HyperLogLog、Geo、Pub/Sub
  • Redis Module : BloomFilter, RedisSearch, Redis-ML, BitMap

淘汰策略

当 Redis 用于缓存的内存不足时,需要怎么处理。就是根据淘汰策略决定的

  • noeviction:新写入操作会报错。
  • allkeys-lru:在键空间中,移除最近最少使用 (less recently used ,LRU) 的key。
  • allkeys-random:在键空间中,随机移除某个key。
  • allkeys-lfu : LFU (Least Frequently Used)最不常用的
  • volatile-lfu :在设置了过期时间的键空间中,移除最不常用的
  • volatile-lru:在设置了过期时间的键空间中,移除最近最少使用的key。
  • volatile-random:在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:在设置了过期时间的键空间中,有更早过期时间(time to live,TTL) 的key优先移除。

默认是抛出异常 redis.cnf

maxmemory-policy noeviction

持久化机制

  • RDB:快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存。(默认机制)
  • AOF:把所有的对 Redis 的服务器进行修改的命令都存到一个文件里。
  • 混合模式:since Redis4.0

应用

  • 分布式锁