Java 开发面试题精选:Redis 一篇全搞定

Java 开发面试题精选:Redis 一篇全搞定

点击关注公众号,更多资讯及时推送↓

在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整体而言并不是单线程。

Java 开发面试题精选:Redis 一篇全搞定


  1. redis支持多种数据结构(如string、list、hash、set、zset等),每个对象类型都是由多个数据结构实现的。因此多线程环境下,加锁复杂、锁粒度不好控制。

  2. 频繁的上下文切换,会带来更多的时间和性能上的开销,从而抵消多线程的优势。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特别适合用于存储对象

. 应用场景

  1. 分布式锁:是指在多台服务器之间共享一把锁。当一个服务器上的应用程序获得锁之后,其他服务器上的应用程序将无法获得该锁。这样就能保证数据的一致性。Redis实现分布式锁非常简单,只需要几行代码就可以实现。分布式锁可以帮助我们在集群环境中实现对共享资源的互斥访问,从而避免数据冲突和脏数据的产生。

  2. 一致性哈希算法Redis集群采用一致性哈希,算法将数据分布到不同的节点上,这样就能有效地利用集群中各个节点的计算和存储能力。

  3. 分布式缓存:Redis作为一个强大的数据库,具有高性能、可扩展性和高可用性,因此被广泛用于分布式缓存。

  4. 日志处理: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 扩展,它的主要作用包括:

  1. 监控:Sentinel 会不断地检查主服务器和从服务器(Slave)的运行状态,确保它们正常工作。

  2. 通知:当某个 Redis 服务器出现问题时,Sentinel 会通知系统管理员或其他程序。

  3. 自动故障转移:当主服务器不可用时,Sentinel 会自动将其中一个从服务器提升为新的主服务器,并通知其他从服务器进行复制。

  4. 配置提供:客户端可以通过 Sentinel 获取当前主服务器的地址,确保总是连接到正确的主服务器。

这些功能共同确保 Redis 集群能够在主服务器故障时继续提供服务,从而提高 Redis 部署的可靠性和可用性。

Redis Sentinel的配置和使用

配置

Redis Sentinel 的配置主要通过编辑 Sentinel 配置文件(通常是 sentinel.conf)来完成。以下是一些关键的配置项:

  1. 监听端口

    • port 26379:Sentinel 默认监听端口为 26379,可以修改。

  2. 监控主服务器

    • sentinel monitor <master-name> <ip> <redis-port> <quorum>:告诉 Sentinel 去监听地址为 <ip>:<redis-port> 的一个主服务器,这里的 <master-name> 可以自定义,<quorum> 是一个数字,指明当有多少个 Sentinel 认为一个主服务器失效时,主服务器才算真正失效。

  3. 认证密码(如果主服务器设置了密码):

    • sentinel auth-pass <master-name> <password>:设置连接主服务器和从服务器时的密码。

  4. 主观下线判断时间

    • sentinel down-after-milliseconds <master-name> <milliseconds>:指定需要多少失效时间,一个主服务器才会被 Sentinel 主观地认为是不可用的。

  5. 并行同步从服务器数量

    • sentinel parallel-syncs <master-name> <numreplicas>:在故障转移期间,可以有多少个从服务器同时对新的主服务器进行同步。

使用

  1. 启动 Sentinel

    • 使用命令 redis-sentinel /path/to/your/sentinel.conf 或 redis-server /path/to/your/sentinel.conf --sentinel 启动 Sentinel。

  2. 检查 Sentinel 状态

    • 通过 Sentinel 提供的命令行工具或 INFO 命令,可以查询 Sentinel 的运行状态和监控的 Redis 服务器状态。

  3. 自动故障转移

    • 当 Sentinel 检测到主服务器不可用时,会自动执行故障转移操作,包括选择一个从服务器提升为主服务器,并通知其他从服务器进行复制。

  4. 客户端连接

    • 客户端可以使用 Sentinel 提供的服务发现功能,通过 Sentinel 获取当前主服务器的地址,并进行连接。


能谈谈Redis如何保证数据安全的吗?

Redis的数据安全性主要通过以下几个方面的措施来保障:‌

  1. 访问控制:‌Redis允许用户通过密码认证和IP白名单等方式限制访问权限,‌防止未授权访问。‌这种机制确保只有经过授权的用户或设备才能访问Redis数据库,‌从而减少了数据被非法访问和篡改的风险1。‌

  2. 数据持久化:‌Redis支持RDB快照和AOF日志两种持久化方式,‌可以将数据定期保存到磁盘上,‌以防止数据丢失。‌这两种持久化机制能够在Redis服务器出现问题时,‌通过恢复持久化文件来保证数据的完整性1。‌

  3. 主从复制:‌Redis支持主从复制机制,‌可以创建主从节点,‌主节点负责写入操作,‌从节点负责读取操作,‌从而保证数据的高可用性和备份。‌这种机制能够在主节点出现问题时,‌快速切换到从节点,‌确保数据的可用性1。‌

  4. 数据加密:‌通过SSL/TLS等方式对Redis的通信进行加密,‌保护数据的传输过程中不被窃取或篡改。‌这种加密措施确保了即使在数据传输过程中,‌数据内容也能得到保护,‌增加了数据的安全性1。‌

  5. 安全更新:‌及时更新Redis的版本,‌以修复可能存在的安全漏洞,‌确保系统的安全性。‌定期的安全更新能够修复已知的安全漏洞,‌提高系统的整体安全性


能谈谈Redis在缓存穿透、缓存雪崩和缓存击穿问题上的解决方案吗?

Redis在缓存穿透、‌缓存雪崩和缓存击穿问题上的解决方案主要包括:‌

  1. 缓存穿透:‌

    • 缓存空值或默认值:‌当查询的数据不存在于缓存或数据库中时,‌可以在缓存中设置一个空值或默认值,‌这样后续的请求可以直接从缓存中读取到空值或默认值,‌避免查询数据库1。‌

    • 使用布隆过滤器:‌布隆过滤器是一种概率型数据结构,‌能够判断某个元素一定不存在或者是可能存在。‌在写入数据库数据时,‌使用布隆过滤器做标记。‌用户请求到来时,‌如果业务线程确认缓存失效,‌可以通过查询布隆过滤器快速判断数据是否存在,‌如果不存在,‌则不通过查询数据库来判断数据是否存在1。‌

  2. 缓存击穿:‌

    • 互斥锁方案:‌如果某个热点数据更新了,‌可以通过互斥锁的方式将其更新,‌避免大量并发请求同时访问失效的热点数据1。‌

    • 不设置TTL或设置随机过期时间:‌对于热点数据,‌可以不设置TTL(‌Time To Live,‌即过期时间)‌,‌或者设置逻辑上的过期标识,‌需要过期的时候直接删除标识。‌也可以设置热点数据的过期时间为随机时间,‌避免在同一时间大量数据同时失效2。‌

  3. 缓存雪崩:‌

    • 多级缓存架构:‌采用多级缓存架构,‌减少缓存层的压力。‌例如,‌先查询一级缓存,‌再查询二级缓存,‌最后才是数据库2。‌

    • 设置较长的缓存过期时间:‌在设置缓存的过期时间时,‌可以将其设置得相对较长,‌避免在短时间内多次发生缓存失效3。‌

    • 添加限流、‌熔断措施:‌在缓存层和数据库层之间添加限流、‌熔断等措施,‌避免因突发流量导致系统崩溃2


原文始发于微信公众号(Java技术前沿):Java 开发面试题精选:Redis 一篇全搞定

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/299556.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!