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

黑马点评面试前复习

文章目录

      • 1.短信登录
        • 1.1 问题1:基于session你是如何实现短信登录的?
        • 1.2 问题2:为什么用redis代替session存储?
        • 1.3 问题3:如何基于redis实现短信登录?
        • 1.4 问题4:用户一直在访问的过程中,突然用户登录的redis过期?
        • 1.4 问题5:上述拦截的路径都是需要登录的,如果用户访问的是不需要登录的怎么办?token还是会过期了
      • 2.商铺查询缓存
        • 2.1 问题1:请你谈谈添加redis缓存的逻辑
        • 2.2 问题2:缓存更新策略有哪些,一般如何选择?
        • 2.3 问题3:操作缓存和数据库是删缓存还是更新缓存?
        • 2.4 问题4:一般是先删缓存还是先操作数据库?
        • 2.5问题5:什么是缓存穿透?如何解决缓存穿透问题?
        • 2.6问题6:什么是缓存雪崩?如何解决缓存雪崩问题?
        • 2.7 问题7:什么是缓存击穿?如何解决缓存击穿?
        • 2.8问题8:逻辑过期时间你具体是怎么设置进去的呢?
      • 3.优惠券秒杀
        • 3.1问题1: 秒杀订单的主键一般如何设置
        • 3.2问题2:实现优惠券秒杀下单的流程是如何的?
        • 3.3 问题3:为什么会出现超卖问题?如何解决超卖问题?
        • 3.4 问题4:乐观锁解决失败率高什么情况如何解决?
        • 3.5 问题5:如何实现一人一单的功能呢?
      • 4.分布式锁
        • 4.1 问题1:锁监视器一般一个jvm对应一个,如果集群模式下如何保证锁成功?
        • 4.2 问题2:什么是分布式锁?如何使用
        • 4.3 问题3:另一个方法想要调用定义了事务的方法,事务如何生效?
        • 4.4问题4:线程1业务阻塞锁超时释放,导致线程2获取锁业务没执行完,线程1释放锁问题如何解决?
        • 4.5问题5:判断锁标识通过到释放锁中间业务阻塞,这可能导致释放别的线程的锁,如何解决?
        • 4.6问题6:基于setnx实现的分布式锁有哪些可以优化的地方?
      • 5.秒杀优化
        • 5.1问题1:上述秒杀都在mysql实现,效率较低如何优化?
        • 5.2 问题2:基于阻塞队列实现会有什么问题?

1.短信登录

1.1 问题1:基于session你是如何实现短信登录的?

1.用户提交发送请求验证码。后端校验用户手机号是否正确,正确的话先保存验证码和手机号到session,并返回验证码到前端
2.用户点击登录。校验手机号和验证码是否和服务端存储再session一致,一致再判断手机号再数据库是否存在,存在,保存到session中。不存在用户信息保存到数据库,再写入session中
3.实现登录校验。自定义一个登录拦截器,获取请求中携带的sessionid,再从session中找到对应的user信息,并保存用户信息到ThreadLocal当中,然后放行

1.2 问题2:为什么用redis代替session存储?

1.session只能存储在某一个tomcat服务器内,如果出现多台tomcat前端访问并不知道自己的信息存储在哪一台,因此需要使用redis存储session,并且redis也刚好符合内存存储,可以实现数据共享,并且是键值对形式存储

1.3 问题3:如何基于redis实现短信登录?

1.用户点击请求验证码。后端生成验证码,并把(手机号,验证码)设置为键值对存储到redis中,并设置有效期
2.用于点击登录的时候,校验手机号通过,判断发送的验证码和redis中该手机号存储验证码是否一致,通过的话。查询数据库,用户信息以Hash形式存储到redis中,其中以UUID生成的随机值作为key(token),并将其返回给前端。并为redis这组数据设置30min有效期

1.4 问题4:用户一直在访问的过程中,突然用户登录的redis过期?
  1. 依然可以在登录校验中进行设置,登录拦截器中获取前端传递的token,从token中获取redis用户,并将用户保存到threadLocal当中,并重置时间为30分钟,因此只要有请求经过了拦截器,就会刷新时间
1.4 问题5:上述拦截的路径都是需要登录的,如果用户访问的是不需要登录的怎么办?token还是会过期了

1.再添加一层拦截器,拦截所有请求路径,把保存ThreadLocal和刷新的动作都放在这里执行 。第一个拦截器没有token或者没有用户直接放行。第二个拦截器判断ThreadLocal是否有值,无就拦截

2.商铺查询缓存

2.1 问题1:请你谈谈添加redis缓存的逻辑

1.用户发起请求,先到redis中查询缓存,缓存命中返回,未命中,查询数据,数据写入redis,再返回给前端

2.2 问题2:缓存更新策略有哪些,一般如何选择?

有内存淘汰,超时剔除,主动更新。内存淘汰是redis内部内存不足,自动淘汰部分数据。超时剔除是给缓存添加过期时间,到期自动删除。主动更新是编写业务逻辑,修改数据库的同时修改缓存。
低一致性需求时:内存淘汰机制。如店铺类型的查询缓存
高一致性需求时:主动更新+超时剔除。如店铺的详情信息

2.3 问题3:操作缓存和数据库是删缓存还是更新缓存?

一般选择删缓存,更新数据库,直接删除缓存,等查询的时候再更新缓存(事务保证同成功/失败)。如果是更新缓存的话,如果数据库更新N次,缓存也要更新N次,压力较大

2.4 问题4:一般是先删缓存还是先操作数据库?

一般是先操作数据库再删缓存。如果是线程1先删缓存,线程2查缓存未命中,查数据库,更新缓存。线程1再更新数据库,此时容易出现数据不一致性的问题。缓存操作一般是微秒级别的,更新数据库较慢,因此这种情况容易发生。
先操作数据库再删缓存。可以大大避免这种情况。先执行慢操作,再执行快操作,降低两者之间其他线程趁虚而入的可能性。

2.5问题5:什么是缓存穿透?如何解决缓存穿透问题?

缓存穿透指的是客户端请求的数据在缓存和数据库中都不存在,这样缓存不会生效,请求都打到数据库里面。
被动: 采用缓存空对象的形式,存到redis中,并设置较短的过期时间
主动:增加id复杂度,做好基础的格式校验,加强用户权限

2.6问题6:什么是缓存雪崩?如何解决缓存雪崩问题?

缓存雪崩指的是同一时段大量缓存的key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
给不同的key的TTL添加随机值
给业务添加多级缓存

2.7 问题7:什么是缓存击穿?如何解决缓存击穿?

缓存击穿问题也称为热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效,无数请求访问数据库带来巨大压力。
解决方案:给缓存重建加互斥锁,一个重建,其他线程等待。或者设置逻辑过期时间,交给另一个线程做缓存重建逻辑(开启互斥锁),自己返回旧数据给请求。前者维护一致性,后者维护可用性

2.8问题8:逻辑过期时间你具体是怎么设置进去的呢?

重新定义一个类,定义逻辑过期字段,和data字段用来存放原本的店铺数据。然后函数new这个类,把这两个字段的数据放进去

3.优惠券秒杀

3.1问题1: 秒杀订单的主键一般如何设置

使用全局ID生成器,(符合位+31位时间戳+32位序列号),序列号是redis自增的数据。
也可以使用UUID生成,但是都是随机的。不够友好

3.2问题2:实现优惠券秒杀下单的流程是如何的?

前端提交优惠券的id,查询优惠券信息,判断是否开始或结束,判断库存是否充足,都满足就返回订单的id给前端

3.3 问题3:为什么会出现超卖问题?如何解决超卖问题?

库存剩下1的时候,100个线程进来查询,有部分刚好同时查询到库存等于1,都执行扣减操作,就会出现超卖问题。
解决超卖问题:1.版本号法,数据库字段增减一个版本号字段,修改了库存,版本号加一,其他线程修改判断不一致就停止修改
2.CAS法:直接拿库存本身做判断 ,比较数据有没有发生变化
总结:更新时候查询的版本和之前查询到的版本是否一致
3.悲观锁,直接给更新的部分加锁

3.4 问题4:乐观锁解决失败率高什么情况如何解决?

库存大于0的时候,就让他执行更新操作,不是更新查询的库存和之前的库存一致。因为库存大于0的时候并发修改时不会造成超卖问题的

3.5 问题5:如何实现一人一单的功能呢?

扣库存之前,添加判断订单表里面用户id和优惠券id是否已经存在,存在就拒接执行。同时给这段代码加悲观锁方案(因为乐观锁方案是用在更新操作上的)

4.分布式锁

4.1 问题1:锁监视器一般一个jvm对应一个,如果集群模式下如何保证锁成功?

使用分布式锁方案,jvm外部的一个锁监视器

4.2 问题2:什么是分布式锁?如何使用

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
利用redis的setnx方法实现互斥效果,并设置超时释放,如果获取锁了返回true,其他线程想获取就会返回false

4.3 问题3:另一个方法想要调用定义了事务的方法,事务如何生效?

因为事务时被spring生成动态代理得,直接调用该方法,使用得时本地方法,没有事务功能,所以要用AopContext.currentProxy().对应方法获取到代理对象,此时该方法就有事务功能
同时pom文件添加aspectjweaver依赖
启动类添加注解暴露代理对象@EnableAspectJAutoProxy(exposeProxy=true)

4.4问题4:线程1业务阻塞锁超时释放,导致线程2获取锁业务没执行完,线程1释放锁问题如何解决?

释放锁的时候,添加一个锁标识,判断是不是自己的锁,再决定是否释放锁

4.5问题5:判断锁标识通过到释放锁中间业务阻塞,这可能导致释放别的线程的锁,如何解决?

需要判断锁标识和释放操作的原子性
使用lua脚本实现分布式锁的释放锁逻辑,主要调用的是redis.call方法
使用RedisTemplate调用lua脚本,stringRedisTemplate.execute()方法

4.6问题6:基于setnx实现的分布式锁有哪些可以优化的地方?

1.不可重入问题
2.不可重试。获取锁只尝试一次就返回false,没有重试机制
3.超时释放。原本业务执行时间就较长
4.主从一致性。如果Redis提供主从集群,主从同步存在延迟,当主宕机时,从未同步完成主的锁节点,新的线程进来就又会setnx,导致锁失效。
解决方案,推荐使用redisson(内置分布式锁的实现方案等等)
redisson也可以实现可重入的作用,实现原理何Reentertlock一致,内部维护一个锁计数器。
利用watchDog延续锁时间,利用信号量设置锁重试等待
Redisson的multiLock,设置多个独立的redis节点,所有节点都获取可重入锁,才算获取锁成功

5.秒杀优化

5.1问题1:上述秒杀都在mysql实现,效率较低如何优化?

将判断库存和一人一单的功能放在redis执行,通过Lua脚本实现。生成订单,先返回给前端。至于真的下单的操作异步执行,通过阻塞队列操作就行。

5.2 问题2:基于阻塞队列实现会有什么问题?

1.jvm内存限制问题,超出jvm内存溢出
2.jvm内存安全问题,服务重启阻塞队列内容丢失

相关文章:

  • 事件驱动架构:从传统服务到实时响应的IT新风潮
  • MySQL 高可用
  • 光谱相机的空间分辨率和时间分辨率
  • 聊一聊接口测试的一致性如何处理?
  • h5,原生html,echarts关系网实现
  • 金融问答系统:如何用大语言模型打造高精度合规的金融知识引擎
  • 数据库故障排查指南:从入门到精通
  • 卡顿检测与 Choreographer 原理
  • 20250516使用TF卡将NanoPi NEO core开发板出厂的Ubuntu core22.04.3系统降级到Ubuntu core16.04.2
  • 视频抽帧并保存blob
  • 用户现场不支持路由映射,如何快速将安防监控EasyCVR视频汇聚平台映射到公网?
  • 分布式锁: Redisson红锁(RedLock)原理与实现细节
  • TC8:SOMEIP_ETS_029-030
  • R语言如何解决导出pdf中文不显示的问题
  • 【C++】 —— 笔试刷题day_30
  • 现在环保方面有什么新的技术动态
  • Python - 爬虫;Scrapy框架之items,Pipeline管道持久化存储(二)
  • 云计算与大数据进阶 | 26、解锁云架构核心:深度解析可扩展数据库的5大策略与挑战(上)
  • 主流数据库运维故障排查卡片式速查表与视觉图谱
  • 25-05-16计算机网络学习笔记Day1
  • 圆桌丨全球化博弈与人工智能背景下,企业如何落地合规体系
  • 美联储官员:美国经济增速可能放缓,现行关税政策仍将导致物价上涨
  • 博物馆日|为一个展奔赴一座城!上海171家博物馆等你来
  • 嫩黑线货物列车脱轨致1名路外人员死亡,3人被采取刑事强制措施
  • 国家统计局:2024年城镇单位就业人员工资平稳增长
  • 王伟妻子人民日报撰文:81192,一架永不停航的战机