Redis面试大总结

Redis吹牛秘籍

当今网络,缓存为王!我们的目标是什么:提高缓存命中率!

首先:redis特点:

Ⅰ、nosql数据库

Ⅱ、redis官方给出的数据,每秒可以处理超过十万次读写操作,是已知最快的key-value DB

Ⅲ、、、支持多中数据类型,每一个value最大限制是1GB,不像memcached只能保存1MB的数据

Ⅳ、缺点:受到物理内存的限制,不能海量的高性能读写,所以,局限在较小数据量的高性能场景中。

          也可以说成redis 的瓶颈在于内存大小,还有网络传输快慢

Ⅴ、支持事物  所有的操作都是原子性,对数据的更改,要么全部执行,要么全部不执行。

Ⅵ、支持持久化、rdb,aop两种持久化方式 

常常应用被应用到:会话缓存,全页缓存,队列,排行榜,计数器,发布,订阅

  1. Redis线程

redis的主要功能是基于单线程模型实现,也就是说redis使用一个线程来服务所有的客户端请求,同时redis 采用了非阻塞式IO,并精细地优化各种命令的算法时间复杂度,这些信息意味着

  1. redis是线程安全的(因为只有一个线程),其所有操作都是原子的,不会因并发产生数据异常
  2. redis速度非常快(因为使用非阻塞式IO,且大部分命令的算法时间的复杂度都是O(1))
  3. 使用高耗时的redis命令是很危险的,会占用唯一的一个线程的大量处理时间,导致所有的请求都被拖慢(例如时间复杂度为O(N)的keys命令,严格禁止在生产环境中使用)
  1. redis优化

从以下几个角度考虑

Ⅰ、存储大小,那么什么因素会影响存储大小呢

  1. 第一,键的长度

redis是一个一个内存数据库,键越小,你的存储空间就越小,数据小的时候看不出来,但是数据量大了,存储大小就会有非常明显的区别

来个栗子:在一个32位的redis服务器上,如果存储存储一百万的键,每个value的长度是32,那么在使用6长度键名时,将会消耗大约96MB的空间,但是如果使用12长度的键名时,空间消耗则会提升至111MB左右。随着键的增多,15%的额外开销将产生重大的影响。

第二、键的规则,无论在什么情况下,redis都会存储一些不再使用的数据,平白的占用了一些空间。(比如,废弃模块中存放的一些数据,忘记删除了)。Reids的弱结构数据让集中存储的内容很难被弄清,所以,就需要一套非常成熟的命名规则,使用合适的命名方法会简化数据库的管理(有一点会比较矛盾,那就是规则的命名需要加一些前缀,比如应用程序,或者模块的名字来划分,这样会加长键的长度,上面刚说了减少键的长度,所以要取舍),这样就可以在数据的迁移,转换或者删除时候轻松识别。

B、第二,合适的数据类型

Redis中有五种数据类型,要使用到不同的场景

其中,Hash类型中value内部为一个hashmap,如果该map的成员较少,则会采用类似一维线性的紧凑格式来存储这个map,这样省去了大量的指针内存开销,这个参数控制对应的在redis.confi配置文件中的第二项:

hash-max-zipmap-entries 64 hash-max-zipmap-value 512

(够不够红,要记住了)

当value这个Map内部不超过多少个成员时会采用线性紧凑格式存储,默认是64,即value内部有64个以下的成员就是使用线性紧凑存储,超过该值自动转成真正的HashMap。

hash-max-zipmap-value 512

含义是当 value这个Map内部的每个成员值长度不超过512字节就会采用线性紧凑存储来节省空间。

  

    高可用,储存大了,直接会导致redis服务器非常容易宕机啊

A、 为了防止redis服务器宕机,就搭建集群,集群模式一共有三种,具体就不介绍了,直接说最常用的,反客为主,哨兵监管机制,一个主节点,下面有子节点,主节点主要负责写操作,子节点负责读操作;具体规则就不介绍了,都懂;

B、哨兵之后,每个节点上的数据都一样多,内存占用的比重是一样的,如果存储100万数据,一共有5个节点,那么就相当于存储了500万数据,造成内存极大,这时候就需要分片机制来解决这个问题,一般哨兵都会配分片的,分片就是把这100万数据根据一些规则分配到各个节点上,这些节点上一共加起来100万,就避免了因为集群造成存储量大的问题。

C、分片中有一个预分片机制,可以在服务器不停机或者停机很短的时间内完成预分片

采用分片技术;有1000万条用户信息数据,以键值对:userid:userinfo的形式存储于redis中。此时有4台主机,每台主机运行一个redis实例:实例A,实例B,实例C,实例D。

分片此时的算为:redis_index=用户的ID %4+1;

例如ID为10000654则可得到redis_index=10000654%4+1=1,即用户10000654的信息被放到了redis实例A上。所有对用户10000654的操作也都被放到了redis1上;假如用户ID以顺序方式出现,这1000万条用户信息被平均分配到这四台主机上的rendis实例上。采用分片以后,数据被分散到4个redis实例中,对数据的操作也被分散 到每个redis实例中,此时单台主机的压力将大大减轻。

分片的部署方式一般有三种:

  1. 、在客户端做分片;这种方式要确定在客户端链接了redis实例,然后直接访问相应的redis实例。
  2. 、在代理中做分片;这种方式,客户端不直接访问redis实例,它也不知道自己要访问 的具体是哪个redis实例,而是由代理转发请求的结果;其工作过程为:客户端将请求发送给代理,代理通过分片算法确定要访问的是哪个redis实例,然后将请求发送给相应的redis实例,redis实例将返回结果给代理,代理最后将结果返回给客户端。
  3. 、在redis服务器端做分片;这种方式被称为”查询路由”,在这种方式中客户端随机选择一个redis实例发送请求,如果所请求的内容不再,将正确的redis客户端信息反馈给客户端,由客户端再去正确的redis实例中发送请求。

分片也是有一定的缺点

  1. 、通常无法支持设计多个键的操作;在redis中有很多一次操作多个Key的操作,例如集合交集的insert操作,该操作涉及了多个键,而这多个键有可能被分片到多个redis实例中,此时就无法执行这种操作。
  2. 、redis 的事务操作中涉及多个键也不能用
  3. 、分片将导致数据处理更加复杂;例如在分片的过程中,随着redis实例的增加,数据备份等操作都将会变的更加复杂。

Redis预分片

  1. 、在新机子上启动新的redis实例;
  2. 、将新的redis实例作为slave将实例作为master,将数据从原redis实例上迁移到redis新实例上;
  3. 、停止客户端
  4. 、更新客户端中redis实例的端口ip信息
  5. 、向新启动的redis发送slaveof noone 的命令,中止新的redis实例对原redis实例的从属关系
  6. 、重启客户端,此时他们会使用新的redis实例;
  7. 、关掉被迁走数据的原redis实例;

 

  Ⅲ、由于redis中内存数据量大,同时现网中未做内存监控,这时候很有可能会造成内存泄露

Redis是怎么应对内存泄露的呢?大家都知道redis自带内存是1G,一般推荐redis设置内存为物理内存的四分之三,所以设置为0.75G,换成byte是751619276

  1. 消耗内存的模块需尽快改造或者停止,业务中使用redis需要设置时间,以释放内存
  2. 针对基础软件服务的监控(磁盘,内存),需完善。
  3. 开发设计时候需要对开发模型redis的写频率,以及消耗大小,评估redis内存消耗的风险
  4. 设置参数删除K,有五种策略

 

3、Redis五大数据类型,是五大,redis本身支持的数据类型有很多种的,要跟并线的技术聊

Ⅰ、String 类型:数据结构是简单的key-value类型,value其实不仅是String,也可以是数字。 常用命令:set,get,dect,incr,mget。

应用场景:String是最常用的一种数据类型,普通的key/value存储都可以归为此类,可以完全实现目前Memcached的功能,并且效率更高。还可以持久化。

Ⅱ、Hash类型

Hash类型,使用的时候有没有发现是三个参数,第一个是redis 的键,第二个是自己存的hash的键,最后一个是value,尤其是在用可视化的redisDesk时候,数据结构一目了然。

Memcache中,我们经常将一些结构化的信息打包成hashmap,然后序列化后存储为一个自付出的值,比如用户的昵称,年龄,性别等属性,这时候在需要修改其中一项时候,通常将所有的值取出来反序列化,修改某一项,然后再序列化存储回去。(听起来都和麻烦的样子,代码量增大就不说,性能方面也增大了开销),如果用redis来存储的话,有两种存储方式,要么把对象封装起来存储,(如果要修改需要序列化)要么就是属性分开存储(这样说存在多个键,内存会增大)各有优缺点,memcache能实现的功能,redis 都可以实现,但是redis 的选择更多一点,这就对了要取舍取舍!!根据自己项目的硬件还有软件进行选择。

   Ⅲ、List   常用命令:lpush,rpush,lpop,lrange等

应用场景:该类型应用场景非常的多,也是redis最重要的数据类型之一,比如:关注列表,粉丝列表,消息队列等都可以用redis的list结构来实现。

   list就是链表,list结构,我们可以轻松地实现最新消息排行的等功能,

揭秘消息队列是怎么利用list结构实现的呢:可以利用Lsits的PUSH操作,将任务存在Lists中,然后工作线程再用POP操作将任务取出进行执行。Redis还提供了操作lists中的某一段API,你可以直接查询,删除lists中某一段的元素。

实现方式:redis list的实现为一个双向链表,既可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,redis内部的很多很多实现,包括发送缓冲队列等也都是用的这个数据结构。

Ⅳ、Set

常用命令:sadd,spop,smembers,sunion等

特点:Set集合中不允许出现重复的元素,无序!如果多次添加相同的元素,Set中将仅保留该元素的一份拷贝。和list相比,Set类型在功能上还存在一个非常重要的特点,就是在服务器端完成多个Set之间聚合计算操作,(并集,交集,差集)。由于这些操作都是服务端完成,一次效率极高!也节省了大量的网络IO开销;Set还提供了判断某个成员是否在一个set集合中的重要接口。

应用场景:通过并集,交集,差集的特点,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。可以非常方便的实现如共同关注,共同喜好,二度好友等功能,对上面所有的集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存在一个新的集合中。

实现方式:set的内部实现是一个value永远为null的HashMap,实际就是通过计算hash 的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

  Ⅴ、zset(全称是:Sorted Set)

  常用命令:zadd、zrange,zrem、zcard等

特点:1、和set数据类型有极为相似,都是不允许重复的成员。2、set和zset最大的区别是zset每一个成员都会有一个分数score与之关联。Redis正是通过分数(score)来为集合中的成员进行小到大的排序,zset的成员是唯一的,但分数(score)却可是重复。所以,zset集合是有序集合!

使用场景:当你需要一个有序的并且不重复的集合列表,那么可以选择Zset数据结构,比如用评论发表时间作为score来存储,这样获取时就自动按照时间排好序的。 可以用来做一些排行榜之类的场景。

实现方式:Zset内部使用Hashmap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

  1. 持久化方式,rdb,aof

Rdb

持久化方式是指在指定的时间间隔将内存中的数据集快照写入磁盘。将数据集写入临时文件,写入成功以后,在替换之前的文件,用二进制压缩存储。

AOF

AOF持久化以日志的行是记录服务器所处理的每一个写,删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

  1. 最后一个雪崩,穿透,击穿,怎么发生的,怎么预防,解决。

缓存穿透的概念:用户想要查询一个数据,发现redis内存中没有,也就是缓存没有命中,于是向数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是就都去请求的数据库。这会给持久层数据库造成很大的压力,这是就会出现缓存穿透。

解决方案:

  1. 、布隆过滤器
  2. 、缓存空对象,当存储层不命中后,即使返回来的空对象也缓存起来,同时设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

使用这两个方法会存在一些问题

1、如果空值被缓存起来,会造成redis实例有大量的空值键

2、设置了对空值的过期时间,还是会缓存层和存储层数据有一段时间窗口不一致,这对于需要保持一致性的业务会有影响。

  1.  

缓存击穿的概念:是指一个key非常热点,在不停的扛着大并发集中对这么一个点进行访问,当这个key在失效的瞬间,持续的大并发就会穿透缓存,直接请求数据库,就像一个墙壁上凿开了一个洞。

解决方案:前端进行校验,对请求key进行规则校验,比如A开头的是业务需要的,B开头的直接放回false,不是A开头规则的key全部直接返回false。

缓存雪崩的概念:当缓存服务器宕机或者大量缓存集中在某一个时间失效,这样在失效的时候,

会给后端造成很大的压力,直到压垮服务器。

 

解决方案:

  1. 、redis高可用,搭建集群
  2. 、限流降级,再缓存失效以后,通过加锁的方式来控制对数据库请求的线程数量。比如对某个key 只允许一个线程查询数据,和写缓存,其他线程等待。
  3. 、数据预热
  4. 、设置random时间的失效时间,不会导致缓存同时失效

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值