一篇Redis不学也枉然

Redis介绍


Redis的产⽣背景

2008年 萨尔瓦多——开发⼀个进⾏⽹站实时统计软件项⽬(LLOOGG),⽬的实时统计功能需要频繁的进⾏数据库的读写(对数据库的读写要求很⾼—数千次/s),MySQL满⾜不了项⽬的需求,萨尔瓦多就使⽤C语⾔⾃定义了⼀个数据存储系统—Redis。后来萨尔瓦多不满⾜仅仅在LLOOGG这个项⽬中⽤redis,就对redis进⾏产品化并进⾏开源,以便让更多的⼈能够使⽤

Redis使⽤

Redis就是⼀个⽤C语⾔开发的、基于内存结构进⾏ 键值对 数据存储的、⾼性能的、⾮关系型NoSQL数据库

Redis可以做什么

  • 数据库访问压⼒:为了降低对数据库的访问压⼒,当多个⽤户请求相同的数据时,我们可以将第⼀次从数据库查询到数据进⾏缓存(存储在内存中),以减少对数据库的访问次数
  • ⾸⻚数据的加载效率:将⼤量的且不经常改变的数据缓存在内容中,可以⼤幅度提⾼访问速度
  • 集群部署下的商品超卖:分布式事务
  • ⽤户登录:分布式会话

Redis⽀持的数据类型

redis是基于键值对进⾏数据存储的,但是value可以是多种数据类型

  • string 字符串
  • hash 映射
  • list 列表(队列)
  • set 集合
  • zset ⽆序集合

Redis特点

  • 基于内存存储,数据读写效率很⾼
  • Redis本身⽀持持久化
  • Reids虽然基于key-value存储,但是⽀持多种数据类型
  • Redis⽀持集群、⽀持主从模式

Redis应⽤场景

  • 缓存:在绝⼤多数的互联⽹项⽬中,为了提供数据的访问速度、降低数据库的访问压⼒,我们可以使⽤redis作为缓存来实现
  • 点赞、排⾏榜、计数器等功能:对数据实时读写要求⽐较⾼,但是对数据库的⼀致性要求并不是太⾼的功能场景
  • 分布式锁:基于redis的操作特性可以实现分布式锁功能
  • 分布式会话:在分布式系统中可以使⽤redis实现 session (共享缓存)
  • 消息中间件:可以使⽤redis实现应⽤之间的通信

Redis的优缺点

优点

  • redis是基于内存结构,性能极⾼(读 110000次/秒,写 81000次/秒)
  • redis基于键值对存储,但是⽀持多种数据类型
  • redis的所有操作都是原⼦性,可以通过lua脚本将多个操作合并为⼀个院⼦操作(Redis的事务)
  • reids是基于单线程操作,但是其多路复⽤实现了⾼性能读写

缺点

  • 缓存数据与数据库数据必须通过两次写操作才能保持数据的⼀致性
  • 使⽤缓存会存在缓存穿透、缓存击穿及缓存雪崩等问题,需要处理
  • redis可以作为数据库使⽤进⾏数据的持久存储,存在丢失数据的⻛险

Redis安装及配置


Redis安装

Redis安装及配置

下载Redis

cd /home

wget http://download.redis.io/releases/redis-5.0.5.tar.gz

安装redis

yum -y install gcc

解压redis安装包

tar -zxvf redis-5.0.5.tar.gz

解压之后进⼈到redis-5.0.5⽬录

cd redis-5.0.5

编译

make MALLOC=libc

安装

make install

启动redis,当我们完成redis安装之后,就可以执⾏redis相关的指令

redis-server

在打开一个命令窗口,打开客户端,启动redis操作客户端(命令⾏客户端)

redis-cli

Redis配置

使⽤ redis-server 指令启动redis服务的时候,可以在指令后添加redis配置⽂件的路径,以设置redis 是以何种配置进⾏启动

redis-server redis-6380.conf &  ## redis以redis-6380.conf⽂件中的配置来启动

如果不指定配置⽂件的名字,则按照redis的默认配置启动(默认配置≠redis.conf)
我们可以通过创建redis根⽬录下 redis.conf 来创建多个配置⽂件,启动多个redis服务

& 代表后台启动

redis-server redis-6380.conf & 
redis-server redis-6381.conf &

常⽤redis配置

## 设置redis实例(服务)为守护模式,默认值为no,可以设置为yes
daemonize no

## 设置当前redis实例启动之后保存进程id的⽂件路径
pidfile /var/run/redis_6379.pid

##  设置redis实例的启动端⼝(默认6379)
port 6380

## 设置当前redis实例是否开启保护模式
protected-mode yes

## 设置允许访问当前redis实例的ip地址列表
bind 127.0.0.1

## 设置连接密码
requirepass 123456

## 设置redis实例中数据库的个数(默认16个,编号0-15)
databases 16

## 设置最⼤并发数量
maxclients

## 设置客户端和redis建⽴连接的最⼤空闲时间,设置为0表示不限制
timeout 0

Redis基本使⽤


Redis存储的数据结构

Redis是以键值对形式进⾏数据存储的,但是value⽀持多种数据类型

在这里插入图片描述

string常⽤指令

设置值/修改值,如果key存在则进⾏修改

set key value

在这里插入图片描述

取值

get key

在这里插入图片描述

批量添加

mset k1 v1 [k2 v2 k3 v3 ...]

在这里插入图片描述

批量取值

mget k1 [k2 k3...]

在这里插入图片描述

⾃增和⾃减

# 在key对应的value上⾃增 +1 
incr key   

# 在key对应的value上⾃减 -1
decr key   

# 在key对应的value上+v 
incrby key v

# 在key对应的value上-v
decrby key v

在这里插入图片描述

添加键值对,并设置过期时间(TTL)

setex key time(seconds) value

在这里插入图片描述

设置值,如果key不存在则成功添加,如果key存在则添加失败(不做修改操作)

setnx key value

在这里插入图片描述

在指定的key对应value拼接字符串

append key value

在这里插入图片描述

获取key对应的字符串的⻓度

strlen key

在这里插入图片描述

hash常⽤指令

向key对应的hash中添加键值对

hset key field value

在这里插入图片描述

从key对应的hash获取field对应的值

hget key field

在这里插入图片描述

向key对应的hash结构中批量添加键值对

hmset key f1 v1 [f2 v2 ...]

在这里插入图片描述

从key对应的hash中批量获取值


hmget key f1 [f2 f3 ...]

在这里插入图片描述

在key对应的hash中的field对应value上加v

hincrby key field v

在这里插入图片描述

获取key对应的hash中所有的键值对

hgetall key

在这里插入图片描述

获取key对应的hash中所有的field

hkeys key

在这里插入图片描述

获取key对应的hash中所有的value

hvals key

在这里插入图片描述

检查key对应的hash中是否有指定的field

hexists key field

在这里插入图片描述

获取key对应的hash中键值对的个数

hlen key

在这里插入图片描述

向key对应的hash结构中添加f-v,如果field在hash中已经存在,则添加失败

hsetnx key field value

在这里插入图片描述

list常⽤指令

在这里插入图片描述

存储数据

# 在key对应的列表的左侧添加数据value
lpush key value 

# 在key对应的列表的右侧添加数据value
rpuhs key value 

在这里插入图片描述

获取数据

# 从key对应的列表的左侧取⼀个值 
lpop key

# 从key对应的列表的右侧取⼀个值 
rpop key 

在这里插入图片描述

修改数据,修改key对应的列表的索引位置的数据(索引从左往右,从0开始)

lset key index value 

在这里插入图片描述

查看key对应的列表中索引从start开始到stop结束的所有值

lrange key start stop

在这里插入图片描述

查看key对应的列表中index索引对应的值

lindex key index

在这里插入图片描述

获取key对应的列表中的元素个数

llen key

在这里插入图片描述

从key对应的列表中截取key在[start,stop]范围的值,不在此范围的数据⼀律被清除掉

ltrim key start stop

在这里插入图片描述

从k1右侧取出⼀个数据存放到k2的左侧

rpoplpush k1 k2

在这里插入图片描述

set常⽤指令

存储元素 :在key对应的集合中添加元素,可以添加1个,也可以同时添加多个元素

sadd key v1 [v2 v3 v4...]

在这里插入图片描述

遍历key对应的集合中的所有元素

smembers key

在这里插入图片描述

随机从key对于听的集合中获取⼀个值(出栈)

spop key

在这里插入图片描述

交集

sinter key1 key2

在这里插入图片描述
在这里插入图片描述

并集

sunion key1 key2

在这里插入图片描述
在这里插入图片描述

差集

sdiff key1 key2

在这里插入图片描述

从key对应的集合中移出指定的value

srem key value

在这里插入图片描述

检查key对应的集合中是否有指定的value

sismember key value

在这里插入图片描述

zset常⽤指令

zset 有序不可重复集合

存储数据(score存储位置必须是数值,可以是float类型的任意数字;member元素不允许重复)

zadd key score member [score member...]

查看key对应的有序集合中索引[start,stop]数据——按照score值由⼩到⼤(start 和 stop指的不是score,⽽是元素 在有序集合中的索引)

zrange key start top

查看member元素在key对应的有序集合中的索引

zscore key member

获取key对应的zset中的元素个数

zcard key

获取key对应的zset中,score在[min,max]范围内的member个数

zcount key min max

从key对应的zset中移除指定的member

zrem key6 member

查看key对应的有序集合中索引[start,stop]数据——按照score值由⼤到⼩

zrevrange key start stop

key相关指令

查看redis中满⾜pattern规则的所有的key(keys *)

keys pattern

查看指定的key谁否存在

exists key

删除指定的key-value对

del key

获取当前key的存活时间(如果没有设置过期返回-1,设置过期并且已经过期返回-2)

ttl key

设置键值对过期时间

expire key seconds 

pexpire key milliseconds

取消键值对过期时间

persist key

db常⽤指令

redis的键值对是存储在数据库中的—db
redis中默认有16个db,编号 0-15

切换数据库

select index

将键值对从当前db移动到⽬标db

move key index

清所有数据库的k-v

flushall

清空当前数据库数据

flushdb

查看当前db中k-v个数

dbsize

获取最后⼀次持久化操作时间

lastsave

Redis的持久化


Redis是基于内存操作,但作为⼀个数据库也具备数据的持久化能⼒;但是为了实现⾼效的读写操作,并不会 即时进⾏数据的持久化,⽽是按照⼀定的规则进⾏持久化操作的

持久化策略Redis提供了2中持久化策略:

  • RDB (Redis DataBase)
  • AOF(Append Only File)

RDB (Redis DataBase)

在满⾜特定的redis操作条件时,将内存中的数据以数据快照的形式存储到rdb⽂件中

在这里插入图片描述

原理

RDB是redis默认的持久化策略,当redis中的写操作达到指定的次数、同时距离上⼀次持久化达到指定的时间 就会将redis内存中的数据⽣成数据快照,保存在指定的rdb⽂件中。

  • 默认触发持久化条件:
    • 900s 1次:当操作次数达到1次,900s就会进⾏持久化
    • 300s 10次:当操作次数达到10次,300s就会进⾏持久化
    • 60s 10000次:当操作次数达到10000次,60s就会就⾏持久化

我们可以通过修改redis.conf⽂件,来设置RDB策略的触发条件:

## rdb持久化开关 
rdbcompression yes

## 配置redis的持久化策略
save 900 1
save 300 10
save 60 10000

## 指定rdb数据存储的⽂件
dbfilename dump.rdb

RED持久化细节分析

缺点

  • 如果redis出现故障,存在数据丢失的⻛险,丢失上⼀次持久化之后的操作数据;
  • RDB采⽤的是数据快照形式进⾏持久化,不适合实时性持久化;
  • 如果数据量巨⼤,在RDB持久化过程中⽣成数据快照的⼦进程执⾏时间过⻓,会导致redis卡顿,因此 save时间周期设置不宜过短;

优点

  • 但是在数据量较⼩的情况下,执⾏速度⽐较快;
  • 由于RDB是以数据快照的形式进⾏保存的,我们可以通过拷⻉rdb⽂件轻松实现redis数据移植

AOF(Append Only File)

Apeend Only File,当达到设定触发条件时,将redis执⾏的写操作指令存储在aof⽂件中,Redis默认未开启aof 持久化

在这里插入图片描述

原理

Redis将每⼀个成功的写操作写⼊到aof⽂件中,当redis重启的时候就执⾏aof⽂件中的指令以恢复数据

配置

## 开启AOF
appendonly yes

## 设置触发条件(三选⼀)
appendfsync always ## 只要进⾏成功的写操作,就执⾏aof
appendfsync everysec  ## 每秒进⾏⼀次aof
appendfsync no      ## 让redis执⾏决定aof

## 设置aof⽂件路径
appendfilename "appendonly.aof"

AOF细节分析:

  • 也可以通过拷⻉aof⽂件进⾏redis数据移植
  • aof存储的指令,⽽且会对指令进⾏整理;⽽RDB直接⽣成数据快照,在数据量不⼤时RDB⽐较快
  • aof是对指令⽂件进⾏增量更新,更适合实时性持久化
  • redis官⽅建议同时开启2中持久化策略,如果同时存在aof⽂件和rdb⽂件的情况下aof优先

Java应⽤连接Redis


设置redis允许远程连接

Java应⽤连接Redis,⾸先要将我们的Redis设置允许远程连接

修改redis-6379.conf

cd /home/redis-5.0.5

vim redis-6379.conf
## 关闭保护模式
protected-mode no
## 将bind注释掉(如果不注释,默认为  bind 127.0.0.1  只能本机访问) 
# bind 127.0.0.1
## 密码可以设置(也可以不设置) 
requirepass 123456

启动redis

redis-server redis-6379.conf

连接

在这里插入图片描述

在普通Maven⼯程连接Redis

使⽤jedis客户端连接

添加Jedis依赖

<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
	<groupId>redis.clients</groupId> 
	<artifactId>jedis</artifactId>
	<version>2.9.0</version>
</dependency>

使⽤案例

public static void main(String[] args) {
	Product product = new Product("101", "AD钙奶", 5); 
	
	//1.连接redis
	Jedis jedis = new Jedis("192.168.88.142", 6379); 

	//2.操作
	String s = jedis.set(product.getProductId(), new Gson().toJson(product)); 
	System.out.println(s);
	
	//3.关闭连接 
	jedis.close();
}

在SpringBoot⼯程连接Redis

  • Spring Data Redis依赖中,提供了⽤于连接redis的客户端:
    • RedisTemplate
    • StringRedisTemplate

创建springBoot应⽤

在这里插入图片描述

配置redis

application.yml⽂件配置redis的连接信息

spring:
  redis:
    host: 192.168.88.142
    port: 6379
    database: 0     
    password: 123456

使⽤redis客户端连接redis

直接在service中注⼊ RedisTemplate 或者 StringRedisTemplate ,就可以使⽤此对象完成redis操作

Spring Data Redis

不同数据结构的添加操作

string,添加数据 set key value

stringRedisTemplate.boundValueOps(product.getProductId()).set( jsonstr);

hash

stringRedisTemplate.boundHashOps("products").put(product.getProductId(),jsonstr);

list

stringRedisTemplate.boundListOps("list").leftPush("ccc");

set

stringRedisTemplate.boundSetOps("s1").add("v2");

zset

stringRedisTemplate.boundZSetOps("z1").add("v1",1.2);

string类型的操作⽅法

添加数据 set key value

stringRedisTemplate.boundValueOps(product.getProductId()).set( jsonstr);

添加数据时指定过期时间 setex key 300 value

stringRedisTemplate.boundValueOps("103").set(jsonstr,300);

设置指定key的过期时间 expire key 20

stringRedisTemplate.boundValueOps("103").expire(20, TimeUnit.SECONDS);

添加数据 setnx key value

Boolean absent = stringRedisTemplate.boundValueOps("103").setIfAbsent(jsonstr);

不同数据类型的取值操作

string

String o = stringRedisTemplate.boundValueOps("103").get(); 

hash

Object v = stringRedisTemplate.boundHashOps("products").get("101"); 

list

String s1 = stringRedisTemplate.boundListOps("list").leftPop();
String s2 = stringRedisTemplate.boundListOps("list").rightPop();
String s3 = stringRedisTemplate.boundListOps("list").index(1);

set

Set<String> vs = stringRedisTemplate.boundSetOps("s1").members();

zset

Set<String> vs2 = stringRedisTemplate.boundZSetOps("z1").range(0, 5);

使⽤Redis做缓存使⽤存在的问题


使⽤redis做为缓存在⾼并发场景下有可能出现缓存击穿、缓存穿透、缓存雪崩等问题

缓存击穿

缓存击穿:⼤量的并发请求同时访问同⼀个在redis中不存在的数据,就会导致⼤量的请求绕过redis同时并发 访问数据库,对数据库造成了⾼并发访问压⼒

使⽤双重检测锁解决缓存击穿问题

@Service
public class IndexImgServiceImpl implements IndexImgService {

	@Autowired
	private IndexImgMapper indexImgMapper;

	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	@Autowired
	private ObjectMapper objectMapper = new ObjectMapper();

	/**
	 * 查询轮播图
	 * @return
	 */
	@Override
	public ResultVO listIndexImgs() {

		List<IndexImg> indexImgList = null;

		try{
			// 1000个并请求,请求轮播图
			//string 结构缓存轮播图信息
			String imgsStr = stringRedisTemplate.opsForValue().get("indexImgs");

			// 1000个请求查询到redis中的数据都是null
			if (imgsStr != null){
				// 从redis中获取到了 值
				JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
				indexImgList = objectMapper.readValue(imgsStr,javaType);
			}else{
				//从redis中没有获取到数据
				// 1000个请求都会进入else   (service类在spring容器中是单例的,1000个并发会启动1000个线程来处理,但是公用一个service实例)
				synchronized (this){
					// 第二次查询redis
					String s = stringRedisTemplate.opsForValue().get("indexImgs");
					if(s == null){
						// 这1000个请求中,只有第一个请求,再次查询redis时,依然为null
						indexImgList = indexImgMapper.listIndexImgs();
						if (indexImgList != null) {
							System.out.println("------------------并发解决:查询数据库了");
							//写入redis
							stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(indexImgList));
							// 设置过期时间,为一天
							stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.DAYS);
						}else{
							// 解决 redis的缓存穿透
							List<IndexImg> arr = new ArrayList<>();
							stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(arr));
							// 设置过期时间,为 10秒
							stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.SECONDS);
						}

					}else {
						System.out.println("------------------双重同步锁-并发解决:查询--redis--了");
						JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
						indexImgList = objectMapper.readValue(s,javaType);
					}
				}
			}
		}catch (JsonProcessingException e){
			e.printStackTrace();
		}

		//返回数据
		if(indexImgList != null){
			return new ResultVO(ResStatus.OK,"success",indexImgList);
		}else{
			return new ResultVO(ResStatus.NO,"fail",null);
		}
	}

}

缓存穿透

缓存穿透:⼤量的请求⼀个数据库中不存在的数据,⾸先在redis中⽆法命中,最终所有的请求都会访问数据 库,同样会导致数据库承受巨⼤的访问压⼒。

解决⽅案:当从数据库查询到⼀个null时,写⼀个⾮空的数据到redis,并设置过期时间

在这里插入图片描述

indexImgs = indexImgMapper.listIndexImgs(); 
if(indexImgs != null) {
	String s = objectMapper.writeValueAsString(indexImgs); 
	stringRedisTemplate.boundValueOps("indexImgs").set(s);
	stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.DAYS); 
} else {
	//当从数据库查询数据为null时,保存⼀个⾮空数据到redis,并设置过期时间 	
	stringRedisTemplate.boundValueOps("indexImgs").set("[]");
	stringRedisTemplate.boundValueOps("indexImgs").expire(10, TimeUnit.SECONDS);
}

缓存雪崩

缓存雪崩:缓存⼤量的数据集中过期,导致请求这些数据的⼤量的并发请求会同时访问数据库

解决⽅案:

  • 将缓存中的数据设置成不同的过期时间
  • 在访问洪峰到达前缓存热点数据,过期时间设置到流量最低的时段

Redis⾼级应⽤


使⽤redis作为缓存数据库使⽤⽬的是为了提升数据加载速度、降低对数据库的访问压⼒,我们需要保证redis 的可⽤性

  • 主从配置
  • 哨兵模式
  • 集群配置

主从配置

主从配置:在多个redis实例建⽴起主从关系,当主redis中的数据发⽣变化, 从redis中的数据也会同步变化

  • 通过主从配置可以实现redis数据的备份( 从redis就是对主redis的备份),保证数据的安全性;
  • 通过主从配置可以实现redis的读写分离
    在这里插入图片描述

主从配置

启动三个redis实例

在redis-5.0.5⽬录下创建 msconf ⽂件夹

cd /home/redis-5.0.5

mkdir msconf

拷⻉redis.conf⽂件 到 msconf⽂件夹 —> redis-master.conf

cat redis.conf |grep -v "#" | grep -v "^$" > msconf/redis-master.conf

修改 redis-master.conf 端⼝及远程访问设置

cd /home/redis-5.0.5/msconf

vim redis-master.conf

在这里插入图片描述

将 redis-master.conf 拷⻉两份分别为:redis-slave1.conf,redis-slave2.conf

sed 's/6380/6381/g' redis-master.conf > redis-slave1.conf

sed 's/6380/6382/g' redis-master.conf > redis-slave2.conf

修改redis-slave1.conf redis-slave2.conf,设置“跟从”—192.168.88.142 6380

slaveof 192.168.88.142 6380
vim redis-slave1.conf

在这里插入图片描述

vim redis-slave2.conf

在这里插入图片描述

启动三个redis实例

cd /home/redis-5.0.5/msconf

redis-server redis-master.conf &

redis-server redis-slave1.conf &

redis-server redis-slave2.conf &

成功启动

在这里插入图片描述
在这里插入图片描述

测试主从

连接

在这里插入图片描述

插入数据测试

在这里插入图片描述

主机

在这里插入图片描述

从1

在这里插入图片描述

从2

在这里插入图片描述

哨兵模式

哨兵模式:⽤于监听主库,当确认主库宕机之后,从备库(从库)中选举⼀个转备为主

在这里插入图片描述

哨兵模式配置

⾸先实现三个redis实例之间的主从配置(如上)

创建并启动三个哨兵。拷⻉sentinel.conf⽂件三份:sentinel-26380.conf sentinel-26382.conf sentinel-26382.conf

创建sentinelconf⽬录。拷⻉sentinel.conf⽂件到 sentinelconf⽬录:sentinel-26380.conf

mkdir /home/redis-5.0.5/sentinelconf

cat sentinel.conf | grep -v "#" | grep -v "^$" > sentinelconf/sentinel-26380.conf

进入文件夹

cd /home/redis-5.0.5/sentinelconf

编辑 sentinelconf/sentinel-26380.conf⽂件

vim sentinel-26380.conf

在这里插入图片描述

port 26380

daemonize no

pidfile /var/run/redis-sentinel-26380.pid

logfile ""

dir /tmp

# 此处配置默认的主库的ip和端口,最后的数字是哨兵数量的1半多1个
sentinel monitor mymaster 192.168.88.142 6380 2

sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1 
protected-mode no

sentinel down-after-milliseconds mymaster 30000

sentinel parallel-syncs mymaster 1

sentinel failover-timeout mymaster 180000

sentinel deny-scripts-reconfig yes

执行复制

cd /home/redis-5.0.5/sentinelconf

sed 's/26380/26381/g' sentinel-26380.conf > sentinel-26381.conf

sed 's/26380/26382/g' sentinel-26380.conf > sentinel-26382.conf

启动 哨兵前先启动我们之前的主从

cd /home/redis-5.0.5/msconf

redis-server redis-master.conf

在这里插入图片描述

cd /home/redis-5.0.5/msconf

redis-server redis-slave1.conf

在这里插入图片描述

cd /home/redis-5.0.5/msconf

redis-server redis-slave2.conf

在这里插入图片描述

再依次启动三个哨兵:

cd /home/redis-5.0.5/sentinelconf

redis-sentinel sentinel-26380.conf

在这里插入图片描述

cd /home/redis-5.0.5/sentinelconf

redis-sentinel sentinel-26381.conf

在这里插入图片描述

cd /home/redis-5.0.5/sentinelconf

redis-sentinel sentinel-26382.conf

在这里插入图片描述

查看是否启动了一个方法

在这里插入图片描述

在这里插入图片描述

测试哨兵模式

我们先把主 - 6380给关闭,ctrl+c就可以关闭的,当我把主 - 6380关闭的时候从 - 6381 和 从 - 6382控制台连接不上了,出现错误了,在等一下我们的哨兵就会出现作用的

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

去到我们哨兵的控制台后,等了一会我发现1-26380,2-23681,3-23682等哨兵,已经开始工作了,也推举出来了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
问答时间:如果6380回来了,还是不是老大?
答:不是

集群配置

⾼可⽤:保证redis⼀直处于可⽤状态,即时出现了故障也有备⽤⽅案保证可⽤性

⾼并发:⼀个redis实例已经可以⽀持多达11w并发读操作或者8.1w并发写操作;但是如果对于有更⾼并发需 求的应⽤来说,我们可以通过读写分离集群配置来解决⾼并发问题

在这里插入图片描述

Redis集群

  • Redis集群中每个节点是对等的,⽆中⼼结构
  • 数据按照slots分布式存储在不同的redis节点上,节点中的数据可共享,可以动态调整数据的分布
  • 可扩展性强,可以动态增删节点,最多可扩展⾄1000+节点
  • 集群每个节点通过主备(哨兵模式)可以保证其⾼可⽤性

集群搭建

进入文件夹,并且创建文件夹

cd /home/redis-5.0.5

mkdir cluster-conf

创建文件

cat redis.conf | grep -v "#"|grep -v "^$" > cluster-conf/redis-7001.conf

cd /home/redis-5.0.5/cluster-conf/

编辑文件

vim redis-7001.conf

在这里插入图片描述

# bind 127.0.0.1

protected-mode no

port 7001

cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000

tcp-backlog 511

timeout 0

tcp-keepalive 300

daemonize yes

supervised no

pidfile /var/run/redis_7001.pid

loglevel notice

logfile ""

databases 16

always-show-logo yes

save 900 1

save 300 10

save 60 10000

stop-writes-on-bgsave-error yes

rdbcompression yes

rdbchecksum yes

dbfilename dump_7001.rdb

dir ./

replica-serve-stale-data yes

replica-read-only yes

repl-diskless-sync no

repl-diskless-sync-delay 5

repl-disable-tcp-nodelay no

replica-priority 100

lazyfree-lazy-eviction no

lazyfree-lazy-expire no

lazyfree-lazy-server-del no

replica-lazy-flush no

appendonly no

appendfilename "appendonly_7001.aof"

appendfsync everysec

no-appendfsync-on-rewrite no

auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb

aof-load-truncated yes

aof-use-rdb-preamble yes

lua-time-limit 5000

slowlog-log-slower-than 10000

slowlog-max-len 128

latency-monitor-threshold 0

notify-keyspace-events ""

hash-max-ziplist-entries 512

hash-max-ziplist-value 64

list-max-ziplist-size -2

list-compress-depth 0

set-max-intset-entries 512

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

hll-sparse-max-bytes 3000

stream-node-max-bytes 4096

stream-node-max-entries 100

activerehashing yes

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit replica 256mb 64mb 60

client-output-buffer-limit pubsub 32mb 8mb 60

hz 10

dynamic-hz yes

aof-rewrite-incremental-fsync yes

rdb-save-incremental-fsync yes

拷⻉6个⽂件,端⼝分别为 7001-7006

cd /home/redis-5.0.5/cluster-conf

sed 's/7001/7002/g' redis-7001.conf > redis-7002.conf

sed 's/7001/7003/g' redis-7001.conf > redis-7003.conf 

sed 's/7001/7004/g' redis-7001.conf > redis-7004.conf

sed 's/7001/7005/g' redis-7001.conf > redis-7005.conf

sed 's/7001/7006/g' redis-7001.conf > redis-7006.conf

启动

cd /home/redis-5.0.5/cluster-conf

redis-server redis-7001.conf &

redis-server redis-7002.conf &

redis-server redis-7003.conf &

redis-server redis-7004.conf &

redis-server redis-7005.conf &

redis-server redis-7006.conf &
ps -ef | grep redis

在这里插入图片描述

测试集群

创建集群

redis-cli --cluster create 192.168.88.142:7001 192.168.88.142:7002 192.168.88.142:7003 192.168.88.142:7004 192.168.88.142:7005 192.168.88.142:7006 --cluster-replicas 1

在这里插入图片描述
在这里插入图片描述

redis有一个哈希槽的概念,默认是 16384

连接集群

redis-cli -p 7001 -c

在这里插入图片描述

查看集群状态

redis-cli --cluster info 192.168.88.142:7001

在这里插入图片描述

平衡节点的数据槽数

redis-cli --cluster rebalance 192.168.88.142:7001

在这里插入图片描述

迁移节点槽

redis-cli --cluster reshard 192.168.88.142:7001

在这里插入图片描述

删除节点

redis-cli --cluster del-node 192.168.88.142:7001 4cc04a0f3c3deb3a77db79d8a2e11d30988e041b

在这里插入图片描述

添加节点

可以看到 7001不在了,所以我们在把他起来,在加入集群
在这里插入图片描述

redis-cli --cluster add-node 192.168.88.142:7001 192.168.88.142:7002

在这里插入图片描述
出现问题,那就解决问题:

解决方法:

1、将需要新增的节点下aof、rdb等本地备份文件删除,同时将新Node的集群配置文件删除,
即:删除你redis.conf里面cluster-config-file所在的文件;

在这里插入图片描述

rm nodes-7001.conf

rm dump_7001.rdb

启动

redis-server redis-7001.conf &

在这里插入图片描述

再次添加新节点如果还是报错,则登录新Node对数据库进行清除

FLUSHDB

清空完之后再次执行命令

redis-cli --cluster add-node 192.168.88.142:7001 192.168.88.142:7002

我有认真的看了一下为什么我还是出现问题,我们看集群信息才知道,7001这个,已经加入了
在这里插入图片描述

SpringBoot应⽤连接集群

添加依赖
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId> 
</dependency>
配置集群节点
spring:
  redis:
    cluster:
      nodes: 192.168.88.142:7001,192.168.88.142:7002,192.168.88.142:7003       
      max-redirects: 3
操作集群
@RunWith(SpringRunner.class)
@SpringBootTest(classes = RedisDemo3Application.class) 
class RedisDemo3ApplicationTests {
	
	@Autowired
	private StringRedisTemplate stringRedisTemplate; 
	
	@Test
	void contextLoads() {
		//stringRedisTemplate.boundValueOps("key1").set("value1"); 
		String s = stringRedisTemplate.boundValueOps("key1").get(); 
		
		System.out.println(s);
    } 
}

Redis淘汰策略

Redis是基于内存结构进⾏数据缓存的,当内存资源消耗完毕,想要有新的数据缓存进来,必然要从Redis的 内存结构中释放⼀些数据。如何进⾏数据的释放呢?---- Redis的淘汰策略

Redis提供的8中淘汰策略

  • volatile-lru —> 从设置了过期时间的数据中淘汰最久未使⽤的数据.
  • allkeys-lru —> 从所有数据中淘汰最久未使⽤的数据.
  • volatile-lfu —> 从设置了过期时间的数据中淘汰使⽤最少的数据.
  • allkeys-lfu —> 从所有数据中淘汰使⽤最少的数据.
  • volatile-random —> 从设置了过期时间的数据中随机淘汰⼀批数据.
  • allkeys-random —> 从所有数据中随机淘汰⼀批数据.
  • volatile-ttl —> 淘汰过期时间最短的数据.
  • noeviction —> 不淘汰任何数据,当内存不够时直接抛出异常.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值