Redis全面总结

一、Redis介绍

1.1 Redis 是什么?

Redis是一个 用C语言开发的、基于内存结构进行键值对存储的、高性能非关系型数据库 数据库

  • 基于内存结构,性能很高
  • 数据是键值对形式存储
  • 非关系型,存储的数据与数据之间是没有关系的

1.2 Redis能干什么?

  • 当应用程序在完成例如点赞、实时排行榜、计数器等对数据实时读写性能要求比较高,对数据的一致性要求并不高的场景,可以使用redis进行数据实时写操作(数据库)
    在这里插入图片描述
  • 缓存:在大多数互联网应用中,为了提高数据的访问速度、降低数据库的并发访问压力,我们可以 使用redis作为查询缓存
    在这里插入图片描述
  • 在分布式并发场景中,可以使用redis实现分布式锁
  • 在分布式会话中,可以使用redis实现共享缓存(session)

1.3 Redis的优缺点

优点

  • redis是基于内存结构,性能极高(读 110000次/秒,写 81000 次/秒)
  • redis虽然是以键值对存储数据的,但是value却可以支持多种类型(string hash list set zset)
  • redis的所有操作都是原子性的,可以通过lua脚本实现redis操作的事务
  • redis的操作是单线程,但是其多路复用技术实现了高性能读写

缺点

  • Redis中的缓存数据与数据库的数据必须通过两次写操作才能保持一致(双写一致)
  • Redis作为缓存使用会存在缓存击穿、缓存穿透、缓存雪崩等问题,在应用中需要进行处理
  • Redis是基于内存存储的,虽然支持持久化,但是在某些场景下可能存下数据丢失的风险

二、Redis安装及配置

2.1 Redis安装

基于linux环境安装redis

2.1.1 下载Redis

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

2.1.2 安装redis

  • 安装gcc (gcc是C语言安装包的编译工具)
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-server 在redis的src目录下)
redis-server &

2.2 Redis多实例启动

使用 redis-server 指令启动Redis,默认端口是6379;
我们可以在启动redis的时候加载指定的redis配置文件,使用redis-server redis.conf 方式启 动就是按照 redis.conf 文件的配置来启动redis

在启动redis服务时,我们可以通过指定其加载的配置文件(redis.conf)来启动多个redis实例
在这里插入图片描述

  • 打开客户端
redis-cli ## 启动redis操作客户端(命令行客户端)

2.3 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.conf 到 confs 目录:

# 需要手动修改port
cat redis.conf | grep -v "#" | grep -v "^$" > confs/redis-6380.conf
sed 's/6380/6381/g' redis-6380.conf > redis-6381.conf

常用redis配置

## 设置redis实例(服务)为守护模式,默认值为no,可以设置为yes
daemonize no
## 设置当前redis实例启动之后保存进程id的文件路径
## 通常将pidfile文件 命名为 redis_port.pid
pidfile /var/run/redis_6379.pid
## 设置redis实例的启动端口(默认6379)
port 6380
## 设置当前redis实例是否开启保护模式(如果允许redis被远程访问,此处修改为 no)
protected-mode yes
## 设置允许访问当前redis实例的ip地址列表 (默认选择只允许当前主机的客户端访问,如如果允许
redis被远程访问,注释此行)
# bind 127.0.0.1
2.4 客户端连接redis
2.4.1 redis-cli
redis安装时,自带了一个本地客户端, 通过 redis-cli 启动
## 设置连接密码:
requirepass 123456
## 设置redis实例中数据库的个数(默认16个,编号0-15)
databases 16
## 设置最大客户端数量
maxclients
## 设置客户端和redis建立连接的最大空闲时间,设置为0表示不限制
timeout 0

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

2.4 客户端连接redis

2.4.1 redis-cli

redis安装时,自带了一个本地客户端, 通过 redis-cli 启动

redis-cli -p port # 连接到指定port的redis实例
[root@qfedu confs]# redis-cli -p 6380
127.0.0.1:6380> get key1
(error) NOAUTH Authentication required.
127.0.0.1:6380> auth 123456 #进行密码认证(如果设置了密码,必须要进行认证)
OK
127.0.0.1:6380> get key1
(nil)
127.0.0.1:6380>

2.4.2 RedisDesktopManager

RedisDesktopMannager连接redis
在这里插入图片描述

三、Redis基本使用

Redis是一个NoSQL数据库——存储数据

  • MySQL:
    • SQL指令
    • JDBC
  • Redis:
    • redis指令     在redis客户端中,可以通过指令完成数据的存取
    • Java代码操作redis     通过Java程序完成redis中数据的存取

3.1 Redis存储的数据结构

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

  • string 字符串
  • hash 映射
  • list 队列
  • set 无序集合
  • zset 有序集合

在这里插入图片描述

3.2 string常用指令

## 设置值/修改值 如果key存在则进行修改
set key value
## 取值
get key
## 批量添加
mset k1 v1 [k2 v2 k3 v3 ...]
## 批量取值
mget k1 [k2 k3...]
## 自增和自减
incr key ## 在key对应的value上自增 +1
decr key ## 在key对应的value上自减 -1
incrby key v ## 在key对应的value上+v
decrby key v ## 在key对应的value上-v
## 添加键值对,并设置过期时间(TTL Time To Live)
setex key time(seconds) value
## 设置值,如果key不存在则成功添加,如果key存在则添加失败(不做修改操作)
setnx key value
## 在指定的key对应value拼接字符串
append key value
## 获取key对应的字符串的长度
strlen key

3.3 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

3.4 list常用指令

在这里插入图片描述

## 存储数据 (通常我们只在固定的一段存数据 - left&right)
lpush key value # 在key对应的列表的左侧添加数据value
rpush key value # 在key对应的列表的右侧添加数据value
## 获取数据 (出栈:会将获取出的数据从列表中移除)
lpop key # 从key对应的列表的左侧取一个值
rpop key # 从key对应的列表的右侧取一个值
## 修改数据
lset key index value #修改key对应的列表的索引位置的数据(索引从左往右,从0开始)
## 查看key对应的列表中索引从start开始到stop结束的所有值
lrange key start stop
## 查看key对应的列表中index索引对应的值(不会从列表移除数据)
lindex key index
## 获取key对应的列表中的元素个数
llen key
## 从key对应的列表中截取index在[start,stop]范围的值,不在此范围的数据一律被清除掉
ltrim key start stop
## 从k1右侧取出一个数据存放到k2的左侧
rpoplpush k1 k2

3.5 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

3.6 zset常用指令

zset 有序不可重复集合 z

## 存储数据(score存储位置必须是数值,可以是float类型的任意数字;member元素不允许重复)
zadd key score member [score member...]
## 查看key对应的有序集合中索引[start,stop]数据——按照score值由小到大(start 和 stop指的不是
score,而是元素在有序集合中的索引)
zrange key start top
##查看member元素在key对应的有序集合中的score
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

3.7 key相关指令

在redis中,数据都是以键值对形式存储的,与key相关的指令——就是根据key进行特定操作的指令

## 查看redis中满足pattern规则的所有的key(keys *)
keys pattern
## 查看指定的key是否存在
exists key
## 删除指定的key-value对
del key
## 获取当前key的存活时间(如果没有设置过期返回-1,设置过期并且已经过期返回-2) Time to live
ttl key
## 设置键值对过期时间
expire key seconds
pexpire key milliseconds
## 取消键值对过期时间
persist key

3.8 db常用指令

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

## 切换数据库
select index
## 将键值对从当前db移动到目标db
move key index
## 清空当前数据库数据
flushdb
## 清所有数据库的k-v
flushall
## 查看当前db中k-v个数
dbsize
## 获取最后一次持久化操作时间
lastsave

四、Redis的持久化 [重点]

Redis是一个基于内存结构的数据库,我们存储在redis中的数据是支持持久化

4.1 基于Redis的点赞业务实现分析

在这里插入图片描述
问题分析:由于Redis是基于内存结构进行数据存储和操作的,如果使用redis作为数据库存储数据、或者作为缓存缓存数据,当遇到Redis实例异常、Redis服务器主机宕机等情况,会导Redis存储/缓存的数据丢失。

4.2 Redis的持久化

在这里插入图片描述

Redis是基于内存操作,但作为一个数据库也具备数据的持久化能力;但是为了实现高效的读写操作,并不会即时进行数据的持久化,而是按照一定的规则进行持久化操作的——持久化策略
Redis提供了2种持久化策略:

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

4.2.1 RDB持久化策略

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
## 指定rdb数据存储的文件(如果启动多个redis实例,则需要修改rdb文件名——带上redis对应的端
口号 )
dbfilename dump-6379.rdb
## 配置redis的持久化策略
save 900 1
save 300 10
save 60 10000
  • RDB持久化细节分析:
    缺点

    • 如果redis出现故障,存在数据丢失的风险,会丢失上一次持久化之后的操作数据;
    • RDB采用的是数据快照形式进行持久化,不适合实时性持久化;
    • 如果数据量巨大,在RDB持久化过程中生成数据快照的子进程执行时间过长,会导致redis卡 顿,因此save时间周期设置不宜过短;

    优点

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

4.2.2 AOF持久化策略

在这里插入图片描述

  • 原理:
    Apeend Only File,Redis将每一个成功的写操作指令写入到aof文件中,当redis重启的时候就执行
    aof文件中的指令以恢复数据,Redis默认未开启aof持久化。
  • 配置:
## 开启AOF
appendonly yes
## 设置aof文件路径
appendfilename "appendonly.aof"
## 设置触发条件(三选一)
appendfsync always ## 只要进行成功的写操作,就执行aof
appendfsync everysec ## 每秒进行一次aof
appendfsync no ## 让redis执行决定aof
  • AOF细节分析:
    • 也可以通过拷贝aof文件进行redis数据移植
    • aof存储的指令,而且会对指令进行整理;而RDB直接生成数据快照,在数据量不大时RDB比较快
    • aof是对指令文件进行增量更新,更适合实时性持久化
    • redis官方建议同时开启2种持久化策略,如果同时存在aof文件和rdb文件的情况下aof优先

五、Java应用连接Redis

5.0 设置redis允许远程连接

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

  • 修改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
  • 阿里云安全组设置放行6379端口
    在这里插入图片描述

5.1 在普通Maven工程连接Redis

在普通Maven工程使用 jedis 客户端连接 redis

5.1.1 添加Jedis依赖

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

5.1.2 使用案例

//1.建立链接
Jedis jedis = new Jedis("1.12.255.11",6380);
//2.密码认证
jedis.auth("123456");
//3.执行操作 Jedis客户端提供的对redis的操作方法名与指令名称是一致的
String s = jedis.set("name", "张三");
//4.执行get操作
String name = jedis.get("name");
System.out.println(name);
//5.关闭客户端
jedis.close();

5.1.3 redis远程可视化客户端

  • Redis desktop manager

5.2 在SpringBoot工程连接Redis

Spring Data Redis, part of the larger Spring Data family, provides easy configuration and access to Redis from Spring applications. It offers both low-level and high-level abstractions for interacting with the store, freeing the user from infrastructural concerns.
Spring Data Redis依赖中,提供了用于连接redis的客户端:

  • RedisTemplate
  • StringRedisTemplate

5.2.1 创建springBoot应用

在这里插入图片描述

5.2.2 配置redis

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

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

5.2.3 使用redis客户端连接redis

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

5.3 Spring Data Redis

5.3.1 不同数据结构的添加操作

@Service
public class ArticleServiceImpl implements ArticleService {
//@Autowired
//private RedisTemplate redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public ResultVO dianZan(String articleId) {
//使用stringRedisTemplate操作redis
//string
stringRedisTemplate.boundValueOps("key1").set("bbb");
//hash
stringRedisTemplate.boundHashOps("key2").put("f3","v3");
//list
stringRedisTemplate.boundListOps("key3").leftPush("bbb");
stringRedisTemplate.boundListOps("key3").rightPush("ccc");
//set
stringRedisTemplate.boundSetOps("key4").add("aaa");
//zset
stringRedisTemplate.boundZSetOps("key5").add("a",1);
stringRedisTemplate.boundZSetOps("key5").add("b",0);
stringRedisTemplate.boundZSetOps("key5").add("c",0.7);
return new ResultVO(200,"success",null);
}

5.3.2 string类型的操作方法

stringRedisTemplate.boundValueOps(articleId).increment(); //incr
stringRedisTemplate.boundValueOps("key1").set("value1"); // set key1
value1
stringRedisTemplate.boundValueOps("key1").setIfAbsent("value1"); // setnx
key1 value1
stringRedisTemplate.boundValueOps("key6").set("cccc"); // setex
key6 10 ccc
stringRedisTemplate.boundValueOps("key6").expire(10, TimeUnit.SECONDS);
String val = stringRedisTemplate.boundValueOps("key1").get(); // get key1

5.3.3 不同数据类型的取值操作

//hash
stringRedisTemplate.boundHashOps("key2").put("f4","v4"); //hset f4 v4
String val = stringRedisTemplate.boundHashOps("key2").get("f4"); //hget f4
//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除了在点赞业务、排行榜实时统计等非常频繁的写操作场景中作为数据库中间件进行数据存储使用之外;更多的是在项目缓存热点数据,作为数据库查询缓存使用。

  • 数据库中间件:当对数据库需要进行频繁的写操作时,我们将mysql的数据先同步到redis, 频繁的写操作在redis中进行,然后周期性的将redis中被修改后的数据同步到mysql
    • 减少对mysql数据库的访问次数
    • 在高频次写操作时弥补mysql数据的性能不足问题
  • 查询缓存:将数据库中频繁被查询的数据存储到redis,当有请求访问这部分数据的时候就不 再查询数据库,而是直接从redis中查询所需的数据
    • 减少对数据库的访问次数(数据库连接)

6.1 redis作为缓存的使用流程

在这里插入图片描述

  1. 当在Service中要查询数据的时候,首先到redis中进行查询
  2. 如果在redis中命中数据,则直接返回数据给Controller
  3. 如果在redis中没有命中查询数据,则到数据库中进行查询
  4. 从数据库中查询到数据之后,在返回给Controller的同时,将查询的数据写入到redis(方便下一次查询)

6.2 查询缓存案例—缓存商品详情

根据商品id查询商品信息

1. 创建数据表,添加测试数据

create table tb_products(
product_id int primary key auto_increment,
product_name varchar(50) not null,
product_desc varchar(200) not null
);
insert into tb_products(product_name,product_desc) values('小米10','小米10描述信
息');
insert into tb_products(product_name,product_desc) values('华为P50','华为P50描述信
息');
insert into tb_products(product_name,product_desc) values('康佳电视','康佳电视描述信
息');
insert into tb_products(product_name,product_desc) values('铁三角麦克风','铁三角麦克
风描述信息');
insert into tb_products(product_name,product_desc) values('海尔冰箱','海尔冰箱描述信
息');
insert into tb_products(product_name,product_desc) values('美的空调','美的空调描述信
息');

2. 常规的商品查询接口实现

  • 创建SpringBoot项目
  • 完成MyBatis整合
  • 接口实现
    • DAO实现
    • Service实现
    • Controller实现
    • 测试接口

3. 使用redis作为查询缓存

按照上述接口的实现,每次查询商品(即时多次查询的是同一个商品)都会对数据库进行查询

  • 在SpringMVC环境专供,JSON格式转换可以使用ObjectMapper类
@SpringBootApplication
@MapperScan("com.qfedu.redis.demo4.dao")
public class RedisDemo4CacheApplication {
public static void main(String[] args) {
SpringApplication.run(RedisDemo4CacheApplication.class, args);
}
@Bean
public ObjectMapper getObjectMapper(){
return new ObjectMapper();
}
}
  • Service查询数据使用redis作为查询缓存实现
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDAO productDAO;
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Override
public ResultVO getProductById(int productId) throws JsonProcessingException
{
//1.从redis查询商品信息 (string: productId---json )
String s = stringRedisTemplate.boundValueOps(productId + "").get();
if(s != null){
//2.如果redis命中,则直接返回当前商品信息
Product product = new ObjectMapper().readValue(s, Product.class);
return new ResultVO(200,"success",product);
}else{
//3.如果redis没有命中,则需要查询数据库
Product product = productDAO.selectById(productId);
System.out.println("----查询MySQL数据库");
//4.将从数据库查询到的商品信息存入redis
String jsonStr = new ObjectMapper().writeValueAsString(product);
stringRedisTemplate.boundValueOps(productId+"").set( jsonStr );
return new ResultVO<>(200,"success",product);
}
}
}

七、Redis缓存问题 [重点]

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

7.1 缓存击穿

7.1.1 缓存击穿概念

缓存击穿:大量的 并发请求 同时访问 同一个在redis中不存在的数据 ,就会导致大量的请求绕过
redis同时并发访问数据库,对数据库造成了高并发访问压力。

  • 特点:并发请求的数据在redis中不存在,但是在MySQL存在

在这里插入图片描述

7.1.2 解决缓存击穿问题

  • 使用双重检测锁解决缓存击穿问题
  • 布隆过滤器【扩展】
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDAO productDAO;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//①②③
public ResultVO getProductById(int productId) throws JsonProcessingException
{
//1.从redis查询商品信息 (string: productId---json )
String s = stringRedisTemplate.boundValueOps(productId + "").get();
if(s != null){
//2.如果redis命中,则直接返回当前商品信息
Product product = new ObjectMapper().readValue(s, Product.class);
return new ResultVO(200,"success",product);
}else{
//线程③
//线程②
//线程①
Product product = null;
synchronized (this) {
//第二次查询redis
String s2 = stringRedisTemplate.boundValueOps(productId +
"").get();
if(s2 != null){
//2.如果redis命中,则直接返回当前商品信息
product = new ObjectMapper().readValue(s2, Product.class);
return new ResultVO(200,"success",product);
}else{
//3.如果redis没有命中,则需要查询数据库
product = productDAO.selectById(productId);
System.out.println("----查询MySQL数据库");
//4.将从数据库查询到的商品信息存入redis
String jsonStr = new
ObjectMapper().writeValueAsString(product);
stringRedisTemplate.boundValueOps(productId +
"").set(jsonStr);
//当线程①执行结束的时候,redis中是否已经有了数据? yes or no ! YES
return new ResultVO<>(200,"success",product);
}
}
}
}
}

7.2 缓存穿透

缓存穿透:大量的并发请求访问一个数据库中不存在的数据,首先在redis中无法命中,最终所有的请求都会访问数据库,同样会导致数据库承受巨大的访问压力。

  • 特点:大量请求的数据在redis中不存在,同时在MySQL也不存在

在这里插入图片描述

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

在这里插入图片描述

  • 如果从数据库查询到数据为null,则写一个非空的数据到redis,以解决缓存穿透问题
  • 如果向数据库中新增了这条数据,为了让请求可以访问新增的数据,向redis写非空数据时需要设 置过期时间
  • 当向redis写非空数据后,在向数据库添加这条数据的时候,如果redis没有达到过期时间,请求依然不能访问数据库中的数据,我们可以通过双写操作实现redis中数据与数据库数据的一致性: 向数据库添加一条数据的同时,将这条数据写入到reids

7.3 缓存雪崩

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

解决方案:

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

7.4 Jmeter测试

Jmeter是一个压力测试工具,模拟并发请求访问被测试接口
下载:Apache Jmeter

  • Jmeter是基于Java开发的一个测试工具,因此需要先安装JDK

解压:

  • home/bin/ApacheJMeter.jar

使用:

  1. 创建测试计划
  2. 创建线程组
  3. 设置线程组请求信息
  4. 查看运行结果

7.4.1 创建测试计划

在这里插入图片描述

7.4.2 创建线程组

在这里插入图片描述

7.4.3 设置HTTP请求

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

7.4.4 执行请求

在这里插入图片描述

7.4.5 查看运行结果

在这里插入图片描述

八、Redis高级应用

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

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

8.1 主从配置

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

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

  • 通过主从配置可以实现redis的读写分离
    在这里插入图片描述
    主从配置示例

  • 启动三个redis实例

## 在redis-5.0.5目录下创建 msconf 文件夹
[root@theo redis-5.0.5]# mkdir msconf
## 拷贝redis.conf文件 到 msconf文件夹 ---> redis-master.conf
[root@theo redis-5.0.5]# cat redis.conf |grep -v "#" | grep -v "^$" >
msconf/redis-master.conf
## 修改 redis-master.conf 端口及远程访问设置
[root@theo msconf]# vim redis-master.conf

在这里插入图片描述

## 将 redis-master.conf 拷贝两份分别为:redis-slave1.conf redis-slave2.conf
[root@theo msconf]# sed 's/6380/6381/g' redis-master.conf > redisslave1.conf
[root@theo msconf]# sed 's/6380/6382/g' redis-master.conf > redisslave2.conf
## 主从配置:
## 修改redis-slave1.conf redis-slave2.conf,设置“跟从”---127.0.0.1 6380
[root@theo msconf]# vim redis-slave1.conf slaveof 127.0.0.1 6381
[root@theo msconf]# vim redis-slave2.conf slaveof 127.0.0.1 6381
## 启动三个redis实例
[root@theo msconf]# redis-server redis-master.conf &
[root@theo msconf]# redis-server redis-slave1.conf &
[root@theo msconf]# redis-server redis-slave2.conf &

8.2 哨兵模式

哨兵模式:用于监听主库,当确认主库宕机之后,从备库(从库)中选举一个转备为主
在这里插入图片描述

  • 哨兵模式配置
##首先实现三个redis实例之间的主从配置(如上)
## 创建并启动三个哨兵
## 拷贝sentinel.conf文件三份:sentinel-26380.conf sentinel-26382.conf sentinel-
26382.conf
## 创建sentinelconf目录
[root@theo redis-5.0.5]# mkdir sentinelconf
## 拷贝sentinel.conf文件到 sentinelconf目录:sentinel-26380.conf
[root@theo redis-5.0.5]# cat sentinel.conf | grep -v "#" | grep -v "^$" >
sentinelconf/sentinel-26380.conf
[root@theo redis-5.0.5]# cd sentinelconf/
[root@theo sentinelconf]# ll
total 4
-rw-r--r-- 1 root root 326 May 19 17:09 sentinel-26380.conf
## 编辑 sentinelconf/sentinel-26380.conf文件
[root@theo sentinelconf]# vim sentinel-26380.conf
port 26380
daemonize no
pidfile "/var/run/redis-sentinel-26380.pid"
logfile ""
dir "/tmp"
sentinel deny-scripts-reconfig yes
# 此处配置默认的主库的ip 和端口 最后的数字是哨兵数量的一半多一个
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel config-epoch mymaster 1
sentinel leader-epoch mymaster 1
protected-mode no
[root@theo sentinelconf]# sed 's/26380/26381/g' sentinel-26380.conf > sentinel-
26381.conf
[root@theo sentinelconf]# sed 's/26380/26382/g' sentinel-26380.conf > sentinel-
26382.conf

测试:

启动 主redis
启动 备1redis
启动 备2redis
再依次启动三个哨兵:
[root@theo sentinelconf]# redis-sentinel sentinel-26380.conf

8.3 Redis集群

高可用:保证redis一直处于可用状态,即时出现了故障也有备用方案保证可用性( 主从配置+哨兵模式 )
高并发:一个redis实例已经可以支持多达11w并发读操作或者8.1w并发写操作;但是如果对于有更高并发需求的应用来说,我们可以通过集群配置 来解决高并发问题

在这里插入图片描述
Redis集群

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

8.3.1 集群搭建

[root@theo ~]# cd /usr/local/redis-5.0.5
[root@theo redis-5.0.5]# mkdir cluster-conf
[root@theo redis-5.0.5]# cat redis.conf | grep -v "#"|grep -v "^$" > clusterconf/redis-7001.conf
[root@theo redis-5.0.5]# cd cluster-conf/
[root@theo cluster-conf]# ls
redis-7001.conf
[root@theo cluster-conf]# vim redis-7001.conf

在这里插入图片描述

//拷贝6个文件,端口分别为 7001-7006
[root@theo cluster-conf]# sed 's/7001/7002/g' redis-7001.conf > redis-7002.conf
[root@theo cluster-conf]# sed 's/7001/7003/g' redis-7001.conf > redis-7003.conf
[root@theo cluster-conf]# sed 's/7001/7004/g' redis-7001.conf > redis-7004.conf
[root@theo cluster-conf]# sed 's/7001/7005/g' redis-7001.conf > redis-7005.conf
[root@theo cluster-conf]# sed 's/7001/7006/g' redis-7001.conf > redis-7006.conf
//启动6个redis实例
[root@theo cluster-conf]# redis-server redis-7001.conf &
[root@theo cluster-conf]# redis-server redis-7002.conf &
[root@theo cluster-conf]# redis-server redis-7003.conf &
[root@theo cluster-conf]# redis-server redis-7004.conf &
[root@theo cluster-conf]# redis-server redis-7005.conf &
[root@theo cluster-conf]# redis-server redis-7006.conf &
//查看6个实例是否启动
[root@theo cluster-conf]# ps -ef|grep redis
root 4789 1 0 10:20 ? 00:00:00 redis-server *:7001 [cluster]
root 4794 1 0 10:20 ? 00:00:00 redis-server *:7002 [cluster]
root 4799 1 0 10:20 ? 00:00:00 redis-server *:7003 [cluster]
root 4806 1 0 10:21 ? 00:00:00 redis-server *:7004 [cluster]
root 4811 1 0 10:21 ? 00:00:00 redis-server *:7005 [cluster]
root 4816 1 0 10:21 ? 00:00:00 redis-server *:7006 [cluster]
//启动集群
//  启动之前安全组/防火墙放行 7001/7006 以及 17001/17006 端口
[root@theo cluster-conf]# redis-cli --cluster create 47.96.11.185:7001
47.96.11.185:7002 47.96.11.185:7003 47.96.11.185:7004 47.96.11.185:7005
47.96.11.185:7006 --cluster-replicas 1

在这里插入图片描述

//连接集群:
[root@theo cluster-conf]# redis-cli -p 7001 -c

8.3.2 集群管理

  • 如果集群启动失败:等待节点加入

    • 云服务器检查安全组是否放行redis实例端口,以及+10000的端口
    • Linux防火墙是否放行redis服务(关闭防火墙)
    • Linux状态(top)---- 更换云主机操作系统
    • redis配置文件错误
  • 创建集群:

[root@theo cluster-conf]# redis-cli --cluster create 47.96.11.185:7001
47.96.11.185:7002 47.96.11.185:7003 47.96.11.185:7004 47.96.11.185:7005
47.96.11.185:7006 --cluster-replicas 1
  • 查看集群状态
[root@theo cluster-conf]# redis-cli --cluster info 47.96.11.185:7001
47.96.11.185:7001 (4678478a...) -> 2 keys | 5461 slots | 1 slaves.
47.96.11.185:7002 (e26eaf2a...) -> 0 keys | 5462 slots | 1 slaves.
47.96.11.185:7003 (5752eb20...) -> 1 keys | 5461 slots | 1 slaves.
[OK] 3 keys in 3 masters.
0.00 keys per slot on average.
  • 平衡节点的数据槽数
[root@theo cluster-conf]# redis-cli --cluster rebalance 47.96.11.185:7001
>>> Performing Cluster Check (using node 47.96.11.185:7001)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
*** No rebalancing needed! All nodes are within the 2.00% threshold.
  • 迁移节点槽

在这里插入图片描述

  • 删除节点
[root@theo cluster-conf]# redis-cli --cluster del-node 47.96.11.185:7001
4678478aa66b6d37b23944cf7db0ac07298538a4
>>> Removing node 4678478aa66b6d37b23944cf7db0ac07298538a4 from cluster
47.96.11.185:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@theo cluster-conf]# redis-cli --cluster info 47.96.11.185:7002
47.96.11.185:7002 (e26eaf2a...) -> 1 keys | 8192 slots | 2 slaves.
47.96.11.185:7003 (5752eb20...) -> 2 keys | 8192 slots | 1 slaves.
[OK] 3 keys in 2 masters.
0.00 keys per slot on average.
  • 添加节点
[root@theo cluster-conf]# redis-cli --cluster add-node 47.96.11.185:7007
47.96.11.185:7002

8.3.3 SpringBoot应用连接集群

//添加依赖
[root@theo cluster-conf]# redis-cli --cluster del-node 47.96.11.185:7001
4678478aa66b6d37b23944cf7db0ac07298538a4
>>> Removing node 4678478aa66b6d37b23944cf7db0ac07298538a4 from cluster
47.96.11.185:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@theo cluster-conf]# redis-cli --cluster info 47.96.11.185:7002
47.96.11.185:7002 (e26eaf2a...) -> 1 keys | 8192 slots | 2 slaves.
47.96.11.185:7003 (5752eb20...) -> 2 keys | 8192 slots | 1 slaves.
[OK] 3 keys in 2 masters.
0.00 keys per slot on average.
[root@theo cluster-conf]# redis-cli --cluster add-node 47.96.11.185:7007
47.96.11.185:7002
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
//配置集群节点
spring:
redis:
cluster:
nodes: 47.96.11.185:7001,47.96.11.185:7002,47.96.11.185: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);
}
}
/*如果集群需要设置密码:
1. redis集群节点在配置文件中除了需要设置 requirepass 之外,还要设置 masterauth :
2. 集群中每个节点的密码必须保持一致*/
masterauth 123456
requirepass 123456

九、Redis淘汰策略

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

Redis提供的8种淘汰策略

redis中缓存的数据按照是否设置过期时间分为:

  • 会过期的数据 (设置了过期时间)
  • 不会过期的数据(没设置过期时间)
# volatile-lru -> 从设置了过期时间的数据中淘汰最久未使用的数据.
# volatile-lfu -> 从设置了过期时间的数据中淘汰使用最少的数据.
# volatile-random -> 从设置了过期时间的数据中随机淘汰一批数据.
# volatile-ttl -> 淘汰过期时间最短的数据.
# allkeys-lru -> 从所有数据中淘汰最久未使用的数据.
# allkeys-lfu -> 从所有数据中淘汰使用最少的数据.
# allkeys-random -> 从所有数据中随机淘汰一批数据.
# noeviction -> 不淘汰任何数据,当内存不够时直接抛出异常.

理解两个算法名词:

  • LRU 最近最久未使用
  • LFU 最近最少使用

在这里插入图片描述

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是二次元穿越来的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值