又到一年金三银四的黄金跳槽季,相信很多人都在这期间蠢蠢欲动,不是正在离职,就是在纠结要不要跳槽。各大公司呢,也开始招兵买马为今年公司的发展储备人才。2019年的金三银四可以说比较特殊了,人们都说,互联网寒冬来了。各大互联网公司裁员,在互联网巨头中有京东,腾讯都裁员不少。再到2019年年初的 996,ICU 事件的持续发酵,程序员们众推了许多大公司包括阿里巴巴,腾讯,有赞等上了996黑名单。再到马云微博的声援996是员工一种福报的价值观引发众多网友反对,甚至成为众矢之的事件。这些事情必然导致今年的金三银四与往年相比有些不一样,员工和企业主都会更加理性了。这个时候还在大面积招人的公司,必然是牛逼的公司。而这个时候勇敢跳槽的人,必然是牛逼的人。
经过一些面试后,深感自己技术理解不够深入,很多停留在表面的使用上,稍有理解的也仅仅只是明白那个道理,却难以举一反三灵活应用,感觉前方的路任重而道远啊。下面是我几个印象比较深刻的面试经历,其中括号中的是我回答的内容和一些解释。
1.阿里口碑
阿里口碑面试是在2019年3月份,当时是猎头推荐的。已经通过了简历筛选,大概过几天就会有电话过来进行简单的沟通。说实话那时我内心是很激动的,因为进入阿里这样的大厂对于多数程序员来说都是终极梦想,我得到这次机会,说明我的工作经历在一定程度上得到了认可。大概过了两三天后的一个晚上,阿里的人打电话过来了
一面:
一面是电话面试,首先进行了自我介绍。然后面试官会针对你的项目介绍问一些问题,一面对技术的问的并不深入,但涉及的广度比较大,因此平时要多做准备,广泛涉猎。下面是问到的一些主要问题。
- 太平洋的大数据平台项目主要用了哪些技术,业务作用是什么,你在项目中担任什么角色。(这个问题基本如实回答就行)
- 在项目中主要使用的Java语言是吧,并发接触的多不多,说一下Java中实现线程安全的方式有哪些(这个问题能牵扯出一大堆问题。synchronize和lock锁可实现线程安全,更深层次的可以对比两种锁的实现原理来讲,当时我了解的没有那么深入就没有说,在项目开发中也会使用到concurrentHashMap和concurrent包下的原子操作类来提供并发的吞吐)
- 在Java中HashMap和HashTable的区别(我只是回答了HashMap线程不安全,HashTable线程不安全。但应该还会有一些别的区别,不然感觉回答的太简单了)
- 在项目开发过程中有使用过连接池吗(使用过,主要使用的就是阿里巴巴的数据库连接池Druid)
- 嗯,说一说数据库使用连接池和不使用连接池有什么区别(如果使用原生的JDBC,每次操作数据库时需要创建连接,使用完毕后需要关闭连接,在并发比较大的时候会因超过数据库连接上限而无法连接,造成系统响应较慢。使用连接池的话,省去了连接维护的成本同时提高系统的稳定性,降低开发成本)
- 如果原生的JDBC查询比较慢怎么优化(这个问题我比较懵,当时首先想的不是sql优化,而是原生的JDBC在客户端是不是可以缓存什么的,所以糊里糊涂的回答了不知道)
- spring boot用过吧,简单聊一下,你是怎么用的。(spring boot是spring MVC的升级版,以约定大于配置的方式极大的简化了spring MVC中繁琐的xml配置,使用spring boot只需要在maven中依赖插件就会自动加载到spring容器中,它的原理是通过springBootApplication注解实现的,springBootApplication是个组合注解,其中比较重要的是EnableAutoConfiguration注解,它可以帮助SpringBoot应用将所有符合条件的@Configuration配置都加载到当前SpringBoot创建并使用的IoC容器。实现自动化加载JavaBean,这也是spring boot这么简单的原因)
- 嗯,说一下mybatis中#和$的区别吧(这个问题简直是送分的,# 仅仅是个占位符,而美元符取的是变量值,#不会出现sql注入攻击,美元符则容易出现sql注入攻击,在开发过程中推荐使用#)
- 了解过幂等吗,在web请求中怎么实现接口的幂等。(没有使用过幂等,但我有去了解过,幂等是为了防止接口在短时间内的重复请求,一般出现在金融支付方面,由于鼠标的机械抖动导致一个支付请求连续发送了两次。可以在请求发送前,先去请求后端的一个接口得到一个一次性的票据,然后在支付时带上这个票据就可以了)
- 如果想实现一个限流的网关,怎么实现。(可以通过spring的拦截器实现,其原理的话,是通过令牌桶的方式,首先创建一个一定容量的容器,在请求来时创建一个令牌并把它放入桶中,在请求返回时移除这个请求对应的令牌。每次请求来时,首先判断容器中的令牌是不是已经满了,如果满了则直接返回这个请求告诉用户请求已经达到最大,让用户稍后访问)
- 嗯,今天面试就到这,你有什么想问我的吗(固定套路,一般碰到这种问题,大概问一下项目或是公司的一些大概情况)
二面:
一面通过后,第二天晚上口碑的电话又打过来了,不过由于当时我在洗澡没有接到,导致错过了两个电话,后来和猎头沟通之后直接约了现场面试。地点是在上海五道口,约的是周六。到达指定的楼层后首先映入眼帘的就是口碑的logo,环境也比较好。当然这栋楼并不是阿里的,只是租了几层吧。到前台做登记后,便有人领我到了一个会议室等待面试官的到来。这里还有一个小插曲,当时先进来一个人,面相比较和蔼,头发有些发白看上去应该有50左右了,先和握了手,然后还简单的介绍了一下自己,隐约记得说他是14年加入阿里的。当时我心里一愣,心想年纪这么大了,应该级别比较高吧,不至于二面就来面试我这样的级别的吧。果然不久又来一个人,看上去就年轻多了30多岁的样子,然后和那个年长的沟通了一下,意思是会议室搞错了,然后就带我去了另外一个会议室。不过这个小经历也让我感觉到,阿里还是很开放的,其实只要有能力所谓的中年危机也没那网上说的那么严重吧。嗯,题外话,下面是二面的主要过程。
- 先做一下自我介绍吧(面试官全程看着电脑,好像在看我的简历。这次我非常紧张,刚开始声音都带一点颤抖,一方面是是对阿里大厂的敬畏,二是怕说错什么,毕竟阿里的人技术肯定都很强,我怕我一说错会让他们觉得我技术很菜。。)
- 项目中主要使用的是mysql吧,说一说数据库中怎么使用索引的(数据库的索引很多,我主要使用的是唯一索引,联合索引等,在查询时尽量使sql优先走索引,以加快查询速度,少使用!=,=null这种操作来避免sql走全表扫描)
- 使用过分表分库,或是主从配置吗,简单讲一下(这块没有了解过)
- 数据库索引的实现原理讲一下(数据库索引的实现主要使用的是B+树,B+树是一种自平衡的多路搜索树,在每个非节点上不存储数据只存储索引,所有数据都存储在叶子节点上,同时所有叶子节点存在着横向的索引,以便于数据库的范围查询。这些回答其实一直在讲B+树结构本身的特点,还是没有讲出数据库为什么使用B+的核心点)
- 叶子节点存在横向索引吗(是的,这我不知道是面试官有意试探,还是他不知道这些细节。在我的记忆里,B+树的叶子节点确实存在横向索引,所以我就给了肯定的回答)
- 使用过redis吗,redis集群是怎么实现数据一致的?(这块我不了解。这里我有点懵,因为我虽然使用过redis,却没自己搭建过redis集群)
- 那你知道ZAB协议吗,简单讲一下(没有接触过ZAB协议。我真的是太紧张了,这个都答出来,这其实也就是上一个问题面试官想要了解的,ZAB协议是Paxos算法得来的。我还专门去看过Paxos算法的过程,如果面试官问zookeeper的一致性原理,我肯定能反应过来了,很可惜)
- 你的离职原因是什么(问到这,其实我感觉已经凉凉了,因为面试官没有问我几个技术问题,就开始问个人问题了,前面几个问题回答的不好吧)
- 谈一谈你的职业规划,你想往哪方面发展(首先我想提高自己的技术,然后往架构师的方向发展)
- 嗯,行,你还有什么想问我的吗
这次面试其实面到一半我就感觉要凉凉了,主要原因还是由于自己太过紧张,影响了我的正常发挥。所以不管以后遇到什么事情,自信是最重要的,回过头来想,其实阿里虽是个大厂但是问的问题基本上和普通公司区别不大,基础打扎实了,基本都能应付过来,主要还是要自信。
2.中国移动产业研究院
这个机会也是猎头推荐的,中国移动是家国企,工资给不高,平时福利待遇会好一些。这家公司我拿到了offer,不过最后没有去,主要还是薪水给的不够。年薪算下来和我现在的持平,但月薪比我现在还低。是按13薪算的。不过每个月有小几千的交通补贴。不过其实我还是蛮想去的,因为研究院主要做的方向是5G金融,算是比较前沿的领域了。现在5G还没有普及,未来不可限量。话不多说,面试过程也简单粗暴,就两轮面试,一轮技术面,二轮人事面。第一轮技术直接就是群面,在一个大会议室,大约有10来个人做在我对面。下面是主要问的问题
一面:
- 先做下自我介绍吧(坐在中间的最先发言,看起来年纪比较大,应该是这些人里面级别最高的吧)
- 嗯,我看你用spring还用的比较多,讲一下spring吧。(spring有两个核心点即IOC和AOP。IOC即控制反转就是将原本通过new对象的方式变成了由spring容器管理对象。pring默认的注入对象是单例的,可通过构造器注入,set方法注入。AOP即面向切面编程,在spring中的体现有前置拦截器,后置拦截器,事务控制等 。其底层原理是通过动态代理方式实现的。会议室坐了10来号人,实际提问的就四五个人,随机发言提问。)
- 讲一下Java的动态代理和spring的动态代理有什么区别(java的动态代理是需要代理类与被代理类实现同一个接口的,而spring的动态代理则是通过cglib来实现动态代理的,在编码上其代理类与被代理类没有直接关系。但实际上在字节码中,代理类是继承了被代理类的,它们两个是继承关系)
- 你有个项目用过spark,讲一下使用场景,什么要使用spark(在原来的系统中,有很多用户系统,用户数据分散在不同的系统中,那个场景是需要汇聚上游业务系统的用户数据,首先是将数据从数据库发送到kafka中,这个功能由另一个team做,我这是通过spark streaming从kafka中拉取数据,经过数据的清洗过滤,最终将数据存入到hbase中)
- 你在项目中担任什么角色,做了什么事情(这个项目分为两个模块,一个是实时处理,另一个是批处理跑历史数据,我是在实时处理模块中担任开发工作,主要负责从kafka消费数据到数据的清洗加工部分)
- 你说你用过Hbase,说一下Hbase的架构吧。(Hbase集群分为HMaster和HRegion,其中HMaster负责管理集群的HRegion,会存储部分元数据。HRegion是真正存储数据的节点,Hbase的一张表会根据rowkey进行散列并存储在不同的HRegion中。所有节点会通过zookeeper管理。当Hbase的客户端发送一个查询请求时,首先会提交给HMaster,HMaster会通过存储在zookeeper的HRegion元数据表信息,将查询请求的数据定位某一个节点从而加快查询速度)
- 说一下spring boot和spring MVC的区别(我觉得spring boot是spring mvc的升级版,它以约定大于配置的理念极大的简化了spring的使用成本,使得开发人员得以从繁琐的配置中解脱出来,同时spring boot内嵌了tomcat,因此spring boot打成包后可以直接运行)
- 你觉得spring boot和spring mvc是一个东西吗(我觉得可以理解为一个升级版,为什么简化spring mvc的使用,降低学习门槛。面试官的眼神中似乎对我的回答不太满意,觉得我有些概念模糊,于是又追问了下面这个第9问。不过我觉得有一些过于纠结概念了)
- 那你觉得spring和spring mvc是一个东西吗(不是,spring仅仅是一个管理对象容器的中间件,而spring mvc是一个可以快速集成第三方开源组件,提供开发效率的企业级框架。回答到此,面试官才不再追问了。。)
- 你在现在这家公司主要做了什么内容(现在公司主要从事安防行业,目前是给上海市公安局维护视频监控平台,包括去年平台的升级,我负责开发一个适配服务,因为平台升级只在市局节点升级了,分局和派出所仍然使用旧版本的系统,因此需要做适配。让所有需要调旧版本的接口全部走我这个适配服务)
- 维护工作主要做些什么内容(主要负责市局的一些小需求变更的开发工作,数据方面的问题,主要是老系统遗留下来的问题,有时会出现数据同步异常的情况,需要人工去解决,这其实也是数据同步架构导致的)
- 数据同步的问题,有解决方案吗(目前没有,因为公安局比较依赖于这个系统,日常摄像机的实时监控都需要通过这个平台,因此我们的首要工作就是保障系统的正常使用,如果想要根治这个问题,需要全节点升级系统,工作量非常大而且造成的影响也无法估计)
在没人提问之后,一面结束。总体感觉不错,虽然是群面但是个人感觉良好,碰到问题有理有据的回答,没有出现紧张的情况。最后坐在中间的那个大佬说话了,要我出去等一会。看来一面是过了。
二面:
一面过后,大概等了半个多小时。二面直接就是人事面了,当时是有点出乎我的意料的,效率这么高。人事是个中年男人,讲话有些轻声细语的。问的问题也比较简单。大致人事都会问这些问题吧
- 简单自我介绍了一下
- 问了一下离职原因
- 介绍了一下公司的情况,目前正在做的项目,发展前景等
- 谈薪阶段,说了一下公司的福利待遇。国企给的薪水不会很高,要有心理准备
3.蚂蚁金服
有几个猎头给我介绍过蚂蚁金服,但听其中一个猎头说,去年他推荐的一个人选在蚂蚁做了7个月就因为加班太严重而离职了。莫名的对这个机会有些犹豫,心里头想该不会是去填坑的吧,于是就不了了之。后来有天晚上,接到了蚂蚁金服的人给我打来电话,问我想不想试一试机会。当时真的很意外,于是便试一下自己的水平吧。面试时间是在周六,过来先做一套笔试题,面试的人很多,很大的一个会议室都坐满了埋头在做笔试题的人,看来今天是专场了。试卷难度倒也不大,主要是为了错开面试候选人的时间吧。大概过了一个小时后,我被领到一间会议室开始了面试,面试有两个人。他们首先在看我的笔试题
一面:
- 这个题怎么写的都是伪代码。(一定要写代码吗,我就用伪代码写了一下思路)
- 行吧,先做下自我介绍吧。(右边那个面试官仍然在翻看我的笔试题,给人感觉很干练,技术也很深厚。后面全程基本上都是他在提问)
- 说一下B+树吧(B+树是一颗自平衡的多路搜索树,数据都存储在叶子节点,非叶子节点存储数据,仅存储索引。在叶子节点上有横向的索引。叶子节点的横向索引可以加快范围搜索的时间)
- B+树是一颗多路搜索树,它为什么能提高查询速度,为什么不使用红黑树做数据库的索引实现呢(因为B+树的多路特性,导致B+树是一颗矮胖树,因此在往下搜索的时候减少了搜索的次数)
- 你说的对,B+树是一颗多路搜索树,但多路搜索就会快吗,一个节点上有多个子节点。这就需要横向的遍历,同样需要耗费时间,而红黑树是一颗二叉树,不需要遍历,只需判断一下就可以了。(不好意思,这我没有深入了解。<从面试官的表情可以看出他明显失望了,也没有再问。这里一定要好好看看,数据库B+树最最重要的原因,是因为磁盘,一张几千万数据的表,可能索引就会有几个G,不可能把索引全加载到内存,因此减少IO次数就是关键,这也是B+数被设计为矮胖的多路搜索树的原因>)
- 谈一下HashMap的底层实现吧,线程不安全怎么办(底层是数组加链表,在jdk1.7以后,HashMap做了优化,节点数大于8时,链表会转化为红黑树。HashMap线程设计的时候就没有考虑线程安全问题,官方也不推荐在并发情况下使用HashMap,而推荐使用ConcurrentHashMap,或是使用HashTable)
- 说一下CouncurrentHashMap的实现原理(CouncurrentHashMap使用分段锁技术,底层包含多个Segement,提供了高并发情况下的吞吐量。)
- 说一下sycorbnize的实现原理(sycorbnize是java中的常用的同步方式,在jdk1.5以前它是一把重量级锁,1.5以后对他多了优化,在使用sycornize时,它首先是偏向锁,然后升级为轻量级锁,再自旋升级为重量级锁)
- 谈一下自旋锁,偏向锁的实现原理,CAS底层是怎么实现的(自旋锁其实是一种侥幸心理,当前线程假设正在持有锁的线程会很快释放锁,因此当前线程就做空循环,即自旋。目的是避免自己进入系统调度,但这个自旋有时间限制,不会无限自旋下去。偏向锁是当前锁偏向于某个线程,即对象头中记录了某个线程的ID,当线程来竞争锁时,只需判断一下线程ID是不是自己,如果是的话直接持有锁。CAS底层是一个原子操作,它的实现是CPU级别的一个指令,在硬件上就保证了原子性)
- 那你知道实现CAS的指令是什么吗(不知道。<很意外,面试官还会问我这个>)
- 实现线程安全的方式有哪些,怎么理解线程的本地内存和主存(sycornize关键字,Lock锁。线程的本地内存在硬件上可理解为CPU的高速缓存和寄存器中的数据,而主存可理解为内存条中的内存)
- 聊一下对你成长最大的一个项目吧,可以在黑板上画一下架构图,描述一下业务流程(好的。<这个过程需要对项目有深入的理解,每个组件的原理和选型>)
- 你这个项目中用到了Spark,为什么要用Spark,怎么不用Flink(这个项目是给太平洋保险做的,他们用的是华为大数据平台的产品,因此使用的Spark。<这个问题,问的我懵的,我也不知道为什么使用Spark,我参与的时候就已经使用这个架构,这也让我吸取教训,写在简历上的项目一定要熟悉。不能简单的只是参与,面试的时候说流水账>)
- 这个架构中如果kafka数据消费的时候,由于消费端出现问题阻塞了怎么解决(你的意思是kafka取到数据后,处理的时候,数据落地到hbase时出现异常怎么处理吧,这个架构中Kafka专门有一个topic,当数据不能入库时,会把数据发回到这个topic,再走一遍流程,避免了数据的阻塞。同时形成闭环,数据不会丢失。)
- 为什么要单独创建一个topic,而不是发送到原来的topic。(这部分数据是异常数据,只有在入库时出现异常才会发回去,如果第二次还是不能入库的,就会把数据写入到文件,人工来处理。专门用个topic也是为了方便查找问题。因为这些都是异常数据,我们只管去这个topic看就行了)
- Hbase落地后怎么进行分区的,怎么保证数据均匀的分布在每个节点上(Hbase是通过rowkey来进行分区的,因此数据在源端发送到kafka时,就要求源端为每条数据生成一个uuid,我是通过这个uuid来保证rowkey能均匀分区的)
- UUID吗?你这样确实能保证数据均匀分布了,但是你怎么在Hbase中查找这条数据呢?(嗯,在实际业务中也确实出现,需要通过表的一些字段条件搜索的情况,因此我在数据存储到Hbase的时候,先会存储一个字段到rowkey的索引到solr中)
- 用了solr做索引,那为什么不用elasticsearch呢?(没有接触过elasticsearch。<我有些崩溃,我也不知道为什么要用solr而不用elasticsearch,我只是个开发啊啊啊。。。>)
- 用UUID能保证唯一性吗(UUID是唯一的,它是根据网卡MAC地址,时间戳,机器码而生成的,肯定能唯一)
- 不一定,UUID也可能出现一样的,只是概率很小(。。。<这倒是让我长见识了,我之前一直以为UUID不会重复,面试完后还特意去查了一下>)
- 你这个架构怎么保证kafka数据不丢失(因为我是自己维护offset的,因此在单个节点上,在提交offset时,使用原子操作类加同步的方式,保证offset有序的更改。这里使用的是spark分布式节点去计算的,后面又发现不同节点去消费同一个topic时,会出现同时提交offset的情况,因此又用zookeeper去做了一个分布式锁来提交offset)
- 有了zookeeper的分布式锁,还有必要在单个节点上保证同步吗。分布式锁就能保证同步了嘛(额。是的<不得不说,这个面试官逻辑很清晰,很快就能找出一些问题>)
蚂蚁金服基本就问了这些,不过和我以前面的公司有很大的不一样。以前的面试基本上是我在讲,面试官在听,而问的问题也是按他自己的思路问。而蚂蚁金服的面试官不一样,他基本是顺着你讲的东西问,在聊的过程中发现问题,并且指正,面试官技术很深厚。也让我感觉到了,要在这条路上走下去,就不能只停留在那些容易变的组件使用上,而是要深入了解其原理