- 2024-08-05·Java后端查看全文大家好,我是程序媛雪儿,今天咱们聊个我新学的项目,AI智能评测应用平台系统。 咱们先了解一下这个系统是干嘛的。 一、业务分析 ...flowersea:关注一下雪儿姐哈哈哈哈,在星球一直看你,但是迁移过来忘记关注了😁1424分享
- 2024-07-24·Java后端查看全文大家好,我是程序媛雪儿,今天我们继续聊redis分片集群。 一、适用场景 redis分片集群是为了解决海量数据存储问题、高并发写的问题而设计的。 二、是什么 ...500分享
- 2024-07-22·Java后端查看全文大家好,我是程序媛雪儿,有两天没和大家唠唠技术了,今天我们聊聊AI流式调用,这块我也是总结鱼皮哥AI答题应用平台项目中的技术,大家看了有兴趣可以学习一下,实操体验一下怎么应用哦~ 现在AI已经在各大软件中广泛应用,你们有没有想过如何在AI应用中实时处理数据流?今天咱们聊聊怎么用SSE Rxjav...鱼友0412:好巧,刚好实习的ai项目也是流式调用,看的云里雾里,知其然不知其所以然1310分享
- 2024-07-16·Java后端查看全文一、是什么 Redis内存不够的时候,此时向redis中添加新的key,那么,redis会按照你配置的规则将数据删除掉 ...程序媛雪儿:redis数据淘汰策略610分享
- 2024-07-14·Java后端查看全文大家好,我是程序媛雪儿,今天给大家带来的知识碎片是缓存雪崩。 一、是什么 缓存雪崩:因为大量的key过期,或者redis直接宕机,导致大量的请求到达数据库,带来了巨大的压力。...程序员鱼皮:感谢分享620分享
大家好,我是程序媛雪儿,今天咱们聊个我新学的项目,AI智能评测应用平台系统。 咱们先了解一下这个系统是干嘛的。 一、业务分析 大致业务流程是应用制作者在创建应用页面填写应用信息,依次添加题目和评分规则生成测评应用,系统管理员可以在应用管理页面审核应用,通过审核的应用会显示在主页,其他用户可以检索应用,并在线答题,查看自己的答题结果,分享应用等(每个用户都可以答题人,也可以发布自己的测评) 我认为这个项目有以下几个业务逻辑是可以考虑复用的 1、审核功能。一般类似知乎、csdn、b站这类用户可以上传自己作品的平台,大多有审核功能,大体上都是用户发表后,有审核员审核,通过后才会给客户推送,就可以复用这块功能,根据具体的业务稍作修改 2、分享功能。为了推广方便,一般项目都是有分享给他人的功能的,点击分享后,手机微信扫二维码,分享给其他人生成小卡片,其他项目也可能用得到 3、AI生成题目,AI生成测评结果。如果我们做的不是测评系统,也是可以用这块的,因为AI生成题目和测评结果,本质是设计prompt提示词,让AI能稳定的生成我们想要的Json串,我觉得这个能力可以给很多项目赋予AI的能力,使得结果更丰富,功能更丰富。 二、技术分析 后端 1、使用策略模式实现测评模块,策略模式一般使用在有多个算法,不同情况下使用各自对应的算法这种情况下。我们的系统是会根据用户选择应用类型是打分、测评以及评分结果是手动还是AI评分来选择对应的测评算法,因此选用策略模式 2、AI模块调用选用的是智谱AI,调用他人的接口,可以先写demo测试,然后根据我们的业务需求封装请求,简化请求(详情看笔记封装AI模块),实现模块解耦,也更方便我们调用接口 3、编写prompt,确保每次输出的json稳定 4、AI流式调用少不了响应式编程,Rxjava sse可以实现AI生成一道题目,前端就展示一道题目的功能 5、缓存击穿问题的优化和实现。我们的项目可以访问题目生成接口,每次都会调用AI大模型,但是调用大模型是要token计费的,如果攻击者短时间内一直调用AI生成题目接口,很可能造成计费,甚至被大模型方认为我们的系统是攻击者,直接禁号了,可以使用caffeine redis分布式锁解决这个问题。 6、某个表因为用户激增导致上百万的数据,调用缓慢,可以采用分库分表的方式解决,这个项目具体是使用的sharding-JDBC实现的。 7、系统幂等性设计方案,利用数据库索引唯一特性,使用乐观锁,分布式锁等等 8、线程是很宝贵的系统资源,如果想实现vip生成题目很快,普通用户限速生成题目这类功能,可以使用线程池隔离技术,让vip用户能使用所有进程,普通用户只能使用某几个进程 9、对用户行为进行统计分析,比如哪些App答题量最多,可以在首页优先显示(这块已实现)根据用户答的测评(MBTI性格测试)推送用户可能喜欢的文章等等(这块没实现) 前端 1、echarts vue-echarts实现统计图表 2、pina状态管理 3、arco design组件库 4、qrcode二维码生成 5、使用umijs的openapi自动生成请求代码 三、页面展示 可查看笔记: http://www.snowyee.cn/实战项目/AI答题应用平台笔记.html#页面效果 四、仓库地址 前端地址:https://gitee.com/gu-feiyin/aidada-frontend 后端地址:https://gitee.com/gu-feiyin/yudada-backend mbti测试小程序地址:https://gitee.com/gu-feiyin/mbti-test-mini 项目完整版笔记: http://www.snowyee.cn/实战项目/AI答题应用平台笔记.html 项目体验地址:我就不公开了哈,因为大模型token要计费,个人项目有点烧不起,还望谅解 随便聊聊: 其实我觉得,弄清楚业务逻辑和实现方法后写代码是最简单的事情了,花不了多少时间。但是搞清楚业务逻辑,自己能举出多种解决方案,并且能根据仅有的资源选出最优解解决问题还是比较难的,所以,宝子们,学项目,写项目,多问问为什么,为什么库表的字段是这样设计?有没有更好的办法?这几种方案各自的优缺点是什么?适合什么样的场景?如果是我做,我打算用什么样的方法?原因是什么?等等,知其然,知其所以然,我们才能做的更好,走得更长远,加油~ 欢迎大家关注我的微信公众号,程序媛雪儿,雪儿会在上面发布编程的知识碎片,也有雪儿博客地址,上面有详细系统的笔记,雪儿是全栈,但是公众号目前主要还是发后端的技术,以后可能也会涉及到一些前端的知识,我们下期见,拜拜~ 项目 人工智能
发现一个有意思的现象,我用的ai都认为9.11比9.9大,包括chatgpt,有懂哥能解释一下这是为啥嘛
大家好,我是程序媛雪儿,今天我们继续聊redis分片集群。 一、适用场景 redis分片集群是为了解决海量数据存储问题、高并发写的问题而设计的。 二、是什么 1、集群里有多个master,每个master保存不同的数据 2、每个master都可以有多个slave节点 3、master之间互相ping来检测彼此的健康状态 4、客户端可以访问集群任何节点,把客户端的请求转发到正确的节点 三、怎么实现的每个master均匀保存数据? redis分片集群使用了哈希槽的概念,redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置到哪个槽,集群的每个节点负责一部分hash槽。 为什么是16384个哈希槽呢? 因为这个数量不会太大,导致管理过于复杂,也不会太小,以至于无法实现有效的数据分布,可以使得数据相对均匀的分布在多个节点上,这是一个在不断实践中总结出来的合理值。 四、知识综合回顾 redis主从复制,是指一个主节点有多个相同的从节点,可以解决高并发读的问题。 redis哨兵模式,是指redis的哨兵会持续关注主从节点的健康状态,主节点宕机,哨兵会根据一定的规则选取某个从节点作为主节点继续工作,为了保障系统高可用需求。 redis分片集群则是一个集群里有多个主节点,每个主节点都有自己的从节点,主节点间通过ping命令检测彼此的监控状态,redis分片集群主要是为了解决海量数据存储问题、高并发写的问题 今日碎碎念,我个人感觉,简单的生活也蛮美好的,我在职场干的第一份长期工作就是自己热爱的事业,可以每天写写文章,写写代码,做做技术总结,然后去健身房拉练自己,看着自己一天天的朝着自己的目标前进,真的很幸运,我还能和爱我的爸爸妈妈在我成年工作后还有这么长一段时间的相处,我们可以交流思想,彼此相互影响,一起变好,人生美好也不过如此吧~ 欢迎大家关注我的微信公众号,程序媛雪儿,雪儿会定期在上面发布编程的知识碎片,也有雪儿博客地址,上面有详细系统的笔记,雪儿是全栈,但是公众号目前主要还是发后端的技术,以后可能也会涉及到一些前端的知识,我们下期见,拜拜~
大家好,我是程序媛雪儿,有两天没和大家唠唠技术了,今天我们聊聊AI流式调用,这块我也是总结鱼皮哥AI答题应用平台项目中的技术,大家看了有兴趣可以学习一下,实操体验一下怎么应用哦~ 现在AI已经在各大软件中广泛应用,你们有没有想过如何在AI应用中实时处理数据流?今天咱们聊聊怎么用SSE Rxjava处理实时数据流。 一、SSE是什么 SSE(后端主动推送给前端) 前端发请求并和后端建立连接,后端实时推动数据给前端 SSE的重要特点 单向通信:SSE只支持服务器向客户端的单向通信 文本格式:SSE使用纯文本格式传输数据,HTTP响应的text/event-stream 保持连接:SSE会保持一个持久的HTTP连接,实现服务器向客户端推送数据 自动重连:如果连接中断,浏览器会尝试自动重连 为什么处理AI流式数据要用SSE? AI对话是服务器单向给客户端流式传输数据,用SSE更加 简单:不需要WebSocket那么复杂,基本的HTTP和JavaScript就搞定。 实时更新:长连接,随时获取最新数据。 轻量:适合频繁更新的小数据量。 二、RxJava是什么 RxJava是一个基于事件驱动的、利用可观测序列来实现异步编程的类库 1、事件驱动 事件可以是任何事情。比如用户的点击操作、网络请求的结果、文件的读写等 2、可观测序列 可观测序列指一系列按照时间序列发出的数据项,可以被观察处理 RxJava的核心知识点 观察者模式 RxJava是基于观察者模式实现的。 观察者:观测数据流 observer 被观察者:实时传输数据流 observable和flowable observable适合处理相对较小的、可控的、不会产生大量数据的场景,不具备背压能力 flowable具备背压能力。也就是说,如果生产数据过快,超过了大多数数据消费者速度,flowable提供了多种背压策略来处理这种情况,保证大量数据仍然能稳定 建立订阅关系 被观察者.subscribe(观察者) 三、后端Rxjava流式调用的demo // region // 生成AI题目流式生成 @GetMapping("/ai_generate/sse") public SseEmitter aiGenerateSSE(AiGenerateRequest aiGenerateRequest){ // 获取应用信息 // 建立SSE连接对象,0表示永不超时 SseEmitter sseEmitter = new SseEmitter(0L); // AI生成(调用AI流式接口),SSE流式返回 Flowable<ModelData> modelDataFlowable = aiManager.doStreamRequest(GENERATE_QUESTION_SYSTEM_MESSAGE, userMessage, null); // 截取流式数据进行数据处理后返回给前端 modelDataFlowable // 指定观察者的线程池 .observeOn(Schedulers.io()) // 先获取数据 .map(modelData -> modelData.getChoices().get(0).getDelta().getContent()) // 先处理数据把没用的空格都去掉 .map(message -> message.replaceAll("\\s","")) .filter(StrUtil::isNotBlank) .flatMap(message ->{ List<Character> characterList = new ArrayList<>(); for (char c : message.toCharArray()) { characterList.add(c); } return Flowable.fromIterable(characterList); }) .doOnNext(c -> { // 按照业务需要处理数据 }) .doOnError((e) -> log.error("异常处理")) .doOnComplete(()->{ sseEmitter.complete(); }) .subscribe(); return sseEmitter; } // endregion 04 四、前端使用sse开启连接,获取数据 /** * 提交流式生成题目,一个一个的生成题目 */const handleSSESubmit = async () => { // 创建SSE请求 const eventSource = new EventSource( // 手动填写完整的后端地址 "http://localhost:8101/ai_generate/sse" ); let first = true; // 接收消息 eventSource.onmessage = function(event) { console.log(event.data); if(first){ console.log('第一次连接'); first = !first; } console.log('传输数据',event.data); }; // 报错或连接关闭时触发 eventSource.onerror = function(event) { // 关闭SSE连接 if(event.eventPhase === EventSource.CLOSED){ console.log('关闭连接'); eventSource.close(); } }; // 连接打开时触发 eventSource.onopen = function(event) { console.log('连接成功'); };}; 基本上就是后端用Rxjava框架观察处理数据,处理成前端需要的形式传给前端,前端用SSE的方式接收数据,进行实时的数据展示。是不是很简单?那今天雪儿的分享就结束啦,也欢迎各位宝宝关注我的微信公众号,程序媛雪儿,雪儿基本上天天都会分享技术碎片,我们一起学习,一起进步,加油哦~#知识碎片# #学习总结#
大家好,我是程序媛雪儿,今天不说晚安,说早上好,哈哈,今天我们唠唠redis数据删除策略。 一、惰性删除 设置key的过期时间,当需要该key,再检查是否过期,如果过期,就删掉,没过期,就返回(只有key过期才会检查) set name zhangsan 10 get name 优点:不会额外消耗cpu 缺点:大量过期的数据占了内存,未及时处理 二、定期删除 每隔一段时间,就对key进行检查(从一定数量的数据库抽取一定数量的key),并删除其中的过期key 两种模式 slow模式:默认是10hz,每次不超过25ms,可以通过修改redis.conf的hz选项来调整这个次数 fast模式:两次间隔不低于2ms,每次耗时不超过1ms 优点:可以通过限制操作删除的执行时长和频率来控制对cpu和内存的影响 缺点:难确定删除的执行时长和频率 Redis的过期删除策略:惰性删除 定期删除配合使用 三、内存淘汰机制(是上篇讲的) 8种策略,nginx.conf中的配置 maxmemory-policy noeviction #默认策略,不淘汰任何key,内存满了不允许写入新数据 volatile-lru:从设置了过期时间的数据集中挑选最近最少使用的数据淘汰。 allkeys-lru:从数据集中挑选最近最少使用的数据淘汰。 volatile-lfu:从设置了过期时间的数据集中挑选使用频率最低的数据淘汰。 allkeys-lfu:从数据集中挑选使用频率最低的数据淘汰。 volatile-random:从设置了过期时间的数据集中随机挑选数据淘汰。 allkeys-random:从数据集中随机挑选数据淘汰。 volatile-ttl:从设置了过期时间的数据集中挑选剩余生存时间最短的数据淘汰。 noeviction:禁止驱逐数据,新的写操作会报错。 还是推荐大家像我上篇文章那样,画个图图记这个知识点 其中,解释一下LRU和LFU算法 LRU(least recently used)最近最少使用,当前时间-最后访问时间,这个值越大越优先淘汰,换句话说就是淘汰最长时间没访问的 LFU (least frequently used ) 最少频率使用,会统计每个key的访问频率,值越小淘汰优先级越高 今天的知识碎片到这里就结束啦~咱们顺便唠唠嗑,我最近每天下班在健身房泡一个小时,跑步机30-40min,拉伸10min,练练背,玩玩哑铃做做力量训练,我觉得真的会很舒服,咱们不管是写代码还是实验室里搞研究,天天坐的时间太久了,能时不时舒展一下,是一件很棒的事情哦,之前雪儿经常肩膀痛,现在已经不痛啦,很推荐各位宝子试一下昂~ 欢迎大家关注我的微信公众号程序媛雪儿,雪儿会经常分享知识碎片和大家一起进步#知识碎片#
一、是什么 Redis内存不够的时候,此时向redis中添加新的key,那么,redis会按照你配置的规则将数据删除掉 二、两个算法 先说两个算法,LRU、LFU LRU(least recently used)最近最少使用,当前时间-最后访问时间,这个值越大越优先淘汰,换句话说就是淘汰最长时间没访问的 LFU (least frequently used ) 最少频率使用,会统计每个key的访问频率,值越小淘汰优先级越高 三、八种策略 8种策略,nginx.conf中的配置 maxmemory-policy noeviction #默认策略,不淘汰任何key,内存满了不允许写入新数据 #知识碎片# 图片只能以这种形式出现,这篇不带这个图片真是不能发,今天雪儿的分享到这里就结束啦,如果大家想详细了解,欢迎关注同名微信公众号,里面有带图解的笔记,雪儿祝大家秋招顺利,早日发财,那么,晚安啦~[月亮] #知识碎片#
大家好,我是程序媛雪儿,今天给大家带来的是redis持久化。 一、RDB(redis数据快照) 含义:Redis数据快照,也就是把内存中的所有数据整体记录到磁盘中,如果redis实例故障重启,可以从磁盘中读取快照文件,恢复数据 实操命令 redis-cli #连接redis# save #Redis主进程执行rdb,会阻塞所有命令 bgsave # 开启子进程执行rdb,避免主进程受到影响 redis.conf文件下也有对应的设置 # 900s内,如果至少有1个key被修改,则执行bgsave save 900 1 save 300 10 save 60 10000 执行原理 执行bgsave命令的时候会把主进程fork得到子进程,子进程和主进程共享同一片物理内存,这时子进程就可以读取内存文件存到rdb中了 这种方式存在脏读的问题,所以fork采用的是copy-on-write技术,也就是让数据加上read-only的锁 当主进程执行读操作时,访问共享内存 当主进程执行写操作时,只能先拷贝一份数据,执行写操作 二、AOF(追加文件) 含义:可以称为追加文件,redis所处理的每一个写命令都会记录到AOF中,可以看作是命令文件 aof默认是关闭的,需要修改redis.conf配置来开启 # 是否开启AOF功能,默认是no appendonly yes # aof文件的名称 appendfilename "appendonly.aof" # aof命令记录的频率 appendfsync no/always/everysec 因为AOF是记录命令,所以要比记录数据的RDB大得多,因为AOF会记录对同一个key多次写操作,但只有最后一次才有意义,那么为了减少aof体积,我们可以合并命令,通过bgrewriteaof命令,可以让aof文件执行重写命令,用最少的命令达到相同的效果 redis.conf配置aof触发阈值重写aof # 文件比上次超多百分之百,也就是上次aop文件两倍触发重写 auto-aof-rewrite-percentage 100 # aop文件体积最小达到多大触发重写 auto-aof-rewrite-min-size 64mb 今天雪儿的分享到这里就结束啦,如果大家想详细了解,欢迎关注同名微信公众号和b站视频,里面有带图解的笔记和视频资料,雪儿祝大家秋招顺利,早日发财,那么,晚安啦~[月亮] #知识碎片#
大家好,我是程序媛雪儿,今天发早点,因为雪儿要早睡早起,睡太晚不好哦,大家也要注意规律作息,保护好我们自己的身体,雪儿今天给大家带来的知识碎片是redis双写一致性 一、是什么 概念:修改数据库的同时要更新缓存,让数据库和缓存保持一致 为什么数据库和缓存会不一样呢? 二、原因 情况1:先删除缓存,再操作数据库 因为线程1把缓存删了,线程2没命中,直接把旧数据读出来写到缓存中,而此时还未把新数据写到数据库,导致缓存里是旧数据 情况2:先操作数据库,再删除缓存也会出现脏数据 也就是说线程1未命中查询到的数据库是旧数据,直接写入缓存了,返回数据了,而此时,线程2正把新数据写入数据库呢,线程1没读到新数据 总结一句话,就是不管先删缓存,还是先改数据库,都可能会出现把旧数据缓存到redis,出现脏数据的情况,所以我们需要在修改数据库前后删两次缓存来保证数据库和redis数据的一致性。 三、解决方案 解决方案1:延迟双删 为什么第二次删除缓存的时候要延时呢? 因为主数据库要把数据写到从数据库上需要时间,但是因为有延时所以还是会有脏数据。 解决方案2:读操作使用共享锁,写操作使用排他锁 共享锁:读不互斥,写互斥 排他锁:读写都互斥 代码示例 读操作使用共享锁 public Item getById(Integer id) { // 获取读写锁 RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ITEM_READ_WRITE_LOCK"); // 获取读锁(读写锁中的读操作部分) RLock readLock = readWriteLock.readLock(); try { // 上锁 readLock.lock(); System.out.println("readLock..."); // 从 Redis 缓存中尝试获取项 Item item = (Item) redisTemplate.opsForValue().get("item:" id); // 如果缓存中有项,则直接返回 if (item != null) { return item; } // 如果缓存中没有项,创建新项 item = new Item(id, "华为手机", "华为手机", 5999.00); // 将新项存入 Redis 缓存 redisTemplate.opsForValue().set("item:" id, item); // 返回新创建的项 return item; } finally { // 解锁 readLock.unlock(); } } 写操作使用排他锁 public void updateById(Integer id) { // 获取读写锁 RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("ITEM_READ_WRITE_LOCK"); // 获取写锁(读写锁中的写操作部分) RLock writeLock = readWriteLock.writeLock(); try { // 上锁 writeLock.lock(); System.out.println("writeLock..."); // 模拟更新操作 Item item = new Item(id, "华为手机", "华为手机", 5299.00); // 模拟延迟操作,可能表示某种复杂的更新过程 try { Thread.sleep(10000); // 延迟 10 秒 } catch (InterruptedException e) { e.printStackTrace(); // 捕获并打印中断异常 } // 删除 Redis 缓存中的项 redisTemplate.delete("item:" id); } finally { // 解锁 writeLock.unlock(); } } 优点:强一致性 缺点:性能较差 解决方案3:使用MQ异步通知 每次修改数据库,我们都发布消息给MQ,缓存随时监听MQ的变化,如果有新的消息,再更新缓存,在高并发下会有数据不一致的情况,但是我们可以保证最终数据的一致性。 解决方案4:使用Canal异步通知 canal记录了所有数据定义数据操作的语句,不包含查询语句 流程如上,每次修改数据库,我们都把消息发给canal,由canal通知缓存数据变化情况,再更新数据,也能保证数据最终的一致性 视频地址: 4.redis双写一致性_哔哩哔哩_bilibili 带图解文章: redis双写一致性-CSDN博客 也欢迎关注我的同名公众号,程序媛雪儿,雪儿和你一起学八股,祝各位宝子们学有所获~
大家好,我是程序媛雪儿,今天给大家带来的知识碎片是缓存雪崩。 一、是什么 缓存雪崩:因为大量的key过期,或者redis直接宕机,导致大量的请求到达数据库,带来了巨大的压力。 二、解决方案 1、如果是因为大量的key过期,那就在设置过期的时间TTL加个随机值,可以减少key同时过期的概率 2、如果是redis宕机了,那就在部署redis的时候,使用redis集群,比如哨兵模式、三主三从的集群模式,来提高服务的可用性 3、给缓存业务添加降级限流策略,比如nginx或spring cloud gateway去添加限流策略 4、给业务添加多级缓存 ,比如把Guava或Caffeine作为一级缓存,nginx作为二级缓存 今天雪儿的分享到这里就结束啦,如果大家想详细了解,欢迎关注同名微信公众号和b站视频,里面有带图解的笔记和视频资料,雪儿祝大家学的开心,学有所获,晚安~[月亮]#知识碎片#
主题:缓存击穿 一、是什么 缓存击穿:给某个Key设置了过期时间,key过期的时候,刚好有大量的请求过来,瞬间把数据库压垮 也就是key过期,发请求发现没有,从数据库往redis存数据的这50ms把数据库击垮 二、解决方案 解决方案1:互斥锁 流程:如果出现查询不到数据的情况,直接对该数据加锁,然后去请求db,把数据写入缓存,才释放锁,如果这个操作过程中其他线程想要获取该数据,会发现被上了锁,就休眠一会再试,直到缓存命中为止。 优点:可以保证数据的强一致性 缺点:性能比较差,所有线程都需要等到数据写入缓存才能返回数据 解决方案2:逻辑过期 所有数据加个过期字段 {"id":1,"expire":156563269} 流程:如果查询数据,发现数据已经过期,加互斥锁,开启新进程去完成从db中往缓存取数据,修改过期时间等,本进程直接返回过期数据,如果此时还有其他进程也访问该数据,但是发现加了互斥锁,直接返回过期数据。直到新线程把数据写到缓存,释放了互斥锁,线程就可以获取新数据了。 优点:高可用、性能好 缺点:返回的数据不一致 使用建议:看应用场景,如果需要高度一致,比如和钱相关的金融业务,那么必须要用互斥锁,如果为了快速响应,提高用户体验,可以用逻辑过期这种处理方式。 回顾 缓存穿透:查询一个不存在的数据,mysql查询不到的数据也不会直接写入缓存,导致每次请求都查数据库。 解决方案: 1、缓存空数据 2、使用布隆过滤器 缓存击穿:给某个Key设置了过期时间,key过期的时候,刚好有大量的请求过来,瞬间把数据库压垮 解决方案: 1、互斥锁 2、逻辑过期 今天雪儿的分享就到这里啦,如果大家想看带图解的可以搜微信公众号程序媛雪儿查看带图解的笔记,如果想看视频,可以在b站上搜程序媛雪儿,视频标题就是缓存击穿。希望大家学有所获,学的开心,我们下次见~#知识碎片#


