阿里一面凉经

阿里一面(凉经)

先说明我大二开始接触计算机学习总共不到两年,很菜加上我比较容易紧张,所以回答的有些不尽人意,事后反思了一下确实很多地方是有问题的,大家如果看出什么问题请告知我一下,我一定虚心接受。

1.主体的流程
  1. 自我介绍(不过多赘述了)

  2. 挑选一个项目进行深入探讨

  3. 八股拷打

  4. 算法

2.项目拷打

在自我介绍里我大概介绍了一下我的三个项目,相比字节的面试官明显流程更加固定,而且也更正式,不会会和你多聊一些学习方面的经历啥的,就是直接进入主题。

在这里我选的苍穹外卖加黑马点评的融合版,因为我的其他两个项目一个是微服务,一个是Agent应用,聊起来都太广泛了,我不确保自己能够完全把细节方面全部讲透。下面就是我们对话的大致内容:

面试官:现在把你的这个项目从模块功能,数据流向,用到了那些东西,具体干了什么讲清楚一下。

我:分别介绍了包括套餐,菜品,口味,商家,用户,订单这些模块,然后讲了商端用了vue3,用户端用的微信小程序,后端主要用了redis缓存数据,解决并发三刺客(击穿,雪崩,穿透),使用websocket进行来单提醒和催单提醒

面试官:现在我们针对秒杀业务来具体聊一聊吧,为什么要用锁

我:因为在无锁的情况下,此时高并发多线程的情况下会造成超卖的问题,我首先采用了乐观锁,利用库存作为版本号,当库存大于0的时候我们认为可以继续购买,经过实际的测试我发现他会出现一人多单的问题,在我们的业务规则里是不允许的,此时我们尝试使用悲观锁,使用了synchronized来进行加锁,但是synchronized是jvm层面的在多实例部署的情况下,会出现失效的情况,然后我们尝试使用redisson分布式锁加lua脚本来实现锁的功能。

面试官:所以最后是用了锁来解决的是吧,那么你是怎么保证吞吐量的呢

我:我采用了Kafka对非数据库操作和数据库操作进行了异步处理


这个地方我的大脑已经绕晕了,这里把上一个锁的方法和这个方法记混了,回答错了,在写这篇文章的时候我才发现

面试官:你的锁的粒度是多大呢

我:我是对数据库操作的方法进行加锁的(事实应该是对用户ID尝试加锁,之后对锁是否成功进行判断来决定是否进行订单创建的工作)

面试官:你怎么能对方法加锁呢

我:我是把数据库操作单独写了一个方法,在另外一个方法调用的时候

面试官:还是不对,在你锁的哪里就冲突了,和后面的还是没有关系

我:我在redisson哪里对用户的ID加了锁,所以多个用户之间是不冲突的

面试官:用户加锁是吧这样确实可以,你是说你用了lua脚本是吧,能不能具体讲一讲lua脚本具体干了什么

我:首先在信息进来之后我要对库存先进行判断,之后再判断他有没有下单过,如果符合购买的资格我们在redis层面对库存-1,我们给他返回一个值比如说是2,代表用户有购买资格,之后我们再对数据库进行库存扣减

面试官:你的Kafka具体对那一部分进行了异步操作

我:我把创建订单那一部分给了Kafka,具体的创建订单的操作是在Kafka的消费者那边完成的

面试官:那么你在消费者那边完成订单的创建,用户是怎么能够知道自己的秒杀劵已经抢购成功了呢(这里是黑马课程的漏洞,教程里卖也没有实现)

我:抱歉,这方面当时没有考虑到

面试官:那么你的redis库存扣减和数据库扣减是分开的,现在我在数据库下单失败,那么redis的库存是不是和数据库的库存出现了数据不一致的情况(这里也是黑马课程的漏洞,不过在上一次面试结束后梳理项目是我自己发现了这个漏洞)

我:这里我使用了Kafka的异常捕获,当下单失败后,在捕获异常之后我对redis的数据进行了一个修改

面试官:那么数据是具体怎么修改了呢

我:首先我们要移除用户信息,毕竟他没有下单成功,其次就是我们要把库存加回去

面试官:那具体是怎么加的呢

我:我就是单纯对库存加了一

面试官:那会不会出现问题呢,现在我给你一个场景,比如你现在要进行回滚数据,然后那边要读库存,会不会出现什么问题呢,怎么解决

这里我不确定我的回答,因为前面的redis是单线程的,读写会造成读到数据马上被修改,也就是我们说的不可重复读的现象,但是后面的redis版本好像是多线程了,我就回答了读写冲突

我:思考了一会,说可能会有读写冲突的情况吧,我能想到的方法就是加读写锁,这里又会有吞吐量的问题发生,我没有更好的方法了

3.八股拷打

这里大家看看问题就行,确实问到我的弱点上了,这部分是我看的最少的

面试官:嗯,我们来一些基础问题吧,redisson是怎么实现的呢

我:它的底层是一个hash一样的结构,大KEY存储自己定义的值,小KEY存储线程ID,value存储重入的次数,它是一个可重入的锁

面试官:嗯,你回答的是它底层代码层面的,我的意思是reids集群怎么实现的分布式锁

我:redis是用setnx。。。打断

面试官:你还是没有理解,我是说redisson是利用redis集群怎么实现的

不知道这里是我听错了还是记错了,我一直没有理解,可能是我的知识层面还不够

我:抱歉,这里我没有涉猎

面试官:jvm了解吧,给我讲讲jvm有几个区,像栈,堆啊这些

我:方法区,栈,堆,jdk8多了元空间,jvm这里我了解的不是很多

面试官:哪垃圾回收有了解吗

我:有标记整理,标记清除,复制整理,对于新生代,我们采用复制整理,在满的情况下我们把数据从form区复制到to区,对form区进行整理,之后form和to交换,老年代使用标记整理啥的

面试官:老年代就有太多算法了不说了,现在我给你一个场景啊,比如你说你刚刚把新生代垃圾回收完,form和to进行交换,此时新进来一个是放在哪里呢

我:思考了一会,应该是还是form区吧(这里确实懵逼了,不知道,随便答了一个,我不知道是不是还有个伊甸区放在哪里)

面试官:为什么新生代,老年代,元空间要使用不同的回收算法呢

我:新生代生命周期短,老年代生命周期相对长一些,元空间存储了一些常量值,新生代使用复制整理资源消耗会大一些,老年代使用的算法相对资源消耗少,允许有短暂的停顿

面试官:栈,和堆存储什么了解吗,比如我现在新建一个对象,分别怎么存储的

我:类的引用存储到栈,类的实例存储到堆

面试官:那么有没有特例,比如存储在栈的对象

我:抱歉,不是很了解

4.算法

求数组中第K大的数,开始先问了我堆排序的时间复杂度,我回答的很拉,拉中之拉,自己都听不下去了,又问了我快排,也回答的垃圾的批爆

之后直接让我做了,不出意外,没有写出来,快排撕出来一半,递归哪里没有写出来,我也确实排序忘的死死的了,好久以前看的了,忘的差不多了

之后也是没有给反问的机会,光速下线,一会就挂了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一入JAVA毁终身

感谢,破费了,破费了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值