基本原理
1、redis是使用c语言编写的,开源的,key-value结构的非关系行数据库,支持5种数据类型:
string、list、set、hash、sortedSet,保证原子性操作,各种排序,为了保证效率,数据都存储在内存中,周期性的将数据写入磁盘或记录文件(aof或rdb),并实现主从之间的同步;
好处:
速度快,存储在内存中;原子性操作;支持多种数据类型;可用于缓存、消息、过期删除等;
2、单线程,效率高?
数据存储在内存中,单线程获取数据快,因为多线程本身就是cpu模拟出来的多个线程情况,这样有个缺点就是上下文切换,对资源有损耗,而单线程的redis不需要上下文切换,保证了效率;
redis用单个cpu绑定一块内存,然后对这块内存进行数据操作,都是在一个cpu上完成的,所以他是单线程操作,在内存的情况下,这就是最优的方案;
这里强调的单线程,只是我们在处理数据的时候,是单线程,但在处理数据存储的时候,是调用fork 命令,使用子线程来处理;
redis的io多路复用,处理多客户端的并发请求,redis使用epoll来时实现io多路复用,将连接信息和事件放到队列,依次给到文件事件分派器,分派器再给到处理器处理;
3、redis的5种数据类型:
sortedSet实现排序,在set的基础上增加了一个score来进行排序,底层使用跳表实现,zset和zipList进行存储,zset中维护两个东西,一个dict存放数据到分数的关系,一个zskipList用于维护链表关系,在插入的时候,zskiplist会计算插入的位置,也算是一种soredSet的实现原理;
4、持久化两种方式:
rdb:快照版本,可能造成一定量的数据丢失,属于内存级别的复制,如果数量大,可能造成io问题;
aof:日志形式追加到文件,不会丢失,可设置有变更追加一次,1s刷一次,或者永远不刷磁盘;
一般都是两种形式配合使用;
5、模糊查询
scan命令取代keys方式;
6、redis分布式锁:
单redis实现存在问题:不可重入、不可重现、超时释放、主从不一致问题
redission解决这些问题:
判断锁是否存在-->增加线程标记-->执行业务
超时释放采用看门狗机制,动态增加时间
主从不一致问题:设置多个主master,只有都一致才获取成功
redlock+redission最佳实现方案:
多个master节点,同时去获取,最终半数以上都获取成功,并且锁存在有效时间,则获取到锁;
7、redis实现消息队列:
list双向链表,缺点消息丢失不能避免
pubsub引入通道概念,但不支持持久化
stream引入组和消费者概念,相对完善
8、string和hash的选择:
两种数据在传输过程中都需要序列化,序列化的方式有多种,但在反序列化的时候,string相对简单,而hash可以存多种数据类型,相对复杂,因此在选择的时候,如果是经常变动的优先选择string,相对稳定而且数据类型丰富的数据使用hash
9、redis哨兵模式:
当主master宕机,会选择其他节点作为master,三个定时任务10s、3s、1s半数存活当选
一主二从三哨兵,监听、选举、故障转移、通知
10、三种集群模式:主从、哨兵、cluster模式
主从如果主节点挂掉,从节点晋升期间不可用,无法实现高可用
哨兵模式只有一个主节点,虽然实现了高可用、读写分离,但存在写入瓶颈
cluster模式多中心模式,解决主节点写入瓶颈问题
11、redis缓存过期策略:
内存不足写入新缓存,提示报错
内存不足写入新缓存,移除最近最少使用的key
内存不足写入新缓存,随机移除某个key
内存不足写入新缓存,在已过期的时间中,移除最近最少使用的key
内存不足写入新缓存,在已过期的时间中,移除随机的key
内存不足写入新缓存,在已过期的时间中,移除更早过期时间的key
12、缓存穿透、雪崩、击穿概念:
穿透:业务访问压根不存在的数据,缓存和db中都没有,处理办法将查询为空的数据返回为null也设置到缓存中,再次查询时候,直接命中缓存中的null,缺点可能导致缓存中大量null值,布隆过滤器,在查询缓存前,先判断当前查询的key是否存在,不存在连缓存都可以不用查询
雪崩:缓存服务器宕机,所有数据全部打到db,解决办法缓存集群处理
击穿:缓存大批量缓存集中过期,导致大量数据批量涌入db,处理办法,只允许一个线程构建缓存,其他的等待,或者换成永远不过期处理
13、redis为何不使用b+tree而使用跳表,b树叶子阶段存储数据,非叶子节点存储索引,属于mysql层面的io操作,而redis是内存操作,不需要io操作