置顶

Redis常见面试题(二)

Redis-常见面试题(二)

内存相关

1、MySQL里有2000w数据,redis中只存20w的数据,如何保证redis的数据都是热点数据?

redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。

2、Redis的内存淘汰策略有哪些?

Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要重新写入且需要申请额外空间的数据。

全局的键空间选择性移除:

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(最常用)
  • allkeys-random:当内存不足以容纳新写入数据时,在设置了过期时间的空间中,有更早过期时间的可以优先移除。

设置过期时间的键空间选择性移除:

  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

总结:

  • Redis的内存淘汰策略的选取并不会影响过期的key的处理。
  • 内存淘汰策略用于处理内存不足时的需要申请额外空间的数据。
  • 过期策略用于处理过期的缓存数据。

3、Redis主要消耗什么物理资源?(内存)

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

如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。

5、Redis如何做内存优化?

可以好好利用Hash,List,Zset,Set等数据结构,因为通常情况下,很多小的key-value可以用更紧凑的方式存放在一起。尽可能使用散列表,散列表使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。例如,你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表中。


线程模型

6、Redis线程模型

Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器(file event handler)。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。

  • 文件事件处理器使用I/O多路复用程序来同时监听多个套接字,并根据套接字目前执行的任务来为套接字关联不同的事件处理器。
  • 当被监听的套接字准备好执行连接应答、读取、写入、关闭等操作时,与操作相对应的文件事件就会产生,这时文件事件处理器就会调用套接字之前关联好的事件处理器来处理这些事情。

虽然文件事件处理器以单线程方式运行,但通过使用I/O多路复用程序来监听多个套接字,文件事件处理器既实现了高性能的网络通信模型,又可以很好的与redis服务器中其它同样以单线程方式运行的模块进行对接,这保持了Redis内部单线程设计的简单性。


事务

7、什么是事务?

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

事务是一个原子操作:事务中的命令要么全部被执行,要么全部不执行。

8、Redis事务的概念

Redis事务的本质是是通过MULTI、EXEC、WATCH等一组命令的集合。事务一次执行多个命令 ,一个事务中所有的命令都会被序列化。在事务的执行过程中,会按照顺序串行化执行队列中的命令,其它客户端提交的命令请求不会插入到事务执行名列序列中。

Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。

9、Redis事务的三个阶段

  1. 事务开始MULTI
  2. 命令入队
  3. 事务执行EXEC

事务执行过程中,如果服务端收到有EXEC、DISCARD、WATCH、MULTI之外的请求,将会把请求放入队列中排队。

10、事务管理概述(ACID)

  • 原子性(Automicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

  • 一致性(Consistency)

事务前后数据的完整性必须保证一致。

  • 隔离性(Isolation)

多个事务并行执行时,一个事务的执行不应影响其他事务的执行。

  • 持久性

持久性是指一个事务一旦被提交,它对数据库中的数据的改变是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

Redis的事务总是具有ACID中的一致性和隔离性,其他特性是不支持的。当服务器运行在AOF持久化模式下,并且appendfsync时,事务也具有耐久性。

11、Redis事务支持隔离性吗?

Redis是单线程程序,并且它保证在执行事务时,不会对事务进行中断,事务可以运行直到执行完所有事务队列中的命令为止。

12、Redis事务保证原子性吗?支持回滚吗?

Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会执行。

13、Redis事务其它实现

  • 基于Lua脚本,Redis可以保证脚本内的命令一次性、按命令执行,其同时也不提供事务运行错误的回滚,执行过程中如果部分命令运行错误,剩下的,命令还是会继续执行。
  • 基于中间标记变量,通过另外的标记变量来标识事务是否完成,读取数据时先读取该标记变量,判断是否事务执行完成。但这样会需要额外写代码实现,比较繁琐。

集群方案

14、哨兵模式(sentinel)

19

  1. 哨兵的介绍

    sentinel,中文名是哨兵。哨兵是redis集群机构中非常重要的一个组件,主要有一下功能:

    • 集群监控:负责监控redis master和slave进程是否正常工作。
    • 消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为警报通知给管理员。
    • 故障转移:如果master node挂掉,会自动转移到slave node上。
    • 配置中心:如果故障转移发生了,通知client客户端新的master地址。
  2. 哨兵用于实现redis集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作

    • 故障转移时,判断一个master node是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。
    • 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成成分的故障转移系统本身是单点的,那就很坑了。
  3. 哨兵的核心知识

    • 哨兵至少需要3个实例,来保证自己的健壮性。
    • 哨兵+redis主从的部署架构,是不保证数据零丢失的,只能保证集群的高可用性。
    • 对于哨兵+redis主从这种复杂的部署结构,尽量在测试环境和生产环境,都进行充足的测试和演练。

15、官方Redis Cluster方案(服务端路由查询)

20

简介

Redis Cluster是一种服务算sharding技术。Redis Cluster并没有使用一致性hash,而是采用slot(槽)的概念,一共分成16384个槽。将求情发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行。

方案说明

  1. 通过hash的方式,将数据分片,每个节点均分存储一定哈希槽的数据,默认分配了16384个槽位。
  2. 每份数据分片会存储在多个互为主从的多节点上。
  3. 数据写入先写主节点,在同步到从节点(支持配置为阻塞同步)。
  4. 同一分片多个节点的数据不保持一致性。
  5. 读取数据时,当客户端的key没有分配在该节点时,redis会返回转向指令,指向正确的节点。
  6. 扩容时需要把旧节点的数据迁移到新节点。

在redis cluster架构下,每个redis要放开两个端口号,比如一个是6379,另一个是加1w的端口号,比如16379。

16379端口号是用来进行节点间通信的,也就是cluster bus的东西,cluster bus的通信,用来进行故障检测,配置更新,故障转移授权。cluster bus用了另外一种二进制的协议,gossip协议,用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间。

节点间的内部通信机制

基本通信原理

集群元数据的维护有两种方式:集中式、Gossip式。

分布式寻址算法

  • hash算法(大量缓存重建)
  • 一致性hash算法(自动缓存迁移)+虚拟节点(自动负载均衡)
  • redis cluster的hash slot算法

优点

  • 无中心结构,支持动态扩容,对业务透明
  • 只能使用0号数据库
  • 不支持批量操作(pipeline管道操作)
  • 分布式逻辑和存储模块耦合

16、基于客户端分配

21

简介

Redis Sharding是Redis Cluster出来之前,业界普遍使用的多Redis实例集群方法。其主要思想是采用哈希算法将Redis数据的key进行散列,通过hash函数,特定的key会映射到特定的Redis节点上。java redis客户端驱动jedis,支持Redis Sharding功能。

优点

  • 优势在于非常简单,服务端的Redis实例彼此独立,相互关联,每个Redis实例像单服务器一样运行,非常容易线性扩展,系统的灵活性很强。

缺点

  • 由于sharding处理放到客户端,规模进一步扩大时给运维带来挑战。
  • 客户端sharding不支持动态增删节点。服务端Redis实例群拓扑结构有变化时,每个客户都需要更新调整。连接不能共享,当应用规模增大时,资源浪费制约优化。

17、基于代理服务器分片

22

简介

客户端发送请求到一个代理组件,代理解析客户端的数据,并将请求转发至正确的节点,最后将结果回复给客户端。

特征

  • 透明接入,业务程序不用关心后端Redis实例,切换成本低
  • Proxy的逻辑和存储的逻辑是隔离的
  • 代理层多了一次转发,性能有所损耗

业务开源方案

  • Twitter开源的Twenproxy
  • 豌豆荚开源的Codis

18、Redis的主从架构

单机的redis,能够承载的QPS大概就在上千万到几万不等。对于缓存来说,一般都支持读高并发的。因此架构做成主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其他的slave节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支持读高并发。

23

redis replication->主从架构->读写分离->水平扩容支持读高并发

redis replication的核心机制

  • redis采用异步方式复制数据到slave节点,不过从redis2.8开始,slave node会周期性地确认自己每次复制的数据量。
  • 一个master node是可以配置多个slave node的。
  • slave node可以连接其他的slave node。
  • slave node做复制的时候,不会block master node的正常工作。
  • slave node在做复制的时候,也不会对自己的查询的操作,他会用旧的数据集来提供服务;但是复制完成的时候,需要删除数据集,加载新的数据集,这个时候,就会暂停对外服务。
  • slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提纲哦吞吐量。

注意,如果采用了主从架构,那么建议必须开启 master node 的持久化,不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制, slave node 的数据也丢了。

另外,master 的各种备份方案,也需要做。万一本地的所有文件丢失了,从备份中挑选一份 rdb 去恢复master,这样才能确保启动的时候,是有数据的,即使采用了后续讲解的高可用机制,slave node 可以自动接管 master node,但也可能 sentinel 还没检测到 master failure,master node 就自动重启了,还是可能导致上面所有的 slave node 数据被清空。

redis主从复制的核心原理

当启动一个slave node的时候,它会发送一个PSYNC命令给master node。

如果这是slave node初次连接到master node,那么会触发一次full resynchronization全量复制。此时,master会启动一个后台程序,开始生成一份RDB快照文件,同时还会将从客户端client新收到的所有写命令缓存在内存中。RDB文件生成完毕后,master会将这个RDB发送给slave,slave会写入本地磁盘,然后再从本地磁盘加载到内存中,接着master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。slave node如果跟master node有网络故障,断开了连接,会自动重连,连接之后master node仅会复制给slave部分缺失的数据。

24

过程原理

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

缺点

  • 所有的slave节点数据的复制和同步都由master节点处理,会造成master节点压力过大。

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

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品。

20、生产环境中redis是怎么部署的?

redis cluster,10 台机器,5 台机器部署了 redis 主实例,另外 5 台机器部署了 redis 的从实例,每个主实例挂了一个从实例,5 个节点对外提供读写服务,每个节点的读写高峰qps可能可以达到每秒 5 万,5 台机器最多是 25 万读写请求/s。

机器是什么配置?32G 内存+ 8 核 CPU + 1T 磁盘,但是分配给 redis 进程的是10g内存,一般线上生产环境,redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。

5 台机器对外提供读写,一共有 50g 内存。

因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis 从实例会自动变成主实例继续提供读写服务。

你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb。100 条数据是 1mb,10 万条数据是 1g。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的请求量。

其实大型的公司,会有基础架构的 team 负责缓存集群的运维。

21、说说Redis哈希槽的概念?

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

22、Redis集群会有写操作丢失吗?

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

23、Redis集群之间是如何复制的?

异步复制。

24、Redis集群最大节点个数是多少?

16384个。

25、Redis集群如何选择数据库?

Redis集群目前无法做数据库选择,默认在0数据库。

-------------本文结束感谢您的阅读-------------