对redis深入理解

 

产生背景:

电脑中除了CPU和内存,其他都是IO设备,IO有性能瓶颈。

一开始有磁盘和内存,磁盘速度是ms毫秒,带宽是G/M级别,磁盘存储数据有IO缓存区,磁道,磁道有扇区,一个扇区分多少字节,查找数据是根据扇区查询的,扇区越小,查询的次数越多,现在系统一般都是4K扇区。

内存速度us微秒,带宽很大。

数据库有page data也是4K大小,index data也是4K大小,b-tree

二叉树,大数据量查询,数据量越多page-data查询越多,磁盘带宽压力越大,IO次数越多,性能越低。这时候纯粹内存技术SAP hana,但是价格贵,用不起,后来出现Redis,一部分数据放内存,一部分数据放磁盘。

1、Redis有哪些数据结构?

字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。如果你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。

2、使用过Redis分布式锁么,它是什么回事?尽量做到无锁,使用akka多线程,单个consumer消费某一个队列,但是要做好边界和隔离

分布式锁是为了锁住行为,而不是锁住数据,假如有5000个并发请求过来,通过Redis分布式锁锁住其他4999个请求,只有一个请求过来请求后端MySQL服务器数据,集群部署方式用单机,也可以用分布式部署,这样对于不同的key用不同的分片,比较安全,不像单机,假如挂了,所有key都没用了,不要用主从复制的集群,因为主从节点同步有延时,会有重复。先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。set指令有非常复杂的参数,这个指令应该是可以同时把setnx和expire合成一条指令来用的。分布式锁基本上有redis和zookeeper两种方案,redis可以使用set key value NX px 命令,还有redission开源的封装实现,redis方案是ap(Availability和Partition tolerance分区容错,就是某一个服务器节点挂了导致网络不通,这时客户端获取不到这个分区的数据了,肯定不能容忍,所有为了不影响客户端获取数据,就把数据复制到各个分区上,这样客户端就可以从另一个节点获取数据,能容忍了,但是数据会不一致,因为不能立即同步)

模式,因为某一个节点挂了,另一个节点升为主节点的时候数据会不一致,缺少部分数据。zookeeper则以临时有序节点,每个线程创建/lock/xxx临时有序节点,然后将自己创建的节点和/lock下最小值比较,等于最小值则获得锁。当前线程不是序号最小的,则对节点序号的前一个节点添加监听。zk的方案是cp(Consistency和Partition tolerance分区容错,某一个服务器节点挂了,但是不影响客户端获取数据,获取数据前,先强制同步sync,保证了一致性)模式。提高分布式锁的性能:1,锁的粒度越小越好,就是锁里面的代码量越少越好;2,把分布式锁切成段,每段都是一把分布式锁,提高并发性能,比如扣减库存。

3、假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。不过keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。也可以用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

4、使用过Redis做异步队列么,你是怎么用的?

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。如果不用sleep的话,list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。如果想生产一次消费多次的话,使用pub/sub主题订阅者模式,可以实现1:N的消息队列,不过pub/sub有不足的地方,在消费者下线的情况下,生产的消息会丢失,这时候得使用专业的消息队列如rabbitmq等。

5、redis如何实现延时队列?

使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。

6、如果有大量的key需要设置同一时间过期,一般需要注意什么?

如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。

7、Redis如何做持久化的?

bgsave做镜像全量持久化,aof做增量持久化。因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件重新构建内存,再使用aof重放近期的操作指令来实现完整恢复重启之前的状态。

8、aof做增量持久化时,突然断电,怎么保存数据?

取决于aof日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。

9、bgsave的原理是什么?

fork和cow。fork是指redis通过创建子进程来进行bgsave操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。

10、Pipeline有什么好处,为什么要用pipeline?

可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。

11、Redis的同步机制了解么?

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。

12、是否使用过Redis集群,集群的原理是什么?

Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。

Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

 

本文转自:https://www.toutiao.com/i6505194629170725389/

posted @ 2018-01-25 23:25  ppjj  阅读(297)  评论(0编辑  收藏  举报