关于redis的知识梳理
思考引入
mybatis 的二级缓存级别是mapper 其作用域是namespace ,sqlSession 共享同一个namespace下所有的mapper,二级缓存开启在单个应用的时候,是可以减少数据库的压力;但是由于其缓存是在本地,容易产生脏数据,所有呢在分布式应用中,是不建议开启的,如果分布式下使用缓存,建议使用redis;
1.redis是个什么东西
redis是个缓存中间件吧(错 片面 ),
--是非关系型数据库(没有表格 行 列) Nosql 可以
2.为什么要用redis啊,如果不用redis会产生什么样的影响我们不想看到,使用的redis 会解决我们什么样的痛点、
高并发的时候,redis为数据库分担压力,防止数据库宕机;
--可以达到每秒8万次的写,11万的读
3.我们在什么时候使用redis啊,redis的使用场景,这些场景是由于其哪些特性决定的
由于其高速的读取能力可以 作为缓存
由于其可以进行持久化到硬盘,也可以作为数据库
redis概念梳理
1.rdb aof
这个是redis持久化方式,默认RDB
rdb:redis 回fork创建一个线程 将数据写到一个文件中,存在时间差,最后一次持久化的数据有可能不是最新的,因此适合数据不是非常敏感
aop:是将所有的命令都记录下来,需要手动开启
2.6379
redis 默认端口
3.redis-benchamark
压力测试工具
4. 内存操作,单线程
redis虽然是单线程的 但是由于其是基于内存操作的,一般意义CUP的效率 是 高于内存的,但是多线程在cup中操作在上下文切换的的时候存在耗时消耗,虽然redis是单线程 基于内存操作,但是效率还是很高的。
5.为什么记不住五种常用基本类型,我理解的redis存储的类型就是类似 map<string,Object> key是string类型,value是多种类型 是吗?
String类型 String(k),String(v)
无序set集合 String(k),【str,str,str..】(v)
有序zset集合 String(k),【str1,str2,str3..】(v)
无序哈希HASH (mini版redis) String(k),【<k,v>,<k,v>....】(v)
有序双向列表list String(k),【....str1,str2,str1....】(v)
6.redis的事务特殊的事务 只是一组命令的集合,不能保证原子性,但是单个命令是具有原子性的
7.Jedis是Redis官方推荐的连接工具
但是springBoot 2.x之后 lettuce Redis连接工具的原因是什么?
因为jedis 线程是不安全的,lettuce是线程安全的
8.RedisTemplate是什么东西?
Jedis是Redis官方推荐的面向Java的操作Redis的客户端,
而RedisTemplate是SpringDataRedis中对JedisApi的高度封装(的客户端)。
SpringDataRedis相对于Jedis来说可以方便地更换Redis的Java客户端,比Jedis多了自动管理连接池的特性,方便与其他Spring框架进行搭配使
9.使用redisTemplate为什么要使用序列化
1.首先序列化解决的问题是 java对象 在传输和存储中 可以正确成功的 读取。
2.因为redisTemplate 默认使用的是 JDK的序列化 所有会存在乱码的现象,为了解决乱码问题 所以,使用JSON进行序列化,K 使用String,value 使用jackson
3.我们自己定义一个RedisTemplate 来替换 默认的redisTemplate
Redis 的进阶问题
1.Redis的发布订阅 实际上是 redis的一个功能 自带有方法,redis客户端 是redis的 发布者 也是订阅者,然后呢redis服务端内部使用队列进行对发布者发布的消息,进行推送
一对一的 发布订阅模式;一对多的频道模式
图片
2.redis服务端主从复制(一主二从),读写分离(主写,从读)的架构图
图片
主机可以写,从机不能写只能读(默认权限)!主机中的所有信息和数据,都会自动被从机保存!
3.哨兵模式 主要用来监控主机是否故障,如果故障自动将从库 转为主库 原型图
图片
4.redis 在访问量大并发量的的时候 容易出现的问题以及解决方案
1.缓存雪崩(宕机了)由于大量的失效或者redis宕机 解决方案:redis集群部署,限流降级,数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中
2.缓存击穿(点) 在key失效的一瞬间 大量请求去访问DB数据库了 ;解决方案 设置key不过期
3.缓存穿透,因为redis中不存在key 所以都去查询数据库了 解决方案 布隆过滤器 在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力;还有查询到的控制也将其缓存起来,但是有可能造成数据不同步
5.分布式为什么要使用redis 用redis 主要解决什么问题?
1.什么是分布式:分布式是将一个系统 拆分成多个系统 ,并且多个系统独立运行,他们共同完成系统功能
2.redis可以实现分布式锁,可以把整个集群当成一个应用去处理,因为redis是独立应用的第三方,可以实现跨jvm通过互斥机制去控制共享资源
3.redis的互斥机制 是通过 方法 setnx 来实现的 ,key存在返回0 ,不存在 设置v 并且返回1
4.设置锁的过期时间,防止锁被无线占用;UUID防止误删除锁 这个uuid是个value值不是key;LUA脚本保证了执行redis命令组的原则性;
删除锁 记得 使用lua脚本
加锁 设置过期时间,循环获取锁
/** * 最终加强分布式锁 * * @param key key值 * @return 是否获取到 * @throws Exception */ public void lock(String key,String UUID) throws Exception { int time = 0; while(true){ if (!hasKey(LOCK_PREFIX + key)) { if (set(LOCK_PREFIX + key,UUID, LOCK_EXPIRE)) { logger.info("RedisTools________lock________加锁成功!锁ID:"+LOCK_PREFIX + key); break; } } try { Thread.sleep(LOCK_WITE); logger.info("RedisTools________lock________"+LOCK_PREFIX+key+"有锁!"+ LOCK_WITE + "秒后重试!"); } catch (InterruptedException e) { } time++; if(time==20){ throw new Exception("RedisTools________lock________lockerror:"+LOCK_PREFIX+key+"验证锁尝试20次失败!"); } } }
//释放锁
public boolean releaseDistributedLock(String lockKey, String requestId){ Jedis jedis = null; try { jedis = this.jedisPool.getResource(); String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId)); if(RELEASE_SUCCESS.equals(result)){ return true; } }catch (Exception e){ logger.error(e); }finally { if(jedis != null){ jedis.close(); } } return false; }
5.为什么要用lua脚本 因为执行了两个语句 保证删除的原子性
没有加lua脚本之前
加了lua脚本的执行的情况
6.线程和进程的区别,以及线程的生命周期,线程锁和进程锁,以及应用锁(分布式锁的区别)
1.线程是cup执行(调度)最小单元,同一类线程共享代码和数据空间; 进程 是资源分配的最小单元,进程有独立的代码和数据空间(进程上下文),进程在切换的时候开销大。
2.线程的基本状态
- 就绪状态:线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。处于就绪状态的线程,随时可能被CPU调度执行。
- 运行状态: 线程已获得CPU,正在运行。
- 阻塞状态: 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
3.声明周期 创建 就绪 运行 阻塞 销毁
1.sleep() (暂停线程,不会释放锁,睡眠结束,线程继续执行,线程自动释放锁)
2.wait() 属于Object类,而不属于Thread类,wait()会先释放锁,再执行等待的动作。由于wait()所等待的对象必须先锁住,因此,它只能用在同步化程序段或者同步化方法内,否则,会抛出异常IllegalMonitorStateException.
wait与notify必须配合synchronized使用,因为调用之前必须持有锁,wait会立即释放锁,notify则是同步块执行完了才释放
3.yield() 方法 该方法与sleep()类似,只是不能由用户指定暂停多长时间,但此时线程任然处于可执行状态,随时可以再次分得cpu时间片。yield()方法只能使同优先级的线程有执行的机会。(暂停当前正在执行的线程,并执行其他线程,且让出的时间不可知,不会释放锁)
4.join()方法
当主线程开启一个或多个子线程的时候,使用join方法,必须等该线程运行结束,主线程或其他子线程才由阻塞状态转为可执行状态。
public class ThreadTset { public static void test() { Thread t1 = new Thread (() -> { for (int i = 0; i < 5; i++) { System.out.println ("A----" + i); } }); Thread t2 = new Thread (() -> { for (int j = 0; j < 5; j++) { System.out.println ("B----" + j); } }); t1.start (); try { t1.join (); } catch (InterruptedException e) { e.printStackTrace (); } t2.start (); } public static void main(String[] args) { test (); } }
执行结果
A----0
A----1
A----2
A----3
A----4
B----0
B----1
B----2
B----3
B----4
Process finished with exit code 0
分析:主线程开始运行t1线程,线程已经进入就绪状态,接着TI线程join方法被调用,主线程处于阻塞状态,等待t1线程执行完毕,主线程状态变为可运行状态,t2线程被执行。
线程锁:
synchronized
多线程可以同时运行多个任务但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误! so,不使用线程锁, 可能导致错误
大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。
当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。
进程锁:
也是为了控制同一操作系统中多个进程访问一个共享资源,
只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,
但是可以使用本地系统的信号量控制(操作系统基本知识)。
分布式锁:
redis
高并发1-Redis分布式锁setnx,setex连用 redis系列
参考尚硅谷课件 F:\工作杂项\中科软科技服务有限公司\统计--遇到技术问题\redis
redis 讲义.docx
redis面试题整理
问题:redis 什么时候存和清空对应key的数据,如果第一次查询的时候,如果缓存中没有,这个时候需要查询数据库并且返回到redis中,别的请求过来,直接从缓存中那,如果数据更新了呢,是不是要去删除
这个查询出来的Entry呢 ,还有一种情况就是,如果这个key值 是通过 基础数据计算出来的,我们更新了基础数据,怎么快速确定你影响的key呢?还有更新数据 后 删除key 还是 先删除key 再去修改数据呢?
最大的问题是没有用redis 去解决实际的需求和问题?
参考:redis是什么?
---Redis缓存淘汰策略
redis内存超出物理内存限制的时候,需要进行缓存淘汰
lru 最近最少使用
lfu 一直以来使用很少
10.redis存什么数据
10.1 操作频率较高数据,且数据量不是很大的,最为典型的就是redis的分布式锁;oauth2 的access_token
10.2 redis常见应用场景
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升