系统设计面试题:综合考察面试者的大招

Posted by 王天一 on 2018-08-31

站在面试官的角度,如何设计一道系统面试题,如何考察面试者的一整套流程,以及相关解答

在高级程序员面试的过程中,系统设计是一个很可能被问到的一个问题,由于它能体现出面试者很多方面的能力,是一道非常考验综合素质的面试题,一直被面试官青睐。

比如:业务理解抽象能力、业务挖掘能力、沟通表达能力、高层系统设计能力、底层服务实现经验、全栈经验

下面用一个自己设计的非常简单的系统设计题来一起体会体会。本人经验也不算多,仅供参考。

提出业务需求

首先面试官必须向面试者将业务讲清楚,比如要做的是什么,给哪些人用(有哪些角色),主要流程是怎样的,有什么系统上的要求,这一阶段同时也需要面试官有一定业务描述能力。最好是当场结合白板画出来讲给面试者听。

在本文中将以一个非常简单的客服系统为例,比如在面试时我会把下面这些告诉面试者:

  • 角色:用户、客服人员
  • 流程:创建工单 - 客服领取工单 - 回复 - 解决/回复
  • 要求:工单的更新实时推送到用户与客服、支持工单内容实时的全文检索功能

把系统的各个模块都画出来,最好从客户端开始,将所有涉及到的中间件、自己搭建的核心服务、第三方平台,并展示它们的关系。给你10分钟完成。

与面试者沟通

面试者在拿到这个题目之后肯定会问一些问题,比如需要支持高并发吗?需要将所有的服务都画出来吗?你可以回答,能支持一定量的高并发更好,不需要把所有服务都画出来,仅仅画出实现整个架构的核心服务就行。

然后面试者开始思考,开始设计,然后画出来了下面的一张图给你,并把他的设计讲给你听。

  1. 从客户端开始,可以使用客户端的缓存拿到上次已经加载过的资源,或者通过CDN拿到一些静态资源如JS、CSS、常用流媒体文件,使用阿里云或AWS的CDN就行,Object Store用的也是对应的对象存储服务。然后通过负载均衡器组访问后端服务器组Web Server,Web Server往下的所有部分都属于Web Service。
  2. Read API,对应着某个工单全部信息查询的API,需要通过访问Ticket Service判断是否保存在缓存中,如果没有保存在缓存里就访问数据库只读副本拿到数据,这里对数据库做的读写分离是为了在高并发场景下的性能优化。
  3. Write API,对应创建、修改、删除工单的API,由于写操作伴随着工单更新状态的推送,以及需要更新全文检索查询的索引来保证一定的全文检索的实时性,所以这两个操作使用队列完成,每个API只需要同步写数据库而已。至于推送的实现,建议使用极光、个推的第三方平台实现,因为不同的终端实现不同且复杂,服务端的长连接要求也比较高。
  4. Search API,对应全文检索API,会在Search Service中请求Elastic Search服务来查询需要的数据。在Search Service也需要安排一个定时任务,定期从数据库只读副本中读取增量数据来重建索引,保证索引建立无差错,同时也能保证日后的数据导入或迁入能够建立索引
  5. 图中只是画出了针对业务的核心服务,省略了很多微服务体系中的关键角色如服务发现注册中心、配置中心、包含鉴权的网关。在部署的时候还需要结合容器化技术和容器管理平台做到多个节点同时服务以保障高可用性和扩展性。

询问底层实现

如果能在当场完成这样一张图的话个人觉得整个面试者在高层设计上已经是比较优秀的了,他对业务的理解,各种中间件的使用,全栈经验都比较不错。但是往往面试者不能设计出这样完整的架构,有个80%就已经不错了。所以我们面试官在设计题目的时候一定要自己写一份比较完整的答案给自己做参考,然后给面试者打分。

接下来就根据时间和你想考察的重点来问几个底层实现的问题了,举几个例子。

工单附件存储方式

问:如果要你考虑到工单的附件可以是图片、视频的话,应该如何设计?

答:首先图片、视频的传输是比较消耗网络资源的,不能交给Ticket Service,让Ticket Service专注负责业务逻辑的处理,所以需要自己实现一个文件服务器或者使用云服务中的对象存储。

扩展性

问:如何评价你设计的系统的扩展性?

答:扩展性是系统在面临某个瓶颈之后需要对系统进行添加成员来突破瓶颈时的扩展能力。如果扩展性好,那么添加中间件(垂直扩展)、添加节点(水平扩展)都会比较方便。图中如果不看CDN、缓存这两部分,那么一旦遇到性能问题,添加这两部分来解决问题也是非常容易的,因为我们的客户端是可配置的,我们的服务端也能支持缓存,当然这并不能体现出设计的好处,如果看水平扩展就好看了,如果要对数据库进行水平扩展,原有数据库已经是主从复制的架构,那么想添加主、从节点也是非常容易的。如果要对服务节点进行水平扩展,那么就需要在部署的方面去考虑了,比如用容器化技术将服务打包成镜像,用容器管理平台管理容器运行状态与节点自动伸缩。

高可用性

问:如何评价你设计的系统的高可用性?

答:这是设计图中无法表现的,但是可以通过其他的方式来说说我的理解。对于服务节点发生的故障,首先服务注册中心就无法收到心跳回应了,容器管理平台也会监测到服务运行状态异常,那么请求就不会再发向这个服务节点,而是转向正常的服务节点,主要是需要提前配置好监控方案已经故障转移方案。

一致性

问:你设计的系统中有什么数据不一致的地方?如何解决?

答:数据库与缓存不一致(根据业务需求决定,本系统并不需要达到实时的数据交互能力,所以使用有过期时间的缓存就行)、数据库与Elastic Search不一致(每次对工单信息的修改就需要将工单信息更新到Elastic Search中,但也会可能有失败,所以有一个定时任务定时增量更新一段时间内的数据到ES)

如何保证高并发能力

答:前端使用缓存与CDN、每个服务都有多个服务节点支撑以及对应的负载均衡、将热点数据通过放入缓存中提高抓取数据的性能、将复杂操作使用队列异步执行任务、数据库读写分离对读与写操作分别进行数据库层面上的优化

由于本人在底层实现方面经验不够,底层实现部分的方案并不一定是最好的方案,我也会在与他人交流之后继续优化这些方案。另外,欢迎客官在评论区提出你的想法,我们一起来优化~

参考

https://github.com/donnemartin/system-design-primer/blob/master/README-zh-Hans.md

号外号外

最近在总结一些针对Java面试相关的知识点,感兴趣的朋友可以一起维护~
地址:https://github.com/xbox1994/2018-Java-Interview