常见面试题-Redis专栏(二)


theme: cyanosis

typora-copy-images-to: imgs

Redisson 分布式锁?在项目中哪里使用?多久会进行释放?如何加强一个分布式锁?

答:

首先入门级别的分布式锁是通过 setnx 进行实现,使用 setnx 实现有四个注意点

  1. 需要设置锁的超时时间(如果不设置,在释放锁时,如果机器宕机,会导致锁无法释放)

  2. 需要设置一个唯一 ID,表示这个锁是哪个用户添加的,必须由添加锁的用户释放

    (如果不设置,线程1在执行任务时,可能锁的超时时间已经达到,被自动释放,此时线程2加锁,开始执行业务,但正好线程1执行完毕,释放锁,由于没有唯一ID表示,线程1将线程2加的锁给释放掉了)

  3. 需要锁续命

    有可能锁的过期时间设置的太短,导致业务没有执行完毕,锁就被自动释放,因此要使用锁续命来解决(大概逻辑是使用子线程执行定时任务,定时任务间隔时间要小于 key 的过期时间,子线程隔一段时间判断主线程是否在执行,如果在执行,就重新设置一下过期时间)

  4. 可重入问题:setnx 实现的分布式锁不可重入,这样获取锁的线程在重复进入相同锁的代码块中会造成死锁

而在 Redission 中已经帮我们实现好了分布式锁,下来看一下 Redission 中的分布式锁:

Redission 中获取锁逻辑:

在 Redission 中加锁,通过一系列调用会到达下边这个方法

他的可重入锁的原理也就是使用 hash 结构来存储锁,key 表示锁是否存在,如果已经存在,表示需要重复访问同一把锁,会将 value + 1,即每次重入一次 value 就加 1,退出一次 value 就减 1

下列方法有三个参数分别为:

  • KEYS[1] : 锁名称
  • ARGV[1]: 锁失效时间
  • ARGV[2]: id + “:” + threadId; 锁的小key
    <T> RFuture<T> tryLockInnerAsync(long leaseTime, TimeUnit unit, long threadId, RedisStrictCommand<T> command) {internalLockLeaseTime = unit.toMillis(leaseTime);
​return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, command,"if (redis.call('exists', KEYS[1]) == 0) then " +"redis.call('hset', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +"if (redis.call('hexists', KEYS[1], ARGV[2]) == 1) then " +"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +"redis.call('pexpire', KEYS[1], ARGV[1]); " +"return nil; " +"end; " +"return redis.call('pttl', KEYS[1]);",Collections.<Object>singletonList(getName()), internalLockLeaseTime, getLockName(threadId));}

Redission 中锁续命原理:

Redission 底层有个看门狗机制,加锁成功后会有一个定时任务,默认锁的失效时间是 30s,该定时任务每隔锁失效时间的 1/3 就会去续约锁时间,也就是每隔 10s 进行锁续命

如何加强一个分布式锁?

也就是如何提升一个分布式锁的性能,分布式锁本质上是将并行操作改为串行,那么我们可以通过使用分段锁来提升性能,比如说有 1000 个库存的话,读入到缓存中将分为 10 份进行存储,即 product_stock_1 = 100, product_stock_2 = 100, ...,给每一份都加上所,那么多个线程来竞争这 10 把锁,比原来竞争 1 把锁的性能提高 10 倍

zset 的底层实现?为什么不用红黑树?

答:

zset 的底层实现是:压缩列表 + 跳表

什么时候使用压缩列表?

  • 有序集合保存的元素个数要小于 128 个;
  • 有序集合保存的所有元素成员的长度都必须小于 64 字节。

否则使用跳表

跳表中每个节点都有多个跳跃指针,因此每个节点的平均跳跃长度较长,可以一次跳过多个节点,当找到大于或等于目标元素的节点后,再使用普通指针开始移动(可以向后移动,也可以向前移动,跳表含有前边节点的指针)寻找目标元素,跳表可以在 O(logn) 的时间内遍历跳表

跳表结构图:

1697874023019.png

为什么不用红黑树?

  • 跳表和红黑树的查找时间复杂度都是O(logn),但是红黑树比跳表的插入/删除效率更低

    • 跳表在插入或删除时,只需考虑相邻节点,而红黑树需考虑节点的旋转问题,焦虑较低
  • 跳表实现比红黑树更简单

zset 几个命令的时间复杂度?

答:

  • zadd:O(logn),添加一个元素的时间复杂度是 O(logn)(因为插入元素的话,时间开销都在查找插入位置上,在 zset 中,查找时间复杂度是 O(logn),因此插入复杂度同是)
  • zrange:O(logn + m) ,n 是集合中元素数量,m 是指定范围内的用户数量

redis 里面的命令,比如 setnx 和 setex 还有 zset 中的命令?

答:

zset 中的常用命令为:

  • zadd <key> <score1> <value1> <score2> <value2> ...

    向集合 key 中添加元素

  • zrange <key> <start> <stop> [withscores]

    查找下标在 start 和 stop 之间的元素,如果后边带上 withscores 参数,会将分数也查询出来

  • zrevrange <key> <start> <stop> [withscores]

    将分数从大到小进行查询,和 zrange 查询顺序相反

  • zrangebyscore <key> <min> <max> [withscores]

    返回集合 key 中所有 score 介于 min 和 max 之间的成员,如果后边带上 withscores 参数,会将分数也查询出来

  • setex <key> <seconds> <value>

    设置 key、value 并且设置过期时间

  • setnx <key> <value>

    仅当 key 不存在时,才将 key 的值设置为 value,成功返回1,失败返回0

缓存怎么保证数据的一致性?

答:

  • 先删除缓存,再更新数据库 (操作简单)

    这种情况造成的缓存不一致为:线程 A 先删除缓存,再去更新数据库,在线程 A 更新数据库之前,如果线程 B 去读取缓存,发现并不存在,去读取数据库,此时读取的是旧数据,再将旧数据写入缓存,此时缓存存储的就是脏数据了。

    使用更新数据库 + 延时双删可以解决此情况的数据不一致,在延时双删中,会删除两次缓存,分为以下几步:

    
    1. 删除缓存
    2. 更新数据库
    3. 睡眠  Thread.sleep()
    4. 再删除缓存
    

    即延时双删在线程 A 更新完数据库之后,休眠一段时间,再去删除缓存中可能存在的脏数据。

    这样第二次删除缓存可能导致线程 A 执行时间过长,第二次可以使用异步去删除缓存

  • 先更新数据库,再删除缓存

    这种情况可能因为线程 A 没有及时删除缓存或者删除缓存失败而导致线程 B 读取到旧数据

    可以使用消息队列来完成:

    1. 先将要删除的缓存值或者是要更新的数据库值暂存到消息队列中
    2. 当程序没有成功删除缓存值或者更新数据库值时,从消息队列中读取这些值,再次进行删除或更新
    3. 如果成功删除缓存或者更新数据库,要将这些值从消息队列中取出,以免重复操作

高级扩展点Canal 监听日志更新 + 定时任务缓存处理,简单概括来说就是 Canal 可以监控 MySQL 的 binlog,当发现数据库的数据发生变化后,就去同步缓存,就可以达到最终的数据一致性了

redis基本数据结构?

答:

有 5 中基本数据结构:字符串、list列表、hash字典、set集合、zset有序集合

基本数据结构添加数据命令:

  • 字符串: set key value [ex seconds | px milliseconds] [nx | xx]

    nx:指定 key 不存在才会设置成功

    xx:指定的 key 必须存在才会设置成功,用于更新 key

  • list:lpush key value [value...] rpush key value [value...]

  • hash: hset key field value 将 key 中的 field 的值设置为 value

  • set: sadd key value [value...]

  • zset:zadd key score value 向 key 中添加一个 value 和 score,根据 score 排序

数据结构基本介绍:

  • list 列表是链表,不是数据
  • set 集合内部的键值对是无序且唯一的

基本数据结构应用场景:

  • 字符串

    • 限速器:防止 DoS 攻击,对 ip 进行访问次数限制,但是无法防止 DDoS 攻击,因为 DDoS 是分布式拒绝服务,使用了不同 ip 不断访问服务器

      
      // 等价于 set 192.168.55.1 ex 60 nx
      // 如果该ip不存在,指定key为ip,value为1,过期时间为60秒
      Boolean exists = redis.set(ip, 1, "ex 60", "nx");
      if(exists != null || redis.incr(ip) <= 5) {// 通过访问
      } else {// 限流
      }
      
  • list

    • lpush + lpop 实现
    • 列表 rpush + lpoplpush + rpop 实现
    • 阻塞式消息队列 lpush + brpop 实现
  • hash

    • 存储对象数据:key 为对象名称,value 为描述对象属性的 Map,对象属性的修改在 Redis 中就可直接完成
  • set

    • 去重操作
  • zset

    • 用户排行榜
    • 用户点赞统计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/113804.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中文编程开发语言工具应用案例:ps5体验馆计时收费管理系统软件

中文编程开发语言工具应用案例&#xff1a;ps5体验馆计时收费管理系统软件 软件部分功能&#xff1a; 1、计时计费功能&#xff1a;只需点开始计时即可&#xff0c;时间直观显示 2、商品管理功能&#xff1a;可以管理饮料等商品 3、会员管理功能&#xff1a;支持只用手机号作…

Arcgis 数据操作

在进行数据操作的时候&#xff0c;需要注意坐标系要一致&#xff0c;这是前提。 数据类型 文件地理数据库&#xff1a;gbd 个人地理数据库&#xff1a;mdb &#xff08;Mircosoft Access&#xff09; 矢量数据&#xff1a;shp 推荐使用gbd数据&#xff0c;效率会更高。 采…

【912.排序数组】

目录 一、题目描述二、算法原理2.1快速排序2.2归并排序 三、代码实现3.1快排代码实现3.2归并代码实现 一、题目描述 二、算法原理 2.1快速排序 2.2归并排序 三、代码实现 3.1快排代码实现 class Solution { public:int getRandom(int left,int right,vector<int>&…

[翻译]理解Postgres的IOPS:为什么数据即使都在内存,IOPS也非常重要

理解Postgres的IOPS&#xff1a;为什么数据即使都在内存&#xff0c;IOPS也非常重要 磁盘IOPS&#xff08;每秒输入/输出操作数&#xff09;是衡量磁盘系统性能的关键指标。代表每秒可以执行的读写操作数量。对于严重依赖于磁盘访问的PG来说&#xff0c;了解和优化磁盘IOPS对实…

Ubuntu系统下使用docker容器配置nginx并部署前端项目

1.下载 Nginx 镜像 命令 描述 docker pull nginx 下载最新版 Nginx 镜像 :2. 创建要挂载的宿主机目录 启动前需要先创建 Nginx 外部挂载的配置文件&#xff08; /home/nginx/conf/nginx.conf&#xff09; 之所以要先创建 , 是因为 Nginx 本身容器只存在 / etc/nginx 目录 ,…

iOS 13以下系统,使用iOS QQ 登录 SDK 崩溃问题

最近用iPhone 6p 系统&#xff1a;12.5.4 调用QQ三方登录&#xff0c;出现崩溃到初始化QQ SDK的位置 在询问了QQ官方客服后&#xff0c;得到了答复&#xff0c;可以放弃治疗了

2.IDEA的安装使用指南

学习Java的第二步应该是从IDEA下手&#xff0c;这篇博文介绍了它的安装及使用&#xff0c;希望大家看完后可以独立安装 ~ 文章目录 一、下载安装包二、安装 IDEA三、IDEA 初步上手 一、下载安装包 安装包可以从官网下载&#xff0c;也可以直接私信我拿取。这里主要介绍如何在官…

Swingbench 压力测试(超详细)

目录 前提需要有配置好的oracle哦 1、环境准备 2、安装Swingbench 3、造数据 4、压测 前提需要有配置好的oracle哦 1、环境准备 启动监听 lsnrctl start 启动数据库 sqlplus / as sysdba startup 创建表 CREATE TABLESPACE soe DATAFILE /u01/app/oracle/oradata/or…

2.卷积神经网络(CNN)

一句话引入&#xff1a; 如果我们要做图像识别&#xff0c;用的是一个200x200的图片&#xff0c;那么BP神经网络的输入层就需要40000个神经元&#xff0c;因为是全连接&#xff0c;所以整个BP神经网络的参数量就是160亿个&#xff0c;显然不能这样来训练网络&#xff0c;所以我…

【java】【重构一】分模块开发设计实战

目录 一、创建项目 1、先创建一个空项目 2、设置项目SDK等 二、创建父模块 选择springboot 1、创建父模块parent 2、删除多余文件&#xff0c;只保留pom.xml 3、修改pom.xml 4、将部分公共依赖加入到pom 三、创建实体类子模块entity 1、创建实体类子模块entity 2、…

Jprofiler V14中文使用文档

JProfiler介绍 什么是JProfiler? JProfiler是一个用于分析运行JVM内部情况的专业工具。 在开发中你可以使用它,用于质量保证,也可以解决你的生产系统遇到的问题。 JProfiler处理四个主要问题: 方法调用 这通常被称为"CPU分析"。方法调用可以通过不同的方式进行测…

C++中的继承(超详细)

C中的继承 1.继承的概念及定义1.1继承的概念1.2 继承定义1.2.1 定义格式1.2.2继承关系和访问限定符1.2.3继承基类成员访问方式的变化 2.基类和派生类对象赋值转换3.继承中的作用域4.派生类的默认成员函数5.继承与友元6.继承与静态成员7.继承的总结和反思 1.继承的概念及定义 1…

新兴网络安全威胁:数字防御新格局

根据Check Point Research (CPR)的数据&#xff0c;今年上半年犯罪活动大幅增加&#xff0c;第二季度全球每周网络攻击激增 8%&#xff0c;这创下了两年来的最高成交量。 勒索软件和黑客行为等传统威胁已经演变&#xff0c;犯罪团伙不断调整其方法和工具来渗透和影响世界各地的…

c语言练习93:环形链表的约瑟夫问题

环形链表的约瑟夫问题 环形链表的约瑟夫问题_牛客题霸_牛客网 描述 编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数&#xff0c;报到 m 的人离开。 下一个人继续从 1 开始报数。 n-1 轮结束以后&#xff0c;只剩下一个人&#xff0c;问最后留下的这个人编号是…

粘包和半包问题及解决办法

粘包问题是指数据在传输时&#xff0c;在一条消息中读取到了另一条消息的部分数据&#xff0c;这种现象就叫做粘包。 半包问题是指数据在传输时&#xff0c;接收端只收到了部分数据&#xff0c;而非完整的数据&#xff0c;就叫做半包。 产生粘包和半包问题原因&#xff1a; …

Error: GlobalConfigUtils setMetaData Fail Cause:java.lang.NullPointerException

文章目录 1、在开发中会出现这样的错误。2、其次&#xff0c;再看其他错误&#xff1a; 1、在开发中会出现这样的错误。 完整错误&#xff1a;Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Error: GlobalConfigUtils setMetaData Fail ! Cause…

【面试HOT100】链表树

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于LeetCodeHot100进行的&#xff0c;每个知识点的修正和深入主要参考…

python自动化测试框架unittest与pytest的区别

有使用过unittest单元测试框架&#xff0c;再使用pytest单元测试框架&#xff0c;就可以明显感觉到pytest比unittest真的简洁、方便很多。 unittest与pytest的区别&#xff1a; 主要从用例编写规则、用例的前置和后置、参数化、断言、用例执行、失败重运行和报告这几个方面比…

vue使用pdf 导出当前页面,(jspdf, html2canvas )

需要安装两个插件 npm install html2canvas jspdfyarn add html2canvas jspdf<div class"app-container" id"pdfPage"><!--这个放你需要导出的内容--> </div><el-button size"mini" click"onExportPdf">导出…

记录一次线下渗透电气照明系统(分析与实战)

项目地址:https://github.com/MartinxMax/S-Clustr 注意 本次行动未造成任何设备损坏,并在道德允许范围内测试 >ethical hacking< 发现过程 在路途中,发现一个未锁的配电柜,身为一个电工自然免不了好奇心(非专业人士请勿模仿,操作不当的话220V人就直了) 根据照片,简…