蚂蚁一面(4月15日)

这个是电话面试,全程问项目(就是一个烂秒杀。。。)

1、一分钟自我介绍

2、这个项目你是承担什么角色呢?

      我答:自己做的小项目。。。

3、简单介绍一下,你怎么解决秒杀场景的高并发问题,说说你的思路?

4、展示商品详情,怎么提升qps?

       我主要答的使用redis来缓存商品数据。然后面试官说对于商品详情页面,进行页面静态化更好。

5、页面静态化后,一些动态数据的应该怎么获取呢?因为一个页面总有不断变化的数据,就比如评论之类的数据?(其实这题是承接上面的讨论)

      我回答的是,前端可以用ajax从后端实时获取不断变化的数据,然后再渲染回页面。(其实我不知道这样做对不对,但是面试官说了好的,应该就是对的吧)

6、验证码的作用,除了人机识别,还有别的目的吗?

     我回答的是,要求用户输入验证码之后才能进行下单操作,避免了用户频繁点击下单按钮,从而降低了服务器的负担。

7、10个请求同时过来,但是只有一件商品,那么谁能抢到这件商品?(其实这里是在问超卖的问题了)

     我回答的是:因为我会把库存先缓存到redis里面,那么哪个请求先在redis里面扣减库存成功,就能成功抢到商品。

8、用redis来扣减库存和直接用DB来扣减库存有什么区别?

    我的回答是:第一个是DB太慢了,太多请求可能会崩。然后就是感觉DB无法解决超卖的问题。

9、redis为何能解决超卖?

     我的回答是:因为redis处理请求的模块是单线程执行的,所以直接用decrease操作就是确保扣减库存的操作是原子性的,从而解决了超卖的问题。

10、那就是要用DB来解决超卖问题,应该怎么做?

     我的回答是:把DB设置为可串行化的事务隔离级别。

    然后面试官说这个办法的确也行,就相当于强制让所有事务串行化执行了,就跟redis一样了。但是,这样做太暴力了(太慢了),不适合秒杀的场景。

    面试官就说可以采用乐观锁的思想:给库存的记录加一个version的字段,每次查询库存的时候,同时查出当前库存和当前版本号,最后在进行update操作的时候,可以加一个where子句,判断版本号是否等于之前查出来的版本号,如果相等,则说明还没有其他事务修改过库存值,所以本次修改成功。当然,update的时候也要相应的把版本号加一。如果发现版本号已经不同了,那么说明库存已经被其他事务修改过了,那么这个update语句就不会执行,然后业务逻辑就可以进行相关判断,直接给前端返回抢购失败,让用户重新抢购即可。

   面试后(面试时太紧张了,根本无法进行太多的深入思考),我想了一下面试官所说的方案。其实,我感觉这个方案的确比直接使用可串行化的隔离级别的性能要好一些,但是也不太好,当然了,直接用DB来扛大流量是不行的,这里就是讨论一下如何直接用DB来解决超卖问题,而不使用redis来解决。其实最后那个update操作在数据库层面也会加锁的,因为涉及到修改了,所以之前面试官所说的乐观锁感觉就不太对了,这样的话,其实全部事务执行到update这条sql语句时,也相当于串行化执行了。当然,前面的查询库存操作是不用串行化的读了,这里的确提升了性能。

然后我觉得不好的原因是:既然update操作都会加锁的,那么直接因为版本号对不上,就扣减失败有点太浪费这次的请求了,因为这时很有可能剩余库存还是足够的。所以,我觉得不用加什么version字段,就是直接在update语句里面加一个where子句,判断一下当前的库存量是否大于等于将要扣减的数量即可,如果大于等于,那么就成功执行update操作,小于则失败。这样做的话,可以让更多并发的请求可以扣减库存成功,而加版本号的做法,只能让并发请求中的一个请求扣减成功。

11、看你还用到了rocketmq,还涉及分布式事务,那这里到底是做啥的?

        这里我就是讲讲rocketmq的事务型消息具体的工作流程就过了,面试官也没有追问太多。

12、看你用了ratelimiter来做限流,那么ratelimiter的机制是什么,是怎么做限流的呢?

        我就先讲了一下令牌桶算法以及漏桶算法,然后说了对于互联网领域,令牌桶算法更合适,因为可以应对一些突发性的流量,而漏桶算法只能以固定的速率处理请求。

       然后其实,虽然ratelimiter是基于令牌桶算法的,但是它比令牌桶算法还做了一些扩展,更适合应对突发性的流量。就是所谓的预消费的概念。然后后续的讨论就是围绕着这个预消费的实现进行的。

 

 

 

 


版权声明:本文为sinat_30955745原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。