前 言
作者简介:半旧518,长跑型选手,立志坚持写10年博客,专注于java后端
☕专栏简介:纯手打总结面试题,自用备用
文章简介:Redis最基础、重要的11道面试题
哈希(hash,键值对形式)
链表(list,元素有序可以重复)
集合(set,元素无序且不可重复,可以进行交、并、差运算)
有序集合(zset,元素有序的集合)
字符串(String,可以存储字符串、数字、二进制数等)
用它进行排序、排名、点赞数统计等
一般我们获取数据,会先访问缓存,如果缓存中存在则直接返回。如果缓存不存在则从数据库中获取,如果数据库中存在,会将获取的数据放入缓存、返回。如果数据库中也获取不到数据,就会直接返回失败。
在一些场景,如用户伪造不存在的数据进行查询,就需要每次都访问数据库。这时,缓存就不起作用了,因此我们称这种情况为缓存穿透。如果穿透了缓存,服务器请求数非常大,数据库可能因为扛不住压力挂掉。可以使用布隆过滤器(其底层是使用哈希算法的map缓存已经存在的数据)解决,但是可能因为哈希冲突导致误判,也可能存在数据更新问题。另外一种解决思路是缓存控制,即使某个用户id(key)的数据在数据库中找不到,也可以把id缓存到redis缓存中,这样该用户获取数据时就不会有缓存穿透问题。
在诸如秒杀活动的场景,同一时刻大量请求访问服务器,而此时缓存失效了,就会导致缓存击穿。缓存击穿的原因是同一时刻的访问量过大,因此可以通过加锁方式解决。也可以从缓存失效的角度出发,可以进行自动续期,防止缓存失效。
缓存雪崩是缓存击穿的plus版本,多个热门key都失效了。问题很严重,我们称为缓存雪崩。可以通过设置过期时间加随机数避免缓存在同一时间失效。另一个角度是从架构角度设计高可用的架构,比如如果使用的是redis做为缓存,可以使用哨兵模式(主机挂掉自动选举新主机)或者集群模式。也可以设置服务降级方案(如直接在配置中读默认数据)进行兜底。
区别:缓存穿透没数据、缓存击穿在缓存中没有数据,缓存雪崩是plus版本的缓存击穿
将master上的数据及时有效的复制到slave上。一个master对应多个slave,但是一个slave只对应一个master。
主从复制的步骤是:建立连接、数据同步、命令传播(解决主机状态在同步过程中发生改变,主从状态不一致问题)。
在命令传播阶段,二者采用心跳机制保持连接确认。
主从复制可能出现的问题:
频繁的全量复制:因为主从复制过程中主机重启导致,可以记住主机runid解决。
从机数据不一致:可能是因为网络延迟导致,可以将主从部署在同一机房环境。
主从复制的好处有:(负载性能、数据安全、服务安全三个方面)
读写分离(主结点写,从结点读),提高负载能力。
数据冗余备份。
故障恢复(主机当掉有从机顶)
负载均衡
高可用的基石
Redis是纯内存的数据库,使用非阻塞式IO,全程使用hash数据结构,读取数据速度很快。
RDB:使用单独的线程进行数据IO,主线程不进行任何的IO,这种方式可以保证性能,但是可能会有数据丢失的情况
AOF:将数据持久化到特定的日志文件中,定时为1s持久化一次。其效率比RDB低。但是其安全性较高。
建议两者同时使用。如果可以容忍数分钟的数据丢失,可以使用RDB方式。
程序清晰简单,不用考虑线程安全问题,但是可能会浪费多核cpu资源,可以同时开启多个redis服务器解决。
哨兵(集群:防止把网络的问题误判为主机的问题)用于监视主机的状态变化(发ping消息),当主机当掉,可以进行主从服务器的切换(由集群的leader执行),并通过「发布者/订阅者机制」通知给客户端,保证系统的高可用。
在特定场景下,如写并发,海量数据的存储压力,需要使用redis集群。Redis的集群采用分布式存储,每台服务器上存储不同的数据内容。其数据分布的策略是使用哈希槽来分配数据,默认一个cluster分配16384个槽,数据存储位置就是哈希值%16384。
在海量数据的情形下,可能需要扩充服务器。常规的哈希算法需要重新计算所以服务实例的哈希值。一致性hash的出现解决了这种问题。将服务器结点构成一个环,每个结点分配一个token。在查找时先根据key计算哈希值,然后顺时针找到第一个大于等于该哈希值的token结点。这样删除、插入新结点只影响相邻的两个结点,缺点是插入、删除结点可能导致数据命中问题。
所谓大key问题,就是key对应的value值较大。如某个热门课程的收藏用户可能是一个很庞大的list。因为redis的主线程是单线程机制,因此大key问题会导致线程阻塞,并发量下降,客户端超时等。产生大key的原因可能有:一直往value里塞数据,但没有删除机制;没有做数据分片,将大key转换为小key。
可以使用big-keys命令或可视化工具找到大key。
解决大key问题可以通过:对于可删除的情况,删除非热点大key;压缩(string)和拆分key(list和set)。