小阿希的面经分享一(redis篇)

2 篇文章 0 订阅

小阿希的面经分享(redis篇)



一、说说Redis的数据类型

String、set、list、zset、hash

string 可以存储字符串、数字和二进制数据
list有序可重复 底层双向链表
set无序不可重复 底层hash+整数数组		可以做共同好友
zset有序不重	底层ziplist+跳表
hash存键值对 底层ziplist+hashtable

二、说说Redis的持久化策略

  • Redis4.0之后,Redis有RDB持久化、AOF持久化、RDB-AOF混合持久化这三种持久化方式
 - RDB(Redis     DataBase:在不同的时间点将 redis 的数据生成的快照同步到磁盘等介质上):内存到硬盘的快照,定期更新。
缺点:耗时,耗性能(fork+io 操作),易丢失数据。 
 - AOF(Append  Only  File:将 redis 所执行过的所有指令都记录下来,在下次 redis 重启时,只需要执行指令就可以了):写日志。
 缺点:体积大,恢复速度慢。
 
 - bgsave 做镜像全量持久化,aof 做增量持久化。因为 bgsave 会消耗比较长的时间,不够实时,在停机的时候会导致大量的数据丢失,需要 aof 来配合,
 在 redis 实例重启时,优先使用 aof 来恢复内存的状态,如果没有 aof 日志,就会使用 rdb 文件来恢复。Redis 会定期做 aof 重写,压缩 aof 文件日志大小。
 Redis4.0 之后有了混合持久化的功能,将 bgsave 的全量 和 aof 的增量做了融合处理,这样既保证了恢复的效率又兼顾了数据的安全性。

三、如何利用Redis实现一个分布式锁?

  • 方法1:setnx key value 但是客户端忘记解锁 会发生死锁。
    如果 expire key seconds 失败 还是会死锁.
  • 方法2:可以set key value nx ex seconds
  • 加锁 set key random-value nx ex seconds #
    解锁 if redis.call(“get”,KEYS[1]) == ARGV[1] then return redis.call(“del”,KEYS[1]) else return 0 end

  • 单个主节点的架构上实现分布式锁,是无法保证高可用的。
  • 若该算法基于多个Redis节点,它的基本逻辑如下: - 这些节点相互独立,不存在主从复制或者集群协调机制;
  • 加锁:以相同的KEY向N个实例加锁,只要超过一半节点成功,则认定加锁成功;
  • 解锁:向所有的实例发送DEL命令,进行解锁; 我们可以自己实现该算法,也可以直接使用Redisson框架。

四、Redis如何与数据库保持双写一致性

先更新缓存再更新数据库
先更新数据库再更新缓存
先删除缓存再更新数据库
先更新数据库再删除缓存

  • 先更新缓存 每次数据变化时都能及时地更新缓存,这样不容易出现查询未命中的情况,操作的消耗很大,如果是写入数据比较频繁的场景,可能会导致频繁的更新缓存却没有业务来读取该数据。
  • 删除缓存的优点是操作简单,无论更新的操作复杂与否,都是直接删除缓存中的数据。这种做法的缺点则是,当删除了缓存之后,下一次查询容易出现未命中的情况,那么这时就需要再次读取数据库。
  • 先删除缓存再操作数据库,如果第二步骤失败可能导致缓存和数据库得到相同的旧数据。
  • 先操作数据库但删除缓存失败则会导致缓存和数据库得到的结果不一致。一般采用重试机制解决,为了避免重试机制影响主要业务的执行,一般建议重试机制采用异步的方式执行。

五、说说Redis数据类型中的zset,它和set有什么区别?底层是怎么实现的?

zset有序不重复,set无序不重复,zset主要通过给每个元素添加分数属性来实现排序,zset常用排行榜相关的功能。

zset底层的存储结构包括ziplist或skiplist,在同时满足有序集合保存的元素数量小于128个和有序集合保存的所有元素的长度小于64字节的时候使用ziplist,其他时候使用skiplist。

    • 当ziplist作为zset的底层存储结构时候,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,第二个元素保存元素的分值。
    • 当skiplist作为zset的底层存储结构的时候,使用skiplist按序保存元素及分值,使用dict来保存元素和分值的映射关系。

六、说说Redis的单线程架构

Redis的网络IO和键值对读写是由一个线程来完成的,但Redis的其他功能,例如持久化、异步删除、集群数据同步等操作依赖于其他线程来执行。底层不是单线程的
单线程可以简化数据结构和算法的实现,并且可以避免线程切换和竞争造成的消耗。
Redis采用了io多路复用机制,这带给了Redis并发处理大量客户端请求的能力。
Redis单线程实现为什么这么快呢?

  • 单线程避免了线程切换和竞争所产生的消耗。
  • 另外Redis的大部分操作是在内存上完成的
  • Redis还采用了IO多路复用机制,使其在网络IO操作中能并发处理大量的客户端请求,实现高吞吐率。

七、如何实现Redis高可用

哨兵和集群两种方式

  • 哨兵模式:哨兵模式是一个分布式架构,它包含若干个哨兵节点和数据节点,每一个哨兵节点都监控着其他的数据节点和哨兵节点,
    当发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它就会与其他哨兵节点协商,可以避免误判,当大多数哨兵节点都认为主节点不可达时,它们便会选择出一个哨兵节点来做自动故障转移工作,可以将从节点晋升为主节点,同时还会实时的通知到应用方,整个过程自动的,实现高可用。
  • 集群模式:Redis集群采用虚拟槽分区来实现数据分片,它把所有的键根据哈希函数映射到0-16383整数槽内,计算公式为slot=CRC16(key)&16383,每一个节点负责维护一部分槽以及槽所映射的键值数据。

说说Redis的主从同步机制

主从同步分为全量同步和增量同步

  • 从机第一次连接主机时不会携带主机id和数据偏移量,主机会对从机的主机id进行校验,第一次连接需要进行全量同步,原理就是将当前数据写到RDB文件发送给从机,从机接收到文件之后将数据读取到从机的内存中
  • 增量同步是第二次和之后连接才会发生,当从机第一次同步完成之后,主机在这期间数据发生变化,会将命令存储在缓冲区,当校验到从机的id正确时会获取从机的偏移量,主机从偏移量记录的命令开始将从机没同步的数据的操作命令发送给从机执行,执行完成后即完成了数据同步

说说Redis的缓存淘汰策略

惰性删除:客户端访问一个key的时候,Redis会先检查它的过期时间,如果发现过期就立刻删除这个key。
定期删除:Redis会将设置了过期时间的key放到一个独立的字典中,并对该字典进行每秒10次的过期扫描, 过期扫描不会遍历字典中所有的key,而是采用了一种简单的贪心策略

  1. 从过期字典中随机选择20个key;
  2. 删除这20个key中已过期的key;
  3. 如果已过期key的比例超过25%,则重复步骤1。
  4. 当写入数据将导致超出maxmemory限制时,Redis会采用maxmemory-policy所指定的策略进行数据淘汰(即 LRU
  • LRU算法的不足之处在于,若一个key很少被访问,只是刚刚偶尔被访问了一次,则它就被认为是热点数据,短时间内不会被淘汰
  1. 当使用LFU策略淘汰数据时,首先会根据数据的访问次数进行筛选,把访问次数最低的数据淘汰出内存。如果两个数据的访问次数相同,LFU再比较这两个数据的访问时间,把访问时间更早的数据淘汰出内存
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值