Redis基础
目录
Redis的数据结构
String
字符串,内存中以字节数组的形式存在。
Redis 规定字符串的长度不得超过 512M 字节
List:
列表:相当于LinkedList 是链表结构不是数组
常用于异步队列使用。将需要延后处理的任务结构体序列化成字符串塞进 Redis 的列表,另一个线程从这个列表中轮询数据进行处理
hash (字典)
1. 结构相当于HashMap(数组加链表的结构)
2.因为 Java 的 HashMap 在字典很大时,rehash 是个耗时的操作,需要一次性全部 rehash。Redis 为了高性能,不能堵塞服务,所以采用了渐进式 rehash 策略。
3.渐进式 rehash 会在 rehash 的同时,保留新旧两个 hash 结构,查询时会同时查询两个 hash 结构,然后在后续的定时任务中以及 hash 操作指令中,循序渐进地将旧 hash 的内容一点点迁移到新的 hash 结构中。当搬迁完成了,就会使用新的hash结构取而代之。
set (集合)
1.相当于java中的hashSet,它内部的键值对是无序的唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值NULL
2.set 结构可以用来存储活动中奖的用户 ID,因为有去重功能,可以保证同一个用户不会中奖两次。
zset (有序集合)
1.Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。它的内部实现用的是一种叫做「跳跃列表」的数据结构。
Redis的过期策略
注意:需要注意的是过期是以对象为单位,比如一个 hash 结构的过期是整个 hash 对象的过期,而不是其中的某个子 key
惰性删除策略:在客户端访问这个 key 的时候,redis 对 key 的过期时间进行检查,如果过期了就立即删除
定时扫描策略:Redis 默认会每秒进行十次过期扫描,过期扫描不会遍历过期字典中所有的key,而是采用了一种简单的贪心策略。
- 从过期字典中随机 20 个 key;
- 删除这 20 个 key 中已经过期的 key;
- 如果过期的 key 比率超过 1/4,那就重复步骤 1;
为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms。
理解:定时扫描是随机抽取的,会导致很多过期的Key没被删除,此时就需要靠惰性删除
但是还是有问题啊? 要是定时没被扫描到,我也不去查,也不走惰性删除,那不是会有漏网之鱼吗,如果大量过期key堆积在内存里,导致redis内存块耗尽了,怎么办?
答案是:走内存淘汰机制。
Redis持久化
RDB(快照):
快照是一次全量备份,快照是内存数据的二进制序列化形式,在存储上非常紧凑
实现原理:Redis 使用操作系统的多进程 COW(Copy On Write) 机制来实现快照持久化。
Redis 在持久化时会调用 glibc 的函数fork产生一个子进程,快照持久化完全交给子进程来处理,父进程继续处理客户端请求。子进程刚刚产生时,它和父进程共享内存里面的代码段和数据段
优点:
RDB对Redis的性能影响非常小,是因为在同步数据的时候他只是fork了一个子进程去做持久化的,而且他在数据恢复的时候速度比AOF来的快
缺点:
RDB都是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判
AOF:
AOF 日志存储的是 Redis 服务器的顺序指令序列,AOF 日志只记录对内存进行修改的指令记录
一样的数据,AOF文件比RDB还要大
那么我们该怎么选择两种持久化方式呢?
你单独用RDB你会丢失很多数据,你单独用AOF,你数据恢复没RDB来的快,真出什么时候第一时间用RDB恢复,然后AOF做数据补全,真香!冷备热备一起上,才是互联网时代一个高健壮性系统的王道
缓存雪崩
指的是在一个时间段内,缓存大量的一起失效。
比如马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
解决方案:
1.避免缓存设置相近的有效期;为有效期增加随机值;统一规划有效期,失效时间均匀分布。
2.设置热点数据永远不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就完事了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。
举个例子,商品的分类啊可以做不同的缓存时间,并且相同类别的商品可以给缓存时间加上随机值,这样避免在同一个时间缓存大面积失效
缓存穿透
指的是 数据库和缓存中都没有数据(比如用id =-1去请求,但是数据库里的id全部都是大于0的),然后你去请求,必然都打到数据库上,每次都这样,并发高点就容易崩掉了。
解决方案:接口层增加校验,比如用户鉴权校验,参数做校验,不合法的参数直接代码Return,比如:id 做基础校验,id <=0的直接拦截等。
缓存击穿
是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。
解决方案:设置热点数据永远不过期。或者加上互斥锁就能搞定了
主从同步
你启动一台slave 的时候,他会发送一个psync命令给master ,如果是这个slave第一次连接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后master会把内存里面缓存的那些新命名都发给slave。
参考资料:https://blog.****.net/weixin_42711549/article/details/83061052