Redis基础知识

数据类型

Redis基础知识_第1张图片

过期策略

Redis会把设置了过期时间的key放入一个独立的字典里,在key过期时并不会立刻删除它。Redis会通过如下两种策略,来删除过期的key:

  • 惰性删除:
    客户端访问某个key时,Redis会检查该key是否过期,若过期则删除。
  • 定期扫描
    Redis默认每秒执行10次过期扫描(配置hz选项),扫描策略如下:
    1.从过期字典中随机选择20个key;
    2.删除这20个key中已过期的key;
    3.如果过期的key的比例超过25%,则重复步骤1;

淘汰策略

当Redis占用内存超出最大限制(maxmemory)时,可采用如下策略
让Redis淘汰一些数据,以腾出空间继续提供读写服务:

  • noeviction:对可能导致增大内存的命令返回错误(大多数写命令,DEL除外);
  • volatile-ttl:在设置了过期时间的key中,选择剩余寿命(TTL)最短的key,将其淘汰;
  • volatile-lru:在设置了过期时间的key中,选择最少使用的key(LRU),将其淘汰;
  • volatile-random:在设置了过期事件的key中,随机选择一些key,将其淘汰;
  • allkeys-lru:在所有的key中,选择最少使用的key(LRU),将其淘汰;
  • allkeys-random:在所有的key中,随机选择一些key,将其淘汰;

LRU算法:维护一个链表,用于顺序储存被访问过的key。在访问数据时,最新访问过的key将被移动到表头,即最近访问的key在表头,最少访问的key在表尾。
近似LRU算法:给每个key维护一个时间戳,淘汰时随机采样5个key,从中淘汰掉最旧的key。如果还超出内存限制,则继续随机采样淘汰。
近似LRU算法比LRU算法节约内存,却可以得到非常相似的效果。

缓存穿透

场景:查询根本不存在的数据,使得请求直达存储层,导致其负载过大,甚至宏机。

解决方案:

  • 缓存空对象
    存储层未命中后,仍将空值存入缓存层。
    再次访问该数据时,缓存层会直接返回空值。
  • 布隆过滤器
    将所有存在的key提前存入布隆过滤器,在访问缓存层之前,先通过过滤器拦截,若请求的是不存在的key,则直接返回空值。

缓存击穿

场景:一份热点数据,它的访问量非常大。在其缓存失效瞬间,大量请求直达存储层,导致服务崩溃。

解决方案:

  • 加互斥锁
    对数据的访问加锁互斥,当一个线程访问该数据时,其他线程只能等待。
    这个线程访问过后,缓存中的数据将被重建,届时其他线程就可以直接从缓存取值。
  • 永不过期
    不设置过期时间,所以不会出现上述问题,这是“物理”上的不过期。
    为每个value设置逻辑过期时间,当发现该值逻辑过期时,使用单独的线程重建缓存。

缓存雪崩

场景:由于某些原因,缓存层不能提供服务,导致所有的请求直达存储层,造成存储层宏基。

解决方案:

  • 避免同时过期
    设置过期时间时,附加一个随机数,避免大量的key同时过期。
  • 构建高可用的Redis缓存
    部署多个Redis实例,个别节点宏基,依然可以保持服务的整体可用。
  • 构建多级缓存
    增加本地缓存,在存储层前面多加一级屏障,降低请求直达存储曾的几率。
  • 启用限流和降级措施
    对存储曾增加限流措施,当请求超出限制时,对其提供降级服务。

分布式锁

场景:
修改时,经常需要先将数据读取到内存,在内存中修改后再存回去。再分布式应用中,可能多个线程同时执行上述操作,而读取和修改非原子操作,所以会产生冲突。增加分布式锁,可以解决此类问题。

基本原理:

  • 同步锁:在多个线程都能访问到的地方,做一个标记,标识该数据的访问权限。
  • 分布式锁:在多个进程都能访问到的地方,做一个标记,标识该数据的访问权限。

实现方式:

  • 基于数据库实现分布式锁;
  • 基于Redis实现分布式锁;
  • 基于Zookeeper实现分布式锁;

Redis实现分布式锁的原则

  • 安全属性:独享。在任一时刻,只有一个客户端持有锁。
  • 活性A:无死锁。即便持有锁的客户端崩溃或者网络被分裂,锁仍然可以被获取。
  • 活性B:容错。只要大部分Redis节点都活着,客户端就可以获取和释放锁。
    Redis基础知识_第2张图片
    Redis基础知识_第3张图片

你可能感兴趣的:(Redis,务实主义,redis,分布式,缓存,数据库)