0.思维导图
1. redis的数据类型♥♥♥
redis有五种数据类型,包括string,list,set,hash,zset;string就类似于java中的字符串,list就类似于Java中的列表,可以存放重复的元素,set就类似于java中的hashset,不能存放重复的元素,hash就类似于Java中的hashMap,存放键值对元素,zset是一个有序集合,每个元素都会有一个score,按照score来进行排序。
2. zset的底层实现♥♥
- 它有两种实现方式:一个是
压缩列表
,还有一种是字典加上跳跃表
- 压缩列表使用紧挨在一起的几点来保存元素和score,第一个节点保存元素,第二个节点保存score,压缩列表的元素按score从小到大排序。
- 它的使用需要满足两个条件,否则就使用字典加跳跃表:元素个数小于128个,元素长度小于64字节
- 跳跃表是一种可以进行二分查找的有序链表。原理就是在原有的有序链表上面增加了多级索引,通过索引来实现快速查找;
- 压缩列表使用紧挨在一起的几点来保存元素和score,第一个节点保存元素,第二个节点保存score,压缩列表的元素按score从小到大排序。
3. BitMaps
4. HyperLogLog
5. redis的持久化方案♥♥♥
-
RDB(默认的持久化方式):定期保存数据快照至一个rdb文件中,并在启动时自动加载rdb文件,恢复之前保存的数据。
-
AOF:把每一个写请求都记录在一个aof文件中,并且在启动时,会把aof文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。
-
区别:RDD效率更高,因为它是直接将Redis的最新数据完整的保存下来,但如果Redis中存储的数据量比较大时,也会有一定的性能消耗,因为它需要创建额外的进程来进行数据的持久化,所以要制定合理的策略;而AOF效率相对RDB要低一些,因为它会将历史的写操作都执行一遍来进行恢复,同时在执行写操作的时候也会将每一个指令存储下来,当我们对数据的安全性要求较高的时候,可以考虑AOF
-
扩展1:数据量较大时进行快照,用时相对会比较长。如果服务器这个期间收到写请求,那么就不能保证快照的完整性。那么Redis是如何做的?
- Redis使用的是操作系统提供的写时复制技术,在执行快照的时候,正常处理写操作。【如果主线程要修改一块数据,这块数据就会被复制一份,生成该数据的副本,此时主线程在该副本上进行修改,fork的子线程继续把原来的数据写入RDB文件中】
-
扩展2:在进行RDB快照的过程中,发生服务崩溃了怎么办?
- 在快照操作过程中不能影响上一次备份的数据,将上一次完整的RDB快照文件作为恢复内存的参考
6. 缓存穿透,缓存击穿,缓存雪崩♥♥♥
- 在应用程序和mysql数据块之间建立一个中间层:redis缓存,通过redis缓存可以有效减少查询数据库的时间消耗,但是引入redis又有可能出现
缓存穿透,缓存击穿,缓存雪崩
等问题 - 缓存穿透:
key在缓存和数据源都没有
,那么所有的请求都会去查询数据源,压垮数据源- 解决:
- 当查询不存在时,也就空保存在缓存中【key-null】
- 采用布隆过滤器,将所有可能存在的数据hash到一个足够大的bitmap中,一个一定不存在的key会被这个bitmap拦截掉,从而避免了对数据源的查询压力。
- 解决:
- 缓存击穿:
key在数据源中有,在缓存中没有,通常时缓存过期了
,这时候大量的并发就会全部去请求数据源,导致数据源瘫痪- 解决:使用互斥锁,利用setnx来实现该功能,因为当Key不存在的时候,它才会设置一个Key
- 缓存雪崩:当缓存服务器重启或者大量key缓存集中在某一个时间失效,这时候给数据源的压力也非常大
- 解决:为key设置不同的缓存失效时间。
7. redis实现分布式锁♥
锁是一种常用的并发控制机制,用于保证一项资源在任何时候只能被一个线程使用,如果其他线程也要使用同样的资源,必须排队等待上一个线程用完。
上面说的锁指的是程序级别的锁,例如java语言中的synchronized和ReentrantLock在但应用中使用不会有任何问题,但如果放到分布式环境下就不适用了,这个时候我们就要使用分布式锁。分布式锁比较好理解就是用于分布式环境下并发控制的一种机制,用于控制某个资源在同一时刻只能被一个应用所使用。
分布式锁比较常见的实现方式有三种:
- Memcached实现的分布式锁:使用add命令,添加成功的情况下,表示创建分布式锁成功。
- Zookeeper实现的分布式锁:使用Zookeeper顺序临时节点来实现分布式锁。
- Redis实现的分布式锁
- 使用setnx,如果创建成功则表名次锁创建成功,否则代表这个锁已经被占用,创建失败。
- setnx lock true 创建锁
- del lock 释放锁
- setnx的问题:setnx虽然可以成功创建分布式锁,但存在一个问题,如果此程序在创建了锁之后,程序异常退出了,那么这个锁将永远不会被释放,就造成了
死锁问题
- 使用set命令来设置分布式锁,并设置超时时间,而且set命令可以保证原子性:set lock true ex 30 nx