redis(基础)

目录

一、十大数据类型

(一)、redis键(keys)

(二)、String

1、set key value

2、getrange/setrange(获取指定区间内的值)

3、数值增减

4、获取字符串长度、字符串追加

5、分布式锁

6、getset

7、应用场景

(三)、list

1、常用

(四)、Hash

(五)、Set

(六)、Zset

(七)、Bitmap

(八)、HyperLogLog

(九)、GEO

(十)、Stream

(十一)、bitfield

二、持久化

(一)、RDB

1、触发RDB

(1)、自动触发

(2)、修改dump文件的保存路径

(3)、修改dump文件的名称

(4)、手动触发

(5)、禁用RDB

(二)、AOF

1、AOF缓冲区三种写回策略

2、开启

3、保存路径

 4、恢复

5、重写机制

(三)、RDB-AOF混合持久化

(四)、纯缓存模式

三、Redis事务

​编辑 1、常用命令

四、Reids管道

五、Redis发布订阅

六、Reids复制(replica)

(一)、概念

(二)、用法

(三)、配置

(四)、复制原理和工作流程

(五)、缺点

七、哨兵(sentinel)

(一)、配置

(二)、哨兵的运行流程和选举原理

八、集群(cluster)

(一)、槽位

(二)、分片

(三)、分片和槽位的优势

(四)、slot槽位映射

1、哈希取余分区

2、一致性哈希算法分区

(1)、一致性哈希环

(2)、节点映射

(3)、key落到服务器的落键规则

(4)、优点

(5)、缺点

3、哈希槽分区

(1)、定义

(2)、为什么redis最大槽数是16384

(3)、集群环境

九、SpringBoot整合Redis

(一)、Jedis

(二)、lettuce

(三)、RedisTemplate

1、单机

2、集群


一、十大数据类型

(一)、redis键(keys)

redis(基础)_第1张图片

redis(基础)_第2张图片

(二)、String

redis(基础)_第3张图片

redis(基础)_第4张图片

1、set key value

set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]

redis(基础)_第5张图片

2、getrange/setrange(获取指定区间内的值)

getrange:获取指定区间范围内的值,类似between......and的关系 获取[a,b]的值,类似与substring

setrange设置指定区间范围内的值,格式是setrange key值 具体值  从[a开始替换值

3、数值增减

redis(基础)_第6张图片

4、获取字符串长度、字符串追加

5、分布式锁

6、getset

先get在set

7、应用场景

(三)、list

底层是双端链表

1、常用

redis(基础)_第7张图片

redis(基础)_第8张图片

(四)、Hash

redis(基础)_第9张图片

redis(基础)_第10张图片

(五)、Set

redis(基础)_第11张图片

redis(基础)_第12张图片

(六)、Zset

redis(基础)_第13张图片

redis(基础)_第14张图片

redis(基础)_第15张图片

(七)、Bitmap

redis(基础)_第16张图片

(八)、HyperLogLog

redis(基础)_第17张图片

(九)、GEO

redis(基础)_第18张图片

(十)、Stream

redis(基础)_第19张图片

redis(基础)_第20张图片

(十一)、bitfield

redis(基础)_第21张图片

二、持久化

(一)、RDB

redis(基础)_第22张图片

redis7之后 

redis(基础)_第23张图片

1、触发RDB

(1)、自动触发

(2)、修改dump文件的保存路径

redis(基础)_第24张图片

(3)、修改dump文件的名称

redis(基础)_第25张图片

(4)、手动触发

redis(基础)_第26张图片

(5)、禁用RDB

或(推荐)

redis(基础)_第27张图片

(二)、AOF

1、AOF缓冲区三种写回策略

redis(基础)_第28张图片

默认everysec

2、开启

redis(基础)_第29张图片

3、保存路径

redis(基础)_第30张图片

/myredis/appendonlydir/xxx.aof

redis(基础)_第31张图片

redis(基础)_第32张图片

 4、恢复

redis(基础)_第33张图片

5、重写机制

重写原理

1:在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

2:与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有的AOF文件的可用性,避免在重写过程中出现意外。

3:当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中

4:当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中

5:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

redis(基础)_第34张图片

(三)、RDB-AOF混合持久化

redis(基础)_第35张图片

1 开启混合方式设置

设置aof-use-rdb-preamble的值为 yes   yes表示开启,设置为no表示禁用

2 RDB+AOF的混合方式---------> 结论:RDB镜像做全量持久化,AOF做增量持久化

先使用RDB进行快照存储,然后使用AOF持久化记录所有的写操作,当重写策略满足或手动触发重写的时候,将最新的数据存储为新的RDB记录。这样的话,重启服务的时候会从RDB和AOF两部分恢复数据,既保证了数据完整性,又提高了恢复数据的性能。简单来说:混合持久化方式产生的文件一部分是RDB格式,一部分是AOF格式。----》AOF包括了RDB头部+AOF混写

redis(基础)_第36张图片

(四)、纯缓存模式

redis(基础)_第37张图片

三、Redis事务

redis(基础)_第38张图片 1、常用命令

redis(基础)_第39张图片

redis(基础)_第40张图片

全体连坐:命令写错了(语法错误)

冤头债主:无语法错误(只有错的那条报错,它下面的命令仍然执行)

四、Reids管道

redis(基础)_第41张图片

redis(基础)_第42张图片

五、Redis发布订阅

redis(基础)_第43张图片

六、Reids复制(replica)

(一)、概念

(二)、用法

redis(基础)_第44张图片

(三)、配置

redis(基础)_第45张图片

(四)、复制原理和工作流程

redis(基础)_第46张图片

(五)、缺点

七、哨兵(sentinel)

(一)、配置

redis(基础)_第47张图片

sentinel down-after-milliseconds

指定多少毫秒之后,主节点没有应答哨兵,此时哨兵主观上认为主节点下线

 

sentinel parallel-syncs

表示允许并行同步的slave个数,当Master挂了后,哨兵会选出新的Master,此时,剩余的slave会向新的master发起同步数据

 

sentinel failover-timeout

故障转移的超时时间,进行故障转移时,如果超过设置的毫秒,表示故障转移失败

sentinel notification-script

配置当某一事件发生时所需要执行的脚本

 

sentinel client-reconfig-script

客户端重新配置主节点参数脚本

redis(基础)_第48张图片

(二)、哨兵的运行流程和选举原理

redis(基础)_第49张图片

redis(基础)_第50张图片

八、集群(cluster)

(一)、槽位

redis(基础)_第51张图片

(二)、分片

redis(基础)_第52张图片

(三)、分片和槽位的优势

(四)、slot槽位映射

1、哈希取余分区

redis(基础)_第53张图片

redis(基础)_第54张图片

2、一致性哈希算法分区

(1)、一致性哈希环

    一致性哈希算法必然有个hash函数并按照算法产生hash值,这个算法的所有可能哈希值会构成一个全量集,这个集合可以成为一个hash空间[0,2^32-1],这个是一个线性空间,但是在算法中,我们通过适当的逻辑控制将它首尾相连(0 = 2^32),这样让它逻辑上形成了一个环形空间。

 

   它也是按照使用取模的方法,前面笔记介绍的节点取模法是对节点(服务器)的数量进行取模而一致性Hash算法是对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希环如下图:整个空间按顺时针方向组织,圆环的正上方的点代表0,0点右侧的第一个点代表1,以此类推,2、3、4、……直到2^32-1,也就是说0点左侧的第一个点代表2^32-1, 0和2^32-1在零点中方向重合,我们把这个由2^32个点组成的圆环称为Hash环。

redis(基础)_第55张图片

(2)、节点映射

   将集群中各个IP节点映射到环上的某一个位置。

   将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置。假如4个节点NodeA、B、C、D,经过IP地址的哈希函数计算(hash(ip)),使用IP地址哈希后在环空间的位置如下:  

redis(基础)_第56张图片

(3)、key落到服务器的落键规则

当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。

如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

(4)、优点

(5)、缺点

Hash环的数据倾斜问题

一致性Hash算法在服务节点太少时,容易因为节点分布不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题,

例如系统中只有两台服务器:

 redis(基础)_第57张图片

3、哈希槽分区

(1)、定义

哈希槽实质就是一个数组,数组[0,2^14 -1]形成hash slot空间。

能干什么

解决均匀分配的问题,在数据和节点之间又加入了一层,把这层称为哈希槽(slot),用于管理数据和节点之间的关系,现在就相当于节点上放的是槽,槽里放的是数据。

redis(基础)_第58张图片

槽解决的是粒度问题,相当于把粒度变大了,这样便于数据移动。哈希解决的是映射问题,使用key的哈希值来计算所在的槽,便于数据分配

多少个hash槽

一个集群只能有16384个槽,编号0-16383(0-2^14-1)。这些槽会分配给集群中的所有主节点,分配策略没有要求。

集群会记录节点和槽的对应关系,解决了节点和槽的关系后,接下来就需要对key求哈希值,然后对16384取模,余数是几key就落入对应的槽里。HASH_SLOT = CRC16(key) mod 16384。以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

(2)、为什么redis最大槽数是16384

redis(基础)_第59张图片

(1)如果槽位为65536,发送心跳信息的消息头达8k,发送的心跳包过于庞大。

在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为65536时,这块的大小是: 65536÷8÷1024=8kb 

在消息头中最占空间的是myslots[CLUSTER_SLOTS/8]。 当槽位为16384时,这块的大小是: 16384÷8÷1024=2kb 

因为每秒钟,redis节点需要发送一定数量的ping消息作为心跳包,如果槽位为65536,这个ping消息的消息头太大了,浪费带宽。

 

(2)redis的集群主节点数量基本不可能超过1000个。

集群节点越多,心跳包的消息体内携带的数据越多。如果节点过1000个,也会导致网络拥堵。因此redis作者不建议redis cluster节点数量超过1000个。 那么,对于节点数在1000以内的redis cluster集群,16384个槽位够用了。没有必要拓展到65536个。

(3)槽位越小,节点少的情况下,压缩比高,容易传输

Redis主节点的配置信息中它所负责的哈希槽是通过一张bitmap的形式来保存的,在传输过程中会对bitmap进行压缩,但是如果bitmap的填充率slots / N很高的话(N表示节点数),bitmap的压缩率就很低。 如果节点数很少,而哈希槽数量很多的话,bitmap的压缩率就很低。 

(3)、集群环境

redis(基础)_第60张图片

节点从属关系调整

九、SpringBoot整合Redis

(一)、Jedis

引入依赖


        
            redis.clients
            jedis
            4.3.1
        
package com.example.redis7_study.demo;

import redis.clients.jedis.Jedis;

import java.util.List;
import java.util.Set;

public class JedisDemo {

    public static void main(String[] args) {

        //1 connection获得,通过指定ip和端口号
        Jedis jedis = new Jedis("192.168.146.134", 6379);
        //2 指定访问服务器的密码
        jedis.auth("123456");
        //3 获得jedis客户端,可以像JDBC一样访问redis
        System.out.println(jedis.ping());

        //keys
        Set keys = jedis.keys("*");
        System.out.println(keys);

        //string
        jedis.set("k4","hello-jedis");
        System.out.println(jedis.get("k3"));

        //list
        jedis.lpush("list","11","12","13");
        List list = jedis.lrange("list", 0, -1);
        for (String element : list) {
            System.out.println(element);
        }

    }
}

(二)、lettuce

依赖



    io.lettuce
    lettuce-core
    6.2.1.RELEASE
package com.example.redis7_study.demo;

import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

import java.util.List;

public class LettuceDemo {

    public static void main(String[] args) {

        //1 使用构建器链式编程来builder出RedisURI
        RedisURI uri = RedisURI.builder()
                .redis("192.168.146.134")
                .withPort(6379)
                .withAuthentication("default","123456")
                .build();

        //2 创建连接客户端
        RedisClient redisClient = RedisClient.create(uri);
        StatefulRedisConnection conn = redisClient.connect();

        //3 创建操作的command
        RedisCommands commands = conn.sync();

        //业务逻辑
        List keys = commands.keys("*");
        System.out.println(keys);

        //4 各种关闭释放资源
        conn.close();
        redisClient.shutdown();
    }
}

(三)、RedisTemplate

依赖


        
            org.springframework.boot
            spring-boot-starter-data-redis
        
        
            org.apache.commons
            commons-pool2
        
        
        
            io.springfox
            springfox-swagger2
            2.9.2
        
        
            io.springfox
            springfox-swagger-ui
            2.9.2
        

1、单机

便笺
package com.atguigu.redis7.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @auther zzyy
 * @create 2022-07-14 15:11
 */
@Service
@Slf4j
public class OrderService
{
    public static final String ORDER_KEY = "order:";

    @Resource
    private RedisTemplate redisTemplate;

    public void addOrder()
    {
        int keyId = ThreadLocalRandom.current().nextInt(1000)+1;
        String orderNo = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(ORDER_KEY+keyId,"京东订单"+ orderNo);
        log.info("=====>编号"+keyId+"的订单流水生成:{}",orderNo);
    }

    public String getOrderById(Integer id)
    {
        return (String)redisTemplate.opsForValue().get(ORDER_KEY + id);
    }
}

序列化问题 

redis(基础)_第61张图片

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @auther zzyy
 * @create 2022-11-17 17:34
 */
@Configuration
public class RedisConfig
{
    /**
     * redis序列化的工具配置类,下面这个请一定开启配置
     * 127.0.0.1:6379> keys *
     * 1) "ord:102"  序列化过
     * 2) "\xac\xed\x00\x05t\x00\aord:102"   野生,没有序列化过
     * this.redisTemplate.opsForValue(); //提供了操作string类型的所有方法
     * this.redisTemplate.opsForList(); // 提供了操作list类型的所有方法
     * this.redisTemplate.opsForSet(); //提供了操作set的所有方法
     * this.redisTemplate.opsForHash(); //提供了操作hash表的所有方法
     * this.redisTemplate.opsForZSet(); //提供了操作zset的所有方法
     * @param lettuceConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
    {
        RedisTemplate redisTemplate = new RedisTemplate<>();

        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        //设置key序列化方式string
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        //设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }
}


 

2、集群

配置文件

# ========================redis集群=====================
spring.redis.password=111111
# 获取失败 最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
#支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
#定时刷新
spring.redis.lettuce.cluster.refresh.period=2000
spring.redis.cluster.nodes=192.168.111.175:6381,192.168.111.175:6382,192.168.111.172:6383,192.168.111.172:6384,192.168.111.174:6385,192.168.111.174:6386

你可能感兴趣的:(redis,数据库,缓存)