美文网首页
Redis相关分享:

Redis相关分享:

作者: 漫行者_ | 来源:发表于2021-05-20 11:54 被阅读0次

    Redis简介

    Redis 是一个开源的使用 C 语言编写、支持网络、可基于内存、分布式、可选持久性的键值对(Key-Value)存储数据库,并提供多种语言的 API。
    Redis 通常被称为数据结构服务器,因为值(value)可以是字符串(String)、哈希(Hash)、列表(list)、集合(sets)和有序集合(sorted sets)等类型。

    问题1. 为什么Redis读取快?

    • 基于内存
      基于内存速度那是相当的高,能达到在一秒内处理10万个用户请求,如果一秒十万还不能满足,那我们就可以使用Redis分片的技术来交给不同的Redis服务器。这样的做饭避免了在同一个 Redis 服务中引入大量的多线程操作。
    • 单线程和多路复用
      在单线程模式下,单线程速度很快,即使连接的网络处理很多,因为有IO多路复用,保证了多线程的特点,没有必要使用多线程


      多路复用模型.png

    (Redis 在最新的几个版本中加入了一些可以被其他线程异步处理的删除操作,我们知道Redis可以使用del命令删除一个元素,如果这个元素非常大,可能占据了几十兆或者是几百兆,那么在短时间内是不能完成的,这样一来就需要多线程的异步支持。)

    • 整个存储结构就是一个hash结构,根据key找到对应的对象。

    问题二:Redis主要用于做缓存:可能面临多种问题。

    • 缓存穿透
      缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
      代码示例:
    1. 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
    2. 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。

    设置空

    jedis.setex("Id + ":info", 60 * 3, JSON.toJSONString("empty"));  
    

    访问的情况

                String json = jedis.get(id);
                if ("empty".equals(json)) {
                    return null;
                }
    
    • 缓存击穿
      缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
      解决方案:
    1. 设置热点数据永远不过期。
    2. 加互斥锁
      当访问不存在的时候开始加互斥锁,存在的问题,极大的影响访问性能。
       /*设置分布式锁 返回值是OK*/
            String token = UUID.randomUUID().toString();
                      /*保证加的锁是加和取消是同一个访问。
                      为了避免当拿到锁的用户在过期时间后依旧没有从数据库中获取到数据,锁已经自动销毁(过期时间已满)
                          这时下一个用户拿到锁,开始访问数据库,但是,上一个拿到锁的用户访问完毕,会回来执行“删除锁”
                          jedis.del(Id + ":lock");命令,这时删除的锁是当前正在访问的用户的锁,造成当前用户访问失败。
                          所以在当前用户拿到锁情况下,上一个用户回来做“删除锁”jedis.del(Id + ":lock");命令时
                          上一个用户应该将此时的newToken和自己拿到锁分配的随机token做比较,相同则是同一个用户,可以删除锁*、*/
              String OK = jedis.set(Id + ":lock", token, "nx", "px", 10 * 1000);
                if (OK != null && !OK.equals("") && OK.equals("OK")) {
                        /*设置成功,有权利在10秒的过期时间内访问数据库*/
                  info = getInfoByIdFromDb(skuId);
                   if (info != null) {
                            /*4.mysql将想要查询的结果返回给redis*/
                            Random random = new Random();
                            jedis.setex(Id + ":info",(random.nextInt(10)+1)*60, JSON.toJSONString(info));
                    } else {
                         
                            jedis.setex(Id + ":info", 60 * 3, JSON.toJSONString("empty"));
                     }                
                   String newToken = jedis.get(Id + ":lock");
                     if (newToken != null && !newToken.equals("") && newToken.equals(token)) {
                            /*  并发问题*/
                            jedis.del(Id + ":lock");
                    }
    }
                    
    
    • 缓存雪崩
      缓存雪崩是指缓存中数据大批量到过期时间,而查询数据量巨大,引起数据库压力过大甚至down机。
      解决方案:
      缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。

    • 缓存读写不一致

    (1)读取时,首先读取缓存,如果没有缓存,则读取数据库,然后取出数据并放入它在缓存中,然后返回Response
    (2)更新时,请先删除缓存,然后再更新数据库
    

    .....

    相关文章

      网友评论

          本文标题:Redis相关分享:

          本文链接:https://www.haomeiwen.com/subject/mrsvjltx.html