redis

常用数据结构:

  1. string类型

    String类型是redis最常用的数据结构类型,存储的值为字符串。注意:key只能是String类型。

    • String类型的应用场景
      • 做与统计有关的业务,如新浪微博(微信朋友圈)中的点赞功能,可以使用incr、incrby、decr、decrby等相关命令

      • 解决多线程的线程安全问题。redis的key是单线程模式,这就意味一瞬间只有一个线程能够持有这个key,所以可以使用redis解决部分涉及线程安全的业务,比如说抢购、秒杀

      • set,get

  2. List类型

    • list类型特点:
      • 基于LinkedList实现。
      • 元素是字符串类型。
      • 列表头尾增删快,中间增删慢,增删元素是常态。
      • 从左至右,从0开始,从右至左,从-1开始。
      • 元素可以重复出现。
      • 最多包含2^32-1元素。
      • lpush,rpush,lpop,rpop
    • List类型应用场景
      • 处理顺序类业务。如新浪微博评论、论坛回帖楼层等
      • 聊天室。
  3. Hash类型(散列)

    • hash类型特点:
      • hash内容由field和与之关联的value组成map键值对组成
      • key、field和value是字符串类型
      • 一个hash中最多包含2^32-1键值对
      • hset key field value,hget key field
    • Hash类型应用场景
      • 节省资源
    • Hash类型不适用的场景
      • 对某一个field设置过期时间。如果仅仅只对一个字段设置过期,就不能使用hash。因为Redis的key的过期功能只能对操作,而Hash结构不能单独对某一个filed设置过期功能。
  4. Set类型(集合)

    • 特点:
      • 无序的、无重复的
      • 元素是字符串类型
      • 最多包含2^32-1元素
      • sadd key member [member, …],smembers key
    • set类型应用场景
      • 新浪微博的共同关注。当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户,将每个用户关注的用户放在集合中,求交集即可
  5. ZSet类型

    • 特点:
      • 类似Set集合
      • 有序的、无重复的
      • 元素是字符串类型
      • 每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。注意:分值可以相同
      • 最多包含2^32-1元素
      • zadd key [score1 member1 score2 member2],zrange key rankStart rankEnd
    • ZSet适用场景
      • 适用于需要有序且唯一的业务或操作:网易音乐排行榜

常见问题缓存问题

  1. 缓存穿透

    业务系统要查询的数据根本就存在!当业务系统发起查询时,按照上述流程,首先会前往缓存中查询,由于缓存中不存在,然后再前往数据库中查询。由于该数据压根就不存在,因此数据库也返回空。这就是缓存穿透。

    • 危害

      如果存在海量请求查询压根就不存在的数据,那么这些海量请求都会落到数据库中,数据库压力剧增,可能会导致系统崩溃,目前业务系统中最脆弱的就是IO,稍微来点压力它就会崩溃,所以我们要想种种办法保护它。

    • 原因

      发生缓存穿透的原因有很多,一般为如下两种:

      1. 恶意攻击,故意营造大量不存在的数据请求我们的服务,由于缓存中并不存在这些数据,因此海量请求均落在数据库中,从而可能会导致数据库崩溃。
      2. 代码逻辑错误。这是程序员的锅,没啥好讲的,开发中一定要避免!
    • 解决方案
      1. 缓存空数据

        之所以发生缓存穿透,是因为缓存中没有存储这些空数据的key,导致这些请求全都打到数据库上。那么,我们可以稍微修改一下业务系统的代码,将数据库查询结果为空的key也存储在缓存中。当后续又出现该key的查询请求时,缓存直接返回null,而无需查询数据库。

        缓存空对象会有两个问题:
        第一,空值做了缓存,意味着缓存层中存了更多的键,需要更多的内存空间 ( 如果是攻击,问题更严重 ),比较有效的方法是针对这类数据设置一个较短的过期时间,让其自动剔除。
        第二,缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。例如过期时间设置为 5 分钟,如果此时存储层添加了这个数据,那此段时间就会出现缓存层和存储层数据的不一致,此时可以利用消息系统或者其他方式清除掉缓存层中的空对象。

      2. BloomFilter,布隆过滤器

        它需要在缓存之前再加一道屏障,里面存储目前数据库中存在的所有key,如下图所示:

        img

        当业务系统有查询请求的时候,首先去BloomFilter中查询该key是否存在。若不存在,则说明数据库中也不存在该数据,因此缓存都不要查了,直接返回null。若存在,则继续执行后续的流程,先前往缓存中查询,缓存中没有的话再前往数据库中的查询。

        这种方法适用于数据命中不高,数据相对固定实时性低(通常是数据集较大)的应用场景,代码维护较为复杂,但是缓存空间占用少。

    • 两种方案的比较

      对于一些恶意攻击,查询的key往往各不相同,而且数据贼多。此时,第一种方案就显得提襟见肘了。因为它需要存储所有空数据的key,而这些恶意攻击的key往往各不相同,而且同一个key往往只请求一次。因此即使缓存了这些空数据的key,由于不再使用第二次,因此也起不了保护数据库的作用。

      因此,对于空数据的key各不相同、key重复请求概率低的场景而言,应该选择第二种方案。而对于空数据的key数量有限、key重复请求概率较高的场景而言,应该选择第一种方案。

  2. 缓存雪崩

    缓存其实扮演了一个保护数据库的角色。它帮数据库抵挡大量的查询请求,从而避免脆弱的数据库受到伤害。

    如果缓存因某种原因发生了宕机,那么原本被缓存抵挡的海量查询请求就会像疯狗一样涌向数据库。此时数据库如果抵挡不了这巨大的压力,它就会崩溃。这就是缓存雪崩。

    • 解决方案
      1. 缓存层设计成高可用的,即使个别节点、个别机器、甚至是机房宕掉,依然可以提供服务。
      2. 使用Hystrix。通过 熔断、降级、限流三个手段来降低雪崩发生后的损失。
  3. 缓存击穿(热点数据集中失效)

    • 什么是热点数据集中失效?

      我们一般都会给缓存设定一个失效时间,过了失效时间后,该数据会被缓存直接删除,从而一定程度上保证数据的实时性。

      但是,对于一些请求量极高的热点数据而言,一旦过了有效时间,此刻将会有大量请求落在数据库上,从而可能会导致数据库崩溃。

    • 解决方案
      • 互斥锁

        当第一个数据库查询请求发起后,就将缓存中该数据上锁;此时到达缓存的其他查询请求将无法查询该字段,从而被阻塞等待;当第一个请求完成数据库查询,并将数据更新值缓存后,释放锁;此时其他被阻塞的查询请求将可以直接从缓存中查到该数据。

        当某一个热点数据失效后,只有第一个数据库查询请求发往数据库,其余所有的查询请求均被阻塞,从而保护了数据库。但是,由于采用了互斥锁,其他请求将会阻塞等待,此时系统的吞吐量将会下降。这需要结合实际的业务考虑是否允许这么做。

      • 永远不过期

        永远不过期”包含两层意思:
        从缓存层面来看,确实没有设置过期时间,所以不会出现热点 key 过期后产生的问题,也就是“物理”不过期。
        从功能层面来看,为每个 value 设置一个逻辑过期时间,当发现超过逻辑过期时间后,会使用单独的线程去构建缓存。

    • 两种方案比较
      • 互斥锁 (mutex key):这种方案思路比较简单,但是存在一定的隐患,如果构建缓存过程出现问题或者时间较长,可能会存在死锁和线程池阻塞的风险,但是这种方法能够较好的降低后端存储负载并在一致性上做的比较好。
      • “ 永远不过期 “:这种方案由于没有设置真正的过期时间,实际上已经不存在热点 key 产生的一系列危害,但是会存在数据不一致的情况,同时代码复杂度会增大。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值