什么是redis?

redis是一款内存数据库,在内存中进行数据存储,使用的场景可以有数据库,缓存,消息代理。

redis可以做什么?

缓存,众所周知的事情,提升服务器性能方面很有成效,比如把耗时长且执行结果不经常变更的sql的结果就可以做缓存处理;
计数器,点赞等功能的开发,利用redis的原子性自增操作,实现用户的点赞等功能
简单的消息队列,类似mq的消息发布订阅功能
session共享,其实个人感觉也是缓存的一种,分布式系统中redis保存session(现在一般使用token),同一个用户在不同的机器访问不需要重新登录,只能拿到session(token)即可登录

redis不可以做什么

不能用redis当作关系数据库使用,比如保存用户信息进行持久化保存,持久化对redis服务器的压力非常大,总结就是数据量大,访问频率低的数据不适合使用redis,相反数据量小,访问频繁,或者不经常变更的数据非常适合

redis为什么这么快?

单线程模型,避免上下文切换和竞态条件
基于内存纯内存操作
网络层默认使用epoll解决高并发问题(非阻塞I/O多路复用机制)
简单介绍下epoll
wiki中是这样说的,epoll是Linux内核的可扩展I/O事件通知机制,功能与poll类似,都是监听多个文件描述符上的事件,时间复杂度是O(log n),
epoll 与FreeBSD的kqueue类似,底层由可配置的操作系统内核对象构建而成,并以文件描述符的形式呈现于用户空间,epoll通过使用红黑树(RB-tree)搜索被监视的文件描述符,在epoll实例上注册事件时,epoll会将该事件添加到epoll实例的红黑树上并注册一个回调函数,当事件发生时会将事件添加到就绪链表中。有关epoll的介绍就到此,更详细的深入可以自己深入学习一下

redis使用了哪些数据结构

String 
Hash 
List 
Set 
SortSet
Bitmaps 
HyperLogLogs 
GEO(地理信息定位)
跳表基于有序链表的扩展,个人理解大白话就是,数据分层级,查找时从上往下依次查找,也就是层级越高的越优先比较,这种比较的优点就是在数据量大时可以省略很多无用的比较,快速定位。
增删数据时会对数据进行抛硬币的形式进行是否往上一级节点增加变动,当大量的数据插入链表之后,上层的索引层级就会不够用,此时使用的抛硬币的方式,如果是正面就继续上移增加一个层级,假设增加一个数字,它的层级为一,此时才去抛硬币的形式,如果正面,层级+1,继续抛硬币循环,直到反面,停止抛硬币,如果是反面,直接停止增加层架,到此结束。此处redis的跳表最大层级是32,即如果一直抛硬币为正面,最大不超过32。具体的跳表原理大概理解就是这个简单的一句话。详细了解可以参考我下面的链接


跳表原理参考链接
https://zhuanlan.zhihu.com/p/53975333
https://courses.csail.mit.edu/6.046/spring04/handouts/skiplists.pdf
http://zhangtielei.com/posts/blog-redis-skiplist.html
https://www.youtube.com/watch?v=2g9OSRKJuzM

红黑树的原理?

红黑树,是一种自平衡的二叉查找树,什么是自平衡的,我们在学习二叉树时知道,二叉树都是左子树节点值小于等于跟节点,右节点值大于等于跟节点值,左右子树也都是二叉树,下面举个例子

 5
4 6
上面这个是典型的二叉树,如果此时在这个树上面增加3,2,1,此时数就会变成这样
    5
   4 6
  3
 2
1    
此时如果查找节点1,性能就会急剧下降,变成线性的查找,所以此时红黑树就上场了,自平衡的意思就是红黑树会自动把上面的树转换成一个平衡的二叉树

红黑树的性质
根节点是黑色
节点是红色和黑色
所有叶子是黑色(非nil节点)
每个红色节点必须有两个黑色的字节点(从每个叶子到根的路径上不能有两个连续的红色节点)
从任一节点到其每个叶子的简单路径都包含相同的黑色节点

红黑树的旋转,自旋鉴于画图麻烦就引用一下,个人感觉写的非常不错的

https://zhuanlan.zhihu.com/p/31805309

定期删除与内存淘汰策略?

定期删除与惰性删除,redis每100ms检查一次,是否存在过期key,有过期的key则删除,(redis并不是每100ms检查所有的key,而是随机进行检查)因此采用定期删除策略,会导致很多key到事件之后没有删除,于是就要使用惰性删除,即在你获取某个key的时候,redis会检查一下这个key是否设置了过期时间,如果设置了过期时间并过期了此时就会删除

采用了定期删除与惰性删除还会有个问题,就是定期删除一直存在删除不到的key,然后也一直没有请求获取key,也就是惰性删除没有触发,此时就要使用到redis的内存淘汰机制

# maxmemory-policy volatile-lru

支持策略,当内存不足容纳新数据时,采用下列策略

noeviction: 写入数据请求报错(del请求和部分请求除外)
allkeys-lru: 在键空间中移除最近最少使用的key
allkeys-random: 在键空间中随机移除某个key
volatile-lru: 在设置了过期时间的键空间中移除最近最少使用的key
volatile-random: 在设置了过期时间的键空间中随机移除某个key
volatile-ttl: 在设置了过期时间的键空间中移除更早过期时间的key

当使用了volatile-lru,volatile-random,volatile-ttl三种策略时,如果没有key可以被淘汰,则和noeviction一样返回错误

缓存雪崩、缓存穿透如何解决?

缓存穿透:大量请求缓存中不存在的数据,导致所有的请求都怼到数据库,从而数据库异常
解决:利用互斥锁,缓存失效的时候先去获取锁,得到锁了再去请求数据库,没得到锁,休息一段时间重试。另一个采用异步更新策略,无论key是否取到值都直接更新,value值维护一个过期时间,缓存如果过期,异步一个线程就去获取数据并更新缓存,(系统启动前需要做缓存预热)。最后一个采用布隆过滤器,内部维护一系列合法的key,能够迅速判断出请求是否合法,如果不合法直接返回。
缓存雪崩:同一时间大面积的缓存失效,此时又来一波请求直接打到数据库上,导致数据库连接异常
解决:给缓存失效时间加一个随机值,避免集体失效。
使用双缓存,缓存a和缓存b,缓存a设置失效时间20分钟,b不设置过期时间,自己做缓存预热功能。从缓存a直接读取数据,有就直接返回,没有就去缓存b读取,并异步一个线程,同时更新缓存a和缓存b