点击关注公众号,更多资讯及时推送↓
在Java开发工程师的面试中,关于Redis的问题可能会涵盖基础概念、数据结构、操作命令、性能优化、持久化策略、高可用与分布式、以及与Java应用的集成等多个方面。而本篇文章将会把大概率被问到的关于Redis的问题,梳理地的清清楚楚,不管你求职者在准备面试,还是面试官在准备招聘,这篇文章都非常值得一读,感觉还不错,别忘了收藏起来,以防迷路找不到。
简述redis特点及其应用场景
Redis (Remote Dictionary Server) ,远程字典服务,Redis是一个开源的、遵循BSD协议的、基于内存的而且目前比较流行的键值数据库(key-value database),是一个非关系型数据库。redis 提供将内存通过网络远程共享的一种服务,提供类似功能的还有memcached,但相比memcached,redis还提供了易扩展、高性能、具备数据持久性等功能。Redis 在高并发、低延迟环境要求比较高的环境使用量非常广泛。
Redis 特性
-
速度快:10W QPS,基于内存,C语言实现
-
单线程
-
持久化
-
支持多种数据结构
-
支持多种编程语言
-
功能丰富:支持Lua脚本,发布订阅,事务,pipeline等功能
-
简单:代码短小精悍(单机核心代码只有23000行左右),单线程开发容易,不依赖外部库,使用简单
-
主从复制
-
支持高可用和分布式
典型应用场景
-
Session 共享:常见于web集群中的Tomcat或者PHP中多web服务器session共享
-
缓存:数据查询、电商网站商品信息、新闻内容
-
计数器:访问排行榜、商品浏览数等和次数相关的数值统计场景
-
微博/微信社交场合:共同好友,粉丝数,关注,点赞,评论等
-
消息队列:ELK的日志缓存、部分业务的订阅发布系统
-
地理位置:基于GEO(地理信息定位),实现摇一摇,附近的人,外卖等功能
以最新为版本为准,解释Redis的线程模型,并谈谈其优缺点。
redis单线程模型
首先需要注意的是,redis整体而言并不是单线程。
-
redis支持多种数据结构(如string、list、hash、set、zset等),每个对象类型都是由多个数据结构实现的。因此多线程环境下,加锁复杂、锁粒度不好控制。
-
频繁的上下文切换,会带来更多的时间和性能上的开销,从而抵消多线程的优势。redis作为数据库,并不是每时每刻都有密集访问。在多线程环境下,访问少时需要将一些线程休眠,访问多时又需要唤醒,这就存在频繁的线程调度问题。
谈谈Redis支持的数据类型有多少种,并简述每种类型的应用场景?
五种数据类型
String,List, Set,SortedSet,Hash
1)List类型可以存储多个String
2)Set类型可以存储不同的String
3)SortedSet可以存储String的排序
4)Hash可以存储多个key-value对
2.1 String
Redis的String是动态字符串。它是Redis最基本的数据类型。一个key可以存储一个字符串。
2.2 List
Redis的List是简单的字符串列表。
按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
2.3 Set
Set是String类型的无序集合。集合成员是唯一的。
2.4 SortedSet
SortedSet也是String类型的集合。
不同的是每个元素都会关联,redis正是通过分数来为集合中的成员进行从小到大的排序。
2.5 Hash
string类型的field和value的映射表。
hash特别适合用于存储对象。
. 应用场景
-
分布式锁:是指在多台服务器之间共享一把锁。当一个服务器上的应用程序获得锁之后,其他服务器上的应用程序将无法获得该锁。这样就能保证数据的一致性。Redis实现分布式锁非常简单,只需要几行代码就可以实现。分布式锁可以帮助我们在集群环境中实现对共享资源的互斥访问,从而避免数据冲突和脏数据的产生。
-
一致性哈希算法:Redis集群采用一致性哈希,算法将数据分布到不同的节点上,这样就能有效地利用集群中各个节点的计算和存储能力。
-
分布式缓存:Redis作为一个强大的数据库,具有高性能、可扩展性和高可用性,因此被广泛用于分布式缓存。
-
日志处理:Redis的日志处理功能可以帮助我们更好地监控集群的状态,从而及时发现和解决问题。需求背景日志处理,是指将日志数据存储到Redis中,然后通过编写python脚本来实现对日志数据的分析处理。
Redis的其他应用场景
消息队列、任务队列、分布式计数器、分布式session等。
Redis常用到的命令操作有哪些?
1. 数据结构操作
字符串(String)
-
SET key value:设置键和值,如果键不存在则创建。
-
GET key:获取键的值。
-
INCR key:键的值加1,并返回新值。
-
DECR key:键的值减1,并返回新值。
-
APPEND key value:将值追加到键的原始值后面。
-
STRLEN key:返回键值的长度。
哈希(Hash)
-
HSET key field value:设置哈希表中给定字段的值。
-
HGET key field:获取哈希表中给定字段的值。
-
HGETALL key:获取哈希表中所有字段和值的列表。
-
HDEL key field:删除哈希表中给定的字段。
列表(List)
-
LPUSH key value:将值插入列表的头部。
-
RPUSH key value:将值插入列表的尾部。
-
LPOP key:弹出并返回列表的头部元素。
-
RPOP key:弹出并返回列表的尾部元素。
-
LRANGE key start stop:获取列表中指定范围内的元素。
集合(Set)
-
SADD key member:向集合中添加成员。
-
SREM key member:从集合中删除成员。
-
SISMEMBER key member:检查成员是否存在于集合中。
-
SMEMBERS key:获取集合中的所有成员。
有序集合(Sorted Set)
-
ZADD key score member:向有序集合中添加成员和分值。
-
ZREM key member:从有序集合中删除成员。
-
ZSCORE key member:获取有序集合中指定成员的分值。
-
ZRANGE key start stop [WITHSCORES]:获取有序集合中指定范围内的成员。
2. 键值对管理
-
DEL key:删除指定键及其值。
-
EXISTS key:检查键是否存在,存在返回1,否则返回0。
-
TTL key:获取键的过期时间,如果未设置过期时间则返回-1。
-
PERSIST key:移除键的过期时间,将键持久化保存(-1代表持久化保存)。
-
TYPE key:获取键的数据类型,例如string、hash、list、set、zset。
3. 服务器管理
-
INFO:获取redis服务器的一些基本信息,包括16个子命令。
-
FLUSHDB:清空当前数据库的所有键及其值。
-
FLUSHALL:清空所有数据库的所有键及其值。
-
SAVE:将数据集导出到磁盘上,阻塞其他客户端操作。
-
BGSAVE:在后台异步保存数据集到磁盘上,不会阻塞其他客户端操作。
4. 其他
-
KEYS pattern:查找匹配的键,pattern可以是正则表达式。
-
RENAME key newkey:将键重命名为新的键名newkey。
-
EXPIRE key seconds:设置键的过期时间,单位为秒。
-
SETEX key seconds value:设置键的值和过期时间,单位为秒。
-
MSET key value [key2 value2 …]:同时设置多个键和值。
-
MGET key [key2 …]:同时获取多个键的值。
能解释Redis的RDB和AOF持久化机制,以及它们之间的区别吗
RDB:存储所有数据
AOF:存储所有命令行
RDB和AOF的介绍
RDB和AOF都会创建(fork)出一个子进程来实现功能。
1.RDB(Redis DataBase)
可以根据设定的条件来备份所有的数据,例如满足下面条件时进行备份:
save 900 1 # 900秒(15分钟)内有1个写入
save 300 10 # 300秒(5分钟)内有10个写入
save 60 10000 # 60秒(1分钟)内有10000个写入
但这样可能会丢失几分钟的数据,所以引出了AOF。
AOF(Append Only File)
AOF文件:
记录所有执行的写入命令到AOF文件中,但肯定不能每执行一条写入命令就记录到文件中,那会严重拖垮性能,于是会准备一个缓冲区,区别于这个缓冲区,操作系统也有一个缓冲区,所以我们需要通过刷新来保证正常写入,可以根据设定的参数来写入并刷新AOF文件,参数如下:
always: 每个事件周期都同步刷新一次
everysec: 每一秒都同步刷新一次
no: 我只管写,让操作系统自己决定什么时候真正写入
AOF重写:
在AOF文件过大时会对这些命令进行AOF重写,去掉无用的命令,以达到简化命令缩小文件体积的效果。例如:
RPUSH name_list ‘高等数学’
RPUSH name_list ‘离散数学’
RPUSH name_list ‘大学物理’
可以合并成一条搞定:
RPUSH name_list ‘高等数学’ ‘离散数学’ ‘大学物理’
AOF重写缓冲区:
如果子进程在压缩重写过程中,AOF文件有了新的写入,那么新的写入会进入缓冲区,重写结束后,缓冲区中的命令会被写入到新的AOF文件中
RDB和AOF的区别
1.RDB(Redis DataBase)
原理:
RDB持久化是通过创建数据集的快照(snapshot)在特定时间点保存数据的。
快照生成是在Redis在后台子进程中完成的,父进程会继续处理客户端请求。
默认情况下,Redis会在特定的间隔内,根据写入数据的频次(如1分钟内至少达到N个key修改),自动生成RDB文件。
优点:
效率高:RDB快照生成对性能影响小,尤其是在恢复大数据集时,RDB方式相比AOF的重放日志速度要快很多。
数据压缩:RDB文件是压缩的二进制格式,所以相比原始的数据集会占用更少的磁盘空间。
适合备份:可以非常方便地将数据集的快照保持在安全的硬盘上,适合灾难恢复。
资源占用较少:相比AOF,RDB在其它时间点占用的系统资源更少,尤其是在数据改动不频繁时。
缺点:
数据丢失:因为是时间点快照,所以在RDB最后一次保存后和故障发生前的数据更新将会丢失,丢失的数据可能会更多。
可能占用大量内存:在保存RDB文件时,如果数据集很大,Redis的复制操作可能会占用与现有数据集几乎同样大小的内存。
频繁写盘:在高频更新数据的场景下,RDB持久化可能会因为频繁的保存数据到硬盘造成磁盘IO压力。
2.AOF(Append Only File)
原理:
AOF持久化是通过保存Redis服务器所处理的每一个写命令来记录数据变化的。
这些命令将被追加到AOF文件的末尾,Redis重启时通过重放这些命令来恢复原始的数据集。
Redis允许你选择不同的fsync策略,例如:每个写命令(fsync=always)、每秒(fsync=everysec)或者不同步(fsync=no)。
优点:
数据完整性好:可以做到近乎实时的数据备份,数据丢失几率小。
可读性强:AOF文件由一系列的文本命令组成,方便理解和分析。
更健壮:AOF中使用了一种被称为append的操作,在使得数据更加安全方面比RDB要高。
缺点:
占用空间大:由于记录了所有的写操作,AOF文件的大小通常会大于RDB文件。
恢复慢:相比于RDB的二进制方式,AOF在恢复大数据集时需要更长的时间,因为需要重新执行所有的写命令。
性能开销:尽管可以配置多种fsync策略减少对性能的影响,但持续的IO操作,特别是fsync设置为always的情况下,会对性能产生影响
能谈谈如何优化Redis的内存使用?
1. 数据结构选择和优化
-
选择合适的数据结构:Redis提供了多种数据结构,如字符串(String)、列表(List)、哈希表(Hash)、集合(Set)、有序集合(Sorted Set)等。每种数据结构都有其特定的使用场景和内存消耗特点。选择最合适的数据结构可以显著减少内存使用。
-
压缩对象:Redis 6及以上版本引入了对字符串的内置LZF压缩支持,可以通过配置参数
activerehashing
来启用,以减少存储空间的占用。
2. 配置文件优化
-
设置最大内存限制:在Redis的配置文件中,可以通过
maxmemory
参数来设置Redis实例能使用的最大内存量。当达到这个限制时,Redis会根据配置的淘汰策略来释放内存。 -
配置内存淘汰策略:通过
maxmemory-policy
参数配置内存淘汰策略,如volatile-lru
(淘汰最久未使用的带过期时间的键)、allkeys-lru
(淘汰最久未使用的键)等,根据业务需求和数据特性选择合适的策略。
3. 过期策略和持久化配置
-
设置合理的过期时间:对于可以自动过期的数据,设置合理的过期时间(TTL)以减少内存占用。
-
选择合适的持久化方式:Redis提供了RDB(定期快照)和AOF(追加日志文件)两种持久化方式。根据数据重要性和恢复需求来配置,或考虑关闭不必要的持久化以减少内存消耗。
4. 连接和客户端优化
-
使用连接池:使用连接池来管理与Redis的连接,减少连接的建立和销毁开销。
-
优化客户端操作:避免在客户端进行大量的数据处理和转换,尽量在Redis层面完成,以减少数据传输量。
5. 监控和调优
-
实时监控内存使用情况:使用Redis自带的INFO命令或第三方监控工具,实时监控内存使用情况、命中率、吞吐量等关键指标。
-
性能测试和调优:通过负载测试工具模拟真实环境的压力,找出性能瓶颈并进行调整。
6. 硬件和部署优化
-
增加内存资源:如果内存资源成为瓶颈,考虑增加Redis实例的内存或CPU资源。
-
集群部署:考虑使用Redis集群部署以增加横向扩展能力和高可用性。
7. 其他优化策略
-
内存碎片整理:定期执行MEMORY DOCTOR和MEMORY PURGE命令来清理碎片并优化内存使用。
-
避免大量小对象:尽量减少存储大量小对象,因为小对象可能会引起内存碎片问题。
-
使用Pipeline和批量操作:通过Pipeline可以在一次通信中发送多个命令,减少每个操作的网络开销和处理开销。
8. 安全性和权限管理
-
设置密码保护:通过设置密码保护Redis,防止未授权访问。
-
访问控制:使用Redis的访问控制功能,限制特定IP或网络段的访问。
能谈谈Redis Sentinel的作用是什么?如何配置和使用?
Redis Sentinel的作用
Redis Sentinel 是一个用于监控、通知和自动故障转移的 Redis 扩展,它的主要作用包括:
-
监控:Sentinel 会不断地检查主服务器和从服务器(Slave)的运行状态,确保它们正常工作。
-
通知:当某个 Redis 服务器出现问题时,Sentinel 会通知系统管理员或其他程序。
-
自动故障转移:当主服务器不可用时,Sentinel 会自动将其中一个从服务器提升为新的主服务器,并通知其他从服务器进行复制。
-
配置提供:客户端可以通过 Sentinel 获取当前主服务器的地址,确保总是连接到正确的主服务器。
这些功能共同确保 Redis 集群能够在主服务器故障时继续提供服务,从而提高 Redis 部署的可靠性和可用性。
Redis Sentinel的配置和使用
配置
Redis Sentinel 的配置主要通过编辑 Sentinel 配置文件(通常是 sentinel.conf)来完成。以下是一些关键的配置项:
-
监听端口:
-
port 26379
:Sentinel 默认监听端口为 26379,可以修改。 -
监控主服务器:
-
sentinel monitor <master-name> <ip> <redis-port> <quorum>
:告诉 Sentinel 去监听地址为<ip>:<redis-port>
的一个主服务器,这里的<master-name>
可以自定义,<quorum>
是一个数字,指明当有多少个 Sentinel 认为一个主服务器失效时,主服务器才算真正失效。 -
认证密码(如果主服务器设置了密码):
-
sentinel auth-pass <master-name> <password>
:设置连接主服务器和从服务器时的密码。 -
主观下线判断时间:
-
sentinel down-after-milliseconds <master-name> <milliseconds>
:指定需要多少失效时间,一个主服务器才会被 Sentinel 主观地认为是不可用的。 -
并行同步从服务器数量:
-
sentinel parallel-syncs <master-name> <numreplicas>
:在故障转移期间,可以有多少个从服务器同时对新的主服务器进行同步。
使用
-
启动 Sentinel:
-
使用命令
redis-sentinel /path/to/your/sentinel.conf
或redis-server /path/to/your/sentinel.conf --sentinel
启动 Sentinel。 -
检查 Sentinel 状态:
-
通过 Sentinel 提供的命令行工具或 INFO 命令,可以查询 Sentinel 的运行状态和监控的 Redis 服务器状态。
-
自动故障转移:
-
当 Sentinel 检测到主服务器不可用时,会自动执行故障转移操作,包括选择一个从服务器提升为主服务器,并通知其他从服务器进行复制。
-
客户端连接:
-
客户端可以使用 Sentinel 提供的服务发现功能,通过 Sentinel 获取当前主服务器的地址,并进行连接。
能谈谈Redis如何保证数据安全的吗?
Redis的数据安全性主要通过以下几个方面的措施来保障:
-
访问控制:Redis允许用户通过密码认证和IP白名单等方式限制访问权限,防止未授权访问。这种机制确保只有经过授权的用户或设备才能访问Redis数据库,从而减少了数据被非法访问和篡改的风险1。
-
数据持久化:Redis支持RDB快照和AOF日志两种持久化方式,可以将数据定期保存到磁盘上,以防止数据丢失。这两种持久化机制能够在Redis服务器出现问题时,通过恢复持久化文件来保证数据的完整性1。
-
主从复制:Redis支持主从复制机制,可以创建主从节点,主节点负责写入操作,从节点负责读取操作,从而保证数据的高可用性和备份。这种机制能够在主节点出现问题时,快速切换到从节点,确保数据的可用性1。
-
数据加密:通过SSL/TLS等方式对Redis的通信进行加密,保护数据的传输过程中不被窃取或篡改。这种加密措施确保了即使在数据传输过程中,数据内容也能得到保护,增加了数据的安全性1。
-
安全更新:及时更新Redis的版本,以修复可能存在的安全漏洞,确保系统的安全性。定期的安全更新能够修复已知的安全漏洞,提高系统的整体安全性
能谈谈Redis在缓存穿透、缓存雪崩和缓存击穿问题上的解决方案吗?
Redis在缓存穿透、缓存雪崩和缓存击穿问题上的解决方案主要包括:
-
缓存穿透:
-
缓存空值或默认值:当查询的数据不存在于缓存或数据库中时,可以在缓存中设置一个空值或默认值,这样后续的请求可以直接从缓存中读取到空值或默认值,避免查询数据库1。
-
使用布隆过滤器:布隆过滤器是一种概率型数据结构,能够判断某个元素一定不存在或者是可能存在。在写入数据库数据时,使用布隆过滤器做标记。用户请求到来时,如果业务线程确认缓存失效,可以通过查询布隆过滤器快速判断数据是否存在,如果不存在,则不通过查询数据库来判断数据是否存在1。
-
缓存击穿:
-
互斥锁方案:如果某个热点数据更新了,可以通过互斥锁的方式将其更新,避免大量并发请求同时访问失效的热点数据1。
-
不设置TTL或设置随机过期时间:对于热点数据,可以不设置TTL(Time To Live,即过期时间),或者设置逻辑上的过期标识,需要过期的时候直接删除标识。也可以设置热点数据的过期时间为随机时间,避免在同一时间大量数据同时失效2。
-
缓存雪崩:
-
多级缓存架构:采用多级缓存架构,减少缓存层的压力。例如,先查询一级缓存,再查询二级缓存,最后才是数据库2。
-
设置较长的缓存过期时间:在设置缓存的过期时间时,可以将其设置得相对较长,避免在短时间内多次发生缓存失效3。
-
添加限流、熔断措施:在缓存层和数据库层之间添加限流、熔断等措施,避免因突发流量导致系统崩溃2
原文始发于微信公众号(Java技术前沿):Java 开发面试题精选:Redis 一篇全搞定
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/299556.html