秒杀项目面试

登录模块

采用的是用户的手机号作为用户名,登录的时候先去判断手机号是否存在,然后再判断密码是否正确。当进行密码判断时,为了保证用户的密码的安全性,我这里使用了md5进行两次加密操作,首先通过salt值对输入密码进行第一次加密md5加密从而防止网络传输的过程中密码被截取,然后在到达服务端后在进行第二次md5加密是为了防止数据库的信息泄露时用户信息被反推出来,之后再将客户端输入密码与数据库中的密码相对比。如果密码正确,则通过uuid随机生成一个token标记该用户,并向cookie中写入此token,redis中存储此token与用户信息的映射,当该用户再次登录时,从cookie中取出token,再去redis中取出与此token对应的用户信息。

秒杀模块

首先判断用户是否为空,然后去判断库存是否充足,这里为了解决超卖问题,首先在sql语句上加入了库存大于0的判断,然后还设置了唯一索引来防止一个用户多次秒杀,并且将预库存缓存到了redis当中,当一个秒杀请求到达时判断预库存是否还足够,同时判断是否已经有了该用户的秒杀订单。这里为了优化用户体验,还用上了rabbitmq消息队列,先将该秒杀请求放入消息队列中,以此实现了异步操作就可以让用户不用等待在这里,然后接收端会从消息队列中取出消息进行处理,这里就是真正的去数据库判断库存是否足够了,并且再次判断用户是否已经秒杀过了,然后进行真正的减库存,下订单,生成订单的操作,在消费者处理消息的过程中客户端会自动轮询来判断秒杀的情况。与此同时,考虑到如果对redis的访问中有过多的无效访问的话,资源开销也是较大的,为了解决这个问题,我使用了内存标记来减少对redis的访问,即设置一个map,key是商品,value在系统初始化时设置成false,当预库存不足时设置成true。当秒杀请求到达判断预库存之前会先判断该商品的value是否为true,为true就直接返回秒杀失败。

秒杀中如何处理超卖问题?

直接由数据库操作库存的sql语句如下所示。依靠MySQL中的排他锁实现

update table_prmo set num = num - 1 WHERE id = 1001 and num > 0

利用redis的单线程特性预减库存处理秒杀超卖问题
在系统初始化时,将商品以及对应的库存数量预先加载到Redis缓存中;(缓存预热)
接收到秒杀请求时,在Redis中进行预减库存(decrement),当Redis中的库存不足时,直接返回秒杀失败,否则继续进行第3步;
将请求放入异步队列中,返回正在排队中;
服务端异步队列(MQ)将请求出队,出队成功的请求可以生成秒杀订单,减少数据库库存,返回秒杀订单详情。

秒杀中如何解决重复下单问题?

  • 前端:就是客户端点击下单之后,在收到服务端响应之前,按钮置灰。
  • 服务器端:在服务端做防重/幂等的处理
    幂等:
    1.利用数据库实现幂等
    可以在订单表里添加一个字段:requestId,添加唯一索引:这样一来,如果是重复的请求,在落库的时候就会报错,为了保证幂等性,我们可以catch住这个异常,根据requestId获取订单号,然后向客户端响应订单号。

缓存和数据库数据一致性如何保证?

先删除缓存,再更新数据库。解决方案是使用延迟双删。
延时双删的方案的思路是,为了避免更新数据库的时候,其他线程从缓存中读取不到数据,就在更新完数据库之后,再 Sleep 一段时间,然后再次删除缓存。
Sleep 的时间要对业务读写缓存的时间做出评估,Sleep 时间大于读写缓存的时间即可。
流程如下:
线程1删除缓存,然后去更新数据库。
线程2来读缓存,发现缓存已经被删除,所以直接从数据库中读取,这时候由于线程1还没有更新完成,所以读到的是旧值,然后把旧值写入缓存。
线程1,根据估算的时间,Sleep,由于 Sleep 的时间大于线程2读数据+写缓存的时间,所以缓存被再次删除。
如果还有其他线程来读取缓存的话,就会再次从数据库中读取到最新值。

减库存成功了,但是生成订单失败了,该怎办?

将减库存与生成订单操作组合为一个事务。要么一起成功,要么一起失败。

密码校验

  • 用户端:PASS = MD5(明文+固定Salt) 作用:防止用户的明文密码在网络上进行传输
  • 服务端:PASS = MD5(用户输入 + 随机Salt) 作用:防止万一数据库被盗,反查表得到密码

如何去减Redis中的库存?

decrement API减库存,increment API回增库存。以上的指令都是原子性的。

秒杀系统面临的问题有哪些?

高并发
超卖、重复卖问题
脚本恶意请求
数据库扛不住
加了缓存之后的缓存三大问题(击穿、穿透、雪崩)

秒杀接口地址隐藏

在秒杀之前先通过uuid随机生成一个额外的path与url拼接生成秒杀路径,然后将该path和用户id一起存入redis,这样当用户访问的时候就不是直接暴露原来的地址了,而是加上了url后的地址,就实现了秒杀接口地址的隐藏。在执行秒杀的时候,如果想要访问秒杀接口,则要先从redis中取path进行验证,判断该path是否存在,存在的话才能进行下面的秒杀活动,同时我还加上了用户验证码,也就是在获取秒杀地址的时候先通过验证码才能获得。

入口大流量限制

采取发放令牌机制(控制流量),根据商品id和一串uuid产生一个令牌存入redis中同时引入了秒杀大闸,目的是流量控制,比如当前活动商品只有100件,我们就发放500个令牌,秒杀前会先发放令牌,令牌发放完则把后来的用户挡在这一层之外,控制了流量。
秒杀令牌(token)每秒钟生成多少个?
跟随用户的请求会动态变化,令牌桶机制可以控制每秒生成令牌的个数。

防刷

进行了限流操作,将用户的访问次数保存在了redis中,每访问一次次数减1,这里设置的是5秒钟内点击5次的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值