redis
2021-05-27 01:02:06 0 举报
AI智能生成
吐血整理redis相关知识
作者其他创作
大纲/内容
redis集群优化
缓存设计
缓存穿透
现象:在缓存中查询一些看似会缓存实际没有缓存的数据,比如黑客发现1000并没有缓存,大量访问1000这个缓存key,查不到,走数据库,结果数据库崩掉
解决办法:1,缓存空对象,比如上述问题缓存1000的key,value为null,第一次进来会塞进去1000-null,后面的查询就不会走库而是返回空
2,布隆过滤器,布隆过滤器说存在那么不一定存在,布隆过滤器说不存在那么一定不存在
2,布隆过滤器,布隆过滤器说存在那么不一定存在,布隆过滤器说不存在那么一定不存在
缓存击穿
现象:短时间内缓存中大量的key失效,导致同时打到数据库,数据库扛不住宕机
解决办法:合理设置缓存失效时间,避免短时间内大量key失效
缓存雪崩
现象:redis集群长期处于满载状态,某一时刻其中一个节点出现问题,此时请求都打到其他节点,这个节点也挂掉,多米罗骨牌效应导致整个集群汰瘫痪
解决方案:1,采用高可用的集群模式,动态扩容
2,熔断限流
2,熔断限流
数据库双写不一致
推荐方案1,读写锁
推荐方案2,写操作只更新数据库,搞一个线程专门去更新缓存,这样缓存可能会延迟更新
key清理策略
被动清除
当客户端操作一个过期的key时,会触发惰性删除
主动清除
由于一些冷数据很难触发惰性删除,redis每隔一段时间会主动删除过期的key
主动清理
当redis已使用内存超过macmemory时,触发主动清理,redis4之前6中策略,redis4之后加上两种供8中
1. volatile-ttl:根据过期时间删除,越早过期的越先被删除
2. volatile-random:清除设置了过期时间的key,随机删除
3. volatile-lru:根据lru算法删除设置了过期时间的key
4. volatile-lfu:根据lfu算法删除设置了过期时间的key
5. allkeys-random:所有key随机删除
6. allkeys-lru:对所有的key进行lru算法清除
7. allkeys-lfu:对所有的key进行lfu算法清除
8. noeviction:不删除任何key,拒绝写入数据并返回error
lru算法:根据最近一次访问时间排序,越远排在越靠前
lfu算法:根据最近一段时间访问频次排序,频次越少排在越靠前
redis默认使用noeviction,不删除任何key并报错。redis默认不会设置maxmemory,但是有个问题,如果不设置的话redis会将部分数据同步到磁盘,并频繁发生磁盘io,性能急剧下降,推荐合理设置maxmemory
数据类型与高性能原理
常用的五种数据类型
String
存储普通键值对象,一个String的value最大存储512M
set [key] [value] EX [seconds] / PX [milliseconds] 设置键值(失效时间)。同setex [key] [seconds] value/psetex [key] [seconds] value
set [key] [value] NX 当key不存在设置value,当key存在则不设置。同setnx [key] [value]
set [key] [value] XX 当key存在设置value,当key不存在则不设置。
get [key] 获取key对应的[value]
getset [key] [value] 返回key的值并将key设置为新[value]
append [key] [value] 如果key存在并且value为字符串,将[value]追加原来的value末尾;如果key不存在,设置key的值为[value]
incr [key] 如果key存在是数字,key++并返回,key存在不是数字,返回错误,key不存在,先将key设为0并执行incr
incrby [key] [increment] 与上面相同,key+ increment
decr [key] 与incr相反
decrby [key] 与incrby相反
mset [key1] [value1] [key2] [value2] ... 批量设置key,如果key存在则会覆盖
mget [key1] [key2] ... 批量获取key对应的value并以list<Object> 返回,如果某个key不存在,将会返回nil
常用在存储普通键值对
Hash
键值对集合 [key] [value]中的value是键值对列表,类似map,每个hash最多存储2的32次方-1个键值对
hset [key] [fied value] 设置key中fied值为value,如果key不存在,会创建新的hash表,如果fied已存在hash表中,会覆盖原来的
hsetnx [key] [fied value] 与setnx类似,如果fied存在key的hash表中则不设置,如果不存在则设置
hget [key] [fied] 获取key的hash表中fied对应的value值,如果不存在则返回nil
hdel [key] [fied1 fied2 ...] 删除key的hash表中的一个或者多个fied,如果fied不存在则忽略
hlen [key] 返回key的hash表中fied的数量
hstrlen [key] [fied] 返回key的表中fied的value的字符串长度
hincrby [key] [fied] [increment] key的hash表中fied+increment,如果存在是数字直接加并返回,如果不存在先设置为0再加,如果存在不是数字返回异常
hincrbyfloat [key] [fied] [increment] key的hash表中fied加一个浮点型数
hmset [key] [fied1 value1] [fied2 value2] ... 批量设置key中fied
hmget [key] [fied1 fied2 ...] 批量查询key的hash表中fied的value
hkeys [key] 返回key的hash表中所有的fied
hvals [key] 返回key的hash表中所有的value
hgetall [key] 返回key的hash表中所有fied和value
常用于存储token这种一一对应的
List
存储简单地字符串列表,列表中最多存储2的32次方-1个元素
lpush [key] [value1 value2 ...] 将一个或多个value插入到key的列表头,key不存在则会创建,key存在但不是列表会返回错误
lpushx [key] [value1 value2 ...] 将一个或多个value插入到key的表头,如果key不存在则不会执行任何操作
rpush [key] [value1 value2 ...]将一个或多个value插入到key的表尾
rpushx [key] [value1 value2...] 将一个或多个value插入到key的表尾
lpop/rpop [key] 将key的表头或表尾第一个元素移除并返回
rpoplpush [key1] [key2] 将key1中表尾元素移除并返回,同时插入到key2表头
lindex [key] [index] 返回key列表中index位置的元素,index>0从表头开始数,index<0从表尾开始数
lset [key] [index] [value] 将key列表中index位置元素替换为value,当index超出范围返回错误
ltrim [key] [index1] [index2] 将key列表截取成index1-index2
可用于模拟堆栈,队列,用于朋友圈点赞等
Set
存储对象列表,与list相似,set中最多存储2的32次方-1个元素
sadd [key] [obj1 obj2 ...]将一个或多个对象存入集合中,key不存在则会创建,key不是集合返回错误
sismember [key] [member ]判断member是否是key集合的元素。是返回1,否则返回0
spop [key] 移除并返回key中任意一个个元素
srandmember [key] [count] 返回集合中count个元素组装成数组,当count>0返回数组不会重复,当count<0数组元素可能重复,count>key.length则返回整个set
srem [key] [member1 member2]移除key中一个或多个元素,不存在则忽略,key不是集合会返回错误
smove [key1] [key2] [member] 将key1中member移到key2中,如果member已存在key2中仅仅移除key1中,如果key1 key2有一个不是集合将会返回错误
用户求共同好友,抽奖实现
Zset
存储有序集合,与set相似,区别在于有序
最经典的应用就是排行榜
高性能原理
redis是完全基于内存的,非常快
cli和server之间是单线程,避免了线程创建销毁的繁琐操作和线程之间的切换,并且避免了多线程操作带来的并发问题
基于epoll的多路复用io,资源利用率高
持久化与主从架构
持久化方式
RDB
将redis中所有缓存数据写入磁盘中,保存的是内存数据,恢复起来相对较快
save
会阻塞用户线程,如果redis中数据较多用户线程会被阻塞,直到save完成
bgsave
不会阻塞用户线程,redis会开启一个后台的子线程处理save,用户的操作不受影响
配置文件中加上save m n 表示redis在m秒时间内执行了n次修改操作,自动bgsave一次
数据丢失比较严重,恢复起来比较快
AOF
将redis的所有更新的操作记录命令写入appendonly.aof,每隔一段时间写入到磁盘,写入磁盘时间可自定
主从架构
一主多从
主从复制原理
全量复制
从节点向主节点发送psync命令,master会在后台执行bgsave生成rdb文件,在rdb期间新的数据会以aof的方式生成,复制完成后通过socket通信发送给从节点,从节点复制数据,master同一时间收到多次psync命令只会生成一个rdb,分别发送给不同的从节点
部分复制
redis2.8以后支持psync命令部分复制,master会维护一个队列用于存放一段时间执行过的操作,master和slave会维护复制数据的offset和进程id,当master与slave断开并重连,slave会请求master复制数据,从offset开始复制。如果master的进程id变化了或者offset太久,会触发全量复制
主从复制风暴
同一时间有很多个slave都来复制数据会引起主从复制风暴,建议搭建多级主从架构解决这个问题
sentinel哨兵模式
每个哨兵也是一个redis实例,客户端实际操作的是哨兵,哨兵根据配置找到master对齐进行操作。哨兵模式只有主节点对外提供读写服务,slave实际上只是做数据备份和防止主节点挂掉替代主节点。无法提供高并发访问。在主节点挂掉重新选举的时候会出现访问瞬断
cluster集群
redis集群通信
集中式:集群的元数据信息集中管理,存储在一个机器上,所有节点向这台机器获取集群信息。优点在于数据更新及时,准群。缺点在于元数据存储压力较大
gossip通信:包含多种命令,ping,频繁向其他节点发送ping包含自己的元数据信息,meet,每个节点向新加入的节点发送meet命令告知自己的集群信息,pong,回复ping和meet,回复自己的集群元数据信息,fail,某个节点发现某个节点挂掉之后会发送fail命令给其他节点以通知大家这个节点宕机了。gossip通信端口,该节点的redis服务端口+10000,比如当前7379端口,那么gossip通信端口就是16379。元数据分散存储,每个节点维护自己的元数据信息,更新不及时是主要问题
redis集群存储原理
搭建高可用的cluster集群。cluster实际上是若干个redis 主从,分片存储,内置了redis自己的hash散列。集群可支持上万个节点,官方推荐1000个。redis会分配16384和虚拟槽位,根据集群中节点数量分配每个槽位存储的数据区间。redis每个节点都会存储槽位信息,如果操作的数据不在当前节点,会返回应该操作的节点信息。
集群的选举
当slave发现自己的master挂掉,会像集群其他节点广播FAILOVER_AUTH_REQUEST消息,只有mater会回复FAILOVER_AUTH_ACK消息,并且只会回复每个小集群中的一个,当slave收到超过半数的master消息,就会把自己置为主节点,并广播整个集群发送pong消息通知其他节点。
slave发现自己的master挂掉并不是马上开始选举,而是有延迟的。根据延迟计算公式,得知节点复制数据越多,延迟越小,越有可能成为新的主节点。
slave发现自己的master挂掉并不是马上开始选举,而是有延迟的。根据延迟计算公式,得知节点复制数据越多,延迟越小,越有可能成为新的主节点。
集群脑裂问题
1主2从中,主从节点之间通信异常,客户端与主节点通信正常,从节点判断主节点挂掉,实际上主节点没有挂掉(正常对外服务),两个从节点重新选举了一个主节点。当网络恢复,旧的主节点会变成slave,并向新的master同步数据,此时,外接向旧的主节点的操作数据全部丢失。
脑裂的解决方案:min‐replicas‐to‐write 1//写数据成功最少同步的slave数量,如果不满足,master会拒绝写数据请求,也就不会有新数据生成,当然不会有数据丢失。此配置有一定风险,如果配置比较大,部分从节点挂掉也不会成功,集群拒绝对外提供写服务。推荐参考半数选举
集群是否完整才能对外提供服务
cluster-require-full-coverage配置为no,表示集群中某个槽位的master下线后集群任可对外提供服务(其他槽位正常服务)
集群对批量操作的支持
取第一个操作的hash计算槽位从而决定存储在哪个节点
redis管道和lua脚本
管道pipeline
将多个命令放入一个集合中,依次执行,不是原子操作,一个命令失败不会影响后续命令执行,管道不会阻塞其他客户端
lua脚本
编写lua脚本放入redis执行,原子操作,一个命令失败会回滚,替代redis事务,lua脚本不应该有耗时的重量级操作,单线程会阻塞其他客户端
0 条评论
下一页