Redis

发布于:2024-09-18 ⋅ 阅读:(145) ⋅ 点赞:(0)

使用关系型数据库会频繁的进行I/O操作,Redis作为Nosql数据库,所有的数据都存放在运行内存中,减少对磁盘的访问。Redis数据存储结构类似哈希表结构,队列元素固定16384个,称之为槽。业务需求通常使用mysql结合redis进行边路缓存机制。

〇、redis的几种数据类型

       虽然数据类型有很多种,但是使用redis时一般key和value都直接使用Json格式的String类型存储。所以重点只看设置String类型的调用方法。

        String:

                set

                get

                setex  设置key存活时间

                setnx  锁

        Set

        Sorted Set

        Hash表

        List

        Stream



 一、 两种储存机制:RDB和AOF

                RDB:快照

                            rdb是redis默认的存储机制;

                            触发规则后将内存数据存储到硬盘的.rdb文件中:

                                        save 900 1
                                        save 300 10
                                        save 60 10000

                            这个规则是指每900秒内至少1次修改,每300s至少10次修改......

                            在意外情况发生时会丢失最后一次触发条件存储之后的所有内存数据          



               AOF:日志

                        aof默认关闭,当打开aof时,默认优先级比rdb高;

                        aof是指将redis执行的修改命令记录到硬盘的以.aof为后缀的日志文件中,redis服务异常关闭可以调用日志命令重新执行一遍,恢复到上一次redis数据库发生异常时的所有数据状态。

          

                        



二、spring框架整合redis

         0)redis项目结构

                        config目录 配置redis模板类对象

                        dao目录     封装对redis方法的调用

        1)添加依赖文件并在springBoot配置中修改redis的主机地址ip,端口号port默认6379

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.11</version>
    </parent>
    <dependencies>
        <!--redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!--redis启动器依赖-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
        </dependency>
    </dependencies>

        2)创建配置类RedisConfig

                2.0)redisTemplate对象

                        内部封装了序列化器对象,redis连接工厂对象。

                        调用此对象可以方便的操作redis中的数据

                2.1)  实现对redisTemplate对象下的序列化器对象配置

                  使用redis中直接存储数据是该数据二进制字节码,如果再直接获取该数据也是二进制字节码。

                  ​​​​​​​这里我不使用序列化器存储键值对

                 需要使用序列化器转换 :     

                          rediskey的序列化器通常使用StringRedisSerializer

                          redisValue的序列化器通常使用GenericJackson2JsonRedisSerializer

@Configuration
public class RedisConfig {

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate();

        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return  redisTemplate;
    }


        3)封装redis的调用函数接口RedisDao。

public interface RedisDao {
     <T>  void setObj(String key,T value);
     <T> void setObjAndTime(String key,T value, int expire, TimeUnit timeUnit);
     <T> boolean setIfAbsent(String key,T value);
     <T> boolean setIfAbsent(String key,T value, int expire, TimeUnit timeUnit);

     <T> T getObj(String key);

     boolean expire(String key,int expire, TimeUnit timeUnit);
     Long getExpire(String key);
     boolean delKey(String key);
     boolean exists(String key);
}


​​​​​​​   4)接口实现类RedisDaoImpl

@Repository
public class RedisDaoImpl implements RedisDao {
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public <T> void setObj(String key, T value) {
        redisTemplate.opsForValue().set(key,value);
    }

    @Override
    public <T> void setObjAndTime(String key, T value, int expire, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key,value,expire,timeUnit);
    }

    @Override
    public <T> boolean setIfAbsent(String key, T value) {
        return   redisTemplate.opsForValue().setIfAbsent(key,value);
    }

    @Override
    public <T> boolean setIfAbsent(String key, T value, int expire, TimeUnit timeUnit) {
        return redisTemplate.opsForValue().setIfAbsent(key,value,expire,timeUnit);
    }

    @Override
    public <T>T getObj(String key) {
        return (T) redisTemplate.opsForValue().get(key);
    }

    @Override
    public boolean expire(String key, int expire, TimeUnit timeUnit) {
        return redisTemplate.expire(key,expire,timeUnit);
    }

    @Override
    public Long getExpire(String key) {
        return redisTemplate.getExpire(key);
    }

    @Override
    public boolean delKey(String key) {
        return redisTemplate.delete(key);
    }

    @Override
    public boolean exists(String key) {
        return redisTemplate.hasKey(key);
    }
}

        5)测试一下 

 



三、主从复制

        一个主redis有多个从redis,每个从redis也可以作为主,也就是从也可以有从

        主具备写的能力;

        从只具备读的能力;



四、哨兵

          单哨兵:

                用来监视所有redis服务器是否正常运行,主噶了,哨兵 乒没有响应会直接将从变为主。                

                实际开发中会​​​​​​​配置多哨兵

 五常见redis问题

5.1 脑裂:

          有时候因为网络延时,哨兵没有及时接到 主服务器的 乓,造成主服务器假死,这时候需要用不同网段的多个哨兵共同监视。当哨兵检测到主死亡达到一定数量时,哨兵间会发起投票,切换主服务器。

   

5.2 缓存穿透

        访问不存在的数据,多次请求关系型数据库mysql而不是缓存数据库redis

5.3 缓存击穿

        访问数据有效期失效,多次请求关系型数据库mysql而不是缓存数据库redis

5.4 缓存雪崩

        访问数据大量失效,多次请求关系型数据库mysql而不是缓存数据库redis

5.5 边路缓存机制

        删除数据比更新数据简单和有效。

        先删除缓存,再更新缓存。避免出现还未更新的垃圾数据被其他人读到



 

六 Redis淘汰策略 :

        1)淘汰时机

                消极

                        读取数据时检测到过期的删除

                积极

                        周期性检测过期数据

                主动

                        内存不够,主动删除

        2)淘汰算法

                LRU

                        最近使用过的数据不容易删除

                LFU

                        没怎么访问的数据删除掉

               ​​​​​​​ FIFO​​​​​​​

                        先进先出

                        



七、在linux中模拟一个假集群

        1)创建模板文件

cd /usr/local

mkdir redis-cluster

cd redis-cluster

vim redis-cluster.tmpl

         2)粘贴模板文件信息,修改ip

 port ${PORT}
 # 设置外部网络连接redis服务
protected-mode no
# 开启集群
cluster-enabled yes
 # Redis群集节点每次发生更改时自动保留群集配置(基本上为状态)的文件
cluster-config-file nodes.conf
# 节点超时时间
cluster-node-timeout 5000
 # 当前IP地址
 cluster-announce-ip 192.168.146.130
 cluster-announce-port ${PORT}
 cluster-announce-bus-port 1${PORT}
# 持久化方式
 appendonly yes

         3)使用shell创建6个目录

for port in `seq 7000 7005`; do \
mkdir -p ./${port}/conf \
&& PORT=${port} envsubst < ./redis-cluster.tmpl > ./${port}/conf/redi
s.conf \
&& mkdir -p ./${port}/data; \
done

         4)创建桥接网路

docker network create redis-net

 docker network ls

         5)创建并启动6个容器

for port in `seq 7000 7005`; do \
 docker run -d -ti -p ${port}:${port} -p 1${port}:1${port} \
-v /usr/local/redis-cluster/${port}/conf/redis.conf:/usr/local/etc/re
dis/redis.conf \
 -v /usr/local/redis-cluster/${port}/data:/data \
 --name redis-${port} --net redis-net \
 --sysctl net.core.somaxconn=1024 redis:6.2.6 redis-server /usr/local/
etc/redis/redis.conf; \
 done

         6)查看容器信息

docker inspect redis-7000 redis-7001 redis-7002 redis-7003 redis-7004 r
edis-7005 | grep IPAddress

         7)创建集群

docker exec -it redis-7000 bash

 redis-cli --cluster create \
 172.18.0.2:7000 \
 172.18.0.3:7001 \
 172.18.0.4:7002 \
 172.18.0.5:7003 \
 172.18.0.6:7004 \
 172.18.0.7:7005 \
 --cluster-replicas 1

                8)进入集群

redis-cli -c -p 7000




网站公告

今日签到

点亮在社区的每一天
去签到