vlambda博客
学习文章列表

今年遇到的PHP面试题--Redis


Redis

Redis有哪些常用数据类型

String、Hash、List、Set、SortedSet、Pub/Sub。
相关链接: Redis 命令参考

怎么用Redis统计上亿访问量的日活跃用户

可以使用Bitmap或者HyperLogLog来进行统计。

Bitmap

因为bitmap的每一位只占据1bit的空间 ,所以利用这个特性我们可以把每一天作为key,value为1亿用户的活跃度状态。假设一个用户一天内只要登录了一次就算活跃。活跃我们就记为1,不活跃我们就记为0。把用户Id作为偏移量(offset)。这样我们一个key就可以存储1亿用户的活跃状态。

HyperLogLog

HyperLogLog 是用来做基数统计的算法,直接把用户ID插入到一个key中,

两者区别

如果需要精确结果的话,可以使用bitmap,1亿数据大约占用12M内存。
如果只需要一个大概结果的话,可以使用HyperLogLog,1亿数据大约占用14k内存。
相关链接: Redis如何存储和计算一亿用户的活跃度

Redis怎么实现分布式锁

将用户ID作为key,在Redis中设置一个value。
需要注意的点是要用到 NX 参数,保证key是不存在才设置成功。
还需要用到 EX 参数设置过期时间,防止出现异常时锁无法释放。
 
   
   
 
set key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds:设置失效时长,单位秒
PX milliseconds:设置失效时长,单位毫秒
NX:key不存在时设置value,成功返回OK,失败返回(nil)
XX:key存在时设置value,成功返回OK,失败返回(nil)
相关链接: redis分布式锁?坑那么多

Redis Cluster集群获取key对应的value的流程

  1. redis cluster模式采用了无中心节点的方式来实现,每个主节点都会与其它主节点保持连接。节点间通过gossip协议交换彼此的信息,同时每个主节点又有一个或多个从节点。

  2. 客户端连接集群时,直接与redis集群的每个主节点连接,根据hash算法取模将key存储在不同的哈希槽上。

  3. 在集群中采用数据分片的方式,将redis集群分为16384个哈希槽。

  4. 每个节点会保存一份数据分布表,节点会将自己的slot信息发送给其他节点,节点间不停的传递数据分布表。

相关链接: 想进大厂,面试却挂在了Redis集群上

Redis Cluster集群中某个节点故障了该怎么获取数据

redis cluster中主节点故障处理方式与哨兵模式较为相像,当约定时间内某节点无法与集群中的另一个节点顺利完成ping消息通信时,则将该节点标记为主观下线状态,同时将这个信息向整个集群广播。
如果一个节点收到某个节点失联的数量达到了集群的大多数时,那么将该节点标记为客观下线状态,并向集群广播下线节点的fail消息。然后立即对该故障节点进行主从切换。等到原来的主节点恢复后,会自动成为新主节点的从节点。 如果主节点没有从节点,那么当它发生故障时,集群就将处于不可用状态。
相关链接: 想进大厂,面试却挂在了Redis集群上

Redis Cluster集群怎么扩容

当集群中加入某个节点时,哈希槽又是如何来进行分配的?
当集群中加入新节点时,会与集群中的某个节点进行握手,该节点会把集群内的其它节点信息通过gossip协议发送给新节点,新节点与这些节点完成握手后加入到集群中。
然后集群中的节点会各取一部分哈希槽分配给新节点。
当集群中要删除节点时,只需要将节点中的所有哈希槽移动到其它节点,然后再移除空白(不包含任何哈希槽)的节点就可以了。
相关链接: 想进大厂,面试却挂在了Redis集群上

Redis主从数据库怎么同步数据

全量同步

  1. 当从节点启动时,会向主节点发送SYNC命令。

  2. 主节点接收到SYNC命令后,开始在后台执行保存快照的命令生成RDB文件,并使用缓冲区记录此后执行的所有写命令。

  3. 主节点快照完成后,将快照文件和所有缓存命令发送给集群内的从节点,并在发送期间继续记录被执行的写命令。

  4. 主节点快照发送完毕后开始向从节点发送缓冲区中的写命令。

  5. 从节点载入快照文件后,开始接收命令请求,执行接收到的主节点缓冲区的写命令。

增量同步

主从复制中因网络等原因造成数据丢失场景,当从节点再次连上主节点。如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。
相关链接: 想进大厂,面试却挂在了Redis集群上

Redis的数据持久化有哪些方式

Redis的数据持久化有两种方式,一种是RDB,一种是AOF。

RDB

RDB:把当前数据生成快照保存在硬盘上。
触发方式有两种
  • 手动触发:save、bgsave命令

  • 自动触发:在Redis的配置文件中配置触发条件

优点
  • RDB文件是一个紧凑的二进制压缩文件,是Redis在某个时间点的全部数据快照。所以使用RDB恢复数据的速度远远比AOF的快,非常适合备份、全量复制、灾难恢复等场景。

缺点
  • 每次进行bgsave操作都要执行fork操作创建子经常,属于重量级操作,频繁执行成本过高,所以无法做到实时持久化,或者秒级持久化。

AOF

AOF:记录每次对数据的操作到硬盘上。
触发方式有两种
  • 手动触发:使用bgrewriteaof命令。

  • 自动触发:根据auto-aof-rewrite-min-size和auto-aof-rewrite-percentage配置确定自动触发的时机。

主要步骤
  1. 命令追加(append):所有写命令都会被追加到AOF缓存区(aof_buf)中。

  2. 文件同步(sync):根据不同策略将AOF缓存区同步到AOF文件中。

  3. 文件重写(rewrite):定期对AOF文件进行重写,以达到压缩的目的。

  4. 数据加载(load):当需要恢复数据时,重新执行AOF文件中的命令。

三种同步策略
  1. always:每次写入缓存区都要同步到AOF文件中,硬盘的操作比较慢,限制了Redis高并发,不建议配置。

  2. no:每次写入缓存区后不进行同步,同步到AOF文件的操作由操作系统负责,每次同步AOF文件的周期不可控,而且增大了每次同步的硬盘的数据量。

  3. eversec:每次写入缓存区后,由专门的线程每秒钟同步一次,做到了兼顾性能和数据安全。是建议的同步策略,也是默认的策略。

优点
  • 持久化的速度快,因为每次都只是追加,rdb每次都全量持久化。

  • 数据相对更可靠,丢失少,因可以配置每秒持久化、每个命令执行完就持久化

缺点
  • 灾难性恢复的时候过慢,因为aof每次都只追加原命令,导致aof文件过大,但是后面会rewrite,但是相对于rdb也是慢的。

  • 会对主进程对外提供请求的效率造成影响,接收请求、处理请求、写aof文件这三步是串行原子执行的。而非异步多线程执行的。Redis单线程!

相关链接: 一篇文章彻底理解Redis持久化:RDB和AOF

Redis过期键回收策略

Redis 过期策略有两种
  1. 定期删除

  2. 惰性删除

定期删除

Redis每隔100ms就会随机抽取一些设置了过期时间的key来进行检查和删除。
需要注意的是,这里是随机抽取,而不是全量遍历,全量遍历会大幅影响Redis性能。
这样造成的后果是部分已过期的key并不会被实时删除。

惰性删除

为了弥补定期删除的缺陷,就需要引入惰性删除机制。
当获取某个key的时候,Redis会检查是否设置了过期时间,key是否已过期,如果已过期则进行删除处理。
相关链接: Redis的过期策略以及内存淘汰机制

Redis内存淘汰策略

当Redis的内存被占满后,如果继续写入数据就会触发淘汰策略。

淘汰策略

  • noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键

  • allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键

  • volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键

  • allkeys-random:加入键的时候如果过限,从所有key随机删除

  • volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐

  • volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键

  • volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键

  • allkeys-lfu:从所有键中驱逐使用频率最少的键

比较常用的是allkeys-lru策略。

LRU算法

LRU 即最近最久未使用。
LRU算法需要一个双向链表来记录数据的最近被访问顺序,但是出于节省内存的考虑,RedisLRU算法并非完整的实现。Redis并不会选择最久未被访问的键进行回收,相反它会尝试运行一个近似LRU的算法,通过对少量键进行取样,然后回收其中的最久未被访问的键。通过调整每次回收时的采样数量maxmemory-samples,可以实现调整算法的精度
相关链接: Redis的过期策略以及内存淘汰机制


----- End -----



更多好文
请扫描下面二维码
欢迎关注~