如何做系统设计的面试题

2015-10-07

系统设计是一类开放型的面试题,没有绝对正确的答案,更多时候是一些取舍。可以比较全面地考查面试者的综合素质,包括知识面,经验,理解和分析能力,抽象能力。这类题目一般是针对有一定工作经验的面试者。事实上,并没有要求在短暂的面试的时间,面试者给出一个完美的答案。世界上没有完美的系统,只有更好的系统。以下面这个例子,说一下这类题应该怎么做。

可穿戴设备会收集用户数据,这些数据会被上传到服务器。设计一下这个业务的存储系统。

理解使用场景和限制

面试官给出的问题描述都会比较简单。所以要做的第一件事情就是:沟通,理解需求。要了解使用的场景和特定的限制。在确认自己理解清楚之前,不要埋头开始做题。就上面的描述,我们大致能明白了是个什么样的问题,但是还有很多细节。

用户量有多少?收集的是哪些数据?这些数据收集后是否要用于分析和查询?每条记录的大小大概是多少?读和写的频率怎么样?还有没有一些特定的业务自身的特征?

假设场景是这样子的,这个业务当前有200w用户。智能设备是为了防止小孩走丢的鞋子,为了简化问题先假设只需要记录位置信息。每条记录大概200字节。需要查询用户当前位置,并且可以查询历史记录,比如当天该用户到过哪些地方,或者曾经到过哪些地方。请求的分布主要还是当前位置信息。每隔10分钟,设备会记录一次位置信息并上传服务器。假设历史数据需要保留五年。这个业务还有个特点是,用户与用户之间,并没有任何联系。

抽象问题

尽管这道题只是问存储相关的一块,但一个系统还是会有分层的设计,我们将功能提取出来。

服务层:

  • 查询当前位置和查询历史信息
  • 接收记录信息

数据存储层:

  • 近乎简单key-value的形式,但是涉及到历史信息查询

这一层的功能数据库那里可能直接提供了,服务层到底需不需要?在抽象问题的时候,这个思考过程肯定要有。

抽象出来的优点:数据存储层可能使用多种异构的数据库,那么在这一层可以提供统一的API。比如对当前位置做缓存,而历史数据直接查数据库;又或者写请求量很大,同步写操作转化为异步的批量写操作等。这一层抽象可以让内部实现对外部透明。需要让面试官知道,你是在做设计,在思考。

接着看数据存储层。该使用什么样的数据库作为这个业务的存储呢?mongo?redis?hbase?或是传统数据库mysql?这里有时间属性和大量历史数据,是否可以考虑一下时序数据库,比如influxdb?告诉面试官你是怎么选择数据库的,它们在这个场景各自的优缺点是什么。

假设面试者对mysql比较熟习,不妨先考虑传统的mysql能否满足需求。

那么接下来就是表结构怎么设计?字段有哪些?假设记录位置数据用的是Location表。Location表中的字段要包括,用户ID,坐标,时间。那么给定当前时间和用户ID可以查询当前位置,给定一个时间区间可以查询到历史记录。如果查询速度有要求,是否需要做次级索引,涉及到这些具体细节,如果面试官感兴趣,都可以深入讨论。

瓶颈

抽象问题之后,该思考一些性能指标,来判断选型的方案是否满足。如果不满足,要继续思考其它的方案。估算是很重要的一项能力,对数据要敏感。

200w用户,10分钟一次写入,如果是按无规律的计时,整个系统的tps大概每秒只有3000多,单个mysql都能hold住的。但如果统一在每10分钟整点写入,则会有3w的峰值,压力比较大。至于读的平均请求,可能还低于写。仍然需要考虑进去的是峰值。注意这里缓存似乎是无帮助的场景--用户只会去查询自己的位置信息,不会查他人,所以没有"热点用户"查询。

200w用户,10分钟一次写入,记录大小200字节。每天会生成大概50G数据的样子。保存5年,那么会有100T的量级。

通过这些分析,可以知道,这里面临的主要不是高并发请求的问题,而是数据存储量比较大的问题。另外,这么多记录条数对于mysql那边的性能影响也要考虑进去。

扩展

如果200w用户变成了2000w用户,甚至2亿用户会怎么样?当前设计的系统能不能扛住?扛不往该怎么样扩展?这个时候应该能立刻想到很多“常识”,负载均衡、缓存、异步等等。

用户之间没有相互联系,这个特点很方便我们按用户去划分。即使数据再涨,都可以加机器应对。

mysql可能会挂,7*24的高可用怎么做?立刻应该想到主备,还有读写分离这些。

这里面任何一个点都可以继续讨论下去,因为都是一些通用的东西。


以上使用的例子纯属虚构,如有雷同纯属巧合。最后推荐两个链接:

http://highscalability.com/all-time-favorites/

http://blog.jobbole.com/84575/

面试题