干货!Redis面试必知必会

Redis 支持哪几种数据类型?

  • string:最基本的数据类型,二进制安全的字符串,最大512M
  • list:按照添加顺序保持顺序的 字符串列表
  • set:无序的字符串集合,不存在重复的元素
  • sorted set:已排序的字符串集合
  • hash:key/value对的一种集合

Redis是单进程的仍是单线程的?

Redis是单进程单线程的,Redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销。程序员

Redis为何是单线程的?

多线程处理会涉及到锁,并且多线程处理会设计到线程切换而消耗CPU。由于CPU不会Redis的瓶颈,Redis的瓶颈最有多是机器内存或者网络带宽。单线程没法发挥多核CPU性能,不过能够经过在单机开启Redis实例来解决。web

Redis的优点

  • **速度快。**由于数据存储于内存中,相似于HashMap,HashMap的优点就是查找和操做的时间复杂度都是O(1)
  • 支持丰富的数据类型,支持string,list,set,sorted set,hash
  • 支持事务,操做都是原子性,所谓的原子性就是对数据的更改要么所有执行,要么所有不执行
  • 丰富的特性:可用于缓存,消息,按key设置过时时间,过时后将会自动删除

Redis和memcached有哪些优点

  • memcached全部的值均是简单的字符串,Reids做为其替代者,支持更为丰富的数据类型
  • Redis的速度比memcached快不少
  • Redis能够持久化其数据
  • Redis支持数据的备份,即master/slave模式的数据备份

Redis key的过时时间和永久有效分别怎么设置?

EXPIREPERSIST命令。redis

Redis 主要消耗什么物理资源?

内存。算法

为何Redis须要把全部数据放到内存中?

Redis为了达到最快的读写速度将数据都读到内存中,并经过异步的方式将数据写入磁盘。数据库

因此redis具备快速和数据持久化的特征。若是不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。后端

在内存愈来愈便宜的今天,redis将会愈来愈受欢迎。 若是设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。缓存

说说Redis哈希槽的概念?

Redis集群没有使用一致性hash,而是引入了哈希槽的概念,Redis集群有16384个哈希槽,每一个key经过CRC16校验后对16384取模来决定放置哪一个槽,集群的每一个节点负责一部分hash槽。安全

Redis中的管道有什么用?

一次请求/响应服务器能实现处理新的请求即便旧的请求还未被响应。这样就能够将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。性能优化

这就是管道(pipelining),是一种几十年来普遍使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。服务器

怎么理解Redis事务?

事务是一个单独的隔离操做:事务中的全部命令都会序列化、按顺序地执行。事务在执行的过程当中,不会被其余客户端发送来的命令请求所打断。

事务是一个原子操做:事务中的命令要么所有被执行,要么所有都不执行。

Redis 事务相关的命令有哪几个?

MULTIEXECDISCARDWATCH

Redis内存回收机制

Redis的内存回收主要围绕如下两个方面:

  1. Redis过时策略:删除过时时间的key值
  2. Redis淘汰策略:内存使用到达maxmemory上限时触发内存淘汰数据

Redis过时策略

Redis过时策略一般有如下三种:

  1. 定时过时 每一个设置过时时间的key都须要建立一个定时器,到过时时间就会当即清除。该策略能够当即清除过时的数据,对内存很友好;可是会占用大量的CPU资源去处理过时的数据,从而影响缓存的响应时间和吞吐量。

  2. 惰性过时 只有当访问一个key时,才会判断该key是否已过时,过时则清除。该策略能够最大化地节省CPU资源,却对内存很是不友好。极端状况可能出现大量的过时key没有再次被访问,从而不会被清除,占用大量内存。

  3. 按期过时 每隔必定的时间,会扫描必定数量的数据库的expires字典中必定数量的key,并清除其中已过时的key。该策略是前二者的一个折中方案。经过调整定时扫描的时间间隔和每次扫描的限定耗时,能够在不一样状况下使得CPU和内存资源达到最优的平衡效果。

Redis中同时使用了惰性过时按期过时两种过时策略。

Redis有哪几种数据淘汰策略

在Redis中,容许用户设置最大使用内存大小server.maxmemory,当Redis内存数据集大小上升到必定大小的时候,就会执行数据淘汰策略

  • volatile-lru:从已设置过时的数据集中挑选最近最少使用的淘汰
  • volatile-ttl:从已设置过时的数据集中挑选将要过时的数据淘汰
  • volatile-random:从已设置过时的数据集中任意挑选数据淘汰
  • allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集中任意挑选数据淘汰
  • noenviction:禁止淘汰数据

Redis支持哪几种持久化方式

RDB持久化 原理是将Redis在内存中的数据记录定时dump到磁盘上的RDB文件。 指定的时间间隔内将内存中的数据集快照写入磁盘,实际操做过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换以前的文件,用二进制压缩存储。

AOF(append only file)持久化 原理是将Redis的操做日志以追加的方式写入文件。 以日志的形式记录服务器所处理的每个写、删除操做,查询操做不会记录,以文本的方式记录,能够打开文件看到详细的操做记录。当服务器重启的时候会从新执行这些命令来恢复原始的数据。AOF命令以Reids协议追加保存每次写的操做到文件末尾。Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。

Redis两种持久化方式优缺点?

RDB持久化

  • 优势:RDB文件紧凑,体积小,网络传输快,适合全量复制;恢复速度比AOF快不少。固然,与AOF相比,RDB最重要的优势之一是对性能的影响相对较小
  • 缺点:RDB文件的致命缺点在与其数据快照的持久化方式决定了必然作不到实时持久化,而在数据愈来愈重要的今天,数据的大量丢失不少时候是没法接受的,所以AOF持久化称为主流。此外,RDB文件须要知足特定格式,兼容性差。

AOF持久化 与RDB持久化相对应,AOF的优势在于支持秒级持久化、兼容性好,缺点是文件大,恢复速度慢,对性能影响大

如何选择Redis持久化方式策略?

在介绍持久化策略以前,首先要明白不管是RDB仍是AOF,持久化的开启都是要付出性能方面的代价的。对比RDB持久化,一方面是bdsave在进行fork操做时Redis主进程会阻塞,另外一方面,子进程向硬盘写数据也会带来IO压力;对于AOF持久化,向硬盘写数据的频率大大提升(everysec策略下为秒级),IO压力更大,设置可能形成AOF追加阻塞文件。此外,AOF文件的重写与RDB的basave相似,会有fork时的阻塞和子进程的IO压力问题。相对来讲,因为AOF向硬盘中写数据的频率更高,所以对Redis主进程性能的影响会更大。

在实际生产环境中,根据数据量、应用对数据的安全要求、预算限制等不一样状况,会有各类各样的持久化策略;如彻底不使用任何持久化,使用RDB或AOF一种,或同事开启RDB和AOF持久化等。此外,持久化的选择必须与Redis的主从策略一块儿考虑,由于主从复制与持久化一样具备数据备份的功能,并且主机master和从机slave能够独立的选择持久化方案。

为何要作Redis分区?

分区可让Redis管理更大的内存,Redis将可使用全部机器的内存。若是没有分区,你最多只能使用一台机器的内存。分区使Redis的计算能力经过简单地增长计算机获得成倍提高,Redis的网络带宽也会随着计算机和网卡的增长而成倍增加。

Redis集群的主从复制模型是怎样的?

为了是在部分节点失败或者大部分节点没法通讯的状况下集群仍然可用,因此集群是用了主从复制模型,每一个节点都会有N-1个复制品

Redis集群会有写操做丢失吗?为何?

Redis并不能保证数据强一致性,这意味着在实际中集群在特定的条件下可能会丢失写操做

Redis集群之间是如何复制的

异步复制。

Redis如何作内存优化

尽量使用散列表(hashes),散列表(是说列表里面存储的数少)使用的内存很是小,因此你应该尽量的将你的数据模型抽象到一个散列表里面,好比你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户全部信息存储到一张散列表中。

Redis经常使用的使用场景

  • Session共享(单点登陆)
  • 页面缓存
  • 队列
  • 排行榜/计算器
  • 发布/订阅

Redis有哪些架构模式?讲讲各自的特色?

单机版

特色:简单

存在问题:

  1. 内存容量有限
  2. 处理能力有限
  3. 没法高可用

主从复制

Redis的复制(replication)功能容许用户根据一个Redis服务器来建立任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而经过复制建立出来的服务器复制品则为从服务器(slave)。主要主从服务器之间的网络链接正常,主从服务器二者会具备相同的数据,主服务器就会一直将发生在本身身上的数据更新同步给从服务器,从而一直保证主从服务器的数据相同。

问题:

  1. 没法保证高可用
  2. 没有解决master写的压力

哨兵

Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:

  • 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运做正常。

  • 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 能够经过 API 向管理员或者其余应用程序发送通知。

  • 自动故障迁移(Automatic failover): 当一个主服务器不能正常工做时, Sentinel 会开始一次自动故障迁移操做。

特色:

  1. 保证高可用
  2. 监控各个节点
  3. 自动故障迁移

缺点:

  1. 主从模式,切换须要时间,会丢数据
  2. 没有解决master写的压力

集群(proxy型)

Twemproxy 是一个 Twitter 开源的一个 redis 和 memcache 快速/轻量级代理服务器; Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII 协议和 redis 协议。

特色:

  1. 多种 hash 算法:MD五、CRC1六、CRC3二、CRC32a、hsieh、murmur、Jenkins
  2. 支持失败节点自动删除
  3. 后端 Sharding 分片逻辑对业务透明,业务方的读写方式和操做单个 Redis 一致

缺点:

  1. 增长了新的 proxy,须要维护其高可用。
  2. failover 逻辑须要本身实现,其自己不能支持故障的自动转移可扩展性差,进行扩缩容都须要手动干预

集群(直连型)

从redis 3.0以后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每一个节点保存数据和整个集群状态,每一个节点都和其余全部节点链接。

特色:

  1. 无中心架构(不存在哪一个节点影响性能瓶颈),少了 proxy 层。
  2. 数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
  3. 可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。
  4. 高可用性,部分节点不可用时,集群仍可用。经过增长 Slave 作备份数据副本
  5. 实现故障自动 failover,节点之间经过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master的角色提高。

缺点:

  1. 资源隔离性较差,容易出现相互影响的状况。
  2. 数据经过异步复制,不保证数据的强一致性

使用过Redis分布式锁吗,它是怎么实现的?

先拿setnx来争抢锁,抢到以后,再用expire给锁加一个过时时间防止锁忘记了释放。 若是在setnx以后执行expire以前进程意外crash或者要重启维护了,那会怎么样? set指令有很是复杂的参数,这个应该是能够同时把setnx和expire合成一条指令来用的!

使用过 Redis 作异步队列么,你是怎么用的?有什么缺点?

般使用 list 结构做为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep一会再重试。

缺点:

  • 在消费者下线的状况下,生产的消息会丢失,得使用专业的消息队列如 rabbitmq 等。
  • 能不能生产一次消费屡次呢?
  • 使用 pub/sub 主题订阅者模式,能够实现 1:N 的消息队列。

什么是缓存穿透?如何避免?

缓存穿透

通常的缓存系统,都是按照key去缓存查询,若是不存在对应的value,就应该去后端系统查找(好比DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统形成很大的压力。这就叫作缓存穿透。

如何避免?

  1. 对查询结果为空的状况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了以后清理缓存。

  2. 对必定不存在的key进行过滤。能够把全部的可能存在的key放到一个大的Bitmap中,查询时经过该bitmap过滤。

什么是缓存雪崩?何如避免?

缓存雪崩 当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力,致使系统崩溃。

如何避免?

  1. 在缓存失效后,经过加锁或者队列来控制读数据库写缓存的线程数量。好比对某个key只容许一个线程查询数据和写缓存,其余线程等待。
  2. 作二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,能够访问A2,A1缓存失效时间设置为短时间,A2设置为长期 3:不一样的key,设置不一样的过时时间,让缓存失效的时间点尽可能均匀

缓存并发

这里的并发指的是多个redis的client同时set key引发的并发问题。其实redis自身就是单线程操做,多个client并发操做,按照先到先执行的原则,先到的先执行,其他的阻塞。固然,另外的解决方案是把redis.set操做放在队列中使其串行化,必须的一个一个执行。

缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。

这样就能够避免在用户请求的时候,先查询数据库,而后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决思路:

  1. 直接写个缓存刷新页面,上线时手工操做下;
  2. 数据量不大,能够在项目启动的时候自动进行加载;

目的就是在系统上线前,将数据加载到缓存中。

Redis回收进程如何工做的?

  1. 客户端执行数据写入操做
  2. redis server接收到写入操做以后,检查maxmemory的限制,若是超过了限制,那么就根据对应的policy清理掉部分数据
  3. 写入操做完成执行。

Redis是单线程的,如何提升多核CPU的利用率?

能够在同一个服务器部署多个Redis的实例,并把他们看成不一样的服务器来使用,在某些时候,不管如何一个服务器是不够的, 因此,若是你想使用多个CPU,你能够考虑一下分片(shard)。

修改配置不重启Redis会实时生效吗?

针对运行实例,有许多配置选项能够经过 CONFIG SET 命令进行修改,而无需执行任何形式的重启。 从 Redis 2.2 开始,能够从 AOF 切换到 RDB 的快照持久性或其余方式而不须要重启 Redis。检索 CONFIG GET * 命令获取更多信息。 但偶尔从新启动是必须的,如为升级 Redis 程序到新的版本,或者当你须要修改某些目前 CONFIG 命令还不支持的配置参数的时候。

Redis的内存用完了会发生什么?

若是达到设置的上限,Redis的写命令会返回错误信息(可是读命令还能够正常返回。)或者你能够将Redis当缓存来使用配置淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

分布式Redis是前期作仍是后期规模上来了再作好?为何?

既然Redis是如此的轻量(单实例只使用1M内存),为防止之后的扩容,最好的办法就是一开始就启动较多实例。即使你只有一台服务器,你也能够一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来讲这操做起来可能比较麻烦,可是从长久来看作这点牺牲是值得的。这样的话,当你的数据不断增加,须要更多的Redis服务器时,你须要作的就是仅仅将Redis实例从一台服务迁移到另一台服务器而已(而不用考虑从新分区的问题)。一旦你添加了另外一台服务器,你须要将你一半的Redis实例从第一台机器迁移到第二台机器。

Redis与其余key-value存储有什么不一样?

Redis有着更为复杂的数据结构而且提供对他们的原子性操做,这是一个不一样于其余数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。Redis运行在内存中可是能够持久化到磁盘,因此在对不一样数据集进行高速读写时须要权衡内存,应为数据量不能大于硬件内存。在内存数据库方面的另外一个优势是, 相比在磁盘上相同的复杂的数据结构,在内存中操做起来很是简单,这样Redis能够作不少内部复杂性很强的事情。 同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,由于他们并不须要进行随机访问。

关注得到更多分享


好文推荐:

相关文章
相关标签/搜索