黑马点评大总结

8.2.1 短信登录

  • 首先是用户提交手机号,后端将生成的验证码以及用户信息存入session中,用户登录时进行拦截并从session中拿出来信息校验,并把用户信息存入ThreadLocal中
  • session共享问题:每个tomcat有自己的一份session,分布式、微服务下有多个tomcat实例,之间的session无法共享
  • 解决: 负载均衡器通过特定算法如IP哈西,保证同一用户的请求始终路由到同一服务器。(失去负载均衡的灵活性)session复制,所有服务器同步session变更。(带宽消耗大)集中存储,将会话数据存储在外部,如redis客户端存储。(安全性挑战)
  • 采用后端生成token存入redis,前端请求头携带token校验身份 方案,并通过两层拦截器解决token刷新TTL问题(背景是有些页面不要求登录即可访问),先拦截所有请求判断token有无,有则刷新并存信息与ThreadLocal,后拦截特殊路径判断是否登录(ThreadLocal中是否有用户信息),有则放行,无则拦截显示请登录 8.2.2 商户缓存
  • 查询逻辑:先查询缓存再查询数据库再写入缓存(背景:老查询数据库,压力很大)
  • 缓存更新策略有内存淘汰、超时剔除、主动更新
  • 缓存双写一致性问题:数据源来自于数据库,数据库发生变化时也要更新缓存
  • 采用先更新数据库再删除缓存的方案,但仍有问题:多线程环境下可能出现缓存正好过期去查询数据库得到旧值,更新操作完成并删除缓存(空缓存)然后旧值被写入(极小概率)
  • 解决: 设置较短的TTL,减少缓存与数据库不一致的时间窗口将策略改为 延迟双删策略
  • 引入缓存提高查询性能,必然会引出一系列问题,上面的缓存双写一致性问题为其一,其二就是缓存穿透问题,若查询本就不存在的数据,每次都会打到数据库上,增加压力
  • 解决: 缓存特殊值:查询数据库后返回特定值比如defaultNull并设置ttl写入缓存,所有命中缓存后增加判断value值一逻辑操作。问题:只能应对正常业务问题,不能应对黑客使用大量不同的key进行攻击问题(还是会全部打到数据库上)布隆过滤器:本质是BitMap+多个Hash函数,将所有有效key存入bitmap,挡在redis前多一次判断。问题:由于其特性(hash冲突问题)导致存在误判(有的不一定有,但无的一定没有)
  • 当大量缓存key同时失效或者redis突然宕机就,导致大量请求打到数据库,造成缓存雪崩
  • 解决: 给不同的Key的TTL添加随机值利用redis集群提高服务的可用性给缓存业务添加降级限流策略给业务添加多级缓存
  • 当一个高并发访问的key突然失效(热门商户),无数的请求打到数据库,造成了缓存击穿问题
  • 解决: 加互斥锁:缓存未命中则加分布式锁(set nx ex)如果失败则进行方法休眠+递归重试,成功则去查询数据库并写入缓存后释放锁。问题1:递归容易造成OOM,改为休眠+自旋重试。问题2:其他线程在重试,当缓存写好锁被释放后,又进行抢锁,改为双检加锁(在自旋过程中尝试去命中缓存),锁被释放后自旋的线程也无需在抢锁。缺点:死锁问题,且只能串行执行,性能受影响逻辑过期:缓存击穿问题主要是key的TTL到了,不设置TTL,而是吧TTL设置到value中,通过逻辑判断是否过期。重新封装一个类包含过期时间以及Object数据。判断过期后获取互斥锁(保证异步任务只提交一次),将查询数据库写入缓存的操作提交给异步线程处理(串行处理也可以)。返回过期数据。缺点:其他线程返回的是脏数据(已经过期的)总结:方案1是串行,执行加锁保证只有一个线程去查询数据库,方案2是异步执行,加锁保证查数据库写入缓存的操作只被执行一次,且先返回已经过期的数据问题:只要加分布式锁(set nx ex)就需要考虑业务未执行完锁超时过期问题,但此处业务是查询以及写入逻辑,即使锁过期导致其他线程获取锁进入逻辑,无非就是多了个线程执行缓存重建操作,但在删除锁时可能会出现张冠李戴的问题(DEL命令即使key不存在也会返回成功),无伤大雅。如果是扣减库存之类的操作就会出现超卖现象,是不允许的,需要增加watchdog。 8.2.3 优惠券秒杀
  • 全局唯一ID:规律性不能太明显,受单表数据量的限制。应当满足 唯一性、高可用、高性能、递增性、安全性。由符号位0+时间戳31bit+序列号32bit(秒内的计数器,支持每秒产生2^32个不同ID)
  • 下单业务逻辑:提交优惠券id - 查询信息 - 判断是否在活动期间 - 库存是否充足 - 扣减库存 - 创建订单
  • 超卖问题: 直接扣减库存在高并发情况下会导致超卖问题。解决:加悲观锁(太重);加乐观锁(CAS):执行sql时多一个库存容量判断是否大于0
  • 一人一单问题:在判断库存后增加 - 根据优惠券id+用户id判断是否已经下过单
  • 问题:多线程下(用户多次点击)可能同时判断出未下单,然后执行下单逻辑造成一人多单
  • 解决:加synchronized锁(判断是否已经购买+下单逻辑)保证只有一个线程执行下单逻辑,加到方法上,锁的粒度太粗,改为在代码块上加锁,用intern()方法从常量池中拿用户数据加锁,因为直接用userId的话不是同一个对象,每个线程都有自己的ThreadLocal,其中的用户信息对象是分别new的,不唯一。问题:方法被spring事务控制,如果在方法内部加锁,可能导致方法事务还没有提交,但是锁已经释放的问题(锁在方法结束时释放,但事务可能还未提交。其他线程可能读取到未提交的数据(脏读),或者覆盖未提交的修改。)
  • 通过加锁可以解决在单机情况下的一人一单安全问题,但是在集群模式(分布式)下还会有超卖问题(用户连多次点击被负载均衡到不同的服务上)
  • 解决:换用分布式锁,在判断完库存充足之后,执行逻辑前先创建锁key,这里以userId作为key(保证该用户的多次请求对应一个分布式锁)。加锁后通过代理对象执行接下来的方法(一人一单判断+扣减库存+创建订单),因为该方法加了@Transactional注解,一个非事务方法调用事务方法,事务不会生效。
  • 问题:若持有锁的线程在执行逻辑时阻塞了,导致锁超时提前释放,这时候其他线程(该用户的相同请求)就会持有锁执行后面逻辑,可能造成超卖问题。(也会出现误删问题,但不是本质问题,重点还是逻辑被执行了多次)
  • 解决:(锁误删解决,属于辅助方案),在获取锁时UUID+ThreadID作为value,在unlock()的时候判断value值是否为自己的锁。问题:unlock的逻辑不是原子的,极端情况下还是会出现误删情况,使用Lua脚本保证逻辑的原子性。(注意:解决误删问题并不能解决超卖问题,这个方案解决的是次要问题-误删锁,属于辅助手段,要想解决这里的超时释放问题得用watchdog机制)
  • 当下分布式锁:需要给锁续期解决超时释放问题,锁不可重入,主从一致性
  • 解决:Redisson中的RedLock 可重入原理:底层Hash结构+Lua脚本实现,大key标识锁是否存在,小key标识锁被那个线程持有重试原理:抢锁过程中,通过tryAcquire进行抢锁,先判锁是否存在,再判断是否属于当前线程watchdog原理:在获取锁后开启一个后台线程监控锁的ttl,超过三分之一后重置TTL 8.2.4 秒杀优化
  • 问题:当前逻辑全是串行执行
  • 解决:将部分逻辑单独提出来,异步执行,在判断用户可以下单后直接返回给用户成功,由后台完成剩下的下单操作,将判断逻辑放入redis中,库存是否足够、是否为一人一单,相应的信息存入redis中,判断后开启异步 queue 难点1:如何在reids中判断,将商品库存信息以及用户下单信息(set集合)提前存入,有库存以及set集合中没有该用户则说明可以下单。基于Lua脚本实现资格判断保证原子性,将订单id返回给前端难点2:如何知道最后下单是否成,将优惠券id和用户id封装后存入阻塞队列 开启独立线程不断从阻塞队列中获取信息实现异步下单逻辑
  • 问题:阻塞队列在JVM内存中,容易OOM;JVM挂了数据订单数据全没了
  • 解决:MQ 基于List的MQ:只支持单消费者,无法避免信息丢失(内存占用多时内存淘汰机制可能淘汰List中的数据,持久化没法保证数据100%持久),使用LPOP/RPOP命令消费消息后,消息立即从队列移除基于Stream的MQ:增加消费者组,生产可用 8.2.5 探店点赞
  • 对于其他用户发的博客可以进行点赞,开始逻辑为 直接数据库+1
  • 问题:用户可以无限点赞,应当为点赞/取消且点赞按钮高亮显示
  • 解决:增加isLike属性,标志是否被当前用户点赞;使用redis set集合判断是否点赞过,key为Blog,value为userId
  • 问题:检查Redis后到执行数据库更新之间存在时间窗口,可能导致多个请求同时通过检查,造成重复更新。
  • 点赞排行榜,显示出最早点赞的几名用户(如TOP5),有唯一性又具备有序性的 zset集合 以时间戳为score存入用户信息 8.2.6 好友关注
  • 一张tb_follow表标示关注信息,根据前端传来的id直接更新数据库保存关系信息
  • 增加共同关注功能需要求交集,利用set集合,存储用户的关注列表,userId作为key,然后用set集合的api求共同关注的用户id,关注则先存入数据库再更新redis,取关则先删除数据库再删除redis
  • 发动态时提醒粉丝,使用 Feed流 完成推送功能,采用TimeLine模式
  • 拉模式:查看时拉去所有Blog然后排序展示
  • 推模式:博主发送Blog时将信息推送给所有粉丝,就是我们在保存完探店笔记后,获得到当前博主的粉丝,然后把数据推送到粉丝的 redis 中去
  • 推拉结合:推送给活跃用户,普通用户拉取
  • 问题:因为数据是不断变化的,传统分页会导致展示重复的数据
  • 解决:Feed流的滚动分页 8.2.7 附近商户
  • redis使用GEO结构存储商家的经纬度以及店铺id,以店铺的typeId为key,将对应的商铺信息存入value 8.2.8 用户签到
  • 直接用数据表记录数据量太大
  • 解决:使用bitmap中的0,1来记录用户的签到情况
  • 吧年和月作为bitMap的key,每次签到把当天对应bitmap位置上的下标从0变为1
  • 获取某月的bitmap数据(十进制展示),与1进行与运算看看此位是否为1,从而进行签到统计(签到总数、连续签到)
全部评论
整体基本没有结构,我觉着一步一步思考是连贯的是没有太多结构的,总之挨着看下来肯定会有收获的
9 回复 分享
发布于 2025-05-06 22:44 河南
可以很全
4 回复 分享
发布于 2025-05-09 15:33 上海
牛逼,辛苦了
3 回复 分享
发布于 2025-05-22 00:21 吉林
3 回复 分享
发布于 2025-05-06 14:31 广东
谢谢佬
1 回复 分享
发布于 2025-05-29 21:34 北京
m
1 回复 分享
发布于 2025-05-29 17:06 江苏
mark学习
1 回复 分享
发布于 2025-05-28 15:35 江西
请问记这些面试够了吗
1 回复 分享
发布于 2025-05-16 17:15 美国
想问一下大家 本人力扣能力 自我感觉良好 项目经历很差 视频速过了黑马点评 而且面试的过程中 感觉面试官基本上都是出手撕 所以侥幸通过 hr电话口头offer 想问一下大家实习过程中 如果项目这些不懂 会被辞退嘛
1 回复 分享
发布于 2025-05-10 15:02 江苏
mark学习
点赞 回复 分享
发布于 01-13 23:58 陕西
mark
点赞 回复 分享
发布于 2025-11-22 18:09 北京
mark学习
点赞 回复 分享
发布于 2025-09-28 16:04 湖北
mark学习
点赞 回复 分享
发布于 2025-09-06 12:45 江苏
mark学习
点赞 回复 分享
发布于 2025-09-02 22:04 广东
mark
点赞 回复 分享
发布于 2025-07-20 14:37 浙江
mark学习
点赞 回复 分享
发布于 2025-07-13 16:00 江西
辛苦了!太厉害了
点赞 回复 分享
发布于 2025-07-12 16:04 江苏
mark
点赞 回复 分享
发布于 2025-07-03 14:24 湖北
mark
点赞 回复 分享
发布于 2025-06-24 08:58 辽宁
mark学习
点赞 回复 分享
发布于 2025-06-07 23:25 河北

相关推荐

05-06 12:25
门头沟学院 Java
点赞 评论 收藏
分享
05-23 03:07
门头沟学院 C++
作为28的双非大学生给大家分享一下我找日常实习的感受。首先很多人觉得才大二就开始找实习会不会太早了,但是我觉得作为双非学生这个时间点能找到一份垂直方向的实习非常重要,首先这能作为你大三找暑期实习的底气,其次能感受真实的职场环境,比较工作和学习的区别,在决定要不要考研上也能有一定帮助。其次就是我为了日常实习做了什么努力:第一就是确定方向,在ai大环境的影响下结合我双非学历的情况,我选择了agent应用开发这个方向。关于这个岗位我的一些看法就是技术变化太快了,我只恨为什么没有早一点接触到,早一点说不定能吃些风口红利。第二就是学习岗位的相关技术,说实话我不知道从何说起,我没有经过系统化的看网课学习,因为我觉得看网课很慢,信息密度太低了,所以我的所有知识来源都来自ai。一开始我问了些agent的相关知识,然后ai给了我一个规则引擎的话术回答客服机器人,再然后我继续深入我了解了怎么接大模型api,怎么将大模型部署在本地。到这里我觉得这个agent好像也没有些什么东西啊。后来我刷到了一些关于agent的技术性名词讲解的视频,什么mcp啊,rag,function calling,skill,prompt我看不懂没有了解过,我就又去问ai,说mcp是一种协议,让你的agent能够使用工具,rag就是给你的agent添加一个知识库等等等等。了解到我也觉得还好也没什么,再后来我去看了跟agent应用开发岗位的相关需求,我就找那什么我不认识的专业术语,一个个问ai。什么workflow,langchain,langgraph。我就开始一个个了解,深没深入没有标准,但我自己感觉是没什么水平的。后面感觉差不多了,嗯开始做项目,最开始没有接触过vibe coding,我就把我的需求给豆包,豆包生成后我再一个个文件创建然后把代码复制过去,(现在使用了Trae后真不知道以前过的是什么苦日子😭),并且由于是第一次做项目蠢蠢的,老是报错,并且又不知道单元测试,导致我只会把报错日志复制给豆包,祈祷豆包能帮我解决但豆包很多时候是真不靠谱,那个依赖冲突总是不能解决,调用格式参数老是出错。后面在网络的宣传下,我去尝试了一下cursor,我靠真的很爽啊,我把需求给豆包让它帮我将需求专业化,再丢给cursor,一次就能跑出来完成能运行的程序,但是我研究后发现很多都是自研的组件,那不行啊我想用langchain,但是发现没有免费额度了,我去问豆包有没有免费的vibe coding工具,最终我接触到了Trae。再后来就是不停的用Trae,用Trae,我慢慢的学习到了项目的工程化,什么分层解耦微服务,测试监控数据库,日志实验发灰度(实际并没做过灰度只听说过)。接着我靠着Trae写了我人生中的第一份简历,做了两个demo,现在看来没什么价值,真的就是玩具。我试着去投了一下,呃感觉不是很好,但也可能是投递的时间和数量不对吧,根本没什么反馈,投了十份左右,只有1个找我约谈,还只是我最不会的lora微调,这东西我都是只跟着教程跑了一遍,原理什么的只知道降秩靠调整少量参数达到效果。我把简历发在了牛客想得到一些建议,也确实有收获,我知道了简历不能光堆专业术语,还得从实际应用场景下解决了什么样的问题,以及项目的各种量化指标。然后我开始就想怎么让我的简历去加上这两样东西,到现在我都还没有能完成,要是有懂的人能看到这里的话希望您能解答我的一些疑惑,首先是项目,我尝试了换各种不同的项目,但是无论什么样的项目我都觉得这个项目没有新意和差异化,HR又该如何从茫茫简历里面选到我。其次,我想要得到量化指标,但是我不知该如何下手,测试项目api的各种指标,但是那是因为底座大模型好才得到的跟我的项目好像没有什么关系,如果说是本地模型,好像数据又不怎么样,就比如我最近做了一个性能推理服务,通过读写分离,路由,语义缓存,批处理优化本地模型的响应速度和吞吐量。但是做下来发现没什么太大的效果,应该是我做的太基础了。并且我的项目没有达到能部署到服务器上的程度也不能说有多少用户,稳定性怎么样,感觉不知道写什么了。就说到这里吧,感谢您的观看。
点赞 评论 收藏
分享
评论
159
904
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务