Redis学习笔记(高级部分)
文章目录
5. Redis其它配置及集群
修改yml(创建的配置文件)文件,方便以后修改Redis配置
5.1 Redis的AUTH
设置通过密码连接,为了更加安全,之前的相关代码与操作都需增加密码操作
方式1:修改配置文件,实现密码校验
三种客户端连接方式:
1.redis-cli:输入正常命令之前,输入auth密码
2.图形化界面:连接时添加密码信息
3.Jedis客户端:
(1)每次获取Jedis对象时通过jedis.auth(password)方法设置,繁琐不推荐
(2)在创建JedisPool时通过带参构造方法设置password
方式2:不修改redis.conf 文件,第一次连接Redis时,输入命令Config set requirepass [password],之后一样需要上述操作验证
5.2 Redis的事务
区别于SQL中支持的事务
Redis事务:一次事务,该成功则成功,该失败则失败
开启事务,执行一系列命令,但命令不会立即执行,而是放在一个队列中,如果执行事务,那么这个队列中的命令全部执行,如果取消事务,队列中命令全部作废
开启事务命令:
multi
事务操作流程:
1.开启事务:multi
2.依次输入命令,命令会放到一个队列中
3.执行事务:exec
4.取消事务:discard
但Redis的事务要发挥实际业务功能,需要和watch监听机制配合使用
即开启事务之前,先通过watch命令监听一个或多个key,开启事务后,若有其他客户端修改了监听的key,事务自动取消
事务执行或取消之后,watch监听自动取消
5.3Redis持久化机制
5.3.1 RDB持久化机制
RDB是Redis默认的持久化机制
1.RDB持久化文件,速度很快,存储二进制文件,传输方便
2.RDB定义了默认的持久化时机,可根据实际使用环境做修改
3.RDB无法保证数据的绝对安全(主要为持久化时间机制原因)
官网下载或安装包找到配置文件可查看相关配置信息
以下为RDB持久化时机机制的相关配置说明
#RDB执行的时机,900s内有一个key改变了,就需执行持久化 save 900 1 #300s秒有10个key改变,执行持久化 save 300 10 #同理,60s内,1000key改变,执行持久化 save 60 10000 #开启RDB持久化的压缩 rdbcompression yes #RDB持久化文件名称 dbfilename dump.rdb #以下为官方文档描述 #ave the DB on disk: # # save <seconds> <changes> # # Will save the DB if both the given number of seconds and the given # number of write operations against the DB occurred. # # In the example below the behaviour will be to save: # after 900 sec (15 min) if at least 1 key changed # after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed
5.3.2 AOF持久化机制
AOF默认为关闭状态,Redis允许同时开启RDB与AOF,官方也推荐同时开启,更加安全,避免数据丢失
1.AOF持久化的速度,相对RDB较慢,存储文本文件,后期文件较大,传输不方便
2.AOF持久化时机
#每执行一个写操作,立即持久化到AOF文件中,性能较低,默认关闭(被注释掉) #appendfsync always #每秒执行一次持久化,推荐 appendfsync everysec #根据操作系统,环境不同,在一定时间执行一次持久化,不实用不安全,默认关闭 appendfsync no
3.相对于RDB,更安全
相关配置
#是否开启AOF,默认为no appendonly no #AOF文件名称 appendfilename "appendonly.aof" appendfsync always appendfsync everysec appendfsync no
备注:若同时开启RDB与AOF,在Redis重启之后,需要加载一个持久化文件,会优先选择AOF文件
如果先开启RDB,后开启AOF,如果EDB执行了持久化,那么RDB中的内容会被覆盖掉,会造成数据丢失,要注意开启顺序,要么先开AOF,要么同时开启
5.4 Redis主从架构
单机Redis尽管读取数非常快,但还是存在读取瓶颈问题,写大约8W/S,读11W/s,若只有一台Redis,请求量非常大时,还是会崩溃
主从架构,可以很好的解决问题,至少需要三台Redis,需要进行相关配置,但避免不了单点故障,master挂掉,“群龙无首”,主从架构土崩瓦解。
5.5 Redis哨兵
哨兵用来解决单点故障问题
实现方式:准备哨兵的配置文件,启动
#哨兵是否后台启动,默认为no
daemonize no
#指定master节点的ip和端口(主)
sentinel monitor master localhost 6379 2
#指定master节点的ip和端口(从)
sentinel monitor master master 6379 2
#哨兵每隔多久监听一次Redis架构,默认30S
sentinel down-after-milliseconds master 30000
故障前架构图,master故障,群龙无首
故障后架构图,新一个master出现,新一代master挺身而出,力挽狂澜
5.6 Redis集群
Redis集群能保证主从加哨兵的基本功能外,还能够提升Redis存储数据的能力,主从架构只有master能写,集群不存在这种限制,因为集群上的节点都是平等的,都可以读写
特点:
1.Redis集群无中心
2.有ping-pang机制(两两发送消息必须有问有答,不然会被认为已经失去连接,进入投票机制,判断失去连接的节点是否还可用)
3.投票机制(Redis集群的节点数量必须是2n+1)
4.Redis集群中默认分配了16384个hash槽,存储数据时,对key进行crc16算法,并对16384取余,根据最终结果将key-value存放在执行的Redis节点中,每个节点都维护着相应的hash槽
5.为保证数据的安全性,每一个集群的节点,至少有一个从节点(备份与备胎的身份)
6.单独针对Redis集群中的某一个节点(请求量很大)搭建主从,分担压力
7.集群中超过半数的节点宕机后,集群瘫痪
架构图
搭建集群,准备相关配置文件,略
5.7 Java连接Redis集群
配置好集群后,Java连接访问比较简单,以下为示例代码
import org.junit.Test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import java.util.HashSet;
import java.util.Set;
public class Demo9Test {
//java集群连接测试
@Test
public void clusterConnectTest(){
//1.创建节点集合
Set<HostAndPort> nodes = new HashSet<>();
//添加地址与端口
nodes.add(new HostAndPort("127.0.0.1",7001));
nodes.add(new HostAndPort("127.0.0.1",7002));
nodes.add(new HostAndPort("127.0.0.1",7003));
nodes.add(new HostAndPort("127.0.0.1",7004));
nodes.add(new HostAndPort("127.0.0.1",7005));
nodes.add(new HostAndPort("127.0.0.1",7006));
//2.创建JedisCluster对象,内置了连接,不需要关心创建与释放连接资源
JedisCluster jedisCluster = new JedisCluster(nodes);
//3.直接进行业务访问操作
String value = jedisCluster.get("redis");
System.out.println(value);
}
}
6.Redis常见问题
6.1 key的生存时间到期,Redis会立即删除吗
不会立即删除
删除机制
1.定期删除:
Redis每隔一端时间会查看设置乐生存时间的key,会在100ms得时间间隔默认查看3个key,比较随机,有些key会长期存在没有被删除
2.惰性删除:
如果查询一个已经过了生存时间的key,Redis会查看当前key的生存时间,若已经到了生存时间,直接删除key,并返回一个空值
6.2 Redis的淘汰机制
在Redis内存不足,要添加新的数据,执行淘汰机制,有8种策略
1.volatile-lru:在设置过了生存时间的key中删除最近最少使用的key
2.allkeys-lru:在全部key中删除最近最少使用的key
3.volatile-lfu:在设置过了生存时间的key中删除最近最少频次使用的key
4.allkeys-lfu:在设置过了生存时间的key中删除最近最少频次使用的key
5.volatile-random:在设置过了生存时间的key中随机删除key(比较危险)
6.allkeys-random:在全部key中随机删除key(危险)
7.volatile-ttl:在设置过了生存时间的key中删除剩余生存时间最少的key
8.noeviction:啥也不做,直接报错(不推荐,但为默认的)
指定淘汰机制:maxmemory-policy 具体策略
设置最大内存:maxmemory
官方配置文档说明,以供参考
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached. You can select one from the following behaviors:
#
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
#
# LRU means Least Recently Used
# LFU means Least Frequently Used
#
# Both LRU, LFU and volatile-ttl are implemented using approximated
# randomized algorithms.
#
# Note: with any of the above policies, Redis will return an error on write
# operations, when there are no suitable keys for eviction.
#
# At the date of writing these commands are: set setnx setex append
# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
# getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy noeviction
6.3 缓存问题
简单架构图:
缓存穿透:
问题原因:查询的数据,Redis中没有,数据库中也没有,而请求量又特别大时(有部分可能是恶意攻击),就会造成数据库宕机
解决方案
1.根据id查询时,如果id是自增的,将id的最大值放到Redis中,直接先比较一下id范围是否合理
2.如果id不是整型,可以将id放到set中,在用户查询之前,查看是否有这样的id
3.获取客户的ip地址,对其添加访问限制
缓存击穿:
问题原因:缓存中得热点数据突然到期了,造成大量请求访问数据库,造成数据库宕机
解决方案:
1.访问缓存中没有的数据时,添加锁,限制访问数据库请求的个数
2.将热点数据的生存时间去掉
缓存雪崩:
问题原因:大量缓存同时到期,大量请求同时访问数据库,造成数据库宕机
解决方案:
将缓存中的数据的生存时间,设置一个范围的随机数,以避免同时到期
缓存倾斜:
问题原因:热点数据放在了一个Redis节点上,Redis节点无法承受大量的请求,最终Redis宕机
解决方案:
1.扩展主从架构,搭建大量的从节点,缓解Redis的压力
2.在Tomcat中做缓存,在查询Redis之前,先查询Tomcat的缓存