保证AP(可用性,容错性)
set key value
get key
incr key
decr key
exists key
del key
setnx key value
双端链表
rpush key value1 value2...
lpush key value1 value2...
lset key index value
lpop key
rpop key
HSET map key value //HSET user name "jyh" age 18
HGET map key //获取指定字段的值
HGETALL map //获取所有键值对
HDEL map key1 key2... //删除字段
HLEN map //获取字段数量
应用场景:购物车(用户id为key 商品id为field 数量为value)
SADD key val1 val2 //向集合中添加元素
SMEMBERS key //获取集合中的所有元素
SCARD key //获取集合中元素数量
SISMEMEBER key val1 //判断元素是否在集合中
SINTER key1 key2... //获取集合的交集
SUNION key1 key2... //获取集合并集
SDIFF key1 key2... //获取集合差集
SPOP key count //随机移除count个元素
SRANDMEMBER key count //随机获取集合中的count个元素
应用场景:共同关注(交集),随机点名
Sorted Set 增加了一个权重参数
score
,使得集合中的元素能够按score
进行有序排列
ZADD set score1 member1 score member2//添加元素
ZCARD set //获取元素数量
ZSCORE set member1 //获取指定元素的score值
ZRANGE set start end //获取start和end之间的元素(score 从低到高)
ZREVRANGE set start end//获取start和end之间的元素(score 从高到低)
ZREVRANK set member //获取元素排名(score从大到小排序)
应用场景:排行榜
查询一个不存在的数据,存储层查不到却没写入缓存,导致每次都去数据库查,可能导致数据库挂掉
解决办法:
设置了过期时间的key,缓存在某个时间点过期的时候,恰好这时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端 DB 加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把 DB 压垮。
解决办法:
设置热点数据永不过期
加互斥锁
在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。
设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB 瞬时压力过重雪崩。
解决办法:
redis高可用(搭建集群)
数据预热
提前访问使得数据提前加载到redis缓存中;过期时间尽量设置均匀
限流降级
在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
RDB是一个快照文件,它是把redis某时间点的数据写到磁盘上,当redis实例宕机恢复数据的时候,方便从RDB的快照文件中恢复数据,快照持久化是 Redis 默认采用的持久化方式。
效率较高,但可能会丢失数据。
两个命令来生成RDB快照文件:
AOF的含义是追加文件(即写日志),当redis操作写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次执行一遍命令来恢复数据
需手动开启:
appendonly yes
AOF持久化实现的流程:
文件同步策略:
对key设置过期时间,我们不去管他,当需要key时,再去检查是否过期,过期就删除,反之返回该key。
每隔一段时间就对一些key进行检查,删除过期的key。
定期清理有两种模式
优点:
缺点:
Redis的过期删除策略:惰性删除+定期删除 ,两种策略配合使用
Redis中的内存不够用时,此时再向Redis中添加新的key,Redis会按照某种规则将内存中的数据删除。
数据淘汰策略有8种:
redis实现分布式锁主要利用命令setnx(set if not exist),用了这个命令之后,只能有一个客户端对某一个key设置值,在没有过期或删除key时,其他客户端不能设置。
# NX 互斥,NX 设置超时时间(不设置可能会导致死锁)
SET lock value NX EX 10
#释放锁
DEL key
自动延时机制:启动watch dog,后台线程,每隔10秒检查一下客户端1还持有锁key,操作共享资源的线程还未执行完成的话,会不断的延长锁key的生存时间
加锁、设置过期时间等操作都是基于lua脚本完成,可以保证原子性。
redisson实现的分布式锁的特点:
可重入(同一个线程可以多次获取锁)
Redis使用hash结构来存储线程信息和重入的次数
不能解决主从一致性
但是可以使用RedLock:在多个Redis实例上创建锁(n/2+1),但是性能低,推荐使用zookeeper实现的分布式锁保证强一致性
提高Redis的并发能力,需要搭建主从集群,实现读写分离。
当从节点服务重启之后,数据就不一致了,这时从节点会请求主节点同步数据,主节点判断这次请求不是第一次请求了,获取从节点的offset值,主节点从命令日志中获取offset值之后的数据,发送给从节点进行数据同步。
哨兵(Sentinel)作用:
监控:不断检查master和slave是否正常工作(心跳检测)
自动故障恢复:若master发生故障,会将一个slave推选为master
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障时,会将最新信息推送给Redis客户端
哨兵选主规则:
由于master节点和slave节点和sentinel处于不同的网络分区,使得sentinel未能心跳感知到master,所以选举将一个slave变为了master,这样就存在了两个master。这样会导致客户端还在旧的master那写入数据,新的master无法同步数据。网络恢复后,旧的master降为slave,这时再从新的master处同步数据,会导致数据丢失。
解决方法:
min-replicas-to-write 1 表示最少的slave节点数为1
min-replicas-max-lag 5 表示数据复制和同步的延迟不能超过5s
特点:
Redis集群引入了哈希槽,有16384个哈希槽,集群中每个主节点绑定了一定范围的哈希槽,key通过CRC16校验后对16384取模来决定放哪个槽,通过槽找到对应节点进行存储。
I/O多路复用值利用单个线程来同时监听多个Socket,并在某个Socket可用时得到通知,从而避免无效等待,充分利用CPU资源。目前的I/O多路复用都是采用的epoll模式实现,它会在通知用户进程Socket就绪的同时,把已就绪的Socket写入用户空间,不需要挨个遍历Socket来判断是否就绪,提升了性能。
其中Redis的网络模型就是使用I/O多路复用结合事件的处理器来应对多个Socket请求,比如,提供了连接应答处理器、命令回复处理器,命令请求处理器;
在Redis6.0之后,为了提升更好的性能,在命令回复处理器使用了多线程来处理回复事件,在命令请求处理器中,将命令的转换使用了多线程,增加命令转换速度,在命令执行的时候,依然是单线程。