一、Jedis的使用
1.修改/usr/local/redis-6.2.6/bin目录下的redis.conf配置文件,然后启动redis服务端
将绑定127.0.0.1注释掉,然后把保护模式关掉
如需设置密码,可以使用以下两种方式:
方式一:通过修改 redis.conf 文件,设置Redis的密码校验
requirepass 密码
方式二:在不修改 redis.conf 文件的前提下,在第一次链接Redis时,输入命令:Config set requirepass 密码
后续连接redis客户端的时候,需要先 AUTH 做一下校验
127.0.0.1:6379> auth 密码
2.创建Maven工程,导入依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
</dependencies>
3.编写实体类
import lombok.Data;
@Data
public class Student {
private String name;
private Integer age;
private String schoolName;
private double weight;
}
4.编写测试类
@Test
public void myTest1() throws JsonProcessingException {
// 通过jedis的构造方法,第一个参数填写主机名,第二个为redis的端口号
Jedis jedis = new Jedis("8.130.166.101",6379);
// 将对象转化为json传输 我这里使用的是jackson
ObjectMapper objectMapper = new ObjectMapper();
// 创建对象并进行赋值
Student student = new Student();
student.setName("张三");
student.setSchoolName("和平路小学");
student.setAge(12);
student.setWeight(168.20);
Student student2 = new Student();
student2.setName("李四");
student2.setSchoolName("南京路小学");
student2.setAge(16);
student2.setWeight(128.20);
// 将对象类型的数据转化为json数据
String s1 = objectMapper.writeValueAsString(student);
String s2 = objectMapper.writeValueAsString(student2);
// jedis调用lpush将数据存入list
jedis.lpush("students",s1,s2);
// 通过key值获取数据并打印出来
List<String> students = jedis.lrange("students", 0, -1);
System.out.println(students);
}
可以在redis图形化工具看到结果
@Test
public void myTest2() throws JsonProcessingException {
// 创建池子的配置对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(15);//最大连接数
jedisPoolConfig.setMaxIdle(30);//设置最大闲置连接数
// 创建连接池对象
JedisPool jedisPool = new JedisPool("8.130.166.101", 6379);
// 通过连接池获取jedis对象
Jedis jedis = jedisPool.getResource();
Student student = new Student();
student.setName("张五");
student.setSchoolName("和平路小学");
student.setAge(12);
student.setWeight(168.20);
// 转为json数据
String stu = new ObjectMapper().writeValueAsString(student);
jedis.set("student",stu);
String s = jedis.get("student");
System.out.println(s);
}
二、Redis中的事务
Redis中的事务和MySQL中的事务有本质的区别,Redis中的事务是一个单独的隔离操作,事务中所有的命令都会序列化,按照顺序执行,事务在执行的过程中,不会被其他客户端发来的命令所打断,因为Redis服务端是个单线程的架构,不同的Client虽然看似可以同时保持连接,但发出去的命令是序列化执行的,这在通常的数据库理论下是最高级别的隔离。
Redis中的事务的作用就是串联多个命令,防止别的命令插队。
常用命令:multi、exec、discard、watch、unwatch
当输入multi命令时,之后输入的命令都会被放在队列中,但不会执行,直到输入exec后,Redis会将队列中的命令依次执行,discard用来撤销Exec之前被暂存的命令,并不是回滚。
watch/unwatch
在执行multi之前,先执行watch key1 [key2...] ,watch提供的乐观锁功能(初始时一个版本号,exec之后会更新当前版本号),在你exec的那一刻,如果被watch的键发生过改动,则multi到exec之间的指令全部不执行。
watch表示监控,相当于加锁,但在执行完exec时就会解锁。
unwatch取消所有锁。
例如下面两个图,都开启锁开启事务,这时候左侧先执行完毕,可以看到右侧的就执行不了了
Redis中的事务的特性总结
1.单独的隔离操作
事务中的所有命令都会序列化,然后按顺序执行,在执行过程中,不会被其他客户端发送的命令打断。2.没有隔离级别的概念
队列中的命令没有被提交之前都不会执行。3.不能保证原子性
Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,不会回滚
八、Redis中的持久化
Redis有两种持久化方式:RDB和AOF。
1.RDB(Redis DataBase)
将内存中的数据以快照的方式写入磁盘中,在redis.conf文件中,我们可以找到如下配置:
save 900 1
save 300 10
save 60 10000
配置含义:
900秒内,如果超过1个key被修改,则发起快照保存
300秒内,如果超过10个key被修改,则发起快照保存
60秒内,如果1万个key被修改,则发起快照保存
RDB方式存储的数据会在
dump.rdb文件中(在哪个目录启动redis服务端,该文件就会在对应目录下生成),该文件不能查看,如需备份,对Redis操作完成之后,只需拷贝该文件即可(Redis服务端启动时会自动加载该文件)
2.AOF(Append Of File)
AOF默认是不开启的,需要手动开启,同样是在redis.conf文件中开启,如下:
配置文件中的appendonly修改为yes,开启AOF持久化。开启后,启动redis服务端,发现多了一个appendonly.aof文件。
之后任何的操作都会保存在appendonly.aof文件中,可以进行查看,Redis启动时会将appendonly.aof文件中的内容执行一遍。
如果AOF和RDB同时开启,系统会默认读取AOF的数据。
3.总结
RDB优点与缺点
优点
如果要进行大规模数据的恢复,RDB方式要比AOF方式恢复速度要快。
RDB是一个非常紧凑(compact)的文件,它保存了某个时间点的数据集,非常适合用作备份,同时也非常适合用作灾难性恢复,它只有一个文件,内容紧凑,通过备份原文件到本机外的其他主机上,一旦本机发生宕机,就能将备份文件复制到redis安装目录下,通过启用服务就能完成数据的恢复。
缺点
RDB这种持久化方式不太适应对数据完整性要求严格的情况,因为,尽管我们可以用过修改快照实现持久化的频率,但是要持久化的数据是一段时间内的整个数据集的状态,如果在还没有触发快照时,本机就宕机了,那么对数据库所做的写操作就随之而消失了并没有持久化本地dump.rdb文件中。
AOF优点与缺点
优点
AOF有着多种持久化策略:
appendfsync always:每修改同步,每一次发生数据变更都会持久化到磁盘上,性能较差,但数据完整性较好。
appendfsync everysec: 每秒同步,每秒内记录操作,异步操作,如果一秒内宕机,有数据丢失。
appendfsync no:不同步。
AOF文件是一个只进行追加操作的日志文件,对文件写入不需要进行seek,即使在追加的过程中,写入了不完整的命令(例如:磁盘已满),可以使用redis-check-aof工具可以修复这种问题
Redis可以在AOF文件变得过大时,会自动地在后台对AOF进行重写:重写后的新的AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建AOF文件的过程中,会继续将命令追加到现有的AOF文件中,即使在重写的过程中发生宕机,现有的AOF文件也不会丢失。一旦新AOF文件创建完毕,Redis就会从旧的AOF文件切换到新的AOF文件,并对新的AOF文件进行追加操作。
缺点
对于相同的数据集来说,AOF文件要比RDB文件大。
根据所使用的持久化策略来说,AOF的速度要慢于RDB。一般情况下,每秒同步策略效果较好。不使用同步策略的情况下,AOF与RDB速度一样快。
九、Redis中的消息的订阅与发布
subscribe channel 订阅频道 例如:subscribe cctv5
publish channel content 在指定频道中发布内容 例如:publish cctv5 basketball
同时打开两个客户端,一个订阅频道,一个在频道中发布内容,订阅频道的客户端会接收到消息。
先订阅
推送消息
可以看到能接收到消息
十、使用Redis图形化程序界面
Redis中默认有16个库,可以在不同的库中存储数据,默认使用0号库存储数据,使用select 0-15可以选择不同的库。
安装之后,输入IP地址登录即可看到如下界面:(连接前需要注释掉bind 127.0.0.1)
十一、Redis的主从复制
主从复制是指将一台Redis服务器的数据,复制到其它的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
默认情况下,每台Redis服务器都是主节点,且一个主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。
主从复制的作用:
1.数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2.故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复,但实际上是一种服务的冗余.
3.负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4.高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础.
配置步骤:
1.查看当前库的信息:
127.0.0.1:6379> info replication
2.关闭当前运行的redis,打开四个链接,进行测试,拷贝三个redis.conf文件(改成6379,6380,6381)
3.分别修改这三个文件信息,需要修改:端口,pid名字,log文件名字,dump.rdb名字
port 6379
pidfile /var/run/redis_6379.pid
logfile "6379.log"
dbfilename dump6379.rdb
port 6380
pidfile /var/run/redis_63780pid
logfile "6380.log"
dbfilename dump6380.rdb
port 6381
pidfile /var/run/redis_6381.pid
logfile "6381.log"
dbfilename dump6381.rdb
4.分别在三个链接中启动6379,6380,6381三台redis-server,在第四个链接中查看
5.配置一主二从
默认情况下,每台Redis都是主节点,我们只需要配置从机即可,我们这里使用6379为主机,6380和6381为从机.
在对应6380的链接中进行配置:
[root@localhost bin]# ./redis-cli -p 6380
127.0.0.1:6380> slaveof 127.0.0.1 6379
6380从机配置成功之后,可以去主机中查看对应信息
6381从机配置方式和6380一样,配置成功之后可以再去看一下主机
6.由于这里使用的是命令进行配置,所以是暂时的,一般公司配置会在配置文件中进行配置,属于永久性配置,相当于一打开当前服务器,该服务器就是从机,一般主机可以写,从机不能写只能读,主机中的所有信息和数据都会被从机保存!
即使主机断开链接(127.0.0.1:6379>shutdown),从机仍然可以连接到主机,如果使用的是命令行配置的从机,从机一旦断开链接后,就会变回主机了,如果再次变回从机,仍旧可以获取主机中的值.
如果主机断开链接,从机可以使用命令:127.0.0.1:6380>slaveof no one 使自己成为主机
7.主从复制原理
Slave启动成功连接到master后会发送一个sync同步命令,Master接到命令后,会启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕后,master将传送整个数据文件到salve,并完成一次完整的同步.
全量复制:salve服务在接收到数据库文件数据后,将其存盘并加载到内存中.
增量复制:master继续将新的所有收集到的修改命令依次传递给salve,完成同步.
十二、Redis的哨兵模式
当主服务器宕机后,并且我们并没有及时发现,这时候就可能会出现数据丢失或程序无法运行。此时,redis的哨兵模式就派上用场了,可以用它来做redis的高可用.
每个哨兵都是监控主节点,主节点宕机,哨兵不会宕机!
功能作用:
1.监控(monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
2.提醒(Notifation):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3.自动故障转移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
配置步骤:
1.创建哨兵配置文件
[root@localhost bin]# vim sentinel.conf
sentinel.conf文件内容如下:(格式:sentinel monitor 被监控名称 host port 1)
sentinel monitor myredis 127.0.0.1 6379 1
注意:后面的数字1表示有1个sentinel认为一个master失效时,master就算真正失效,slave会以投票的方式选举成为主机.
2.启动哨兵
[root@localhost bin]# ./redis-sentinel sentinel.conf
3.如果Master节点断开了(主机宕机了),过一会,会发送哨兵日志,并自动通过算法在其他两个从机中选择一个成为主机.
![]()
如果之前的主机6379又重新启动了,过一会,哨兵检测到了之后,会把6379设置为从机!
哨兵模式的优缺点
优点
1.哨兵集群模式是基于主从模式的,所有主从的优点,哨兵模式同样具有。
2.主从可以切换,故障可以转移,系统可用性更好。
3.哨兵模式是主从模式的升级,系统更健壮,可用性更高。
缺点
1.Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
2.实现哨兵模式的配置也不简单,甚至可以说有些繁琐
十三、Redis缓存穿透,击穿,雪崩,倾斜
1.1 缓存穿透(查不到)
概念:当用户去查询数据的时候,发现redis内存数据库中没有,于是向持久层数据库查询,发现也没有,于是查询失败,当用户过多时,缓存都没有查到,于是都去查持久层数据库,这会给持久层数据库造成很大的压力,此时相当于出现了缓存穿透。
解决方案:
1.布隆过滤器:是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的压力.
2.缓存空对象:当存储层查不到时,即使返回的空对象也将其缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护后端数据.
但会有两个问题:
1.如果空值被缓存起来,就意味着需要更多的空间存储更多的键,会有很多空值的键.
2.即使对空值设置了过期时间,还是会存在 缓存层和存储层会有一段时间窗口不一致,这对于需要保持一致性的业务会有影响.
1.2 缓存击穿(访问量大,缓存过期)
指对某一个key的频繁访问,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就会直接请求数据库,就像在一个屏障上凿开了一个洞,例如微博由于某个热搜导致宕机.
其实就是:当某个key在过期的瞬间,有大量的请求并发访问,这类数据一段是热点数据,由于缓存过期,会同时访问数据库来查询最新数据,并回写缓存,导致数据库瞬间压力过大。
解决方案:
1.设置热点数据永不过期:从缓存层面上来说,不设置过期时间,就不会出现热点key过期后产生的问题.
2.添加互斥锁:使用分布式锁,保证对每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可,这种方式将高并发的压力转移到了分布式锁上,对分布式锁也是一种极大的考验.
1.3 缓存雪崩
指在某一个时间段,缓存集中过期失效或Redis宕机导致的,例如双十一抢购热门商品,这些商品都会放在缓存中,假设缓存时间为一个小时,一个小时之后,这些商品的缓存都过期了,访问压力瞬间都来到了数据库上,此时数据库会产生周期性的压力波峰,所有的请求都会到达存储层,存储层的调用量暴增,造成存储层挂掉的情况.
其实比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网,因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,此时的数据库还是可以顶住压力的,而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,有可能瞬间就把服务器压垮.
解决方案:
1.配置Redis的高可用:其实就是搭建集群环境,有更多的备用机.
2.限流降级:在缓存失效后,通过加锁或者队列来控制读服务器以及写缓存的线程数量,比如对某个key只允许一个线程查询数据和写缓存,其他线程等待.
3.数据预热:在项目正式部署之前,把可能用的数据预先访问一边,这样可以把一些数据加载到缓存中,在即将发生大并发访问之前手动触发加载缓存中不同的key,设置不同的过期时间,让缓存失效的时间尽量均衡.
1.4 缓存倾斜
指某一台redis服务器压力过大而导致该服务器宕机.
十四、Redis集群搭建(自己动手,丰衣足食)
十五、Redis其他常见问题
1.key的生存时间到了,Redis会立即删除吗?
不会立即删除
1.1定期删除:Redis每隔一段时间就去会去查看Redis设置了过期时间的key,会再100ms的间隔中默认查看3个key。
1.2惰性删除:如果当你去查询一个已经过了生存时间的key时,Redis会先查看当前key的生存时间,是否已经到了,直接删除当前key,并且给用户返回一个空值。
2.Redis的淘汰机制
在Redis内存已经满的时候,添加了一个新的数据,执行淘汰机制。(redis.conf中配置)
2.1 volatile-lru:在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少使用的key。
2.2 allkeys-lru:在内存不足时,Redis会在全部的key中干掉一个最近最少使用的key。
2.3 volatile-lfu:在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少频次使用的key。
2.4 allkeys-lfu:在内存不足时,Redis会在全部的key中干掉一个最近最少频次使用的key。
2.5 volatile-random:在内存不足时,Redis会在设置过了生存时间的key中随机干掉一个。
2.6 allkeys-random:在内存不足时,Redis会在全部的key中随机干掉一个。
2.7 volatile-ttl:在内存不足时,Redis会在设置过了生存时间的key中干掉一个剩余生存时间最少的key。
2.8 noeviction:(默认)在内存不足时,直接报错。
方案:指定淘汰机制的方式:maxmemory-policy具体策略,设置Redis的最大内存:maxmemory 字节大小