当前位置: 首页 > news >正文

JAVA面试(六)

缓存

  • Memcached
  • redis
    • Redis常见数据类型和使用
    • Redis缓存持久化
      • RDB-快照
      • AOF-追加文件
    • Redis数据过期机制
      • 惰性删除
      • 定期删除
      • Redis缓存淘汰策略(8种)
        • 算法
          • LRU (Least Recently Used):最近最少使用
          • LFU(Least Frequently Used):最近最少频率使用
    • Redis事务
    • Redis为什么要用分布式缓存
    • Redis集群
      • 主从模式 - 最简单的
      • 哨兵模式
      • Redis Cluster
    • Redis常见问题及解决方案
      • 缓存击穿
      • 缓存穿透
      • 缓存雪崩
      • bigKey
      • 热Key
      • 慢查询命令
      • 如何保障数据库和缓存数据的一致性
        • 延时双删
        • 异步更新缓存
      • 假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?
      • 什么情况下可能会导致 Redis 阻塞
      • 怎么提高缓存命中率
      • 怎么实现分布式锁
  • 分布式点这里
  • MongDB
  • 数据库点这里
  • 消息队列
  • Spring、SpringBoot、SpringCloud点这里

Memcached

简洁的key-value存储系统,其实是内存中维护一张巨大的Hash表。不支持集群,Memcached彼此之间不进行通信,所以,可能会造成数据丢失。
和redis对比

MemcachedRedis
数据类型只支持key-value
数据持久化Memcached 把数据全部存在内存之中Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用
集群模式支持没有原生的集群模式3.0 版本起是原生支持集群模式的
线程模型多线程,非阻塞 IO 复用的网络模型单线程的多路 IO 复用模型
特性支持Redis 支持发布订阅模型、Lua 脚本、事务等功能
过期数据删除只用了惰性删除策略惰性删除策略、定期删除策略

redis

redis是一个缓存中间件。
数据基于内存,内存的访问速度比磁盘快很多
单线程,基于I/O多路复用

  • 6.0后支持多线程,但是命令执行还是单线程

Redis 除了可以用作缓存之外,还可以用于分布式锁、限流、消息队列、延时队列等>场景

  • 延时队列:Redisson 内置了延时队列(基于 Sorted Set 实现的)
  • 消息队列:Redis 自带的 List 数据结构可以作为一个简单的队列使用。(Rpush +Lpop)
    Redis 5.0 中增加的 Stream 类型的数据结构更加适合用来做消息队列。
  • 限流: 通过 Redis + Lua 脚本的方式来实现限流。key是ip,value是访问次数
  • redis搜索引擎:借助 RediSearch
  • redis延时任务

Redis常见数据类型和使用

5 种基础数据类型
String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。

  • String,二进制安全的,可以存储图片或者序列化的对象,值最大存储为512M
    set key value
    get key
  • Hash
    hset key field value
    hget key field
  • List
    lpush key value [value ...]
    lrange key start end
  • Set(集合)
    sadd key element [element ...]
    smembers key
  • ZSet(有序集合)
    zadd key score member [score member ...]
    zrank key member

3 种特殊数据类型
HyperLogLog(基数统计)、Bitmap (位图)、Geospatial
(地理位置)。

除了上面提到的之外,还有一些其他的比如 Bloom filter(布隆过滤器)open in new
window、Bitfield(位域)。

场景应用:排行耪

选用ZSet,这是一个有序集合。根据score来排序
Zrange (从小到大排序)、 ZrevRange (从大到小排序)、ZrevRank (指定元素排名)。

Redis缓存持久化

4.0之后,RDB 和 AOF 混合使用实现持久化

RDB-快照

定时将redis中的所有键值对数据保存到到一个临时文件中,这个文件就是dump.rdb文件。恢复时候将这个临时文件替换上次持久化的文件即可。

AOF-追加文件

每次操作命令时候,将这次的操作通过Write函数追加到文件中。恢复时候,会自动执行备份文件中的所有命令,达到恢复上次数据的效果。

总结:

  • RDB是默认持久化方式,当两种方式同时开启时,数据恢复Redis会优先选择AOF恢复。
  • 持久化机制: 当Redis重启后通过把硬盘文件重新加载到内存
  • 实现:单独创建fork()一个子进程,将当前父进程的数据库数据复制到子进程的内存中,然后由子进程写入到临时文件中,持久化的过程结束了,再用这个临时文件替换上次的快照文件,然后子进程退出,内存释放。

Redis数据过期机制

设置expire(过期时间)后才会触发。
Redis 采用的是 定期删除+惰性/懒汉式删除 结合的策略

惰性删除

当查询key时候,先看该key是否过期,没有过期就返回数据;负责,删除该key,且不返回数据

定期删除

在一定时间,随机抽取设置过期时间的key,若这些含的key大部分过期,就删除这些过期key

  • Redis 的定期删除过程是随机的(周期性地随机从设置了过期时间的 key 中抽查一批),所以并不保证所有过期键都会被立即删除。这也就解释了为什么有的 key 过期了,并没有被删除。

  • 并且,执行时间已经超过了阈值,那么就中断这一次定期删除循环,以避免使用过多的 CPU 时间

  • 可在配置文件中设置频率
    由 hz 参数控制的。hz 默认为 10,代表每秒执行 10 次

Redis缓存淘汰策略(8种)

当redis内存不够用的时候,当一个新key需要存放时候就会按某种规则将内存中的数据删掉,这个删除规则就是淘汰策略。

  • noeviction:默认策略。不删除任何key,新增的key也不写入,内部不足直接报错
  • volatile-ttl:对设置TTL时间的key,剩余时间越短的先删除
  • allkeys-random:对全体key随机淘汰
  • volatile-random:对设置TTL时间的key随机淘汰
  • allkeys-LRU:对全体key使用LRU短发淘汰
    有明显冷热数据区分
  • volatile-LRU: 对设置TTL时间的key使用LRU短发淘汰
    数据有置顶的需求 — 置顶数据不设置过期时间,这些数据就一直不被删除,会淘汰其他设置过期时间的数据
  • allkeys-LFU:对全体key使用LFU短发淘汰
  • volatile-LFU: 对设置TTL时间的key使用LFU短发淘汰
算法
LRU (Least Recently Used):最近最少使用

用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。

public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int CACHE_SIZE;// 这里就是传递进来最多能缓存多少数据public LRUCache(int cacheSize) {super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);//这块就是设置一个hashmap的初始大小,//同时最后一个true指的是让linkedhashmap按照访问顺序来进行排序//即 最近访问的放在头,最老访问的就在尾CACHE_SIZE = cacheSize;}@Overrideprotected boolean removeEldestEntry(Map.Entry eldest) {return size() > CACHE_SIZE; // 这个意思就是说当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据}}
LFU(Least Frequently Used):最近最少频率使用

会统计每个key的访问频率,值越小淘汰优先级越高。

Redis的数据淘汰策略有哪些 ?- 以下回答背熟,大概用时1min。

redis有个策略叫数据淘汰策略,具体指的是当Redis中的内存不够用时,此时在向Redis中添加新的key,那么Redis就会按照某一种规则将内存中的数据删除掉。这个策略redis提供了8种方案,默认的叫noeviction,就是不删除任何数据,内部不足直接报错。方案的切换是可以在redis的配置文件中进行设置的,里面有两个非常重要的概念,一个是LRU,另外一个是LFU。
LRU,即Least Recently Used,意思就是最近最少使用,我们用当前时间减去最后一次访问时间,这个值越大则淘汰优先级越高。
LFU,即Least Frequently Used,意思就是最近最少频率使用。我们会统计每个key的访问频率,值越小淘汰优先级越高。

Redis事务

  • redis提供了一种命令,可以将多个命令打包一起后按顺序执行,执行途中不会被影响
  • MULTI(开始事务),EXEC(执行事务)直接包着命令集
  • 不能保证原子性。可以这么说,是一种比较弱的事务。原子性就是要么都成功,要么都失败,对应到redis中,批量命令执行时候,假如中间出错了,前面执行过的无法回滚

Redis为什么要用分布式缓存

Redis集群

https://segmentfault.com/a/1190000043133394

主从模式 - 最简单的

这里是引用
Redis主从复制优点: 做到读写分离,提高服务器性能;
Redis主从复制缺点: 在主从模式中,一旦Master节点由于故障不能提供服务,需要人工将Slave节点晋升为Master节点

哨兵模式

当主服务器宕机后,需要手动把一台从服务器切换为主服务器,需要人工干预费事费力,为了解决这个问题出现了哨兵模式
哨兵模式优点:最大的优点就是主从可以自动切换,系统更健壮,可用性更高;

哨兵模式缺点:最大的缺点就是还要多维护一套哨兵模式,实现起来也变的更加复杂增加维护成本;
在这里插入图片描述

Redis Cluster

主要是针对海量数据+高并发+高可用的海量数据场景,Redis集群模式的性能和高可用性均优于哨兵模式。

Redis常见问题及解决方案

缓存击穿

热key在缓存中过期了,所以不在缓存中,会导致瞬时大量的请求直接打到了数据库上,对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
解决方案:

  • 永不过期(不推荐):设置热点数据永不过期或者过期时间比较长。
  • 提前预热(推荐):针对热点数据提前预热,将其存入缓存中并设置合理的过期时间比如秒杀场景下的数据在秒杀结束之前不过期。
  • 加锁(看情况);:在缓存失效后,通过设置互斥锁确保只有一个请求去查询数据库并更新缓存

缓存穿透

大量请求的 key 是不合理的,根本不存在于缓存中,也不存在于数据库中 。导致这些请求直接到了数据库上对数据库造成了巨大的压力,可能直接就被这么多请求弄宕机了。
解决方案:

  • 首先做好参数校验,不合法的参数请求直接抛出异常信息返回给客户端
  • 缓存无效 key,SET key value EX 10086 设置过期时间
  • 布隆过滤器
  • 接口限流,用户或者 IP 对接口进行限流,对于异常频繁的访问行为,还可以采取黑名单机制

缓存雪崩

缓存在同一时间大面积的失效,导致大量的请求都直接落到了数据库上,对数据库造成了巨大的压力
解决方案:

  • 针对 Redis 服务不可用的情况:
    Redis 集群
    多级缓存(本地缓存+Redis 缓存的二级缓存组合)
  • 针对大量缓存同时失效的情况
    设置随机失效时间
    针对热点数据提前预热,并设置合理的时间
    对于某些关键性和变化不频繁的数据,持久缓存永不过期

bigKey

一个 key 对应的 value 所占用的内存比较大,那这个 key 就可以看作是 bigkey.

  • String 类型的 value 超过 1MB
  • 复合类型(List、Hash、Set、Sorted Set 等)的 value 包含的元素超过 5000 个

产生原因:

  • 设计不当---- 使用string存储较大文件的二进制流
  • 数据规模考虑不到位---- 使用集合类型没有考虑到数据量的快速增长

带来什么问题 — 阻塞

  • 客户端超时阻塞:redis是单线程的,操作大key时候耗时

如果解决

  • bigkeys 命令去扫描(redis-cli -p 6379 --bigkeys -i 3 表示扫描过程中每次扫描后休息的时间间隔为 3 秒)
  • 找到后,手动清理;用合适的数据结构

热Key

访问频率较高的Key。
会出现的问题

  • 某个热点数据访问量暴增 占用大量的 CPU 和带宽,影响redis的其他请求处理;严重情况下,导致宕机

如果查看

  • 可以通过hotkeys 参数来查找

如果解决

  • 读写分离:主节点处理写请求,从节点处理读请求。
  • 使用 Redis Cluster:将热点数据分散存储在多个 Redis 节点上
  • 二级缓存:hotkey 采用二级缓存的方式进行处理,将 hotkey 存放一份到 JVM 本地内存中(可以用 Caffeine)。

慢查询命令

为什么会有慢

如何保障数据库和缓存数据的一致性

就是通常讨论的淘汰缓存和更新数据库的顺序怎么样比较合适,下文是较好的方案:

延时双删

写入库的前后,都删除缓存【redis.del(key)操作】
步骤
先删除缓存 —> 再写数据库 —> 休眠 500 毫秒 —> 再次删除缓存
缺点:
最差的情况就是在超时时间内数据存在不一 致,而且又增加了写请求的耗时。

异步更新缓存

MySQL binlog 增量订阅消费+消息队列+增量数据更新到 redis
步骤

假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?

keys 命令和 scan 命令,使用 scan 更好

什么情况下可能会导致 Redis 阻塞

Redis 主机的 CPU 负载过高;
数据持久化占用资源过多;
使用Redis时 API 或 指令不合理

怎么提高缓存命中率

怎么实现分布式锁

分布式点这里

MongDB

分布式文件储存的数据库

  • 存储数据:数据库中存储的对象设计BSON,一种类似json的二进制文件,由键值对组成
  • 链接方式(默认为27017)
    mongodb://[username:password@]host1[:port1][,host2[:port2]
  • 库简单认识
    文档 - row
    集合 - table
    数据库 - database
  • 复制工作
    MongoDB的复制工作是基于主从复制实现的。其中一个节点被定义为主节点,其他的节点被定义为备份节点,数据会进行实时同步。在某些情况下,主节点可能会失效或消失,这时候从节点将被提升为主节点继续工作。
  • 支持存储过程吗
    支持,它是javascript写的,保存在db.system.js表中。

数据库点这里

消息队列

Spring、SpringBoot、SpringCloud点这里

相关文章:

  • JAVA语言开发的一套(智慧工地监管系统源码)让工地变得更加“聪明”
  • 接口联调测试工作总结
  • Python 设计模式(第2版) -- 第二部分(结构型模式)
  • Java启动jar设置内存分配详解
  • JWT整合Gateway实现鉴权(RSA与公私密钥工具类)
  • 示例:WPF中DataGrid简单设置合并列头
  • 数据结构和算法之复杂度比较
  • 数据治理:如何通过优化数据提取流程提高数据分析效果
  • 使用 Python 中的美丽汤进行网络数据解析的完整指南
  • python从入门到精通6:变量类型
  • ES6数组新增API
  • Jenkins简要说明
  • uniapp中u-input点击事件失效
  • 流媒体传输协议HTTP-FLV、WebSocket-FLV、HTTP-TS 和 WebSocket-TS的详细介绍、应用场景及对比
  • 高通Android13 WIFI配置国家码
  • Asm.js的简单介绍
  • Facebook AccountKit 接入的坑点
  • PHP那些事儿
  • ReactNative开发常用的三方模块
  • Spring核心 Bean的高级装配
  • Zsh 开发指南(第十四篇 文件读写)
  • 从零开始学习部署
  • 复习Javascript专题(四):js中的深浅拷贝
  • 后端_MYSQL
  • 基于组件的设计工作流与界面抽象
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 爬虫模拟登陆 SegmentFault
  • 前端学习笔记之观察者模式
  • 什么软件可以剪辑音乐?
  • 算法-图和图算法
  • 通信类
  • 微信小程序实战练习(仿五洲到家微信版)
  • 自制字幕遮挡器
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​LeetCode解法汇总518. 零钱兑换 II
  • !!java web学习笔记(一到五)
  • ![CDATA[ ]] 是什么东东
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (三)elasticsearch 源码之启动流程分析
  • (三十)Flask之wtforms库【剖析源码上篇】
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (转载)从 Java 代码到 Java 堆
  • .naturalWidth 和naturalHeight属性,
  • .NET CLR Hosting 简介
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET/C# 使用 #if 和 Conditional 特性来按条件编译代码的不同原理和适用场景
  • //解决validator验证插件多个name相同只验证第一的问题
  • @Builder用法
  • @private @protected @public
  • @SentinelResource详解
  • @Valid和@NotNull字段校验使用
  • [ vulhub漏洞复现篇 ] Grafana任意文件读取漏洞CVE-2021-43798
  • [] 与 [[]], -gt 与 > 的比较