PHP面试宝典之Redis下篇

redis主从同步?

全量同步:

什么时候进行全量同步?

1:从节点第一次连接主节点时

2:从节点断开时间太久,日志中的offset被覆盖时

全量同步的过程?

1:从节点请求增量同步

2:主节点检查replid不一致,拒绝增量同步,开始全量同步

3:主节点将完整内存数据生成rdb文件,发送给从节点

4:从节点清空本地数据,加载rdb文件

5:主节点将rdb期间接收到的命令记录在日志中,并持续将命令发送给从节点

6:从节点接收到命令,与主节点保持同步

增量同步?

什么时候使用增量同步?

1:从节点提交自己的offset到主节点,主节点获取日志中offset之后的命令发送给从节点

增量同步步骤?

1:从节点请求增量同步

2:主节点检查replid是否一致

3:一致,主节点从日志中获取offset后的数据

4:主节点发送offset后的命令

5:从节点接收后执行命令

6:完成同步

什么时候进行数据同步的?

在从服务节点初始化完成,也就是全量同步完成后,每一次主节点的操作命令,都会立刻同步到从节点上

redis主从同步结构模型?

1:主从复制,一主多从
2:级联复制,一个主节点,一个从节点可以做其他从节点的主节点

redis挂掉之后该如何处理?容灾策略?

哨兵模式:主从切换技术,常规的主从需要人工干预,费时费力;

哨兵是一个独立的进程,通过发送命令,等待redis响应,从而监控redis的运行状态

redis集群模式?

1:主从复制(一主一或多从)读写分离,主动同步,无容错,恢复功能

2:哨兵(基于主从,多了哨兵模式)

3:cluster(多主多从,推荐3主3从)数据分区

哨兵集群和cluster集群的区别 是什么?

哨兵模式: 着眼于高可用,在 主节点 宕机时会自动将 从节点 提升为主节点,继续提供服务。

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

哨兵的作用?

1:通过发送命令,让redis返回运行状态(检查是否挂了)

2:当哨兵监测到redis主机宕机,会自动将从节点替换主节点,然后通过发布订阅模式,通知其他从节点,修改配置文件,切换主机

当哨兵进程监控出错该怎么办?

一个哨兵进程监控出错,可以使用别的哨兵对其进行监控,各个哨兵之间相互监控,也叫多哨兵模式

主观下线:

主服务器宕机,哨兵1先监测到结果,但是系统并不会马上进行故障转移,仅仅是哨兵1主观认为主服务器不可用,这种现象叫主观下线

客观下线:

当其他哨兵也监测到主服务不可用,并且达到一定数量时,哨兵之间会进行投票,选举出一个头领,然后由这个头领,选择由哪个从节点代替主节点,选择成功,就会发布订阅模式,通知其他哨兵,修改从属关系

哨兵头领如何选择替代者?

1:健康性:从节点响应时间

2:完整性:数据备份的完整性

3:稳定性:心跳检测

4:以上都一样,节点启动分配的id,最小的那个

redis宕机怎么办?

1:使用数据持久化方式保证数据不丢失

2:redis集群(哨兵或cluster),正常情况主机工作,备机备份不工作;备机每隔几秒向主机发送一个ping,主机若正常就会返回一个peng,如果不返回,备机就会连续发送三次ping,如果一直没有返回,说明主机宕机,备机就会顶上,这叫心跳监测

队列满了,大量请求挤压时该如何处理?

1:先确保消费速度没问题

2:在线扩容,建立临时队列,写一个临时分发程序,以轮询方式写入临时队列

3:等大量数据请求完成后,恢复正常队列

队列执行失败如何处理?

以laravel为例;laravel消息队列,支持执行失败的任务,进行重试,失败任务会被存储在failed_jobs数据表中,可以指定最大尝试次数,如果负载过高,可以延迟失败任务的重试

Redis 做异步队列怎么实现?

一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。也可以使用blpop命令,他会在没有消息的时候,会阻塞住直到消息到来。

Redis队列能不能生产一次,消费多次?

使用 pub/sub 主题订阅者模式,可以实现1:N 的消息队列。

pub/sub 有什么缺点?

在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 RabbitMQ等。

redis 如何实现延时队列?

原理:
使用 zset有序集合,拿时间戳作为score权重分数,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。

实现:
1:定义延迟队列类;
2:构造方法:创建redis对象
3:插入队列方法:zadd方法将任务写入队列中
4:队列处理:轮询队列,使用zrangebyscore获取满足到期时间的元素,判断是否为空,为空,终止循环;不为空,则使用zrem方法将元素从集合中删除,并进行逻辑处理

怎么理解 Redis 事务?

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

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

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

multi、exec、discard、watch

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

答:expire 和 persist 命令。

秒杀,库存超卖?少卖?

原理:使用redis链表,pop操作是原子的,高并发时,是按照顺序执行的
1:将商品库存数据写入到redis 队列

2:秒杀,判断用户是否存在,存在就终止,不存在继续抢购

3:出库,使用lpop移除库存,若库存为0则终止,若非0则继续

4:记录成功用户,将抢购成功用户存入新的消费队列

5:消费队列持久化抢购数据,将抢购用户记录到数据库中完成最终消费

如果消息队列失败,可能会导致少卖,这时需要配置重试策略,当失败后,会立刻尝试第二次、第三次消费,如果仍然失败,就将消息持久化到磁盘,交给补偿服务轮询处理

laravel的消息队列?

1:queue:table,生成队列任务表

2:配置env文件redis队列

3:jobs目录下创建任务类,构造方法中获取参数,handle方法处理业务逻辑

4:分发任务,控制器中使用任务类静态调用dispatch进行分发,当业务触发时,就会将消息分发给队列异步执行

缓存问题?

缓存穿透:数据库和缓存都没有数据(都没数据+并发访问)
缓存击穿:数据库有,缓存没有(单个key过期+并发访问)
缓存雪崩:数据库有,缓存没有(大量key过期+并发访问)

解决:
缓存穿透:
1:缓存空对象,设置较短过期时间(浪费内存,数据不一致)

2:步隆过滤器,判断key是否存在,存在就返回,不存在返回空

缓存击穿:
1:不给key设置过期时间,或者设置定时器,定期更新缓存

2:给key加锁,当第一次请求时,去数据库获取数据并更新缓存,然后释放锁,当其他请求时,由于缓存中已经有值,就不再请求数据库

缓存雪崩:
1:如果key大量过期,将key的过期时间打散

2:如果redis故障,使用哨兵模式

如何保证缓存一致性:

内存淘汰、超时剔除、主动更新

内存淘汰:内存不足时,自动淘汰部分数据,下次查询时更新

超时剔除:设置缓存过期时间,到期自动删除,下次查询时更新

主动更新:编写业务逻辑,更新数据库时更新缓存

主动更新保证一致性的方案?

1:先更数据库,再更缓存(数据库脏读数据,会被跟新到缓存)

2:先更缓存,再更数据库(缓存成功,数据库失败,数据不一致)

3:先删缓存,再更数据库

4:先更数据库,再删缓存(更新成功,删除失败)推荐方案

删除缓存失败解决方案?

1:使用消息队列,数据库更新成功后,向队列发送消息,缓存模块监听到新消息,会执行删除,利用消息队列手动提交机制,可保证删除顺利完成

2:canal监听;监听mysql变化,发生变化后,立即通知缓存服务,缓存收到通知,删除缓存

redis锁有哪些?

1:setnx命令;可能在获取锁之后,程序挂了,没来得及释放锁,导致死锁

2:setnx+expire命令;可能在这之间程序挂了,锁未释放,导致死锁

3:set命令在redis2.8中setnx和expire可以同时设置;

4:new Redlock对象,lock加锁,unlock删锁

redis是如何保证原子性的?

因为redis是单进程单线程的,对redis来说,执行get、set以及eval等api,都是一个一个的任务,这些任务都会由redis的线程去负责执行,任务要么成功,要么失败,这就是redis原子性的原因,redis是io多路复用模型,即一个线程来处理多个tcp连接,好处就是客户端并发请求,也得排队处理,一定程度上解决了多线程模型带来的并发问题;

redis单线程就能解决原子性问题吗?

也不一定,但redis提供了原子操作命令,也即是锁命令:incr(get和set的集合体)、decr、setnx等

什么是分布式锁?

分布式锁:是控制分布式系统,或不同系统之间,共同资源访问时,一种锁的实现;不同系统之间共享某个资源时,往往需要互斥来防止彼此干扰,保证一致性

分布式锁,需要具备哪些条件?

1:互斥性;在任意时刻,只有一个客户端持有锁

2:无死锁;即便持有锁的客户端崩溃,锁仍然可以被获取

3:容错;只要大部分redis节点都活着,客户端就可以获取和释放锁

分布式锁的实现:数据库、memcached、redis

Redis分布式锁,是怎么回事?

先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。

如果在 setnx 之后执行 expire之前进程意外崩溃或者要重启维护了,会怎么样?

我记得 set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和expire 合成一条指令来用的!

你可能感兴趣的:(面试宝典,redis,面试,php)