redis学习八spring.data.redis、连接、序列化、high/low api

redis学习八spring.data.redis、连接、序列化、high/low api

      • redis 缓存击穿
        • 解决方案
      • 缓存穿透
      • 缓存雪崩
      • 分布式锁
      • 常用API
      • 基本API演示

redis 缓存击穿

客户端访问redis,redis的下级还有有mysql,击穿发生在redis做缓存的时候
,redis中的key设置了过期时间或者过期策略(LRU和LFU),如果key过期了
那么很多请求会直达数据库。【前置肯定是发生了高并发,且key过期了】
redis学习八spring.data.redis、连接、序列化、high/low api_第1张图片

解决方案

并发有了:要组织并发到达DB,redis没有请求的key【redis单进程单实例的】
所有客户端增加一个逻辑,使用setnx()-》约等于是一把锁,所有的人去抢这把锁,
只有获得所得去访问DB。
整个流程是:
先去getkey如果失败了以后,大家都去setnx,拿到锁的人去DB,其他的人则去随机等待。
redis学习八spring.data.redis、连接、序列化、high/low api_第2张图片
产生问题:
如果第一个人挂了,会产生让其他人一直等待【死锁】,所以可以设置锁的过期时间,
但是这样会产生,如果第一个人没挂,但是锁超时了,其他的人来也超时了,【此时使用多线程一个线程取DB另一个线程去监控是否取回来,更新锁时间,但是会提高客户端代码逻辑复杂度】
redis学习八spring.data.redis、连接、序列化、high/low api_第3张图片

缓存穿透

从业务接收查询的是你系统根本不存在的数据,(缓存和数据库里面没有),这样会造成数据库压力变大

解决方案:
使用布隆过滤器:
1、客户端包含布隆过滤器的算法,对客户端内存要求大
2、客户端只包含算法,然后使用redis的bitmap来存,这样客户端是无状态的
3、redis里面集成一个bloom的模块指令(算法数据都有,客户端比较简单)
但是会有如下问题:
1、不能删除(换成布谷鸟等布隆过滤器,设置一个空key【有key无value】)
redis学习八spring.data.redis、连接、序列化、high/low api_第4张图片

缓存雪崩

客户端访问redis,redis做缓存用,出现情况,大量的key同时失效,间接造成大量的访问到达DB。
解决方案:
随机过期时间:
分为时点性无关【随机过期时间】
时点性有关的【必须要零点去刷新DB的数据到内存】,则需要强依赖击穿的方案,在业务层里面
加一个判断,零点延时(业务层只要到了十二点了就做一个延时,等待更新完毕)
redis学习八spring.data.redis、连接、序列化、high/low api_第5张图片

分布式锁

1、setnx
2、过期时间
3、多线程(守护线程)延长过期时间使用
使用redisson 和zookeeper做分布式锁

常用API

jedis,多线程不安全,需要做池化技术
,如客户端1开启的事务未提交,客户端2的请求又来了,那么是拿不到结果的
redis学习八spring.data.redis、连接、序列化、high/low api_第6张图片

基本API演示

redis学习八spring.data.redis、连接、序列化、high/low api_第7张图片
redis学习八spring.data.redis、连接、序列化、high/low api_第8张图片

本地连接时配置
在这里插入图片描述
在这里插入图片描述
redis常用操作:
首先引入如下依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-json</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

启动类通过如下方式去调用:

@SpringBootApplication
public class DemoApplication {

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

}
@Autowired
    private RedisTemplate  redisTemplate;

    //这种方式redis的key是序列化了的
    @Autowired
    private StringRedisTemplate  stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    public void testRedis(){

        redisTemplate.opsForValue().set("hello01","china");
        System.out.println(redisTemplate.opsForValue().get("hello01"));

        RedisConnection conn = redisTemplate.getConnectionFactory().getConnection();

        conn.set("hello02".getBytes(),"test".getBytes());
        System.out.println(new String(conn.get("hello02".getBytes())));


        HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
        hash.put("sean","name","lsd");
        hash.put("sean","age","22");
        System.out.println(hash.entries("sean"));


        Person p = new Person();
        p.setName("zhangsan");
        p.setAge(16);
        //value是个Integer,此处通过json的方式去转换
       stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        //第二个参数是是否展开,就是说是否包含内部类
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
        stringRedisTemplate.opsForHash().putAll("sean01",jm.toHash(p));
        Map map = stringRedisTemplate.opsForHash().entries("sean01");
        //转换取出的map
        Person per = objectMapper.convertValue(map, Person.class);
        System.out.println(per.getName());

}

也能自定义template:

/**
 * 自定义template
 */
@Configuration
public class MyTemplate {

    @Bean
    public StringRedisTemplate ooxx(RedisConnectionFactory fc){

        StringRedisTemplate tp = new StringRedisTemplate(fc);

        tp.setHashValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        return  tp ;
    }

}

@Component
public class TestRedis {

    @Autowired
    private RedisTemplate  redisTemplate;

    //这种方式redis的key是序列化了的
    @Autowired
    @Qualifier("ooxx")
    private StringRedisTemplate  stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    public void testRedis(){

        redisTemplate.opsForValue().set("hello01","china");
        System.out.println(redisTemplate.opsForValue().get("hello01"));

        RedisConnection conn = redisTemplate.getConnectionFactory().getConnection();

        conn.set("hello02".getBytes(),"test".getBytes());
        System.out.println(new String(conn.get("hello02".getBytes())));


        HashOperations<String, Object, Object> hash = stringRedisTemplate.opsForHash();
        hash.put("sean","name","lsd");
        hash.put("sean","age","22");
        System.out.println(hash.entries("sean"));


        Person p = new Person();
        p.setName("zhangsan");
        p.setAge(16);
        //value是个Integer,此处通过json的方式去转换
       stringRedisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        //第二个参数是是否展开,就是说是否包含内部类
        Jackson2HashMapper jm = new Jackson2HashMapper(objectMapper, false);
        stringRedisTemplate.opsForHash().putAll("sean01",jm.toHash(p));
        Map map = stringRedisTemplate.opsForHash().entries("sean01");
        //转换取出的map
        Person per = objectMapper.convertValue(map, Person.class);
        System.out.println(per.getName());



        stringRedisTemplate.convertAndSend("ooxx","hello");

        RedisConnection cc = stringRedisTemplate.getConnectionFactory().getConnection();
        cc.subscribe(new MessageListener() {
            @Override
            public void onMessage(Message message, byte[] pattern) {
                byte[] body = message.getBody();
                System.out.println(new String(body));
            }
        }, "ooxx".getBytes());

        while(true){
            stringRedisTemplate.convertAndSend("ooxx","hello  from wo zi ji ");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

}

你可能感兴趣的:(redis,redis,学习,spring)