19

头条终面:写个消息中间件

 3 years ago
source link: http://www.cnblogs.com/yescode/p/13808398.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

每个时代,都不会亏待会学习的人。

大家好,我是 yes。

这种设计类问题想必大家都不陌生,面试时或多或少都能碰到。

比如如何写一个线程池?如何写一个 HashMap ?如何写一个 RPC 框架等等,当然这里的写不是真的叫你用代码写出来,只是说说设计理念,整体架构。

这个面试题来自于一个读者的字节面试经历,我会从面试技巧和消息中间件的设计两个方面阐述。

我觉得重点在于面试技巧,因为它通用。

两种极端的情况

大多数同学遇到这种问题会出现两种极端的情况:

  • 第一种:一脸懵逼,两眼无神,不知从何说起,万般思绪,都化作一声叹息。

  • 第二种:夸夸其谈,像是口中架起了一把加特林,哒哒哒哒哒哒哒哒,还冒着蓝火。

yaa2iuv.png!mobile

第一种不用说了,好一点的面试官可能会引导你,会问一些提示性的问题,一步一步地带你渐入佳境,当然你要是胸中无点滴,那还是没救的,场面就异常地尴尬。

第二种会把面试官整蒙了,或许你真的懂很多,很多细节也都清晰,但是你不能一股脑儿的都抛出来,这会显得你抓不住重点。

面试官也是人

这点其实很关键,很多把面试官当成一个莫得感情的提问机器人,觉得他无所不能可以完全 get 到你的点,殊不知你引以为傲的细节回答,他可能觉得你在说蛇皮。

是人就会有感情,就需要交流,好的面试官会把控整体进度,从拉家常开始,让场子热起来再一步一步的深挖。

当然也有一些面试官比较弱,这时候就需要你来 特意地流出一点空白,来让面试官涂鸦 ,让面试官感觉你这人就很舒服,你这波就稳了。

当然即使面对着把控全场的面试官你也得主动出击,每个人都有自己的擅长点,你需要引导面试官来询问你的长处。

正确的回答姿势

正确的回答姿势是 BFS(广度优先搜索) 而不是 DFS (深度优先搜索),什么意思呢?

就是我们需要 先从大局上讲出需要设计的东西的重点,然后再等待面试官的继续提问,深挖

我们需要 揣摩面试官的心理 ,从他的提问可以看出他想要知道的重点是哪个方向的。

比如就拿 HashMap 来说,你 简单的 把获取、写入、冲突处理、扩容啥的都说了,然后等待面试官接下来的提问,有可能会往线程安全方面深入,也有可能会往扩容方向再挖,比如引出 Redis 的 hash 扩容等等。

所以说给面试官留提问的机会,抓住他的喜好或者说熟知的方向回答,这样如果你答得好,相互之间谈的来,面试官会对你高度认可。

而且在说各设计要点的时候也要注意停顿,要留机会给面试官插话,让面试官充分参与你的设计。

还是拿 HashMap 作为例子,比如你说了获取、写入、冲突之后稍作停顿,这时候大概率面试官还会问还有吗?让面试官有参与感, 让他感觉经过他的引导这个设计才逐步地完善

ia22EbN.png!mobile

当然如果不问也没事,你停顿下继续说就行。

让面试成为一场技术交流,这是面试的最高境界,相信面试完了之后双方都会有意犹未尽的感觉,惺惺相惜就是这么来的。

但是这种场景也不是这么容易碰到的,首先你和面试官得有相同方向的喜好,比如你对 JVM 有很深入的研究,而面试官对存储方面有很深入的研究,JVM 懂的不深,这样就碰不出火花了。

所以说会有很多人碰到这么个情况:我面这个公司一面挂,另一家公司面面超神,这都是很正常的。

当然你要是说你全能,那当我没说。

小结一下面试技巧

首先要正确的看待面试官,你和面试官是同等的,不要一来就低声下气的。

其次回答问题需要抓住重点,不要一股脑儿的把你知道的都说了,要留白待面试官提问。

要把控面试的节奏,往自己熟知的方向上引。

如何写个消息中间件

接下来咱们再看看如何写个消息中间件。

首先我们需要明确地提出消息中间件的几个重要角色,分别是生产者、消费者、Broker、注册中心。

简述下消息中间件数据流转过程,无非就是生产者生成消息,发送至 Broker,Broker 可以暂缓消息,然后消费者再从 Broker 获取消息,用于消费。

而注册中心用于服务的发现包括:Broker 的发现、生产者的发现、消费者的发现,当然还包括下线,可以说服务的高可用离不开注册中心。

然后开始简述实现要点,可以同通信讲起:各模块的通信可以基于 Netty 然后自定义协议来实现,注册中心可以利用 zookeeper、consul、eureka、nacos 等等,也可以像 RocketMQ 自己实现简单的 namesrv (这一句话就都是关键词)。

为了考虑扩容和整体的性能,采用分布式的思想,像 Kafka 一样采取分区理念,一个 Topic 分为多个 partition,并且为保证数据可靠性,采取多副本存储,即 Leader 和 follower,根据性能和数据可靠的权衡提供异步和同步的刷盘存储。

并且利用选举算法保证 Leader 挂了之后 follower 可以顶上,保证消息队列的高可用。

也同样为了提高消息队列的可靠性利用本地文件系统来存储消息,并且采用顺序写的方式来提高性能。

可根据消息队列的特性利用内存映射、零拷贝进一步的提升性能,还可利用像 Kafka 这种批处理思想提高整体的吞吐。

至此就差不多了,该说的要点说的都差不多了,面试官心里已经想,这人好像有点东西。

yAjM7rR.png!mobile

之后可以深挖的点就很多了,比如提到的 Netty,各种注册中心就能问很多,比如各注册中心之间的选型对比等。

你还提到了选举算法,所以可能会问 Bully 算法、Raft 算法、ZAB 算法等等。

你还提到了分区,可能会问这个分区和 RocketMQ 的队列有什么不同啊?具体分区要怎么实现?

然后你提到顺序写,可能会问为什么要顺序写啊?你说的内存映射和零拷贝又是什么啊?那你知道 RocketMQ 和 Kafka 用了哪个吗?(这些我都分析过,可以看 RocketMQ 和 Kafka 底层存储之那些你不知道的事

当然还有可能问各种细节,比如消息的写入如何存储、消息的索引如何生成等等,来深挖看你有没有看过消息中间件的源码。

可以问的还很多,这篇文章我也不可能每个点都延伸开说, 这些知识点还是得靠大家日积月累和平日的多加思考

当然日后的文章可以写一写今天提到的一些点,比如 Netty、选举算法啊,多种注册中心对比啊啥的。

面试官想问的是什么

再回到这个面试题,其实面试官想问的就是大方向上的设计,包括整体的架构、数据的流转和一些特性的把握, 所以对于这个问题他想听到的就是那些重点,而不是那些细节。

而继续的深挖取决于你回答这个问题时提出的各个关键词,对于面试官自身而言熟悉的词一抓到,他就已经知道下一步要问你什么了。

所以 在回答面试官的时候不仅要 get 到他的点,还得为之后的回答铺路 ,不会说的点不要提,擅长的点多提提。

最后

之前我已经提到了,这篇文章的重点其实不在于如何回答写一个消息中间件,而在于面试的技巧。

因为面试题千千万,而技巧掌握了那么千千万的面试题都适用。

我还想提一下关于面试的一些个人看法,我个人是面试驱动学习型选手,我学习的动力就是面试,我享受面试官问我啥我都嘴角一翘微微一笑的那种不羁。

但是我不提倡那种纯粹背面试题的做法,学习是一个日积月累的过程,就像我每篇文末说的,从一点点到亿点点,又像我每篇开头都会提的,每个时代,都不会亏待会学习的人。

我的面试驱动不仅仅是说为了面试而学习,还要以面试场景来学习,什么意思呢?

学任何一种东西,都模拟一个面试官在你前面,让他从各种角度向你提问,驱动你全方位的理解一个知识点,这才是我说的面试驱动学习型选手。

所以如果你看过我之前的文章会发现我经常会提出为什么呢,然后再作答。

还有一点要注意, 动手能力,这很关键。

Talk is cheap, show me the code。

我是 yes,从一点点到亿点点,我们下篇见。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK