Redis面试

Redis面试题

☀Redis是什么?

Redis的全称是Remote Dictionary Server(远程字典服务器),是完全开源免费的,用C语言编写的,一种基于键值对(key-value)的高性能的分布式内存数据库。

与很多键值对数据库不同的是,Redis中的值可以是由string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)等多种数据结构和算法组成。

 

Redis与其他key-value存储有什么不同?

1. Redis有着更为复杂的数据结构并且提供对他们的原子性操作。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。

2.  Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另一个优点是, 相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为它们并不需要进行随机访问。

 

Redis的特点是什么?

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

 

☀为什么Redis能够快速执行

  1. Redis的所有数据都是存放在内存中的,因此绝大部分请求是纯粹的内存操作(非常快速)
  1. Redis是用C语言实现的,一般来说C语言实现的程序“距离”操作系统更近,执行速度相对会更快。
  1. Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务,避免了不必要的上下文切换竞争问题

 

☀使用Redis有哪些好处?

1. 速度快

因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

2. 基于键值对的数据结构服务器

与很多键值对数据库不同的是,Redis中的值不仅可以是字符串,而且还可以是具体的数据结构,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率

3. 丰富的功能

  除了5种数据结构,Redis还提供了许多额外的功能:

    • 提供了键过期功能,可以用来实现缓存。
    • 提供了发布订阅功能,可以用来实现消息系统。
    • 支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
    • 提供了简单的事务功能,能在一定程度上保证事务特性。
    • 提供了流水线(Pipeline)功能,这样客户端能将一批命令一次性传到Redis,减少了网络的开销。

4. 简单稳定

    • Redis的代码量少
    • Redis使用单线程模型,不仅使得Redis服务端处理模型变得简单,而且也使得客户端开发变得简单。
    • Redis不需要依赖于操作系统中的类库,Redis自己实现了事件处理的相关功能。

5. 客户端语言多

支持Redis的客户端语言几乎涵盖了主流的编程语言

6. 持久化

通常看,将数据放在内存中是不安全的,一旦发生断电或者机器故障,重要的数据可能就会丢失,因此Redis提供了两种持久化方式:RDB和AOF,即可以用两种策略将内存的数据保存到硬盘中,这样就保证了数据的可持久性

7. 主从复制

Redis提供了复制功能,实现了多个相同数据的Redis副本。

8. 高可用和分布式

Redis从3.0版本正式提供了分布式实现Redis Cluster,它是Redis真正的分布式实现,提供了高可用、读写和容量的扩展性。

缺点:

  • 由于是内存数据库,所以,单台机器存储的数据量,跟机器本身的内存大小。虽然 redis 本身有 key 过期策略,但是还是需要提前预估和节约内存。如果内存增长过快,需要定期删除数据。
  • 如果进行完整重同步,由于需要生成 rdb 文件,并进行传输,会占用主机的 CPU,并会消耗现网的带宽。不过 redis2.8 版本,已经有部分重同步的功能,但是还是有可能有完整重同步的。比如,新上线的备机。
  • 修改配置文件,进行重启,将硬盘中的数据加载进内存,时间比较久。在这个过程中,redis 不能提供服务。

 

☀Redis使用场景

  1. 缓存
    Redis作为缓存层,MySQL作为存储层,绝大部分请求的数据都是从Redis中获取。由于Redis具有支撑高并发的特性,所以缓存通常能起到加速读写和降低后端压力的作用。
  1. 排行榜系统
  1. 计数器应用

    计数器在网站中的作用至关重要,例如视频网站有播放数、电商网站有浏览数,为了保证数据的实时性,每一次播放和浏览都要做加1的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。Redis天然支持计数功能而且计数的性能也非常好

  1. 共享session
    分布式Web服务将用户的Session信息(例如用户登录信息)保存在各自服务器中,但是分布式服务会将用户的访问均衡到不同服务器上,用户刷新一次访问可能会发现需要重新登录。为了解决这个问题,可以使用Redis将用户的Session进行集中管理,只要保证Redis是高可用和扩展性的,每次用户更新或者查询登录信息都直接从Redis中集中获取。
  1. 社交网络
    赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适合保存这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。
  1. 消息队列系统
    消息队列系统是大型网站的必备基础组件。Redis提供了发布订阅功能和阻塞队列的功能,虽然和专业的消息队列比还不够足够强大,但是对于一般的消息队列功能基本可以满足。
  1. 短信验证码限速
    很多应用出于安全的考虑,会在每次进行登录时,让用户输入手机验证码,从而确定是否是用户本人。但是为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率,例如一分钟不能超过5次
  2. 设置过期时间

 

☀Redis 和Memcached的区别

区别:

  • 访问速度
    Redis的速度比Memcached快很多
  • Redis和Memcached都是将数据存放在内存中,都是内存数据库。不过Memcached还可用于缓存其他东西,例如图片、视频等等。
  • 数据支持类型
    Redis不仅支持简单的key-value类型的数据,同时还提供list,set,hash等数据结构的存储。Memcached所有的值均是简单的字符串
  • 数据持久化
    Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启时可以再次加载进行使用。所以Redis数据丢失后可以通过AOF恢复。
    Memcached不支持内存数据的持久化操作,Memcached挂掉后,数据不可恢复。
  • 数据备份
    Redis支持数据的备份,即master-slave模式的数据备份。
  • 内存空间
    • Redis在2.0版本后增加了自己的VM特性,突破物理内存的限制;可以对key-value设置过期时间(类似memcached)
    • Memcached可以修改最大可用内存,采用LRU算法
  • value大小
    Redis最大可以达到1GB,而Memcached只有1MB
  • 网络IO模型
    • Redis使用单线程的IO复用模型。
    • Memcached使用多线程,非阻塞IO复用的网络模型。
  • 内存管理机制
    • Redis通过定义一个数组来记录所有的内存分配情况。数组的每一个元素代表当前程序所分配的内存块的个数,且内存块的大小为该元素的下标。
      • 在Redis中,并不是所有的数据都一直存储在内存中的。
      • 当物理内存用完时,Redis可以将一些很久没用到的value交换到磁盘。
    • Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎片问题。
  • 数据一致性问题
    • Redis没有提供cas 命令,并不能保证多个并发访问操作同一份数据的一致性问题,不过Redis提供了事务的功能,只能保证事务中的每个操作连续执行。
    • Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题。
  • 集群管理
    • Redis更偏向于在服务器端构建分布式存储。
    • Memcached只能采用客户端实现分布式存储。

 

选择:

  • 若是简单的存取key-value这样的数据用Memcached好一些
  • 若是要支持数据持久化,多数据类型(如集合、散列之类的),用列表类型做队列之类的高级应用,就用Redis

 

☀Redis单线程

单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程。

 

单进程模型来处理客户端的请求。对读写等事件的响应是通过对epoll函数的包装来做到。Redis的实际处理速度完全依赖主进程的执行效率。

Epoll是Linux内核为处理大批量文件描述符而做了改进的epoll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。

 

单线程带来的好处:

  • 单线程可以简化数据结构和算法的实现。
  • 单线程避免了线程切换和竞态产生的消耗,对于服务端开发来说,锁和线程切换通常是性能杀手。

 

单线程带来的问题:

  • 对于每个命令的执行时间都是有要求的。如果某个命令执行过长,会造成其他命令的阻塞。

 

使用单线程注意:

  1. 一次只运行一条命令
  2. 拒绝长(慢)命令

 

面试题:为什么Redis是单线程的?

因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案

 

☀为什么单线程的Redis比多线程Memcached效率要高?

  1. 内存访问,Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,这是Redis达到每秒万级别访问的重要基础。
  1. 非阻塞I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。
  1. 单线程避免了线程切换和竞态产生的消耗。

 

为什么Redis需要把所有数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以Redis具有快速和数据持久化的特征。

如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天,Redis将会越来越受欢迎。 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。

 

Redis的内部实现

内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,不在io上浪费一点时间 这3个条件不是相互独立的,特别是第一条,如果请求都是耗时的,采用单线程吞吐量及性能很差。Redis为特殊的场景选择了合适的技术方案。

 

Redis关于线程安全问题

Redis实际上是采用了线程封闭的观念,把任务封闭在一个线程,自然避免了线程安全问题,不过对于需要依赖多个Redis操作的复合操作来说,依然需要锁,而且有可能是分布式锁。

 

☀Redis数据结构有哪些?

Redis五大基本数据结构:

  • String
  • Hash
  • List
  • Set
  • Zset

 

Redis 的 List 结构相关的操作

  •  lpush/rpush/lrange
  •  lpop/rpop
  •  lindex,按照索引下标获得元素(从上到下)
  •  llen
  •  lrem key 删N个value
  •  ltrim key 开始index 结束index,截取指定范围的值后再赋值给key
  •  rpoplpush 源列表 目的列表
  •  lset key index value
  •  linsert key  before/after 值1 值2

 

☀Redis 如何实现持久化?

  • RDB 持久化
    RDB持久化是在指定的时间间隔内把当前进程数据生成快照保存到硬盘的过程,相当于备份数据库状态。它恢复时是将快照文件直接读到内存里。
  • AOF持久化
    AOF持久化是以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中的命令达到恢复数据的目的。相当于备份数据库接收到的命令,所有被写入 AOF 的命令都是以 Redis 的协议格式来保存的。

 

 

☀Redis两种持久化方式的优缺点

RDB的优点:

  • RDB 是一个非常紧凑的二进制文件,代表Redis在某个时间点的数据快照。可用于灾难恢复。
  • RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
  • 只有一个文件dump.rdb,方便持久化。
  • 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以是IO最大化。
  • 相对于数据集大时,比AOF的启动效率更高。

 

RDB的缺点:

  • RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,属于重量级操作,频繁执行成本过高。
  • RDB文件使用特定二进制格式保存,Redis版本演进过程中有多个格式的RDB版本,存在老版本Redis服务无法兼容新版RDB格式的问题。
  • 数据安全性低。
  • 在一定间隔时间内做一次备份,所以如果Redis意外down掉,最后一次持久化后的数据可能丢失

AOF的优点:

  • 数据安全,AOF持久化可以配置appendfsync属性,有always,每进行一次命令操作就记录到aof文件中一次。
  • 通过append模式写文件,即使中途服务器宕机,可以通过Redis-check-aof工具解决数据一致性问题。

 

AOF的缺点:

  • 文件会比RDB形式的文件大。
  • 数据集大的时候,比RDB启动效率低。

 

 

Redis如何设置密码及验证密码?

设置密码:config set requirepass 123456

授权密码:auth 123456

 

☀Redis的主从复制是怎么实现的?

 

 

过程原理:

  1. 当从库和主库建立MS关系后,会向主数据库发送SYNC命令
  1. 主库接收到SYNC命令后会开始在后台保存快照(RDB持久化过程),并将期间接收到的写命令缓存起来
  1. 当快照完成后,主Redis会将快照文件和所有缓存的写命令发送给从Redis
  1. 从Redis接收到后,会载入快照文件并且执行收到的缓存的命令
  1. 之后,主Redis每当接收到写命令时就会将命令发送从Redis,从而保证数据的一致

 

缺点:所有的slave节点数据的复制和同步都由master节点来处理,会照成master节点压力太大,使用主从结构来解决

 

☀Redis常见的性能问题都有哪些?如何解决?

  1. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
  1. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
  1. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
  2. Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内

 

☀常见的缓存策略(maxmemory-policy)或者数据淘汰策略有哪些?

  • volatile-lru:使用LRU算法移除key,只对设置了过期时间的键
  • allkeys-lru:使用LRU算法移除key
  • volatile-random:在过期集合中移除随机的key,只对设置了过期时间的键
  • allkeys-random:移除随机的key
  • volatile-ttl:移除那些TTL值最小的key,即那些最近要过期的key
  • noeviction:不进行移除。针对写操作,只是返回错误信息

 

默认的缓存策略是noeviction

 

缓存数据过期后的更新如何设计

 

如何做到缓存(比如 Redis)与 DB 里的数据一致性,你们项目中用到了什么缓存系统,如何设计的

 

☀什么是缓存雪崩

Redis不可能把所有的数据都缓存起来(内存昂贵且有限),所以Redis需要对数据设置过期时间,并采用的是惰性删除+定期删除两种策略对过期键删除。

如果缓存数据设置的过期时间是相同的,并且Redis恰好将这部分数据全部删光了。这就会导致在这段时间内,这些缓存同时失效,全部请求到数据库中。这会导致缓存雪崩:

  • Redis挂掉了,请求全部走数据库。
  • 对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。

缓存雪崩如果发生了,很可能就把我们的数据库搞垮,导致整个服务瘫痪!

 

☀如何防止缓存雪崩

对于“对缓存数据设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库。”这种情况,可以在缓存的时候给过期时间加上一个随机值,这样就会大幅度的减少缓存在同一时间过期。

 

对于“Redis挂掉了,请求全部走数据库”这种情况,可以有以下的思路:

  • 事发前:实现Redis的高可用(主从架构+Sentinel 或者Redis Cluster),尽量避免Redis挂掉这种情况发生。
  • 事发中:万一Redis真的挂了,可以设置本地缓存(ehcache)+限流(hystrix),尽量避免我们的数据库被干掉(起码能保证我们的服务还是能正常工作的)
  • 事发后:Redis持久化,重启后自动从磁盘上加载数据,快速恢复缓存数据。

 

什么是缓存穿透

缓存穿透是指查询一个一定不存在的数据。由于缓存不命中,并且出于容错考虑,如果从数据库查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,失去了缓存的意义。

 

这就是缓存穿透:

  • 请求的数据在缓存大量不命中,导致请求走数据库。

缓存穿透如果发生了,也可能把我们的数据库搞垮,导致整个服务瘫痪

 

如何防止缓存穿透

解决缓存穿透也有两种方案:

  • 由于请求的参数是不合法的(每次都请求不存在的参数),于是我们可以使用布隆过滤器(BloomFilter)或者压缩filter提前拦截,不合法就不让这个请求到数据库层
  • 当我们从数据库找不到的时候,我们也将这个空对象设置到缓存里边去。下次再请求的时候,就可以从缓存里边获取了。
  • 这种情况我们一般会将空对象设置一个较短的过期时间。

 

请思考一个方案,设计一个可以控制缓存总体大小的自动适应的本地缓存。

 

如何看待缓存的使用(本地缓存,集中式缓存),简述本地缓存和集中式缓存和优缺点。本地缓存在并发使用时的注意事项。

 

Redis 的并发竞争问题如何解决

 

Redis 事务的 CAS 操作

 

☀使用Redis如何设计分布式锁?使用Zookeeper可以吗?如何实现?这两种哪个效率更高?

Redis:

SETNX key value:如果key不存在,则创建并赋值

如果设置成功,返回1;如果设置失败,返回0。

 

Redis2.6.12起:

image.png

 

Redis2 和 Redis3 的区别,Redis3 内部通讯机制。

 

当前 Redis 集群有哪些玩法,各自优缺点,场景。

 

 

Redis 的选举算法和流程是怎样的。

 

Redis 的集群怎么同步的数据的。

 

知道哪些 Redis 的优化操作。

 

 

☀Redis的集群模式是如何实现的?Redis的key是如何寻址的?

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值