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

news2024/12/23 17:02:26

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.coloradmin.cn/o/1119640.html

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

相关文章

6.MySQL内置函数

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 日期函数 current_date() 当前日期 select 可以做表达式和函数的计算。 current_time() 当前时间 current_timestamp() 当前日期加时间 注意&#xff1a;值得说明的是这三个函数底层调用的都是同一个函数&#xff0c;只不…

C语言关键字

关键字作用 关键字是 C 语言中预先保留的单词 C语言关键字 注意&#xff1a;在定义变量或者常量的时候&#xff0c;不要使用关键字

设计模式:组合模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

简介&#xff1a; 组合模式&#xff0c;它是一种用于处理树形结构、表示“部分-整体”层次结构的设计模式。它允许你将对象组合成树形结构&#xff0c;以表示部分和整体的关系。这种模式的主要目的是简化客户端代码&#xff0c;并使客户端以一致的方式处理单个对象和组合对象。…

数字图像处理实验记录五(图像的空间域增强-锐化处理)

前言&#xff1a; 文章目录 一、基础知识1&#xff0c;什么是锐化&#xff1f;2&#xff0c;为什么要锐化&#xff1f;3&#xff0c;怎么进行锐化&#xff1f; 二、实验要求任务1&#xff1a;任务2&#xff1a;任务3&#xff1a; 三、实验记录&#xff1a;任务1&#xff1a;任…

计算机网络第三章习题

1.假定1km长的CSMA/CD网络的数据率为1Gb/s。设信号在网络上的传播 速率为200000km/s。求能够使用此协议的最短帧长. 问题刨析: 逻辑链: 最短帧长数据传输率x争用期2τ(2倍端到端所需要的时间) 题目已经给出数据率为1Gb/s,所以我们要知道争用期2τ是多少. 端到端所需要的时间信…

订单 延后自动关闭,五种方案优雅搞定!

前 言 在开发中&#xff0c;往往会遇到一些关于延时任务的需求。例如 生成订单30分钟未支付&#xff0c;则自动取消生成订单60秒后,给用户发短信 对上述的任务&#xff0c;我们给一个专业的名字来形容&#xff0c;那就是延时任务 。那么这里就会产生一个问题&#xff0c;这个…

画程序流程图

一。在线程序流程图。类图和时序图 Integrations | Mermaid 二。VSCODE画UML图和各种种 1.下载plantuml.jarReleases plantuml/plantuml GitHubGenerate diagrams from textual description. Contribute to plantuml/plantuml development by creating an account on GitHu…

B-tree(PostgreSQL 14 Internals翻译版)

概览 B树(作为B树访问方法实现)是一种数据结构&#xff0c;它使您能够通过从树的根向下查找树的叶节点中所需的元素。为了明确地标识搜索路径&#xff0c;必须对所有树元素进行排序。B树是为有序数据类型设计的&#xff0c;这些数据类型的值可以进行比较和排序。 下面的机场代…

【在英伟达nvidia的jetson-orin-nx上使用调试摄像头-初步调试USB摄像头与Camera Conn.#0/#1接口-基础测试】

【在英伟达nvidia的jetson-orin-nx上使用调试摄像头-初步调试USB摄像头与Camera Conn.#0/#1接口-基础测试】 1、概述2、实验环境3、 物品说明&#xff08;0&#xff09;各种各样摄像头&#xff08;1&#xff09;USB摄像头&#xff08;2&#xff09;CSI摄像头&#xff08;3&…

【JavaEE】线程安全的集合类 -- 多线程篇(9)

线程安全的集合类 多线程环境使用 ArrayList多线程环境使用队列多线程环境使用哈希表 多线程环境使用 ArrayList 自己使用同步机制 (synchronized 或者 ReentrantLock)Collections.synchronizedList(new ArrayList); synchronizedList 是标准库提供的一个基于 synchronized 进…

【AIGC】百度文库文档助手之 - 一键生成PPT

百度文库文档助手之 - 一键生成PPT 引言一、文档助手&#xff1a;体验一键生成PPT二、文档助手&#xff1a;进阶用法三、其它生成PPT的方法3.1 ChatGPT3.2 文心一言 引言 就在上个月百度文库升级为一站式智能文档平台&#xff0c;开放四大AI能力&#xff1a;智能PPT、智能总结、…

正则表达式提取http和http内容

http.* 这样匹配到的就是我们要的内容 取反正则&#xff1a;^((?!要取反的正则表达式).)*$ 取反&#xff1a;^((?!http.).)$ 这样匹配到的就是我们不要的内容 提取域名 /[(http|ftp|https):\/\/]?([\w_-](?:(?:\.[\w_-])))([\w.,?^%&:\/~#-]*[\w?^%&\/~#-]…

APK与小程序渗透

文章目录 APK与小程序渗透1. APK2. 小程序2.1 源代码2.2 小程序的默认下载位置 3. 安装证书3.1 openssl配置环境变量3.2 安装证书 APK与小程序渗透 由于APK和小程序与服务器通信还是采用的是https协议&#xff0c;只是使用了加密。只要获取到了HTTP的请求报文就可以回归到Web渗…

单目3D目标检测论文汇总

基于语义和几何约束的方法 1. Deep3DBox 3D Bounding Box Estimation Using Deep Learning and Geometry [CVPR2017] https://arxiv.org/pdf/1612.00496.pdfhttps://zhuanlan.zhihu.com/p/414275118 核心思想&#xff1a;通过利用2D bounding box与3D bounding box之间的几何约…

『C语言进阶』字符函数和内存函数(2)

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f516;系列专栏&#xff1a; C语言、Linux、Cpolar ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 文章目录 一、strtok函数1.1 函数认识1.2 注意事项 二、strerror函数2.1 函数认识2.2 注意事项 三、memcpy函数3.1 函数…

1024渗透测试如何暴力破解其他人主机的密码(第十一课)

1024渗透测试如何暴力破解其他人主机的密码(第十一课) 1 crunch 工具 crunch是一个密码生成器&#xff0c;一般用于在渗透测试中生成随机密码或者字典攻击。下面是常见的一些使用方法&#xff1a; 生成密码字典 生成6位数字的字典&#xff1a;crunch 6 6 -t -o dict.txt …

【LeetCode】145. 二叉树的后序遍历 [ 左子树 右子树 根结点]

题目链接 文章目录 Python3方法一&#xff1a; 递归 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法二&#xff1a; 迭代 ⟮ O ( n ) ⟯ \lgroup O(n) \rgroup ⟮O(n)⟯方法三&#xff1a; Morris ⟮ O ( n ) 、 O ( 1 ) ⟯ \lgroup O(n)、O(1) \rgroup ⟮O(n)、O(1)⟯写…

学成在线第二天-查询课程、查询课程分类、新增课程接口实现以及跨域的处理思路和全局异常处理的使用以及面试题

目录 一、接口的实现 二、跨域的处理思路 三、全局异常处理 四、面试题 五、总结 一、接口的实现 1. 查询课程接口 思路&#xff1a; 典型的分页查询 按需查询 模糊查询的查询 controller&#xff1a; ApiOperation(value "课程列表", notes "课程…

字节码进阶之java Instrumentation原理详解

文章目录 0. 前言1. 基础2. Java Instrumentation API使用示例 3. Java Agent4. 字节码操作库5. 实际应用6. 注意事项和最佳实践 0. 前言 Java Instrumentation是Java API的一部分&#xff0c;它允许开发人员在运行时修改类的字节码。使用此功能&#xff0c;可以实现许多高级操…

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

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