redis高级
事务机制
简述
redis事务是基于队列实现的,创建一个事务队列,然后将事务操作都放入队列中,最后依次执行
作用
保证数据可以恢复操作,确保数据的完整性
列子
#我的关注 user:用户id:follow 被关注的用户id
#我的粉丝 user:用户id:fans 粉丝用户id
#开启事务
multi
#添加命令
#小明用户为1001 , 小张用户id为1002
sadd user:1001:follow 1002
sadd user:1002:follow 1001
sadd user:1001:fans 1002
sadd user:1002:fans 1002
#执行事务
exec
# 取消事务
discard
事务的机制
语法错误(编译)
#开启事务
multi
#命令
set name zhangsan
set age
seterror sex male
#执行事务
exec
#获取正确指令数据
get name
事务队列中的命令在进入队列后,在执行exec命令前,队列中的命令存在语法错误,此时队列中的所有命令都会执行失败
执行错误(运行)
#开启事务
multi
#命令
set lesson java
rpush lesson eureka feign nacos
set lesson redis
#执行事务
exec
#获取数据
get lesson
事务队列中的命令在进入队并执行exec命令后,出现错误,此时队列中其他命令不会受到影响正常执行
springboot实现redis事务操作
1)修改RedisConfig配置类,开启事务控制
//开启redis事务控制
redisTemplate.setEnableTransactionSupport(true);
2)自定义方法,测试事务效果
@Test
@Transactional(rollbackFor = Exception.class)
public void multiTest(){
//开启事务
redisTemplate.multi();
try{
redisTemplate.opsForValue().set("lesson","java");
redisTemplate.opsForSet().add("lesson","eureka","feign","gateway");
redisTemplate.opsForValue().set("lesson","redis");
System.out.println(redisTemplate.opsForValue().get("lesson"));
}catch (Exception e){
//回滚
System.out.println("出现异常");
redisTemplate.discard();
}finally {
redisTemplate.exec();
}
}
持久化机制
RDB快照
RDB(Redis DataBase)是Redis默认存储方式。其基于快照思想,当符合一定条件(手动或自动触发)时,Redis会将这一刻的内存数据进行快照并保存在磁盘上,产生一个经过压缩的二进制文件,文件后缀名.rdb
触发条件
自动
在redis.conf文件中配置了一些默认触发机制。
手动
在redis客户端执行save或bgsave命令,手动触发RDB快照。
#进入客户端
bin/redis-cli
#执行save命令(同步执行)
save
#执行bgsave命令(异步子线程执行)
bgsave
save或bgsave命令的区别
save:同步处理,阻塞Redis服务进程,服务器不会处理任何命令,直到RDB文件保存完毕。
bgsave:会fork一个和主线程一致的子线程负责操作RDB文件,不会阻塞Redis服务进程,操作RDB文件的同时仍然可以处理命令。
Redis默认使用的是 bgsave 来保存快照数据。
执行过程
1)Redis服务进程判断,当前是否有子线程在执行save或bgsave。
2)如果有,则直接返回,不做任何处理。
3)如果没有,则以阻塞式创建子线程,在创建子线程期间,Redis不处理任何命令。
4)创建完子线程后,取消阻塞,Redis服务继续响应其他命令。
5)同时基于子线程操作RDB文件,将此刻数据保存到磁盘。
AOF
AOF(append only file)是Redis提供了另外一种持久化机制。与RDB记录数据不同,当开启AOF持久化后,Redis会将客户端发送的所有更改数据的命令,记录到磁盘中的AOF文件。 这样的话,当Redis重启后,通过读取AOF文件,按顺序获取到记录的数据修改命令,即可完成数据恢复。
举个例子,对Redis执行三条写命令:
set name itheima
hset cart shop nike
sadd lesson java python hadoop
RDB会将name、cart、lesson三个键值对数据进行保存,而AOF会将set、hset、sadd三个命令保存到AOF文件中。
触发方式
AOF方式需要手动开启,修改redis.conf
# 是否开启AOF,默认为no
appendonly yes
#设置AOF文件名称
appendfilename appendonly.aof
对于AOF的触发方式有三种:always、everysec、no。 默认使用everysec。可以通过redis.conf中appendfsync属性进行配置。
- always:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,并将AOF文件同步到磁盘。该方式效率最低,安全性最高。
- everysec:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中。 并且每隔一秒会由子线程将AOF文件同步到磁盘。该方式兼备了效率与安全,即使出现宕机重启,也只会丢失不超过两秒的数据。
- no:每次执行写入命令都会将aof_buf缓冲区文件全部内容写入到AOF文件中,但并不对AOF文件进行同步磁盘。 同步操作交由操作系统完成(每30秒一次),该方式最快,但最不安全。
执行原理
开启AOF后,重启Redis,进入Redis客户端并执行多条写命令,这些命令会被保存到appendonly.aof文件中。
set name zhangsan
set age 18
set sex male
get name
get age
get sex
此时查看redis/data目录,会新产生一个appendonly.aof文件。 查看文件内容
*2 #表示该命令有两个词 (select 0 查询0号数据库)
$6 #表示第一个词由6个字符组成
SELECT #表示第一词为select
$1 #表示第二个词由1个字符组成
0 #表示第二词为0
*3
$3
set
$4
name
$8
zhangsan
*3
$3
set
$3
age
$2
18
*3
$3
set
$3
sex
$4
male
出现的*1 $1这些可以防篡改
重写优化
随着操作redis越多,命令数据占用大量存储空间、数据还原花费的时间多
自动
#当前aof文件大小超过上一次aof文件大小的百分之多少时进行重写。如果之前没有重写过,以
启动时aof文件大小为准
auto-aof-rewrite-percentage 100
#限制允许重写最小aof文件大小,也就是文件大小小于64mb的时候,不需要进行优化
auto-aof-rewrite-min-size 64mb
手动
直接调用bgrewriteaof命令。(命令:redis-cli bgrewriteaof)
高可用
redis集群,主从分离,当一台服务器中数据更新后,可以自动的将更新的数据同步到其他服务器上
读写分离
在生产环境下,读请求会远远多于写请求,大概10:1的比率。 当单机无法应对大量读请求时,可以通过主从复制机制,实现读写分离。主节点只负责写请求,从节点只负责读请求
持久化优化
从节点上开启持久化、在主节点关闭持久化
操作流程
1、Slave服务启动,主动连接Master,并发送SYNC命令,请求初始化同步;
2、Master收到SYNC后,执行BGSAVE命令生成RDB文件,并缓存该时间段内的写命令;
3、Master完成RDB文件后,将其发送给所有Slave服务器;
4、Slave服务器接收到RDB文件后,删除内存中旧的缓存数据,并装载RDB文件;
5、Master在发送完RDB后,即刻向所有Slave服务器发送缓存中的写命令;
作用
- 读写分离:主写从读,提高服务器的读写负载能力
- 负载均衡:基于主从结构,配合读写分离,由slave分担master负载,并根据需求的变化,改变slave的数量,通过多个从节点分担数据读取负载,大大提高Redis服务器并发量与数据吞吐量
- 故障恢复:当master出现问题时,由slave提供服务,实现快速的故障恢复
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
- 高可用基石:基于主从复制,构建哨兵模式与集群,实现Redis的高可用方案
哨兵模式
如果主库挂了,我们就需要运行一个新主库,比如说把一个从库切换为主库,把它当成主库。
这就涉及到三个问题:
-
主库真的挂了吗?
-
该选择哪个从库作为主库?
-
怎么把新主库的相关信息通知给从库和客户端呢?
哨兵(sentinel) 是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
单机版哨兵
注意:
-
哨兵也是一台redis服务器,只是不提供数据服务
-
通常哨兵配置数量为单数
-
如果配置启用单节点哨兵,如果有哨兵实例在运行时发生了故障,主从库无法正常
切换啦,所以我们需要搭建 哨兵集群
哨兵集群
- Redis提供了哨兵的命令,是一个独立的进程
- 原理 哨兵通过发送命令给多个节点,等待Redis服务器响应,从而监控运行的多个Redis实例的运行情况
- 当哨兵监测到master宕机,会自动将slave切换成master,通过通知其他的从服务器,修改配置文件切换主机
注意:
哨兵必须要配置大于等于3的奇数,因为哨兵要进行投票判断主服务器是否挂了
如果某个哨兵检测到主服务器挂了,但是其他没有检测到,就说明哨兵出现了误判1!
主观下线
哨兵检测到主服务器挂了就会先把它标记为“主观下线”,并进行投票。
客观下线
当哨兵判断主服务器挂的票数多于半数时,主服务器就会变成客观下线(此时才拿掉,客观下线条件只适用于主服务器)
仲裁
投票的过程就叫仲裁
高可扩
先通过crc16算法判断数据是否有问题再通过hash槽进行计算,然后分配数据到Master服务器
key过期淘汰策略
定时删除
它会在设置键的过期时间的同时,创建一个定时器, 当键到了过期时间,定时器会立即对键进行删除。 这个策略能够保证过期键的尽快删除,快速释放内存空间
优缺点:
- Redis的操作频率是非常高的
- 会造成出现大量定时器执行,严重降低系统性能
- 该策略对内存空间足够友好, 但对CPU非常不友好,会拉低系统性能,因此不建议使用
惰性删除
它不持续关注key的过期时间, 而是在获取key时,才会检查key是否过期,如果过期则删除该key
优缺点:
- 不持续关注key的过期时间, 而是在获取key时,才会检查key是否过期,如果过期则删除该key
- 惰性删除对CPU足够友好,但是对内存空间非常不友好,会造成大量内存空间的浪费
定期删除
- 默认每秒运行10次会对具有过期时间的key进行一次扫描,但是并不会扫描全部的key,因为这样会大大延长扫描时间。
- 每次默认只会随机扫描20个key,同时删除这20个key中已经过期的key。
- 如果这20个key中过期key的比例达超过25%,则继续扫描。
可以通过参数配置修改每秒扫描次数只需要修改redis.conf中的hz参数即可。
缺点:
因为是随机扫描,所以可能会出现过期了但一直没有扫描到的情况
内存淘汰策略
作用
Redis会检查内存空间大小,如超过最大内存,则触发内存淘汰策略,redis通过释放内存中的数据,来保证新数据的添加
最大内存参数配置
修改redis.conf中的maxmemory 来设置最大内存。
淘汰策略
过期时间数据淘汰
- volatile-lru
删除设置了ttl2,且最近中最久未被使用过的key - volatile-lfu
删除设置了ttl,且最近中最少使用过的key - volatile-ttl
删除设置了ttl,且即将过期的key - volatile-random
从设置了ttl中的key中随机删除
所有数据淘汰
- allkeys-lru
所有key中,删除最近中最久未被使用过的key - allkeys-lfu
所有key中,删除最近中最少使用过的key - allkeys-random
从所有key中,随机删除key
不淘汰
- noeviction
不删除,当内存空间不足时,直接报异常
策略设置
redis默认使用noeviction,我们可以通过修改redis.conf中maxmemory-policy属性值设置不同的内存淘汰策略。
使用场景
1、Redis只做缓存,不做DB持久化,使用allkeys。如状态性信息,经常被访问,但数据库不会修改。
2、同时用于缓存和DB持久化,使用volatile。如商品详情页。
3、存在冷热数据区分,则选择LRU或LFU。如热点新闻,热搜话题等。
4、每个key被访问概率基本相同,选择使用random。如企业内部系统,访问量不大,删除谁对数据库也造成太大压力。
5、根据超时时间长久淘汰数据,选择选用ttl。如微信过期好友请求。
redis6.0新特性
支持多线程
- redis6多线程只是用来处理网络数据的读写和协议解析上,底层数据操作还是单线程
- 执行命令仍然是单线程,之所以这么设计是不想因为多线程而变得复杂,需要去控制 key、lua、事务,LPUSH/LPOP 等等的并发问题
- 默认不开启
io-threads-do-reads yes
io-threads 线程数
- 官方建议 ( 线程数小于机器核数 )
4 核的机器建议设置为 2 或 3 个线程
8 核的建议设置为 4或6个线程, - 不会有安全问题,Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行。
acl
给用户创建权限,通过限制对命令和密钥的访问来提高安全性,以使不受信任的客户端无法访问
3.redis的客户端支持缓存
类似浏览器缓存一样
lettuce客户端
lettuce的依赖
jedis的依赖
lettuce的配置
jedis的配置
api一样