Loading

Redis6

安装

源码安装Redis

#安装gcc
yum install -y gcc-c++ autoconf automake

#centos7 默认的 gcc 默认是4.8.5,版本小于 5.3 无法编译,需要先安装gcc新版才能编译
gcc -v

#升级新版gcc,配置永久生效
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils

scl enable devtoolset-9 bash  
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile 

#解压 + 重命名目录
tar -zxvf redis-6.0.8.tar.gz

mv redis-6.0.8 redis6

cd redis6

#编译redis 安装到指定目录
mkdir -p /usr/local/redis

make PREFIX=/usr/local/redis install

#创建目录
#- 日志 /usr/local/redis/log
#- 数据 /usr/local/redis/data
#- 配置文件 /usr/local/redis/conf/redis.conf

# 在redis目录下
mkdir -p ./conf/redis.conf

#在bin目录下,启动redis命令
./redis-server ../conf/redis.conf

bin目录下连接redis

./redis-cli -h host -p port -a password

host:远程redis服务器host

port:远程redis服务端口

password:远程redis服务密码(无密码的的话就不需要-a参数了)

数据结构

常用命令

官网:Redis命令中心(Redis commands) -- Redis中国用户组(CRUG)

exists:判断key是否存在
del:删除key
type:判断key类型
ttl:查看key存活时间

String

介绍
	存储字符串类型的key-value
命令
	set/get:设置和获取 key-value
	mset/mget:批量设置或获取多个key的值
		MGET key [key ...]
		MSET key value [key value ...]
	incr:incr对key对应的值进行加1操作,并返回新的值; 
		incr key
	incrby:将key对应的数字加increment。如果key不存在,操作之前,key就会被置为0
		incrby key increment
	setex:设置key对应字符串value,并且设置key在给定的seconds时间之后超时过期,原子操作
		SETEX key seconds value
	setnx:将key设置值为value,如key不存在等同SET命令。 key存在时什么也不做,  是set if not exists的简写。
		SETNX key value
	getset:设置key的值,返回key旧的值
		 GETSET KEY_NAME VALUE
注意
	值的长度不能超过512 MB
	key命名规范,不要过长,冒号分割,业务名:表名:ID

List

介绍
	字符串列表,按照插入顺序排序
	双向链表,插入删除时间复杂度O(1)快,查找为O(n)慢
命令
	lpush:将一个或多个值插入到列表头部
		LPUSH key value1 [value2] 
    lpop:从key对应的list的尾部删除一个元素,并返回该元素
    	LPOP key 	
    	
	rpush:在key对应的list的尾部添加一个元素
		RPUSH key value1 [value2] 
	rpop:移除并获取列表头部一个元素
		RPOP key 
	brpop:移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
		BRPOP LIST1 LIST2 .. LISTN TIMEOUT 
		
	llen:获取列表长度
		LLEN key
	lindex:通过索引获取列表中的元素
		LINDEX key index
	lrange:获取key对应的list的指定下标范围的元素, 0 表示头部第一个元素, 1 表示第二个元素,  -1表示获取所有元素( lrange key 0 -1);  
		LRANGE key start stop 
	lrem:移除元素,可以指定移除个数(LREM kk -2 'hello')
		LREM KEY COUNT VALUE
		案例:LREM test -2 'hello' ->test这个list中减去2和值为'hello'的元素
注意
	通常添加一个元素到列表的头部(左边)或者尾部(右边)
	存储的都是string字符串类型
	支持分页操作,高并发项目中,第一页数据都是来源list,第二页和更多信息则是通过数据库加载
	一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表不超过40亿个元素)

image-20220924171009579

Hash

介绍
	是一个string类型的field和value的映射表,hash特别适合用于存储对象
命令
	hset
		设置 key 指定的哈希集中指定字段的值
		HSET key field value
	hget	
		返回 key 指定的哈希集中该字段所关联的值
		HGET key field
	hgetall
		返回 key 指定的哈希集中所有的字段和值
		HGETALL key
	hdel
		从 key 指定的哈希集中移除指定的域
		HDEL key field [field ...]
	 hexists
		返回hash里面field是否存在
		HEXISTS key field
	hincrby
		增加 key 指定的哈希集中指定字段的数值,  如果是-1 则是递减
		HINCRBY key field increment
	hmset
		设置 key 指定的哈希集中指定字段的值
		HMSET key field value [field value ...]
	hmget
		返回 key 指定的哈希集中指定字段的值
		HMGET key field [field ...]
注意
	每个 hash 可以存储 232 - 1 键值对(40多亿)

image-20220924172424322

Set

介绍
	将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略
应用场景
	去重
	社交应用关注、粉丝、共同好友
	统计网站的PV、UV、IP
	大数据里面的用户画像标签集合
常用命令
	sadd
		添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略
		SADD key member [member ...]
	scard
		返回集合存储的key的基数 (集合元素的数量).
		SCARD key
	sdiff
		返回的集合元素是第一个key的集合与后面所有key的集合的差集
		SDIFF key [key ...]
	sinter
		返回指定所有的集合的成员的交集.
		SINTER key [key ...]
	sismember
		返回成员 member 是否是存储的集合 key的成员.
		SISMEMBER key member
	srem
		在key集合中移除指定的元素. 如果指定的元素不是key集合中的元素则忽略
		SREM key member [member ...]
	sunion
		返回给定的多个集合的并集中的所有成员.
		SUNION key [key ...]
	smembers
		返回key集合所有的元素.		
		SMEMBERS key
注意
	集合是通过哈希表实现的

Sorted Set

介绍
	用于将一个或多个成员元素及其分数值加入到有序集当中
	如果某个成员已经是有序集的成员,那么更新这个成员的分数值,分数值可以是整数值或双精度浮点数。
	有序集合可以看做是在Set集合的的基础上为集合中的每个元素维护了一个顺序值: score,它允许集合中的元素可以按照score进行排序
应用场景
	实时排行榜:商品热销榜、体育类应用热门球队、积分榜
	优先级任务、队列
	朋友圈 文章点赞-取消,逻辑:用户只能点赞或取消,统计一篇文章被点赞了多少次,可以直接取里面有多少个成员
常用命令
	zadd
		向有序集合添加一个或多个成员,或者更新已存在成员的分数
		ZADD key score1 member1 [score2 member2]
	zcard
		获取有序集合的成员数
		ZCARD key
	zcount
		计算在有序集合中指定区间分数的成员数
		ZCOUNT key min max
	zincrby
		ZINCRBY key increment member
		有序集合中对指定成员的分数加上增量 increment
	zrange
		通过索引区间返回有序集合指定区间内的成员, 成员的位置按分数值递增(从小到大)来排序
		ZRANGE key start stop [WITHSCORES]
	zrevrange
		通过索引区间返回有序集合指定区间内的成员, 成员的位置按分数值递增(从大到小)来排序
		ZREVRANGE key start stop [WITHSCORES]
	zrevrank
		返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
		ZREVRANK key member
	zrank
		返回有序集key中成员member的排名。其中有序集成员按score值递增(从小到大)z
		ZRANK key member
	zrem
		移除有序集合中的一个或多个成员
		ZREM key member [member ...]
	zscore
		返回有序集中,成员的分数值
		ZSCORE key member
注意
	底层使用到了Ziplist压缩列表和“跳跃表”两种存储结构
	如果重复添加相同的数据,score值将被反复覆盖,保留最后一次修改的结果

Springboot整合

jedis

Jedis 是直连模式,在多个线程间共享一个 Jedis 实例时是线程不安全的,需要使用连接池

其API提供了比较全面的Redis命令的支持,相比于其他Redis 封装框架更加原生

Jedis中的方法调用是比较底层的暴露的Redis的API,Java方法基本和Redis的API保持着一致

使用阻塞的I/O,方法调用同步,程序流需要等到socket处理完I/O才能执行,不支持异步操作

lettuce

高级Redis客户端,用于线程安全同步,异步响应

基于Netty的的事件驱动,可以在多个线程间并发访问, 通过异步的方式可以更好的利用系统资源

添加依赖 spring-boot-starter-data-redis

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

注意

  • Springboot2后默认使用Lettuce作为访问redis的客户端

RedisTemplate

  • RedisTemplate介绍

    • ValueOperations:简单K-V操作
    • SetOperations:set类型数据操作
    • ZSetOperations:zset类型数据操作
    • HashOperations:针对map类型的数据操作
    • ListOperations:list类型的数据操作
  • RedisTemplate和StringRedisTemplate的区别

    • StringRedisTemplate继承RedisTemplate
    • 两者的数据是不共通的(默认的序列化机制导致key不一样)
    • StringRedisTemplate默认采用的是String的序列化策略
    • RedisTemplate默认采用的是JDK的序列化策略,会将数据先序列化成字节数组然后在存入Redis数据库
    • 总结
      • 当redis数据库里面本来操作的是字符串数据的时候,那使用StringRedisTemplate即可
      • 数据是复杂的对象类型,那么使用RedisTemplate是更好的选择

SpringCache

  • SpringCache简介

    • 文档:https://spring.io/guides/gs/caching/
    • 自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象
    • 提供基本的Cache抽象,方便切换各种底层Cache
    • 只需要更少的代码就可以完成业务数据的缓存
    • 提供事务回滚时也自动回滚缓存,支持比较复杂的缓存逻辑
    • 核心
      • 一个是Cache接口,缓存操作的API;
      • 一个是CacheManager管理各类缓存,有多个缓存框架的实现
  • 使用

    • 项目中引入starter
    <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    
    • 配置文件指定缓存类型
    spring:
      cache:
        type: redis
    
    • 启动类开启缓存注解
    @EnableCaching
    

Cacheable

  • 标记在一个方法上,也可以标记在一个类上
  • 缓存标注对象的返回结果,标注在方法上缓存该方法的返回值,标注在类上缓存该类所有的方法返回值
  • value 缓存名称,可以有多个
  • key 缓存的key规则,可以用springEL表达式,默认是方法参数组合
  • condition 缓存条件,使用springEL编写,返回true才缓存
  • 案例
//对象
@Cacheable(value = {"product"}, key="#root.methodName")

//分页
@Cacheable(value = {"product_page"},key="#root.methodName + #page+'_'+#size")
  • spEL表达式
    • methodName 当前被调用的方法名
      • root.methodname
    • args 当前被调用的方法的参数列表
      • root.args[0]
    • result 方法执行后的返回值
      • result

CacheManger

  • 修改redis缓存序列化器和配置manager过期时间
@Bean
@Primary
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory) {
    RedisCacheConfiguration config = instanceConfig(3600L);
    return RedisCacheManager.builder(connectionFactory)
        .cacheDefaults(config)
        .transactionAware()
        .build();
}

@Bean
public RedisCacheManager cacheManager1Day(RedisConnectionFactory connectionFactory) {
    RedisCacheConfiguration config = instanceConfig(3600 * 24L);
    return RedisCacheManager.builder(connectionFactory)
        .cacheDefaults(config)
        .transactionAware()
        .build();
}

private RedisCacheConfiguration instanceConfig(Long ttl) {
    Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    objectMapper.registerModule(new JavaTimeModule());
    // 去掉各种@JsonSerialize注解的解析
    objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
    // 只针对非空的值进行序列化
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    // 将类型序列化到属性json字符串中
    objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
                                       ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

    jackson2JsonRedisSerializer.setObjectMapper(objectMapper);

    return RedisCacheConfiguration.defaultCacheConfig()
        .entryTtl(Duration.ofSeconds(ttl))
        .disableCachingNullValues()
        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));

}

KeyGenerator

  • Key规则定义麻烦,支持自定规则
  • 实战
@Bean
public KeyGenerator springCacheDefaultKeyGenerator(){

    return new KeyGenerator() {
        @Override
        public Object generate(Object o, Method method, Object... objects) {
            return o.getClass().getSimpleName() + "_"
                + method.getName() + "_"
                + StringUtils.arrayToDelimitedString(objects, "_");
        }
    };

}
  • 使用
    • key 属性和keyGenerator属性只能二选一
@Cacheable(value = {"product"},keyGenerator = "springCacheCustomKeyGenerator", cacheManager = "cacheManager1Minute")

CachePut

  • 根据方法的请求参数对其结果进行缓存,每次都会触发真实方法的调用

  • value 缓存名称,可以有多个

  • key 缓存的key规则,可以用springEL表达式,默认是方法参数组合

  • condition 缓存条件,使用springEL编写,返回true才缓存

  • 案例实战

@CachePut(value = {"product"},key = "#productDO.id")

CacheEvict

  • 从缓存中移除相应数据, 触发缓存删除的操作

  • value 缓存名称,可以有多个

  • key 缓存的key规则,可以用springEL表达式,默认是方法参数组合

  • beforeInvocation = false

    • 缓存的清除是否在方法之前执行 ,默认代表缓存清除操作是在方法执行之后执行;

    • 如果出现异常缓存就不会清除

    • beforeInvocation = true

      • 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
  • 案例实战

@CacheEvict(value = {"product"},key = "#root.args[0]")

Caching

  • 组合多个Cache注解使用
  • 允许在同一方法上使用多个嵌套的@Cacheable、@CachePut和@CacheEvict注释
  • 实战
@Caching(
    cacheable = {
        @Cacheable(value = "product",keyGenerator = "xdclassKeyGenerator")
    },
    put = {
        @CachePut(value = "product",key = "#id"),
        @CachePut(value = "product",key = "'stock:'+#id")
    }
)

Redis6高级

持久化配置

RDB(Redis DataBase))

简介: Redis6.x持久化配置介绍和RDB讲解

  • Redis持久化介绍

    • Redis是一个内存数据库,如果没有配置持久化,redis重启后数据就全丢失
    • 因此开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。
  • 两种持久化方式

    • RDB (Redis DataBase)
    • AOF (append only file)
  • RDB持久化介绍

    • 在指定的时间间隔内将内存中的数据集快照写入磁盘
    • 默认的文件名为dump.rdb
    • 产生快照的情况
      • save
        • 会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止
      • bgsave
        • fork创建子进程,RDB持久化过程由子进程负责,会在后台异步进行快照操作,快照同时还可以响应客户端请求
      • 自动化
        • 配置文件来完成,配置触发 Redis的 RDB 持久化条件
        • 比如 "save m n"。表示m秒内数据集存在n次修改时,自动触发bgsave
      • 主从架构
        • 从服务器同步数据的时候,会发送sync执行同步操作,master主服务器就会执行bgsave
  • 优点

    • RDB文件紧凑,全量备份,适合用于进行备份和灾难恢复
    • 在恢复大数据集时的速度比 AOF 的恢复速度要快
    • 生成的是一个紧凑压缩的二进制文件
  • 缺点

    • 每次快照是一次全量备份,fork子进程进行后台操作,子进程存在开销
    • 在快照持久化期间修改的数据不会被保存,可能丢失数据
  • redis.conf 配置项

    • daemonize yes 配置后台运行,默认no
    • bind 绑定指定ip访问,0.0.0.0是不限制,配置多个ip例子 12.13.432.12 31.12.43.13 用空格隔开
    • port 端口号 默认6379
    • requirepass 密码配置
    • dbfilename 配置redis持久化文件名称
    • dir 配置redis持久化文件存储地址
    • save 配置redis持久化机制
#任何ip可以访问
bind 0.0.0.0

#守护进程
daemonize yes

#密码
requirepass 123456

#日志文件
logfile "/usr/local/redis/log/redis.log"

#持久化文件名称
dbfilename xdclass.rdb

#持久化文件存储路径
dir /usr/local/redis/data

#持久化策略, 10秒内有个1个key改动,执行快照
save 10 1

######之前配置######

#导出rdb数据库文件压缩字符串和对象,默认是yes,会浪费CPU但是节省空间
rdbcompression yes
# 导入时是否检查
rdbchecksum yes
  • 备注: linux内存分配策略
0 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程

1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
2 表示内核允许分配超过所有物理内存和交换空间总和的内存

解决方式
echo 1 > /proc/sys/vm/overcommit_memory


持久化配置
vim /etc/sysctl.conf

改为
vm.overcommit_memory=1
修改sysctl.conf后,需要执行 sysctl -p 以使生效。

image-20221002103600414

AOF(append only file)

  • AOF持久化介绍

    • append only file,追加文件的方式,文件容易被人读懂
    • 以独立日志的方式记录每次写命令, 重启时再重新执行AOF文件中的命令达到恢复数据的目的
    • 写入过程宕机,也不影响之前的数据,可以通过 redis-check-aof检查修复问题
  • 配置实战

    • appendonly yes,默认不开启
    • AOF文件名 通过 appendfilename 配置设置,默认文件名是appendonly.aof
    • 存储路径同 RDB持久化方式一致,使用dir配置
  • 核心原理

    • Redis每次写入命令会追加到aof_buf(缓冲区)
    • AOF缓冲区根据对应的策略向硬盘做同步操作
    • 高频AOF会带来影响,特别是每次刷盘
  • 提供了3种同步方式,在性能和安全性方面做出平衡

    • appendfsync always
      • 每次有数据修改发生时都会写入AOF文件,消耗性能多
    • appendfsync everysec
      • 每秒钟同步一次,该策略为AOF的缺省策略。
    • appendfsync no
      • 不主从同步,由操作系统自动调度刷磁盘,性能是最好的,但是最不安全
bind 0.0.0.0

daemonize yes

requirepass 123456Xdclass

logfile "/usr/local/redis/log/redis.log"

dbfilename xdclass.rdb

dir /usr/local/redis/data

#save 10 2
#save 100 5
save ""
rdbcompression yes
#对rdb数据进行校验,耗费CPU资源,默认为yes
rdbchecksum yes

appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
  • rewrite 重写介绍

    • AOF文件越来越大,需要定期对AOF文件进行重写达到压缩
    • 旧的AOF文件含有无效命令会被忽略,保留最新的数据命令
    • 多条写命令可以合并为一个
    • AOF重写降低了文件占用空间
    • 更小的AOF 文件可以更快地被Redis加载
  • 重写触发配置

    • 手动触发
      • 直接调用bgrewriteaof命令
    • 自动触发
      • auto-aof-rewrite-min-size和auto-aof-rewrite-percentage参数
      • auto-aof-rewrite-min-size
        • 表示运行AOF重写时文件最小体积,默认 为64MB。
      • auto-aof-rewrite-percentage
        • 代表当前AOF文件空间和上一次重写后AOF文件空间(aof_base_size)的比值。
    # 是否开启aof
    appendonly yes
    
    # 文件名称
    appendfilename "appendonly.aof"
    
    # 同步方式
    appendfsync everysec
    
    # aof重写期间是否同步
    no-appendfsync-on-rewrite no
    
    # 重写触发配置
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
    # 加载aof时如果有错如何处理
    # yes表示如果aof尾部文件出问题,写log记录并继续执行。no表示提示写入等待修复后写入
    aof-load-truncated yes 
    

RDB AOF 选择与优缺点

  • RDB的优缺点

    • 优点:
      • RDB最大限度地提高了Redis的性能,父进程不需要参与磁盘I/O
      • RDB文件紧凑,全量备份,适合用于进行备份和灾难恢复
      • 在恢复大数据集时的速度比 AOF 的恢复速度要快
      • 生成的是一个紧凑压缩的二进制文件
    • 缺点:
      • 如果您需要在Redis停止工作时(例如断电后)将数据丢失的可能性降至最低,则RDB并不好
      • RDB经常需要fork才能使用子进程持久存储在磁盘上。如果数据集很大,Fork可能会非常耗时
  • AOF的优缺点

    • 优点:
      • 数据更加安全
      • 当Redis AOF文件太大时,Redis能够在后台自动重写AOF
      • AOF以易于理解和解析的格式,一个接一个地包含所有操作的日志
    • 缺点:
      • AOF文件通常比同一数据集的等效RDB文件大
      • 根据确切的fsync策略,恢复的时候AOF可能比RDB慢
  • 在线上我们到底该怎么做?

    • RDB持久化与AOF持久化一起使用
    • 如果Redis中的数据并不是特别敏感或者可以通过其它方式重写生成数据
    • 集群中可以关闭AOF持久化,靠集群的备份方式保证可用性
    • 自己制定策略定期检查Redis的情况,然后可以手动触发备份、重写数据;
    • 采用集群和主从同步
  • Redis4.0后开始的rewrite支持混合模式

    • 就是rdb和aof一起用
    • 直接将rdb持久化的方式来操作将二进制内容覆盖到aof文件中,rdb是二进制,所以很小
    • 有写入的话还是继续append追加到文件原始命令,等下次文件过大的时候再次rewrite
    • 默认是开启状态
    • 好处
      • 混合持久化结合了RDB持久化 和 AOF 持久化的优点,采取了rdb的文件小易于灾难恢复
      • 同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失
    • 坏处
      • 前部分是RDB格式,是二进制,所以阅读性较差
    • 数据恢复
      • 先看是否存在aof文件,若存在则先按照aof文件恢复,aof比rdb全,且aof文件也rewrite成rdb二进制格式
      • 若aof不存在,则才会查找rdb是否存在

info+config

服务端配置info命令介绍

  • 服务器的各种信息和统计数值
Server:有关redis服务器的常规信息
  redis_mode:standalone                         # 运行模式,单机或者集群
  multiplexing_api:epoll                        # redis所使用的事件处理机制
  run_id:3abd26c33dfd059e87a0279defc4c96c13962ede # redis服务器的随机标识符(用于sentinel和集群)
  config_file:/usr/local/redis/conf/redis.conf       # 配置文件路径

Clients:客户端连接部分
  connected_clients:10           # 已连接客户端的数量(不包括通过slave连接的客户端)
  
Memory:内存消耗相关信息
  used_memory:874152  # 使用内存,以字节(byte)B为单位
  used_memory_human:853.66K # 以人类可读的格式返回 Redis 分配的内存总量
  used_memory_rss:2834432 # 系统给redis分配的内存即常驻内存,和top 、 ps 等命令的输出一致
  used_memory_rss_human:2.70M  # 以人类可读的格式返回系统redis分配的常驻内存top、ps等命令的输出一致
  used_memory_peak:934040  # 内存使用的峰值大小
  used_memory_peak_human:912.15K

  total_system_memory:1039048704  # 操作系统的总内存 ,以字节(byte)为单位
  total_system_memory_human:990.91M 
  used_memory_lua:37888  # lua引擎使用的内存
  used_memory_lua_human:37.00K

  maxmemory:0  # 最大内存的配置值,0是不限制
  maxmemory_human:0B  
  maxmemory_policy:noeviction  # 达到最大内存配置值后的策略
  
Persistence:RDB和AOF相关信息
  rdb_bgsave_in_progress:0   # 标识rdb save是否进行中
  rdb_last_bgsave_status:ok        # 上次的save操作状态
  rdb_last_bgsave_status:ok        # 上次的save操作状态
  rdb_last_bgsave_time_sec:-1        # 上次rdb save操作使用的时间(单位s)
  rdb_current_bgsave_time_sec:-1    # 如果rdb save操作正在进行,则是所使用的时间

  aof_enabled:1                    # 是否开启aof,默认没开启
  aof_rewrite_in_progress:0        # 标识aof的rewrite操作是否在进行中
  aof_last_rewrite_time_sec:-1    # 上次rewrite操作使用的时间(单位s)
  aof_current_rewrite_time_sec:-1 # 如果rewrite操作正在进行,则记录所使用的时间
  aof_last_bgrewrite_status:ok    # 上次rewrite操作的状态
  aof_current_size:0                # aof当前大小


Stats:一般统计
  evicted_keys:0                    # 因为内存大小限制,而被驱逐出去的键的个数


Replication:主从同步信息
  role:master                        # 角色
  connected_slaves:1                # 连接的从库数
  master_sync_in_progress:0        # 标识主redis正在同步到从redis


CPU:CPU消耗统计

Cluster:集群部分
  cluster_enabled:0  # 实例是否启用集群模式

Keyspace:数据库相关统计
  db0:keys=4,expires=0,avg_ttl=0  # db0的key的数量,带有生存期的key的数,平均存活时间

服务端配置config命令介绍

  • config命令介绍(都有默认值)
    • 可以动态地调整 Redis 服务器的配置(configuration)而无须重启
    • config get xxx、config set xxx
  • 常用配置
daemonize  #后端运行
bind #ip绑定
timeout  #客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接

databases #设置数据库的个数,可以使用 SELECT 命令来切换数据库。默认使用的数据库是 0
save  #设置 Redis 进行rdb持久化数据库镜像的频率。
rdbcompression #在进行镜像备份时,是否进行压缩

slaveof #设置该数据库为其他数据库的从数据库
masterauth  #当主数据库连接需要密码验证时,在这里配置

maxclients  #限制同时连接的客户数量,当连接数超过这个值时,redis 将不再接收其他连接请求,返回error

maxmemory  #设置 redis 能够使用的最大内存,
  • maxmemory #设置 redis 能够使用的最大内存,

  • 备注

    • 防止所用内存超过服务器物理内存, maxmemory限制的是Redis实际使用的内存量, 也就是used_memory统计项对应的内存
    • 由于内存碎片率的存在, 实际消耗的内存可能会比maxmemory设置的更大, 实际使用时要小心这部分内存溢出
    • 默认无限使用服务器内存, 为防止极端情况下导致系统内存耗尽, 建议所有的Redis进程都要配置maxmemory
    • 在64bit系统下,maxmemory设置为0表示不限制Redis内存使用,在32bit系统下,maxmemory不能超过3GB
  • 注意:

    • redis在占用的内存超过指定的maxmemory之后,通过maxmemory_policy确定redis是否释放内存以及如何释放内存

主从复制读写分离

读写分离介绍

  • 背景

    • 单机部署简单,但是可靠性低,且不能很好利用CPU多核处理能力
    • 生产环境-必须要保证高可用-一般不可能单机部署
    • 读写分离是可用性要求不高、性能要求较高、数据规模小的情况;
  • 目标

    • 读写分离,扩展主节点的读能力,分担主节点读压力
    • 容灾恢复,一旦主节点宕机,从节点作为主节点的备份可以随时顶上来
  • Redis主从架构介绍

配置文件,redis1.conf

bind 0.0.0.0
port 6379
daemonize yes
requirepass "123456"

logfile "/usr/local/redis/log/redis1.log"
dbfilename "xdclass1.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly1.aof"
masterauth "123456"

redis2.conf

bind 0.0.0.0
port 6380
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis2.log"
dbfilename "xdclass2.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly2.aof"
replicaof 203.189.210.168 6379
masterauth "123456"

redis3.conf

bind 0.0.0.0
port 6381
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis3.log"
dbfilename "xdclass3.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly3.aof"
replicaof 203.189.210.168 6379
masterauth "123456"

启动

#启动主
./redis-server /usr/local/redis/conf/redis1.conf

#启动从
./redis-server /usr/local/redis/conf/redis2.conf

#启动从
./redis-server /usr/local/redis/conf/redis2.conf

Redis6.X主从复制-读写分离原理解析

  • 主从复制分两种(主从刚连接的时候,进行全量同步;全同步结束后,进行增量同步)

    • 全量复制
      • master服务器会开启一个后台进程用于将redis中的数据生成一个rdb文件
      • 主服务器会缓存所有接收到的来自客户端的写命令,当后台保存进程 处理完毕后,会将该rdb文件传递给slave服务器
      • slave服务器会将rdb文件保存在磁盘并通过读取该文件将数据加载到内存
      • 在此之后master服务器会将在此期间缓存的命令通过redis传输协议发送给slave服务器
      • 然后slave服务器将这些命令依次作用于自己本地的数据集上最终达到数据的一致性
    • 增量复制
      • Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程
      • 服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令
  • 特点

    • 主从复制对于 主/从 redis服务器来说是非阻塞的,所以同步期间都可以正常处理外界请求
    • 一个主redis可以含有多个从redis,每个从redis可以接收来自其他从redis服务器的连接
    • 从节点不会让key过期,而是主节点的key过期删除后,成为del命令传输到从节点进行删除
      • 从节点开启 sync 看日志
  • 加速复制

    • 完全重新同步需要在磁盘上创建一个RDB文件,然后加载这个文件以便为从服务器发送数据
    • 在比较低速的磁盘,这种操作会给主服务器带来较大的压力
    • 新版支持无磁盘的复制,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储
    • repl-diskless-sync yes (默认是no)
  • 主从断开重连

    • 如果遭遇连接断开,重新连接之后可以从中断处继续进行复制,而不必重新同步
    • 2.8版本后 部分重新同步这个新特性内部使用PSYNC命令,旧的实现中使用SYNC命令

Sentinel

Redis6.X节点高可用监控之Sentinel介绍

  • 背景

  • 前面搭建了主从,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,人工干预费事费力,还会造成一段时间内服务不可用

  • 哨兵模式介绍

    • Redis提供了哨兵的命令,是一个独立的进程
    • 原理 哨兵通过发送命令给多个节点,等待Redis服务器响应,从而监控运行的多个Redis实例的运行情况
    • 当哨兵监测到master宕机,会自动将slave切换成master,通过通知其他的从服务器,修改配置文件切换主机
  • Sentinel三大工作任务

    • 监控(Monitoring)
      • Sentinel 会不断地检查你的主服务器和从服务器是否运作正常
    • 提醒(Notification)
      • 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知
    • 自动故障迁移(Automatic failover)
      • 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器
      • 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器
  • 问题

    • 一个哨兵进程对Redis服务器进行监控,可能会出现问题
    • 一般是使用多个哨兵进行监控,各个哨兵之间还会进行监控,形成多哨兵模式
  • 多哨兵模式下线名称介绍

    • 主观下线(Subjectively Down, 简称 SDOWN)

      • 是单个 Sentinel 实例对服务器做出的下线判断,比如网络问题接收不到通知等
      • 一个服务器没有在 down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线
    • 客观下线(Objectively Down, 简称 ODOWN)

      • 指的是多个 Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断
      • 一个 Sentinel 可以通过向另一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线
      • 客观下线条件只适用于主服务器
    • 仲裁 qurum

      • Sentinel 在给定的时间范围内, 从其他 Sentinel 那里接收到了【足够数量】的主服务器下线报告, 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线
      • 这个【足够数量】就是配置文件里面的值,一般是Sentinel个数的一半加1,比如3个Sentinel则就设置为2
      • down-after-milliseconds 是一个哨兵在超过规定时间依旧没有得到响应后,会自己认为主机不可用
      • 当拥有认为主观下线的哨兵达到sentinel monitor所配置的数量时,就会发起一次投票,进行failover
    • 优点

      • 主从可以自动切换,可用性更高
    • 缺点

      • 主从切换会丢失短暂数据
      • 主节点的写能力和存储能力受限

Sentinel哨兵搭建环境准备

  • 核心流程
    • 每秒ping,超过时间不响应 则认为主观下线
    • 满足多个,则认为是客观下线
    • 投票选择主节点
    • 如果没有足够的节点同意master下线,则状态会被移除
  • 环境准备
    • 配置3个哨兵,每个哨兵的配置都是一样的
    • 启动顺序 先启动主再启动从,最后启动3个哨兵
    • 哨兵端口是 【26379】记得开放
#不限制ip
bind 0.0.0.0

# 让sentinel服务后台运行
daemonize yes

# 配置监听的主服务器,mymaster代表服务器的名称,自定义,172.18.172.109 代表监控的主服务器,6379代表端口,
#2代表只有两个或两个以上的哨兵认为主服务器不可用的时候,才会进行failover操作。
sentinel monitor mymaster 172.18.172.109 6379 2

# sentinel auth-pass定义服务的密码,mymaster是服务名称,123456是Redis服务器密码
sentinel auth-pass mymaster 123456

#超过5秒master还没有连接上,则认为master已经停止
sentinel down-after-milliseconds mymaster 5000

#如果该时间内没完成failover操作,则认为本次failover失败
sentinel failover-timeout mymaster 30000

sentinel-1.conf

port 26379
bind 0.0.0.0
daemonize yes
pidfile "/usr/local/redis/run/redis-sentinel-1.pid"
logfile "/usr/local/redis/log/sentinel_26379.log"
dir "/usr/local/redis/data"
sentinel monitor mymaster 203.189.210.168 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel auth-pass mymaster 123456
sentinel failover-timeout mymaster 30000

sentinel-2.conf

port 26380
bind 0.0.0.0
daemonize yes
pidfile "/usr/local/redis/run/redis-sentinel-1.pid"
logfile "/usr/local/redis/log/sentinel_26380.log"
dir "/usr/local/redis/data"
sentinel monitor mymaster 203.189.210.168 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel auth-pass mymaster 123456
sentinel failover-timeout mymaster 30000

sentinel-3.conf

port 26381
bind 0.0.0.0
daemonize yes
pidfile "/usr/local/redis/run/redis-sentinel-1.pid"
logfile "/usr/local/redis/log/sentinel_26381.log"
dir "/usr/local/redis/data"
sentinel monitor mymaster 203.189.210.168 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel auth-pass mymaster 123456
sentinel failover-timeout mymaster 30000

启动哨兵集群

./redis-server /usr/local/redis/conf/sentinel-1.conf --sentinel

./redis-server /usr/local/redis/conf/sentinel-2.conf --sentinel

./redis-server /usr/local/redis/conf/sentinel-3.conf --sentinel

springBoot整合Redis主从+Sentinel哨兵

  • 注释掉 host和port
  • 新增配置
sentinel:
    master: mymaster
    nodes: 203.189.210.168:26379,203.189.210.168:26380,203.189.210.168:26381

集群和分片

Cluster集群

  • 背景
    • Sentinel解决了主从架构故障自动迁移的问题
    • 但是Master主节点的写能力和存储能力依旧受限
    • 使用Redis的集群cluster就是为了解决单机Redis容量有限的问题,将数据按一定的规则分配到多台机器
  • Redis集群模式介绍
    • Cluster模式是Redis3.0开始推出
    • 采用无中心结构,每个节点保存数据和整个集群状态, 每个节点都和其他所有节点连接
    • 官方要求:至少6个节点才可以保证高可用,即3主3从;扩展性强、更好做到高可用
    • 各个节点会互相通信,采用gossip协议交换节点元数据信息
    • 数据分散存储到各个节点上

image-20221003090240255

Cluster数据分片和虚拟哈希槽

  • 背景

    • 主节点的写能力和存储能力受限
    • 单台机器无法满足需求,因此把数据分散存储到多个机器
    • 类似案例:mysql分库分表

    image-20210420113524874

  • 常见的数据分区算法

    • 哈希取模
      • 对选择的 partitioning key 计算其哈希值,得到的哈希值就是对应的分区
    • 范围分片
      • 通过确定分区键是否在某个范围内来选择分区
    • 一致性Hash分区
    • redis cluster集群没有采用一致性哈希方案,而是采用【数据分片】中的哈希槽来进行数据存储与读取的
  • 什么是Redis的哈希槽 slot

    • Redis集群预分好16384个槽,当需要在 Redis 集群中放置一个 key-value 时,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中
  • 大体流程

    • 假设主节点的数量为3,将16384个槽位按照【用户自己的规则】去分配这3个节点,每个节点复制一部分槽位
      • 节点1的槽位区间范围为0-5460
      • 节点2的槽位区间范围为5461-10922
      • 节点3的槽位区间范围为10923-16383
      • 注意:从节点是没有槽位的,只有主节点才有
    • 存储查找
      • 对要存储查找的键进行crc16哈希运算,得到一个值,并取模16384,判断这个值在哪个节点的范围区间
      • 假设crc16("test_key")%16384=3000,就是节点一
      • crc16算法不是简单的hash算法,是一种校验算法

image-20221003090405616

  • 使用哈希槽的好处就在于可以方便的添加或移除节点。
    • 当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
    • 当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了

Cluster集群环境准备

  • 说明
    • 旧版本的需要使用ruby语言进行构建,新版5之后直接用redis-cli即可
    • 6个节点,三主双从,主从节点会自动分配,不是人工指定
    • 主节点故障后,从节点会替换主节点
  • 注意点:
    • 把之前的rdb、aof文件删除
  • 配置
bind 0.0.0.0
port 6381
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis1.log"
dbfilename "xdclass1.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly1.aof"
masterauth "123456"

#是否开启集群
cluster-enabled yes

# 生成的node文件,记录集群节点信息,默认为nodes.conf,防止冲突,改为nodes-6381.conf
cluster-config-file nodes-6381.conf

#节点连接超时时间
cluster-node-timeout 20000

#集群节点的ip,当前节点的ip
cluster-announce-ip 172.18.172.109

#集群节点映射端口
cluster-announce-port 6381

#集群节点总线端口,节点之间互相通信,常规端口+1万
cluster-announce-bus-port 16381

cluster/redis1.conf...redis6.conf

bind 0.0.0.0
port 6381
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis1.log"
dbfilename "xdclass1.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly1.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6381.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6381
cluster-announce-bus-port 16381
bind 0.0.0.0
port 6382
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis2.log"
dbfilename "xdclass2.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly2.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6382.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6382
cluster-announce-bus-port 16382
bind 0.0.0.0
port 6383
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis3.log"
dbfilename "xdclass3.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly3.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6383.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6383
cluster-announce-bus-port 16383
bind 0.0.0.0
port 6384
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis4.log"
dbfilename "xdclass4.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly4.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6384.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6384
cluster-announce-bus-port 16384
bind 0.0.0.0
port 6385
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis5.log"
dbfilename "xdclass5.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly5.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6385.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6385
cluster-announce-bus-port 16385
bind 0.0.0.0
port 6386
daemonize yes
requirepass "123456"
logfile "/usr/local/redis/log/redis6.log"
dbfilename "xdclass6.rdb"
dir "/usr/local/redis/data"
appendonly yes
appendfilename "appendonly6.aof"
masterauth "123456"

cluster-enabled yes
cluster-config-file nodes-6386.conf
cluster-node-timeout 20000
cluster-announce-ip 203.189.210.168
cluster-announce-port 6386
cluster-announce-bus-port 16386

启动6个节点

./redis-server ../conf/cluster/redis1.conf
./redis-server ../conf/cluster/redis2.conf
./redis-server ../conf/cluster/redis3.conf
./redis-server ../conf/cluster/redis4.conf
./redis-server ../conf/cluster/redis5.conf
./redis-server ../conf/cluster/redis6.conf
  • 加入集群(其中一个节点执行即可)
    • --cluster 构建集群全部节点信息
    • --cluster-replicas 1 主从节点的比例,1表示1主1从的方式
./redis-cli -a 123456 --cluster create 203.189.210.168:6381 203.189.210.168:6382 203.189.210.168:6383 203.189.210.168:6384 203.189.210.168:6385 203.189.210.168:6386 --cluster-replicas 1

image-20221002164933138

  • 检查状态信息(其中一个节点执行即可)
./redis-cli -a 123456 --cluster check 203.189.210.168:6381

image-20221002165018779

posted @ 2022-10-03 10:12  yonugleesin  阅读(128)  评论(0编辑  收藏  举报