小林求职记(四)不会吧不会吧,面试还真会问这些呀

  前传


小林求职记(三)一上来就围绕电商系统层层提问,我太难了....


经历了好几次求职失败的经历,小林最终找到了自己以前一起工作合作的老同事王哥,并向前请教面试技巧。


小林: 王哥,我最近面试了好几家公司,但是面试都挂了,我觉得自己好多知识点似乎都学得不是很深入啊,自己都快“裂”开了啊。


王哥 :哦,你平时大多数时间都是怎么学习的啊?会定期自己的做一些知识脑图的梳理工作吗?


小林 :啥,下班时间一般我都是很晚了,回到家也基本没有时间去学习。就算有休息时间一般也是陪朋友打打农药,吃吃鸡之类的。


王哥 :嗯嗯,就这???


小林 :不然呢,不会吧不会吧,你平时工作也挺忙的样子,居然下班还有时间去学习??


小林求职记(四)不会吧不会吧,面试还真会问这些呀


此时的小林内心不禁感到有些无奈,知识点错综乱杂,有些知识点掌握地似乎自我感觉良好,却又总是能被面试官戳中盲区。


王哥 :这样吧,我最近也在面试别人,我先来帮你大致做下模拟面试吧。


小林 :嗯嗯,好的,还是王哥你这兄弟靠谱。

于是王哥和小林两人便开始了一场一对一的模拟面试场景....


王哥 :首先我们从一些网络基础方面开始聊起吧,作为一名工作多年的java程序员,不应该只停留在crud层面,不知道你对于网络这块的知识点了解得如何。下边我将会从浅至深地询问你一些关于网络的知识点。


小林正好前段时间准备了些网络的知识点,于是便开始表现得跃跃欲试了。


王哥的第一道问题便开始了:


你可以讲解下自己对于三次握手的理解吗?为啥要三次握手,以及三次握手中设涉及的细节点。


小林 :嗯呢,其实我对于三次握手的理解有过一定的整理归纳(前几天刚刚看了某位大佬了这块的文章(狗头))。


为什么要做三次握手?


个人的总结理解 这是为了保证通信的双方都具备有收数据和发数据的能力,而三次握手正好在最有限的次数中完成了这一项校验工作。


三次握手中的细节点


首先连接端会发起一个SYN的信号量,其中会携带几个核心的参数,分别是ack,seq

这些标志位参数在发送的过程中会有一定的规律(seq和ack的规律有点记不太清楚了)。


如果三次握手成功,那么就会继续后续的网络通信环节。


王哥: 嗯嗯,你说的大概意思我能理解,但是如果在面试过程中能说得更加详细些就更好了:


首先三次握手应该分成三个阶段,显示SYN_SEND阶段,这个阶段中,客户端会给服务端发送一个SYN,接着在SYN-RECEVIED阶段里面,会返回ACK+SYN,最后在ESTABLISH环节客户端会再次发送ACK通知服务端客户端具有接收数据的能力。


小林求职记(四)不会吧不会吧,面试还真会问这些呀


ps:关于三次握手的底层细节可以借助一些抓包工具去实际操作进行理解。


小林: 嗯嗯,大佬所言极是。这些细节点我平时工作中都基本用不到,为啥你却对它那么熟悉呢?


王哥: 其实也没有啦,这些东西偶尔在一些特殊场景还是会使用到的。不知道你有没有用过一些特殊的抓包工具来对网络请求做过深入分析,如果有实践过的话,这些问题应该难不倒你。


ps:通常在工作中我们都会使用fillder这款工具进行抓包,不过通常fiddler抓包对于一些tcp报文的解析并不友好,所以有时候可以尝试使用下wireshark这款抓包工具。使用这款抓包工具有时候能对ACK,SYN这种包信息有更深入对理解。


小林求职记(四)不会吧不会吧,面试还真会问这些呀


王哥:那么你了解http2.0的一些新特性吗?


小林:嗯嗯,在http2.0里面出现了一个非常实用的特性,解决了传统的串行化传输问题(例如字符串的依次传输),采用并行传输的方式(在传输数据的时候,通过帧对数据进行顺序标识传输的顺序数据到达对方一端的时候重组信息)。


王哥:嗯嗯。那下边我们来聊聊你的一些项目细节点把。


小林:嗯嗯。


王哥:我看你的工作经验主要还是以电商项目为主,你因该又遇到过秒杀类型的场景把,能讲讲自己在应对秒杀场景的时候的一些思路吗?


小林:嗯嗯,我先自己整理下思路。


(内心疯狂回忆以前的秒杀项目做法)


小林:嗯嗯,首先基本秒杀的逻辑是这样的。用户点击网页,小程序,或者app等客户端应用的下单按钮,然后会进过一次查询商品,生成订单,锁定指定商品,支付回调,扣减库存,更新订单状态,秒杀业务完成。


小林求职记(四)不会吧不会吧,面试还真会问这些呀

王哥:嗯嗯,问几个问题哈。你在处理支付回调的时候有遇到过哪些特殊情况吗?


小林:嗯嗯,有的,有时候第三方的回调会延迟,甚至是重复回调,因此我们一般会在回调接口那块做幂等的防护机制处理。比较常见的方式是通过加入分布式锁的技术方案来实现,在工作中一般也是借助redis来实现分布式锁,之前我也看了下项目内部分布式锁的实现方式,是通过lua脚本来实现的。


王哥:嗯嗯,你刚才提到来分布式锁,那么你对于一把合格的分布式锁觉得需要考虑到哪些问题因素呢?另外为什么不用zk来做分布式锁呢?


小林:首先我来解答一下为什么不用zk做分布式锁。CAP理论告诉我们,一个分布式系统

不可能同时满足以下三种


  • 一致性(C:Consistency)
  • 可用性(A:Available)
  • 分区容错性(P:Partition Tolerance)


这是因为zk本身更多是偏向于支持CP的模式,对于分布式锁这类公用组件,通常使用场景都是需要对高可用有一定支持性,因此我们没有使用zk来做分布式锁。

需要考虑的问题场景:



  1. 当分布式锁加锁过程中,出现未知异常,需要主动释放锁,通常会采用try...finally的模版方式来做实现。


  1. 对于每次加锁都应该设置超时机制,否则会一直处于抢占资源的状态不做释放。尤其是高并发场景中,如果加锁过程中出现了某些不可预料的情况,导致锁没有正常释放,一直在redis中存储且没有设置过期时间,那么会一直占用redis的资源。


  1. 对于加锁过程中,业务调用接口长时间堵塞(但是并没有抛出异常,例如说查询数据的数据量非常大,处理时间很久),堵塞时间远远超过了加锁的时常,那么这个时候应该设计一种自动给锁进行延期的机制。 ps: 这里不妨可以参考一下redisson框架的设计思路,内部采用了watch dog机制来做这块的优化。


王哥:嗯嗯,看来对于分布式锁的一些应用你平时还是蛮有经验的嘛。那么我再问下你几个问题把。在用户点击秒杀抢单按钮的时候,你会怎么处理这块的业务呢?


小林:嗯嗯,其实这个环节是属于整个业务流程中并发量最大的部分来,对于这块由于我之前的那个业务部门的秒杀并发数并不是很高,当时预计的tps在3000左右,针对这类业务场景而言,我当时给出了两大点方案,首先是在客户端做限流处理。也就是在点击按钮的位置做拦截。


拦截方案有以下几类:


  1. 点击按钮一次之后,按钮置灰,需要等待个三四秒之后才能再次请求,这一部分由前端的js来控制


  1. 对于一些恶意攻击的黑客而言,可能会从js中看到按钮请求的url,因此url也需要做拦截,我当时给出的方案是在url上边加一个和用户绑定关系的校验参数(类似于token),每次请求的时候会在redis中存储对应的key,value是指定的请求时间,下次请求的时候,如果后台校验发现该key的请求在最近的几秒内有存在过访问记录那么就不允许再次请求,减少对于程序下游的访问次数。


这块的限流脚本是由当时的一些大佬编写了一套lua脚本放在了nginx上边做限制。


小林求职记(四)不会吧不会吧,面试还真会问这些呀


王哥:嗯嗯,那为什么要设计token来识别呢,用ip鉴别不是更加简单吗?


小林:虽然说使用请求的ip来鉴别一些恶意攻击的请求是可以,但是ip做限流容易有“误伤”的情况,例如说一些学校,医院,公司这类场所,他们大多数的出口ip都是固定的,使用ip做识别防范的话,误伤概率有点大。(经典面试题,敲黑板~~)

王哥继续耐心听小林分析下去。


小林:当时我们的服务在进行秒杀活动开启之前对前端对一些静态页面做了预先加载的处理,页面会被缓存在了cdn上边,当秒杀开启之前,用户无法进入到秒杀界面,当秒杀开启的时候,会有后端一个定时脚本去将cdn上边的js做修改,客户端加载到js之后,秒杀界面就会开启。秒杀服务是一种典型的高并发场景,面对这种场景需要将后端的微服务进行单独部署,以免拖垮其他机器,同时也方便扩容处理,另外对于带宽也要特殊增加处理。


王哥:等等,你刚才说到了在cdn上加入一个js文件来控制客户端是否真正访问到正式秒杀的页面是吗?能讲下具体实现策略吗?


小林:嗯嗯,是的。这块当时是我们老大做的,细节点我也没有太了解。


ps:关于如何控制页面是否开启实际秒杀页面可以借助使用JavaScript脚本控制,在秒杀商品静态页面中加入一个JavaScript文件引用,该JavaScript文件中包含 秒杀开始标志为否;当秒杀开始的时候生成一个新的JavaScript文件(文件名保持不变,只是内容不一样),并被用户浏览器加载,控制秒杀商品页面的展示。


如何防止浏览器,cdn,反向代理对这份文件产生缓存这个JavaScript文件的加载可以加上随机版本号(例如xx.js?v=32353823),这样就不会被浏览器、CDN和反向代理服务器缓存。这个JavaScript文件非常小,即使每次浏览器刷新都访问JavaScript文件服务器也不会对服务器集群和网络带宽造成太大压力。


王哥:好吧,那你后边再去了解下,我们继续吧。


小林:嗯嗯,当用户下单成功之后,需要对请求进行限制,通常我们会将真实有用的请求先写入一个消息队列中,避免请求都到达数据库。后端会讲商品的库存加载在redis里面,扣除库存的工作在业务服务器集群中执行,先对redis中的库存数据做校验扣除,然后再更新到mysql中。当秒杀活动结束后,请求后台的服务会返回一个秒杀活动结束的标识。大概就是这些吧。


王哥:嗯嗯,你大概把秒杀的一些简单流程点给讲明白了,但是其实在扣库存,防止超卖,服务降级这些精华点却似乎并没有提及太多。


小林:那块之前我并没有负责,所以就没有去做过多的了解......


小林求职记(四)不会吧不会吧,面试还真会问这些呀


王哥:哎呀,你这样让我问到 “高潮” 阶段就突然没了,感觉有点难受啊(狗头),不过我看你前边的基础好像回答得也还可以,我们这边正好最近也在招人,我帮你内推一下吧,你可以修改下简历发给我就好了。不过我只是一面的技术官,我这边的老大对于技术要求非常苛刻,尤其是性能优化,分布式技术那方面,你可要好好准备下哦。


小林:好的,太赞了,好哥们儿,下班之后我请你吃顿宵夜。


未完待续....


原创不易,如果各位读者喜欢,希望能点赞支持一下小林啦。

上一篇:优秀的摄影师必看:拍照秘籍之用光的技巧


下一篇:Comparison method violates its general contract!