JAVA基础面试题总结(七)——Redis部分(上)

Redis基础

Redis 为什么这么快?

1、Redis 基于内存,内存的访问速度是磁盘的上千倍;

2、Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用

3、Redis 内置了多种优化过后的数据结构,性能非常高。

Redis应用

Redis 除了做缓存,还能做什么?

分布式锁:通过 Redis 来做分布式锁是一种比较常见的方式。通常情况下,我们都是基于 Redisson 来实现分布式锁。关于 Redis 实现分布式锁的详细介绍,可以看我写的这篇文章:分布式锁详解open in new window

限流:一般是通过 Redis + Lua 脚本的方式来实现限流。相关阅读:《我司用了 6 年的 Redis 分布式限流器,可以说是非常厉害了!》open in new window

消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。它比较类似于 Kafka,有主题和消费组的概念,支持消息持久化以及 ACK 机制。

延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)。

分布式 Session :利用 String 或者 Hash 数据类型保存 Session 数据,所有的服务器都可以访问。

复杂业务场景:通过 Redis 以及 Redis 扩展(比如 Redisson)提供的数据结构,我们可以很方便地完成很多复杂的业务场景比如通过 Bitmap 统计活跃用户、通过 Sorted Set 维护排行榜。

分布式锁介绍

为什么需要分布式锁?

在这里插入图片描述

分布式系统下,不同的服务/客户端通常运行在独立的 JVM 进程上。如果多个 JVM 进程共享同一份资源的话,使用 ReetrantLock 类、synchronized 关键字这类JDK自带的本地锁就没办法实现资源的互斥访问了。

分布式锁

分布式锁应该具备哪些条件?

一个最基本的分布式锁需要满足:

  • 互斥:任意一个时刻,锁只能被一个线程持有。
  • 高可用:锁服务是高可用的,当一个锁服务出现问题,能够自动切换到另外一个锁服务。并且,即使客户端的释放锁的代码逻辑出现问题,锁最终一定还是会被释放,不会影响其他线程对共享资源的访问。这一般是通过超时机制实现的。
  • 可重入:一个节点获取了锁之后,还可以再次获取锁。

除了上面这三个基本条件之外,一个好的分布式锁还需要满足下面这些条件:

  • 高性能:获取和释放锁的操作应该快速完成,并且不应该对整个系统的性能造成过大影响。
  • 非阻塞:如果获取不到锁,不能无限期等待,避免对系统正常运行造成影响。

分布式锁的常见实现方式有哪些?

常见分布式锁实现方案如下:

  • 基于关系型数据库比如 MySQL 实现分布式锁吗,一般是通过唯一索引或者排他锁实现。
  • 基于分布式协调服务 ZooKeeper 实现分布式锁。
  • 基于分布式键值存储系统比如 Redis 、Etcd 实现分布式锁。

Redis数据结构

String 的底层实现是什么?

String 是 Redis 中最简单同时也是最常用的一个数据类型,redis自己构建了一种 简单动态字符串(Simple Dynamic String,SDS)

相比于 C 的原生字符串,Redis 的 SDS有下面的提升:

1、可以避免缓冲区溢出:DS 被修改时,会先根据 len 属性检查空间大小是否满足要求,如果不满足,则先扩展至所需大小再进行修改操作。

2、获取字符串长度的复杂度较低:SDS 的长度获取直接读取 len 属性即可,时间复杂度为 O(1)

3、减少内存分配次数:SDS 实现了空间预分配和惰性空间释放两种优化策略。当 SDS 需要增加字符串时,Redis 会为 SDS 分配好内存,并且根据特定的算法分配多余的内存,这样可以减少连续执行字符串增长操作所需的内存重分配次数。当 SDS 需要减少字符串时,这部分内存不会立即被回收,会被记录下来,等待后续使用。

Redis五种基本数据类型

String

1、String 是 Redis 中最简单同时也是最常用的一个数据类型,redis自己构建了一种 简单动态字符串(Simple Dynamic String,SDS)

应用:
需要存储常规数据的场景

举例:缓存 Session、Token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。

相关命令:SET、GET。

需要计数的场景

举例:用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数。

相关命令:SET、GET、 INCR、DECR 。

分布式锁
利用 SETNX key value 命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)

2、List

底层数据结构:双向链表

应用:

最新文章、最新动态

3、Hash

对象数据存储场景
举例:用户信息、商品信息、文章信息、购物车信息。

4、Set:
共同好友(交集)、共同粉丝(交集),文章点赞、动态点赞

5、Sorted set

需要随机获取数据源中的元素根据某个权重进行排序的场景
举例:各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。

Redis三种特殊数据类型

1、Bitmap (位图)

需要保存状态信息(0/1 即可表示)的场景
举例:用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)

2、HyperLogLog(基数统计)
数量量巨大(百万、千万级别以上)的计数场景

3、Geospatial (地理位置)
需要管理使用地理空间数据的场景
举例:附近的人。

Redis线程模型

Redis 后台线程了解吗?

我们虽然经常说 Redis 是单线程模型(主要逻辑是单线程完成的),但实际还有一些后台线程用于执行一些比较耗时的操作:

1、后台线程来释放 AOF / RDB 等过程中产生的临时文件资源。

2、后台线程调用 fsync 函数将系统内核缓冲区还未同步到到磁盘的数据强制刷到磁盘( AOF 文件)。

3、后台线程释放已删除的大文件占用的内存空间。

Reids事务

什么是 Redis 事务?

你可以将 Redis 中的事务理解为:Redis 事务提供了一种将多个命令请求打包的功能。然后,再按顺序执行打包的所有命令,并且不会被中途打断。

除了不满足原子性和持久性之外,事务中的每条命令都会与 Redis 服务器进行网络交互,这是比较浪费资源的行为。因此,Redis 事务是不建议在日常开发中使用的。

Redis 事务支持持久性吗?

Redis 不同于 Memcached 的很重要一点就是,Redis 支持持久化,而且支持 3 种持久化方式:

  • 快照(snapshotting,RDB)
  • 只追加文件(append-only file, AOF)
  • RDB 和 AOF 的混合持久化(Redis 4.0 新增)

与 RDB 持久化相比,AOF 持久化的实时性更好。在 Redis 的配置文件中存在三种不同的 AOF 持久化方式( fsync策略),它们分别是:

appendfsync always    #每次有数据修改发生时都会调用fsync函数同步AOF文件,fsync完成后线程返回,这样会严重降低Redis的速度
appendfsync everysec  #每秒钟调用fsync函数同步一次AOF文件
appendfsync no        #让操作系统决定何时进行同步,一般为30秒一次

AOF 持久化的fsync策略为 no、everysec 时都会存在数据丢失的情况 。always 下可以基本是可以满足持久性要求的,但性能太差,实际开发过程中不会使用。

因此,Redis 事务的持久性也是没办法保证的。

即:Reids中有三种持久化方式:RDB、AOF以及RDB和AOF的混合持久化。与 RDB 持久化相比,AOF 持久化的实时性更好,但是AOF的no、everysec 的持久化方式都会存在数据丢失的情况,always 下可以基本是可以满足持久性要求的,但性能太差,实际开发过程中不会使用,Redis 事务的持久性也是没办法保证的。

Redis性能优化

使用批量操作减少网络传输

原生批量操作命令

Redis 中有一些原生支持批量操作的命令,比如:

  • MGET(获取一个或多个指定 key 的值)、MSET(设置一个或多个指定 key 的值)。

缺点:在Redis Cluster集群方式下,无法保证原子性,因为无法保证所有的 key 都在同一个 hash slot(哈希槽)上。

pipeline

对于不支持批量操作的命令,我们可以利用 pipeline(流水线) 将一批 Redis 命令封装成一组,这些 Redis 命令会被一次性提交到 Redis 服务器,只需要一次网络传输。

缺点:在Redis Cluster集群方式下,无法保证原子性,因为无法保证所有的 key 都在同一个 hash slot(哈希槽)上。

Lua 脚本

Lua 脚本同样支持批量操作多条命令。一段 Lua 脚本可以视作一条命令执行,可以看作是 原子操作

缺点:在Redis Cluster集群方式下,无法保证原子性,因为无法保证所有的 key 都在同一个 hash slot(哈希槽)上。

  • 12
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值