阅读 42

【系统设计】如何设计一个图片类的应用?

这个题目,很多公司都会出,因为现在的图片类应用太多了,仅仅是图像滤镜,就养活了很多公司。但是这里我们从一个大局观的角度来看,默认我们面对的是设计一个类似于500px或者花瓣网一样的图片应用网站,围绕着用户体验、性能优化、网络部署等等大的问题,我们会对系统设计有一个较为清晰的认识。

话不多说,让我们开始吧!

首先要明确目标客户群体的画像,我们做任何设计,都是为了特定的产品场景来做的,成本耗费太高但受众太低,可能就无法满足公司后期发展,毕竟维护也是一笔巨大的开支,因此,我们首先需要知道客户需要什么。

比如这些需求,你该怎么考虑?

  • 内网外网
  • 访问量
  • 图片质量
  • 账户权限
  • 社交网络
  • 社群类型
  • 等等

系统设计都是开放性的问题,通过不断的发问来探究被考察者的知识面、心理素质、思考能力等等。因此下面提到的一些内容,仅仅是笔者的知识范围与思考范围,也许你还有更多的考虑,面试时应该大胆回答!

下面我们会把这个问题拆分为几个子问题来解决,当然每个子问题不是完全割裂的,阅读下面的文段时,你应该站在一个较高的位置来把控所有问题。

  1. 需求录入
  2. 架构设计
  3. 前端设计
  4. 网络设计
  5. 后端设计
  6. 数据库设计
  7. 工程化问题
  8. 售后服务&用户体验

1. 需求录入

明确需求乃软件工程首要事务,一个不明确的需求,会造成项目反复开发,最终让系统老化死去。 既然我们的目标是设计一款图片类的应用。至少可以分析这些点:

  1. 客户范围。公网和内网应用的开发模式有着很大的区别,这一点最好明确。
  2. 客户群体。包括客户量、年龄、偏好、地理位置等信息
  3. 应用类型。移动端应用、网页端应用、桌面端应用要明确,或者说要支持哪些类型。
  4. 并发请求。同时支持多人在线?预估并发访问量。
  5. 应用体验。需要支持什么样的用户体验,比如500px针对的高质量用户人群,相应的用户体验也不一样,这也涉及到权限分层以及后期收费的功能。
  6. 基本功能。比如图片应用一般支持上传下载、图片分类分级、账户登录登出、多级用户权限管理、社交功能等等。

对大多数开发人员来说,他往往不会关心需求是怎么录入的,这造成了一系列问题,因为一句话在转述过程中,会有很多偏差产生,就像光的偏振一样,最终开发出来的产品可能就不是当初想象的样子。因此,再次强调,开发人员一定要明确需求,如果有必要,你可以去一线亲自和客户交流。

2. 架构设计

很明显,需求一旦明确了,剩下就是开工造轮子。但我们不应该这么急,实现一个软件,往往60%-70%的工作都应放在架构设计上,为什么呢?架构就像是软件项目的地基,很难想象房子都造完了再去改地基的行为,这将是一场灾难。

通常情况下,录入需求后你需要召集所有的工程师开个会,设计内容至少要有

  1. 前台架构设计,面向用户
  2. 后台架构设计,完善的服务
  3. 网络架构设计,部署和访问方案
  4. 数据库架构设计,持久化数据
  5. 运维方案

每一个层次的子问题,都会有无数的解,我们需要做一些抉择,选择这其中满足我们需求的最优解。

小结

再次强调,明确上面两点非常重要,作为一个系统工程师,你不要一拿到问题就打开你的IDE,要多做一个倾听者和思考者,努力寻找最优解。

3. 前端设计

终于到具体的软件实施方案了。到前端开发这里,我们能选择的技术方案就太多了。注意一个方案的选择一定要结合你团队的实际技术情况。由于前端开发具有一定的通用性,我们这里可以分为两个角度来看待图片应用的前端设计。

通用方案

  1. 基本的开发语言、框架选择
  2. 打包方案确定
  3. 状态管理:基本数据一般都是内存内,方案多种,也可升级到持久化,利用浏览器缓存
  4. 主题设计:一致的UI设计语言
  5. 埋点设计:页面性能监控、请求监控、操作统计、错误统计、用户地域范围统计等等
  6. 高可用的页面Accessibility。元素的兼容性,用户可用性,鼠标和键盘等外设的支持、支持的浏览器平台、降级方案、弹性布局、终端适配、弱网环境检测和降级等等
  7. 动态效果:骨架屏方案、加载动画方案、通用的过渡效果
  8. https和http2.0(3.0) 支持
  9. 多CDN支持、Gzip支持
  10. 多级缓存方案。http cache、dns cache、localstorage、indexDB等等
  11. SPA / MPA / SSR
  12. 反爬虫方案
  13. 其他网页性能优化的方案

以上方案是任意网站都可以考虑的方案,一般通过这些技术手段,我们的网页访问体验都能达到很好的效果了。

针对性方案

当然只回答了通用的一些方案,可能并不会给你带来多大的优势,因为你可能只是在列举一些名词而已,只有针对性的处理一些问题,才能体现你的思考。

  1. 图片文件如何处理?

    • 文件上传。现在的图片大多都很大,是否涉及到断点续传?分包上传?
    • 文件下载。骨架屏当然是一个方案,多层次的图片大小也是一种方案,比如500px就是,列表展示时图片都是压缩过的非原图,当你权限足够时,才可以通过二次查看、下载等操作来访问原图。这就涉及到了用户体验了。
    • 文件预处理。现代JavaScript引擎已经很快了,我们甚至可以利用浏览器来做图片的预处理,分减服务端的压力。甚至一些通用算法也可以通过webassembly技术打包为wasm在网页上加载运行,作为图像预处理的一种手段。
    • 使用瀑布流还是随机方块,这也涉及到一些简单的图相关的算法
  2. 如果出现网络问题怎么办?

    • 缓存方案就派上用场了。比如indexDB如果用的好,我们很多公共的图片都可以存储到用户电脑上;或者是用localstorage存储图片的url,减少向后端发送的请求数量(因为一般图片都是放在特定的服务器上或者CDN上的)
    • PWA也可以作为一个备选方案,让网站访问如同原生应用一样。
    • 降级,网络降速后可能接口就会超时,超时可以重复尝试、可以提示用户网络问题等等。

以上只列举了两个问题,你可以问一下你自己,如果有其他的问题你是否可以解决,比如

  1. 如何反爬虫?
  2. 如何达到最好的图片加载速度?
  3. 图片水印功能如何实现?
  4. 图片压缩、分类是否能在前端实现?

4. 网络设计

在网络层面,我们要关心一些安全性和稳定性的问题。

  1. 网络是否可用
  2. 网络访问速度
  3. 备用功能,灾备处理
  4. 数据安全,预防网络攻击
  5. https / http2.0 / http 3.0 / websocket / long polling

除此之外,任意服务器的部署形态,集合起来就成了一个拓扑关系网,每个访问请求最终落到哪个服务器,都是需要具体设计处理的。 尤其是网络安全,作为一个公网部署的应用,尤其要重视。

  1. 服务器安全性,防入侵
  2. https
  3. 客户端防攻击
  4. 反爬虫方案

5. 服务端设计

服务端设计同样需要考虑安全性与稳定性。除此之外,基本的接口功能,权限、算法等方案也需要有一些具体的示例,也就是说你给的方案都能解决一些什么问题。

  1. 基本数据接口。需要反爬虫,权限鉴定,容忍并发量统计,不能因为访问量稍微一大一点就拖累了其它服务。因此,有肯能基本数据接口作为一个微服务单独部署。
  2. 算法模块。首先要明确目的是什么?第一,图片的压缩、解压缩、滤镜等算法都需要高效,降低软硬件资源占用,第二,用户行为也是可分析的,我们可以通过机器学习,分析用户的行为特征,比如某个地域的人可能更喜欢户外运动,某个城市的人更喜欢狗而不是猫等等。如何获取特征呢?可以通过设置表单让用户上传,这是最传统的方案,更优雅的方案是统计图片本身的特征,在后台做机器学习。凡此种种,算法有理由成为你网站的核心竞争力,参考某宇宙级公司的崛起。
  3. 权限模块。权限限制可以分为用户等级的限制,也可以分为操作类型的限制,也可以分为区域性限制等等,权限模块可能作为网站的现金流的底层技术,也是值得重视的。
  4. 消息通信。各个微服务之间如何做消息同步?如何才能做到某服务挂掉了不影响用户体验,或者降低错误的风险?等等问题都是可以考虑的。并且,随着用户增长,社交网络越来越复杂,你的消息通信能否承受住数据量的考验?虽然我们不需要做超前设计,但至少你设计的系统,要能够承担一些峰值,甚至峰值再加20%的访问量。
  5. 日志处理。日志也是一个重要的模块,快速定位问题或者分析用户行为都离不开日志。但日志也不能打多,关键点的日志打出来就行了。另外日志文件要定期清理或者备份,不能占用太多系统资源。日志也是可以作为一个单独的服务。
  6. 灾备处理。至少有一主一备吧,让你的系统更可靠。大公司甚至可能有三四个备份服务器。这些服务器的备份时间节点怎么选择,太频繁了影响机器性能,间隔时间太长了万一中间服务挂掉了怎么办?这些都是现实问题。像数据库,更可能是某个服务访问完成后,发送广播到其他备份服务器,让备份服务器也存储。说到广播,这又回到了消息通信上面了。
  7. 安全性。防止网络入侵、服务器账号管理、数据安全等等也是需要考虑的。防火墙策略,xss攻击防范,数据安全性校验,文件格式校验等等。比如用户把一个植入木马的文件上传了,爆你数据库,岂不哭了。

以上是笔者考虑到的一些点,当然,还有很多其他点,你可以再补充。

可以看到,架构设计的要点就是不断的反问你自己,算法是否足够快?内存占用有多少?并发请求量级?线程池是否会爆栈?服务挂了怎么办?什么原因会造成服务挂掉?服务器性能是否用到了极致?等等一些列问题,因为在系统设计中,就是通过不断对话来挖掘你的潜力。加油,到目前为止你所思考的已经很多了。

6. 数据库设计

由于笔者主要写前端,数据方面的知识委实匮乏(待加强)。这里只提一些可能思考的点

  1. 分库存储
  2. 查询效率
  3. 存储效率
  4. 数据同步
  5. 数据安全
  6. 灾备处理

上面这些问题,需要一些专业解答。这里只做抛砖引玉。

小结

以上讲了客户端、网络、服务端、数据库等方面可能思考到的点。当然这些只是概要性的总结,每一个子问题都应该结合具体问题进行具体分析。比如你老是说根据访问量来设计架构,那怎么统计访问量呢?怎么搜集服务器真实的运行状态(cpu | mem | disk)呢?这些铺开来,又是可以成书了。所以希望读者以思考者的角度看待任意子问题,要学会对自己发问,这一个模块是否只能这么做?或者说是否已经做到了最好?

另外,笔者又要强调客户体验了。

系统设计的核心虽然是软硬件设计和网络设计。但用户体验也重要,软件架构设计如果你驾轻就熟,那么当别人问到你如何设计一个功能的时候,请注意一切从客户出发,首要事务是了解客户的需求,任何软硬件设计都是以提升用户体验,真正满足客户需要为目标的。再这基础上去做你的软件架构设计,可能会有更多收获。

7. 工程化

读者可能以为,到软硬件设计完整了,系统设计也就结束了。可能软件设计和编码是结束了(暂时性),但问题远没有结束。至少我可以问你这些问题

  1. 架构是设计好了,你又如何保障你的软件质量呢?(多级测试 | code review | 试运行)
  2. 产品是交付了一版了,面对用户持续需求,你如何做到快速响应?(敏捷开发 | 团队活力 | 架构扩展性)
  3. 软件是部署到服务器了,你如何做后期的运营和维护呢?(服务器扩容 | 备份 | 日志采集 | 性能监控)
  4. 客户数量已经到达一定程度了,你如何保证客户的数据安全呢?(社会工程学攻击 | 病毒 | 恶意攻击 | 攻防演练 | 安全意识)

还有很多可以发现的问题,读者可以问一下自己,是否能够处理好?比如,如何带小团队、大团队?如何进行技术攻坚?

8. 售后服务

到这里才接近尾声了。产品已经卖出,我们的服务也很好,但是总有客户反馈问题,如何解决呢?

  1. 服务不可用?(服务器崩溃 | 受攻击 | DNS污染 | 算法崩溃 | 并发量问题 | 日志撑爆 | 运营商问题...)
  2. 网站访问慢?(客户端网络条件 | 运营商网络条件 | 服务端处理效率 | 并发处理能力...)
  3. 使用体验不好?(权限设计问题 | UI设计问题 | 服务不可达 | 字体 | 图片模糊 | 推荐算法...)

小结

工程化和售后服务这块,既是质量的保证与监督,又是新需求的挖掘点。日常工作中也是接触最多的(大多数情况下开发时间只占很少一部分,大部分时间我们是在维护和优化我们的应用),生活处处有学问,还请读者留心。

终结

感谢您花了几分钟时间阅读我这一段文字,这既是我一次系统面试的总结,也是我以后工作的思考方向,写完这一段文字后不得不感慨,要成为一名合格的工程师,还需要更多的历练。

时间很长,我们一起努力。

原文地址(公众号文章, 多一张思维导图)

原创不易,谢谢阅读