redis击穿,穿透,雪崩,分布式锁,api(jedis,luttuce)

击穿:(redis做缓存用,肯定发生了高并发,到达数据库查询)
    设置key 的过期时间,过期后没有这个key,找不到了,就穿过了(其中一个key过期导致并发访问数据库)
    LRU (LRU,即:最近最少使用淘汰算法(Least Recently Used)。LRU是淘汰最长时间没有被使用的页面。)
    LFU (LFU,即:最不经常使用淘汰算法(Least Frequently Used)。LFU是淘汰一段时间内,使用次数最少的页面)
    1.key为null
    2.setnx 
    如果key存在,则什么都不做
    在 Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果,不过很多人没有意识到 SETNX 有陷阱!
    比如说:某个查询数据库的接口,因为调用量比较大,所以加了缓存,并设定缓存过期后刷新,问题是当并发量比较大的时候,如果没有锁机制,那么缓存过期的瞬间,大量并发请求会穿透缓存直接查询数据库,造成雪崩效应,如果有锁机制,那么就可以控制只有一个请求去更新缓存,其它的请求视情况要么等待,要么使用过期的缓存。
    3.只有获得锁的去访问DB

    并发有了:阻止并发到达DB,redis又没有key
    鉴于redis是单进程实例,如果所有请求都没找到这个key的话就由第二轮的第一个请求创建一个key作为锁
    setnx()->1.get key
    2.setnx
    3.1 ok表示获取到锁,去DB
    3.2 false表示未获取到锁,sleep ->1
    问题:如果第一个人挂了?
    可以设置锁的过期时间
    问题:没挂,但是锁超时了?
    用多线程解决
    一个线程获取DB
    一个线程监控是否取回来,更新锁时间

穿透:(redis做缓存用,从业务接收查询的是你redis根本不存在的数据,到达数据库查询)
    解决方案:
    用布隆过滤器
    1.client客户端包含
    2.客户端包含算法,bitmap->redis
    3.redis集成布隆
    布隆过滤器只能增加不能删除,所以可以用布谷鸟过滤器替代
    空key,查的是空就返回
    扩展:
    布隆过滤器:
    它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
    tips:看完这个我们可以知道是一个叫布隆的人提出的一个用来检索一个元素是否在一个集合中的算法,效率高,性能好。
    布谷鸟过滤器:
    布谷鸟过滤器源于布谷鸟Hash算法,布谷鸟Hash表有两张,分别两个Hash函数,当有新的数据插入的时候,它会计算出这个数据在两张表中对应的两个位置,这个数据一定会被存在这两个位置之一(表1或表2)。一旦发现其中一张表的位置被占,就将改位置原来的数据踢出,被踢出的数据就去另一张表找对应的位置。通过不断的踢出数据,最终所有数据都找到了自己的归宿。
    但仍会有数据不断的踢出,最终形成循环,总有一个数据一直没办法找到落脚的位置,这代表布谷Hash表走到了极限,需要将Hash算法优化或Hash表扩容。
    布谷鸟过滤器只会存储元素的指纹信息(几个bit,类似于布隆过滤器),由于不是存储了数据的全部信息,会有误判的可能。
    由于布谷鸟过滤器在踢出数据时,需要再次计算原数据在另一种表的Hash值,因此作者设计Hash算法时将两个Hash函数变成了一个Hash函数,第一张表的备选位置是Hash(x),第二张表的备选位置是Hash(x)⊕hash(fingerprint(x)),即第一张表的位置与存储的指纹的Hash值做异或运算。这样可以直接用指纹的值 异或 原来位置的Hash值来计算出其另一张表的位置。

雪崩:(redis做缓存用,大量的key同时失效,大量数据到达数据库)
    随机过期时间
    1.时间性无关
    2.零点 业务层加判断,零点延时()-->零点(双11折扣,过了零点开始抢购)-->强依赖击穿方案

    分布式锁:
    分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性。
    1.setnx
    2.过期时间
    3.多线程(守护线程) 延长过期
    redisson
    zookeeper 做分布式锁

API
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>

 

@Component
public class TestRedis {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    @Qualifier("ooxx")
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    ObjectMapper objectMapper;

    public void testRedis(){
//        redisTemplate.opsForValue().set("hello", "hello koukay");
        //高级api
       /* stringRedisTemplate.opsForValue().set("hello02", "hello koukay");
        System.out.println(stringRedisTemplate.opsForValue().get("hello02"));*/
       //低级api
        RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
        connection.set("hello03".getBytes(), "123".getBytes());
        System.out.println(new String(connection.get("hello03".getBytes())));

       /* HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
        hash.put("sean", "name", "
koukay
");
        hash.put("sean", "age", "18");
        System.out.println(hash.entries("sean"));*/

        Person p = new Person();
        p.setName("jack");
        p.setAge(18);


        /*Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
        redisTemplate.opsForHash().putAll("sean01" , jm.toHash(p));
        Map map = redisTemplate.opsForHash().entries("sean01");
        Person person = objectMapper.convertValue(map, Person.class);
        System.out.println(person);
        System.out.println(person.getName()+"<==>"+p.getAge());*/
//序列化hash值字符串
//        stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
        stringRedisTemplate.opsForHash().putAll("sean02" , jm.toHash(p));
        Map map = stringRedisTemplate.opsForHash().entries("sean02");
        Person person = objectMapper.convertValue(map, Person.class);
        System.out.println(person);
        System.out.println(person.getName()+"<==>"+p.getAge());




        //获得连接
        RedisConnection cc = stringRedisTemplate.getConnectionFactory().getConnection();
        //订阅消息
        cc.subscribe(new MessageListener() {
            @Override
            public void onMessage(Message message, byte[] bytes) {
                byte[] body = message.getBody();
                System.out.println(new String(body));
            }
        }, "ooxx".getBytes());
        while (true){
            //发送消息
            stringRedisTemplate.convertAndSend("ooxx", "hello");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

@Configuration
public class MyTemplate {
    @Bean
    public StringRedisTemplate ooxx(RedisConnectionFactory fc){
        StringRedisTemplate tp = new StringRedisTemplate(fc);
        tp.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        return tp;
    }
}

@SpringBootApplication
public class SpringbootStudyApplication {

   public static void main(String[] args) {
      ConfigurableApplicationContext ctx = SpringApplication.run(SpringbootStudyApplication.class, args);
      TestRedis redis = ctx.getBean(TestRedis.class);
      redis.testRedis();

   }

}
 
原文地址:https://www.cnblogs.com/hikoukay/p/12110226.html