Java面试——Redis系列总结

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Java面试——Redis系列总结

文章目录:


1.什么是Redis

2.为什么要用 Redis / 为什么要用缓存?

3.Redis为什么这么快?

4.Redis都有哪些数据类型?

5.什么是Redis持久化?Redis 的持久化有哪些实现方式?

6.什么是Redis事务?

7.谈谈你对Redis集群方案——哨兵模式的理解

8.Redis主从复制的原理是什么?

9.Redis如何实现分布式锁?

10.Redis中的缓存穿透、缓存击穿、缓存雪崩是什么?

1.什么是Redis?


Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。


Redis可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、散列表、集合、有序集合。


与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务、持久化、LUA脚本、LRU驱动事件、多种集群方案。


2.为什么要用Redis / 为什么要用缓存?


主要从高性能高并发这两点来看待这个问题。


高性能

假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。再将该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!


高并发

直接操作缓存能够承受的请求是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。


3.Redis为什么这么快?


1.    完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于 HashMapHashMap 的优势就是查找和操作的时间复杂度都是O(1)

2.    数据结构简单,对数据操作也简单,Redis 中的数据结构是专门进行设计的;

3.    采用单线程,避免了不必要的上下文切换和竞争,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

4.    使用 I/O 多路复用模型,非阻塞 IO


4.Redis都有哪些数据类型?


Redis主要有5种数据类型,包括StringListHashSetZSet

数据类型

可以存储的值

操作

应用场景

String

字符串、整数或者浮点数

对整个字符串或者字符串的其中一部分执行操作对整数和浮点数执行自增或者自减操作

做简单的键值对缓存

List

列表

从两端压入或者弹出元素对单个或者多个元素进行修剪,只保留一个范围内的元素

存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的数据

Hash

包含键值对的无序散列表

添加、获取、移除单个键值对获取所有键值对检查某个键是否存在

结构化的数据,比如一个对象

Set

无序集合

添加、获取、移除单个元素检查一个元素是否存在于集合中计算交集、并集、差集从集合里面随机获取元素

交集、并集、差集的操作,比如交集,可以把两个人的粉丝列表整一个交集

ZSet

有序集合

添加、获取、删除元素根据分值范围或者成员来获取元素计算一个键的排名

去重但可以排序,如获取排名前几名的用户

·       String应用场景:

               商品编号、订单号采用incr命令生成;
               
是否喜欢的文章(点赞数incr

·       Hash应用场景:

               购物车(新增商品hset、增加商品数量hincrby
                             
商品总数hlen、全部选中hgetall

·       List应用场景:

               微信订阅公众号(订阅lpush、查看订阅号文章lrange

·       Set应用场景:

               抽奖活动(参与sadd、显示参与人数scard
                                 
随机抽取srandmemberspop
               
文章点赞(新增点赞sadd、取消点赞srem
                                 
展现所有点赞用户smember、点赞数统计scard
               
社交平台(两个人的共同关注sinter
                                  QQ
可能认识的人求差集sdiff

·       Zset应用场景:

               根据商品销售对商品进行排序(zaddzincrbyzrange
               
抖音热搜排行榜


5.什么是Redis持久化?Redis 的持久化有哪些实现方式?


持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

Redis提供两种持久化机制 RDB(默认) AOF 机制:

RDB持久化:是Redis DataBase缩写,快照

RDBRedis默认的持久化方式。在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里,对应产生的数据文件为dump.rdb通过配置文件中的save参数来定义快照的周期。

如何触发RDB快照;保持策略。

配置文件中默认的快照配置,这三行save代码的意思是:

3600秒(一个小时)内,如果有1个数据发生改变,则进行持久化。

30秒内,如果有10个数据发生改变,则进行持久化。(原先是 save 300 100),我为了后面测试RDB,这里进行了修改。

60秒内,如果有10000个数据发生改变,则进行持久化。

配置

1. # 表示是否开启AOF持久化(默认no,关闭)
2. appendonly yes


工作流程

1.    redis根据配置尝试去生成rdb快照文件

2.    redis主进程fork一个子进程出来

3.    子进程尝试将内存中的数据dump到临时的rdb快照文件中

4.    完成rdb快照文件的生成之后,覆盖旧的快照文件


优点

1.    只有一个文件 dump.rdb,方便持久化,容灾性好。

2.    性能最大化,fork 子进程来完成写操作,让主进程继续处理命令,保证了 redis 的高性能

3.    数据集大时,比 AOF 的启动效率更高。


缺点

1.    数据安全性低。RDB 是间隔一段时间进行持久化,如果持久化之间 redis 发生故障,会发生数据丢失。

6.什么是Redis事务?


事务是逻辑上的一组操作,要么都执行,要么都不执行。Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。


Redis事务可以理解为一个打包的批量执行脚本,redis 事务不保证原子性,且没有回滚,中间某条命令执行失败,前面已执行的命令不回滚,后续的指令继续执行。


Redis事务可以一次执行多个命令,并且带有以下三个重要的保证:

·       批量操作在发送 EXEC 命令前被放入队列缓存。

·       收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,前面已执行的命令不回滚,后续的命令继续执行。

·       事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。


Redis事务的三个阶段

1.    事务开始 MULTI

2.    命令入队

3.    事务执行 EXEC

Redis事务的相关命令:

命令

描述

WATCH

WATCH 命令是一个乐观锁,可以为 Redis 事务提供 check-and-set CAS)行为。可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,监控一直持续到EXEC命令。

UNWATCH

UNWATCH命令可以取消watch对所有key的监控。

MULTI

MULTI命令用于开启一个事务,它总是返回OKMULTI执行之后,客户端可以继续向服务器发送任意多条命令,这些命令不会立即被执行,而是被放到一个队列中,当EXEC命令被调用时,所有队列中的命令才会被执行。

EXEC

EXEC:执行所有事务块内的命令。返回事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil

DISCARD

通过调用DISCARD,客户端可以清空事务队列,并放弃执行事务,并且客户端会从事务状态中退出。


7.谈谈你对Redis集群方案——哨兵模式 的理解



哨兵的介绍

sentinel,中文名是哨兵。哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:

·       集群监控:负责监控 redis master slave 进程是否正常工作。

·       消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。

·       故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。

·       配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。


哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。


8.Redis主从复制的原理是什么?


1.    从节点执行 slaveof 命令

2.    从节点只是保存了 slaveof 命令中主节点的信息,并没有立即发起复制

3.    从节点内部的定时任务发现有主节点的信息,开始使用 socket 连接主节点

4.    连接建立成功后,发送 ping 命令,希望得到 pong 命令响应,否则会进行重连

5.    如果主节点设置了权限,那么就需要进行权限验证;如果验证失败,复制终止。

6.    权限验证通过后,进行数据同步,这是耗时最长的操作,主节点将把所有的数据全部发送给从节点。

7.    当主节点把当前的数据同步给从节点后,便完成了复制的建立流程。接下来,主节点就会持续的把写命令发送给从节点,保证主从数据一致性


9.Redis如何实现分布式锁?


Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系,Redis中可以使用SETNX命令实现分布式锁。

SETNX是『SET if Not eXists(如果不存在,则 SET)的简写。

当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作

返回值:设置成功,返回 1 。设置失败,返回 0


使用SETNX完成同步锁的流程及事项如下:

·       使用SETNX命令获取锁,若返回0key已存在,锁已存在)则获取失败,若返回1则获取成功

·       为了防止获取锁后程序出现异常,导致其他线程/进程调用SETNX命令总是返回0而进入死锁状态,需要为该key设置一个合理的过期时间

·       释放锁,使用DEL命令将锁数据删除


10.Redis中的缓存穿透、缓存击穿、缓存雪崩是什么?


缓存穿透:

当我们访问某个key的时候,此时会去redis缓存中查找,但是此时redis缓存中并不存在这个key,那么它就会去数据库中查找。而我们每次请求都是在查找这个key → redis缓存中没有 → DB中查找,反反复复就使得应用服务器压力变大、redis命中率降低,同时过多的非正常url请求也会造成数据库崩溃。

解决方案:

·       对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟。

·       设置可访问的名单(白名单):使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。

·       采用布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。


缓存击穿:

key对应的数据存在,但在redis中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案:

·       预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的存活时长,避免在高并发期间这些数据过期。

·       实时调整:现场监控哪些数据热门,实时调整key的过期时长。

·       使用锁


缓存雪崩:

当我们访问多个key对应的数据时,这些keyredis中都过期(无法获取)了,那么这些大量的高并发请求就会转到后端DB中去查找访问,进而造成了数据库的崩溃现象。缓存雪崩与缓存击穿的区别在于:缓存雪崩是针对很多key而言的缓存,而缓存击穿则是针对某一个key


解决方案:


·       构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)。

·       使用锁或队列:用加锁或者队列的方式保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况。

·       设置过期标志更新缓存:记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。

·       将缓存失效时间分散开:比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
打赏
0
0
0
0
85
分享
相关文章
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 + 无锁架构 + EDA架构 + 异步日志 + 集群架构
阿里面试:Redis 为啥那么快?怎么实现的100W并发?说出了6大架构,面试官跪地: 纯内存 + 尖端结构 +  无锁架构 +  EDA架构  + 异步日志 + 集群架构
java面试-基础语法与面向对象
本文介绍了 Java 编程中的几个核心概念。首先,详细区分了方法重载与重写的定义、发生阶段及规则;其次,分析了 `==` 与 `equals` 的区别,强调了基本类型和引用类型的比较方式;接着,对比了 `String`、`StringBuilder` 和 `StringBuffer` 的特性,包括线程安全性和性能差异;最后,讲解了 Java 异常机制,包括自定义异常的实现以及常见非检查异常的类型。这些内容对理解 Java 面向对象编程和实际开发问题解决具有重要意义。
41 15
Java社招面试中的高频考点:Callable、Future与FutureTask详解
大家好,我是小米。本文主要讲解Java多线程编程中的三个重要概念:Callable、Future和FutureTask。它们在实际开发中帮助我们更灵活、高效地处理多线程任务,尤其适合社招面试场景。通过 Callable 可以定义有返回值且可能抛出异常的任务;Future 用于获取任务结果并提供取消和检查状态的功能;FutureTask 则结合了两者的优势,既可执行任务又可获取结果。掌握这些知识不仅能提升你的编程能力,还能让你在面试中脱颖而出。文中结合实例详细介绍了这三个概念的使用方法及其区别与联系。希望对大家有所帮助!
214 60
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
尼恩提供了一系列文章,旨在帮助开发者轻松搭建一键开发环境,涵盖Java分布式、高并发场景下的多种技术组件安装与配置。内容包括但不限于Windows和CentOS虚拟机的安装与排坑指南、MySQL、Kafka、Redis、Zookeeper等关键组件在Linux环境下的部署教程,并附带详细的视频指导。此外,还特别介绍了Vagrant这一虚拟环境部署工具,
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
java连接redis和基础操作命令
通过以上内容,您可以掌握在Java中连接Redis以及进行基础操作的基本方法,进而在实际项目中灵活应用。
137 30
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
150 14
Java 面试必问!线程构造方法和静态块的执行线程到底是谁?
大家好,我是小米。今天聊聊Java多线程面试题:线程类的构造方法和静态块是由哪个线程调用的?构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节有助于掌握Java多线程机制。下期再见! 简介: 本文通过一个常见的Java多线程面试题,详细讲解了线程类的构造方法和静态块是由哪个线程调用的。构造方法由创建线程实例的主线程调用,静态块在类加载时由主线程调用。理解这些细节对掌握Java多线程编程至关重要。
66 13
Java线程调度揭秘:从算法到策略,让你面试稳赢!
在社招面试中,关于线程调度和同步的相关问题常常让人感到棘手。今天,我们将深入解析Java中的线程调度算法、调度策略,探讨线程调度器、时间分片的工作原理,并带你了解常见的线程同步方法。让我们一起破解这些面试难题,提升你的Java并发编程技能!
117 16
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
117 9
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
100 12

热门文章

最新文章