Redis主从关系
当有多个客户端请求Redis时,Redis可能会过载
可以建立Redis集群,并确定主从关系
应用程序
写入
主-Master 6379端口
复制 复制
读取
Slaver 6380端口 Slaver 6381端口
Monster以写为主,Slaver以读为主,读写分离,提高效率
如果某个Slaver不能正常工作,可切换另一个slaver
只有能有一个Monster
搭建一主二从
新建3个redis服务
创建另外目录将redis.conf到 /hspredis
mkdir /hspredis
cd /hspredis
cp /etc/redis.conf /hspredis/
修改对应三个conf文件
include /hspredis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
include /hspredis/redis.conf
pidfile /var/run/redis_6380.pid
port 6380
dbfilename dump6380.rdb
include /hspredis/redis.conf
pidfile /var/run/redis_6381.pid
port 6381
dbfilename dump6381.rdb
即可有3个redis服务
再Xshell分别开启这三个redis服务
现在三个服务都是Monster,通过指令更改6380 6381为6379的仆人
redis-cli -p 6380 指定端口进入对应redis
slaverof 127.0.0.1 6379
6379写入数据,从6380和6381都可以读到
info replication 查看主从关系
注意事项
仆redis每次重启都会默认变为Monster,重新设置为Slaver后能同步主redis的数据
主redis关掉后,仆redis不会变Monster,等主Redis再启动再变为其仆redis
薪火相传
主Redis 仆Redis1 仆Redis2
A B C
B是A仆Redis,C也可以是B的仆Redis,可以减少A的服务器压力
反客为主
slaveof no one 让仆redis变为Monster
哨兵模式
反客为主自动版,能够后台监控主机是否故障,如果故障,将票数最多从库转为主库(上面的B),如果原主机再启动一样成为新主机从机
先到redis们所在文件修改sentinel.conf
cd /hspredis/
vi sentinel.conf
sentinel monitor redis_master 127.0.0.1 6379 1 //进行监控
监控名(自取) 几个哨兵
redis-sentinel /hspredis/sentinel.conf 即可开启监控
Redis集群
redis容量不够,并发操作太多时候需要多个redis
无中心化集群
A从机 node1
A主机 node2
B主机 node3 C主机
B从机 ... C从机
各个Redis仍然采用主从结构,各个Redis服务连通的,都可以作为请求入口,都可以请求转发,即使某个redis服务故障,集群仍可继续运行,每个redis服务为一个节点node
得先删除rdb和aof文件
首先打开集群模式
例如6379.conf文件
cluster-enabled yes 打开集群模式
cluster-config-file nodes-6379.conf 设置节点配置文件名
cluster-node-timeout 15000 失联多久切换主从模式
其他6380 6381 6382...类似
cp redis6379.conf redis6380.conf
将6个节点合成一个集群
cd /opt/redis-6.2.6/src/ 先到此目录
rdis-cli --cluster create --cluster-replicas 1 192.168.198.135:6379 192....:6380 ...6381
合成集群
--cluster-replicas 1:表示为每个集群每个主节点创建个从节点
主从关系认定
cluster nodes 查看主从关系
每个replicates后面对应的端口即为他的主机
集群方式登录
redis-cli -c -p 6379
-c:自动重定向,设置key时使用
注意事项:
一个集群至少3个主节点
一共有16383个插槽slot(用于放置Key),平均分给3个主机,每次设置key会计算插槽值放到对应主机
A负责 0-5460号插槽
B 5461-10922
C 10923-16383
当插入多个key时,可能他们的slot不同故可以
mset k2{name} v2 k3{name} v3 k4{name} v4 可放在同一slot下
查找key对应插槽值
cluster keyslot key
cluster countkeysinslot slot 查找该插槽下有多少key
cluster getkeysinslot slot count 查找该插槽count个key
Redis集群故障恢复
主节点下线,从节点会自动上升为主节点;原主机恢复变为从机
即使连接的不是主机,集群也会自动切换主机储存。主机写,从机读
缓存穿透
key对应的数据在数据源(redis和mysql)不存在,反复针对此key的请求都拿不到则会压垮数据源,应用服务器压力变大,Redis命中率降低,一直查数据库
解决:
1对空值缓存
2.设置可访问名单(白名单)
3.布隆过滤器
4.进行实时监控
缓存击穿
key对应数据存在,但在redis过期,若有大量请求发来,会从后端DB加载数据到缓存,这时候的大量并发请求可能会压垮后端DB,Redis正常,但数据库瘫痪了
解决:
1.预先设置热门数据
2.实时调整key过期时间
3.使用锁
缓存雪崩
key对应数据存在,但在redis过期,此时大量并发请求传来,会从后端DB加载数据,可能会把后端DB压垮,与缓存击穿区别是缓存雪崩针对很多key缓存,而缓存击穿只是某一个key
解决:
1.构建多级缓存架构
2.使用锁或队列
3.设置国企标志更新缓存
4.将缓存失败时间分散开
分布式锁
分布式项目分布在各个机器上,单纯的Java Api不能提供分布式锁的能力,需要一种跨JVM的互斥机制控制共享资源访问,这就是分布式锁要解决的问题
请求 请求 请求
分布式锁
子模块1 子模块2
主流方案:
基础数据库实现
基于缓存实现(redis等) 性能最高
基础Zookeeper 可能性最高
基本实现分布式锁(基于Redis)
setnx key value key是锁的键vlaue是锁的值
del key 释放锁
expire key seconds 给锁设置过期时间防止死锁
ttl key 查看某个锁(过期时间)
set key value nx ex seconds 设置锁并过期时间
通过SpringBoot+Redis实现分布式锁
index1 index2 index3
Redis通过setnx()加锁
在Controller内
@GetMapping("/lock")
public void lock(){
Boolean lock redisTemplate.opsForValue().
setIfAbsent("lock","ok",3,TimeUnit.SECONDS); //设置锁 过期时间3秒
redisTemplate.delete("lock"); //释放锁
}
UUID防误删锁
可能第一个业务未完成,锁就释放了,其他请求又拿到锁,第一个请求可能造成混乱把第二个请求的锁给释放了
解决:给锁设置uuid
lock(){
String uuid = UUID.randoUUID().toString(); //获取UUID
Boolean lock redisTemplate.opsForValue().
setIfAbsent("lock",uuid,3,TimeUnit.SECONDS); //然后赋给锁值
if(uuid.equals(redisTemplate.opsForValue().get("lock"))){ //判断是不是自己的锁
redisTemplate.delete("lock");
}
}
Lua脚本可保障删除的原子性
ACL
Redis访问控制列表
该功能限制可以执行的命令和可以访问的键
常用指令
acl list 展现用户权限列表
acl cat 命令 添加权限
acl who am i 查看当前用户
acl setuser 命令创建和编辑用户ACL
IO多线程
Redis加入多线程处理网络数据的读写和协议解析,执行命令依然是单线程