记一次蚂蚁金服的面试经历
本文转载自:微信公众号【Java极客技术】 作者: 子悠
博客地址:http://www.justdojava.com/2019/03/28/cd-ali-interview/#
微信公众号地址:https://mp.weixin.qq.com/s/7M66smtt_pTlRNtfGMS2kQ
2015在实习的时候,当时一个一起实习的朋友在2019年3月份的时候突然在微信上找我,问我要不要面试下蚂蚁金服。问了下相关信息才知道他在2018年11月的时候进到蚂蚁金服,现在招人就想到了我,问我要不要试一下。
刚开始还是有所顾虑的,因为毕竟是大厂,进去应该不容易,但是这个朋友进去了,想想应该也没有很难吧,毕竟当时实习的时候,他技术并不怎么样。但是毕竟过去好几年了,现在人家可能变厉害了。所以一开始并没有急着提交简历,而是说准备下再提交简历。然后就准备了一周,写简历,刷题,在网上找蚂蚁金服的面经。提交了一份简历,然后发现简历上面没有写学历,幸好他还没提交,就修改了下重新发了一份,然后他又给我提了几个建议,所以又改了一版,才最终提交。
提交简历后的第二天下午,上班的时候蚂蚁金服的面试官打电话过来了,说要面试,当时正在上班,就说了下不方便,就约了当天晚上再面试。谁知道当天小组因为来了新人,晚上要聚餐,所以没办法,就厚着脸皮给面试官发了短信,说了下晚上临时有事不能参加,想约下第二天或者周末。没想到面试官很理解,主要提出第二天晚上八点面试,短信上还让我好好准备,好好加油。
题外话:
有时间冲突的时候及时跟面试官沟通,往往第一面是技术面,大家都是做技术的,能理解的。
平时多交点朋友往往会有意外的惊喜
电面一
第二天晚上六点多快七点的时候面试官提前打电话了,这天是周五幸好及时下班,原本是想着早点下班回去再准备准备,谁知道电话来的那么突然,刚点好晚饭,还没来得及吃。既然电话都打来了,那就面呗,就到店外面面试了。
流程
1、2分钟的自我介绍
大致讲了自己的姓名,毕业院校,哪年毕业,个人爱好以及平时空闲时间做点什么,这个如实回答就好。因为之前有面试过,所以准备过。建议可以自己提前写下来,多说几遍,找点感觉。
2、你自己认为自己最熟悉的技术是什么?
这个就因人而异了,每个人熟悉的东西都不一样,一定要说自己最擅长的东西,不要给自己挖坑。因为面试官下一步就会根据你的回答进行提问。对于我来是,工作了几年学的东西多而杂,没有什么很深入的,但是总不能说没有吧,所以就说了 Java 开发比较多,所以 Java 语言熟悉多一点。然后面试官就说:“好,那我就问你一点 Java 语言方面的。”
3、 HashMap 底层实现原理是什么?
这个作为一个面试必问的题目,所以我还是提前准备过的,看过源码。所以这个问题不是问题,答完,面试官说回答的对了。
HashMap,HashTable,ConcurrentHashMap 面试必备,针对1.7和1.8的不同实现加以说明。包括底层的数据结构,Hash 碰撞生成链表,Java8的链表转红黑树。
4、Java 的多线程有没有使用过
根据自身情况,用过就用过,没用过就没有用过。我回答有简单的使用过,但是使用的场景不多。面试官也就没追问了,说了没关系,就继续。
5、讲一下线程池,以及实现固定大小线程池底层是如何实现的?
讲了下四中线程池,单一线程池,固定大小线程池,缓存线程池,定时线程池。但是关于固定大小线程池底层是如何实现的,回答的不好,面试官直接问底层的源码是不是没看过,就说是的。面试官说没关系。。。
追加:线程池底层都是通过
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
来实现的。
corePoolSize
: 表示需要设置的线程个数;
maximumPoolSize
: 线程池允许的最大线程个数;
keepAliveTime
: 空闲线程存活的时间,超过这个时间就会被回收;
unit
: 存活时间的单位;
workQueue
: 需要执行的任务队列。
threadFactory
: 线程工厂,用于创建线程,一般用默认的即可;
handler
: 拒绝策略,当任务太多来不及处理,如何拒绝任务;
拒绝策略:
直接丢弃(DiscardPolicy)
丢弃队列中最老的任务(DiscardOldestPolicy)
抛异常(AbortPolicy)
将任务分给调用线程来执行(CallerRunsPolicy)
6、Redis 为什么这么高效,使用的场景是什么?
回答了一下我们使用 redis 做缓存和登录 session 存在的场景,以及 redis 是单线程的。
1、完全基于内存,大多数请求都是内存操作,非常快速;
2、数据结构简单,操作简单;
3、采用单线程,避免了不必要的上下文切换和竞争条件,不存在多进程或者多线程的切换,不用考虑锁带来的性能消耗;
4、使用多路 I/O复用模型,非阻塞 IO
7、分布式服务是否了解,zookeeper,dubbo 是否使用过?
关于 zk 和 dubbo 这块用的不多,zk 主要是在使用 kafka 的时候会用到,但是不涉及原理上面的研究。dubbo 虽然项目中有用过,但是并不是很深入,就没说用过,直接说没用过。
8、幂等概念有没有了解过
幂等性是数学上的含义是对于参数 x,f(x)=f(f(x));比如绝对值函数。
在分布式环境下表示的是对于同样的请求,在一次或者多次请求的情况下对系统的使用资源是一样的。保证失败重试不会导致提交两次。
方法:
带版本号的方式;
采用数据库唯一索引方式;
9、常用的数据库是什么?
我们常用的数据库是 MySQL,所以就回答了 MySQL。
10、MySQL 的事务特性有哪些?
- 首先事务是作为单个逻辑工作单元执行的一系列操作,这些操作作为一个整体一起向系统提交,要么都执行,要么都不执行。事务是一个不可分割的逻辑单元。
- A(原子性)事务的各步操作是不可分的,保证一系列的操作要么都完成,要么都不完成;
- C(一致性)事务完成,数据必须处于一致的状态;
- I(隔离性)对数据进行修改的所有并发事务彼此之间是相互隔离,这表明事务必须是独立的,不应以任何方式依赖或影响其他事务;
- D(持久性)表示事务对数据处理结束后,对数据更改必须持久化,不管是事务成功还是回滚。事务日志都能够保持事务的永久性。
11、如果现在一台生产的数据库挂了怎么处理?
首先这题没有 get 的面试官想问的点是什么,所以就根据自己项目本身的情况做答了。我们项目生产上的数据库是有主备的,在主数据库挂掉的情况下是会切换到备数据库,先保证业务的稳定性,然后在对崩溃现场进行保留,方便后续分析问题,找到原因。这里面试官追问了一下,我们主备的切换是自动的还是手动的,这个由于是公司运维团队负责的,自己本身不是特别清楚,但是根据对公司运维团队的了解,应该是自动的。所以就这样如实的回答了。
12、数据库如何实现 rollback 的?
数据库在写入数据之前是先讲对数据的改动写入 redo log 和 undo log,然后在操作数据,如果成功提交事务就会讲操作写入磁盘;如果失败就会根据redo log 和 undo log 逆向还原到事务操作之前的状态。
13、工作这么久你遇到的最难的技术点是什么?
我这边根据具体的工具经理,回答的是 kafka 的初次使用,因为当时是公司内部第一个引入 kafka,之前没有小组使用过,所以要采很多坑。并且那个时候 kafka 还没有发布1.0版本,官网和网上提供的版本很杂乱不兼容。
14、用过Kafka 的话说下 Kafka优缺点有哪些?
- Kafka 是一个高吞吐量的消息队列。基本的组件有生产者,消费者,node 节点,生产者负责生产消息,将消息发送到指定的 topic 或者 partition 当中。
- 每个 partition 可以有多个分区副本,并且存放在不同的 broker 节点上,保证数据的安全。partiton 的底层是根据 segment 段存放的一系列日志文件,文件里面存放的具体的消息内容,每条消息都有一个唯一的 offset 偏移量,并且是按照磁盘顺序存放的。由于磁盘是顺序读写,所以 kafka 可以有很高的吞吐量。磁盘的顺序读写比随机读写的性能高很多。
- 每个消费者都属于一个消费者组,可以消费指定 topic 下的数据。
15、TCP/IP 协议是如何保证数据可靠性的?
首先 TCP是面向连接的传输协议。主要通过消息确认和重试机制来保证数据传输的可靠性。
电面二
二面的时间是在第二周,周四下午的时候打电话过来,问是否可以面试。但是当时在上班就说不方便,能否周五晚上面试。面试官说可以。谁知道,第二天中午还没下班就打电话过来说面试,可能本来周五大家各自事情都多吧,他也想尽快搞完。我这边被突然的面试电话给搞懵了一下,想着不是约好了晚上么,怎么搞突击。。。但是没办法,已经推过一次,没好意思再推掉。就说了我要找个安静地方,稍等下。
整个面试过程不是很好,主要是在公司内部找了个没人的地方,说话声音都不敢大,而且还经常有人经过,来来回回的。感觉这点没有决策好,也是这次的一个遗憾。所以大家电话面试的时候一定要找个没人的地方。
流程
1、先进行自我介绍,然后介绍自己做过的项目,从项目流程架构设计等方面介绍
根据个人经历说了自己所做的项目,以及流程和架构方面,因为是自己参与的项目,所以整个流程说的还是很流畅的。毕竟自己很熟悉。这块尽量多从几个方面讲,流程,架构,设计等。
2、HashMap 的查询时间复杂度
理想情况下是 O(1)的,但是实际中会出现 hash 碰撞,导致无法达到效果。
3、LinkedList和ArrayList的区别
- LinkedList 底层是基于双向链表实现的,而 ArrayList 底层是基于动态数组实现的;
- 查询的时候 LinkedList 的效率要低于 ArrayList,因为 LinkedList 需要遍历链表,而 ArrayList 底层数组根据下标直接获取数据。
- 插入删除数据的时候,LinkedList 效率比ArrayList 效率高,因为 ArrayList 在数据多的情况下会进行数组扩容或移动数组。
4、多进程与多线程在编程上面有什么需要注意的
首先进程是资源分配的最小单元,线程是任务调度的最小单元
对比维度 | 多进程 | 多线程 | 总结 |
---|---|---|---|
数据共享、同步 | 数据共享复杂,需要用IPC;数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂 | 各有优势 |
内存、CPU | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 线程占优 |
创建销毁、切换 | 创建销毁、切换复杂,速度慢 | 创建销毁、切换简单,速度很快 | 线程占优 |
编程、调试 | 编程简单,调试简单 | 编程复杂,调试复杂 | 进程占优 |
可靠性 | 进程间不会互相影响 | 一个线程挂掉将导致整个进程挂掉 | 进程占优 |
分布式 | 适应于多核、多机分布式;如果一台机器不够,扩展到多台机器比较简单 | 适应于多核分布式 | 进程占优 |
5、ThreadLocal的使用场景
ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。
6、堆内存和栈内存有什么区别
- 堆内存是线程共享的,栈内存是线程私有的;
- 堆内存用来存放由new创建的对象和数组,栈内存中存放一些基本类型的变量和对象的引用变量;
7、堆排序时间复杂度
排序名称 | 稳定性 | 平均时间复杂度 | 最好时间复杂度 | 最坏时间复杂度 |
---|---|---|---|---|
桶排序 | 不稳定 | O(n) | O(n) | O(n) |
基数排序 | 稳定 | O(n) | O(n) | O(n) |
归并排序 | 稳定 | O(nlogn) | O(nlogn) | O(nlogn) |
快速排序 | 不稳定 | O(nlogn) | O(nlogn) | O(n^2) |
堆排序 | 不稳定 | O(nlogn) | O(nlogn) | O(nlogn) |
冒泡排序 | 稳定 | O(n^2) | O(n) | O(n^2) |
选择排序 | 不稳定 | O(n^2) | O(n^2) | O(n^2) |
8、如果优化数据库的数据查询,另外应用层上还能如何优化?
1)数据库层面上:
- 除了主键索引,唯一索引之外,对于常用的查询字段也要加索引。查询的时候尽量使用主键索引,因为MySQL 的 InnoDB 的主键索引索引的是整行数据,而普通索引索引的是主键,会有回表操作。当然索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,需要酌情考虑。
2、优化查询语句,尽量采用确认性查询语句,减少 or,in,not in,%xxx%语法的使用。
2)应用层面上:
- 采用缓存机制,将常用的数据进行缓存,增加访问速度;
- 分库分表,读写分离,将数据分开读写,提升性能
9、强一致性,弱一致性,最终一致性
- 强一致性:对于更新后的数据,要求后续所有节点的任何操作都要获取最新值的情况;
- 弱一致性:对于更新后的数据,后续节点的数据操作可以是新值,也可以是旧值,通过一段时间后后续节点对数据的操作都是新值;
- 最终一致性:是弱一致性的特殊形式,存储系统保证在没有新的更新的条件下,最终所有的访问都是最后更新的值。
10、有一个一百万行的文件,内部是购买的商品ID,如何获取到购买最多的前一百个商品。
- 思路:首先考察的肯定是大数据处理方案,这些数据肯定不能一次性读取到内存,那就需要拆分,将数据分隔处理。假设要分隔为 n 个文件。
- 分隔:如果 ID 是整型的话,可以直接采用取模(id % n)的方式;如果 ID 是字符串可以先计算 hash 值然后再取模(hash(x) % n)的方式,将相同 ID 的商品分到同一个文件中。
- 针对每个小文件进行 top100的排序,返回购买最多的100个商品 ID
- 根据 n 个文件中的100个 ID,在进行一次排序,即可得到需要的数据。
小结
首先很感谢内推的那个朋友才有了这次的面试机会,虽然结果不尽人意,但是为自己的学习成长之旅增加了一些精彩。
然后说下这次的面试体验,总得来说,感觉不是很好,因为几次打电话都是在公司上班期间,毕竟在公司接到面试电话还是很不好的。没有按照约定的时间点打电话,可能是我接触的少,不知道其他公司是怎么样的,总觉得这样不太好。
身为一个目前在职三年,工作在深圳这样的大环境下,还是有很大压力的。以前上学的时候想着什么时候能月入过万应该就不愁什么的,但是渐渐的发现,即使月入过万也还是过不好生活。周围比你厉害比你强的人多了去了,你能做的就只有不断的学习,不断的进步。