在面向架构编程一文中,我阐述了自己对架构和代码之间的关系的看法:「代码需要反映出架构」!
本文通过对文件服务核心功能的设计与实现,来验证这一观点 。设计过程融合了「用例驱动设计」和「领域驱动设计」!
本文及后续几篇文章会设计并开发几个实际的系统,同时尝试总结一套适用的架构设计与开发流程 。欢迎探讨!功能文件服务器的核心功能就两个:「文件上传」和「文件下载」!其中上传可能需要支持断点续传、分片上传 。而下载可能需要进行下载保护,例如非指定客户端无法下载 。
除了这两个核心功能,一般都会有一个额外功能,就是「转换」!转换包括:
- 图片规格转换:一张图片需要切分多个不同的尺寸
- 添加水印:图片或视频需要添加水印
- 格式转换:
- 文件格式转换:office转pdf,pdf转word,pdf转图片,office转图片等
- 视频格式转换:mp4转m3u8,码率转换等
- 安全性:是否需要认证后才能上传或下载
- 伸缩性:是否支持扩容,提高访问量
- 可用性:作为基础服务,可用性不低于4个9
- 可配置性:对于转换方式、上传下载方式等内容需要提供可配置能力
- 扩展性:能方便的进行功能扩展,例如对转换方式的扩展
- 上传流程
文章插图
- 下载流程
文章插图
初步模块划分根据功能,可划分如下功能模块:
- 上传模块(核心模块):处理文件上传
- 下载模块(核心模块):处理文件下载
- 转换模块:处理文件类型转换
- 配置模块:对文件服务进行配置
- 安全模块:对文件服务进行安全保护
- 应用层:配置模块,安全模块
- 领域层:上传模块,下载模块,转换模块
文章插图
从上面的流程可以看到「上传模块」对「转换模块」有一定的依赖,像下面这样:
文章插图
但是,「上传模块」是核心模块,而「转换模块」是非核心模块 。核心模块的功能相对稳定,非核心模块的功能相对不稳定 。让稳定的模块去依赖不稳定的模块,会导致稳定的模块也不稳定,所以需要对依赖进行「倒置」 。
文章插图
「依赖倒置」解决了模块依赖问题 。但是转换是个很耗时的过程,例如用户上传视频,在不转换的情况下,只要上传完成就可以得到响应,但是如果转换的话,可能就需要双倍甚至三四倍的时间才能得到反馈,体验非常的不好 。且一般上传和观看的时效性并不需要即时性,所以转换应该是个异步的过程 。
异步执行的方式很多,比如基于事件,自定义线程等 。这里通过事件的方式来进行处理 。(领域事件可参考领域设计:领域事件)
文章插图
文件上传会创建UploadEvent,UploadListener监听UploadEvent事件,当监听到了UploadEvent,则执行转换 。
转换流程异步化后,如何告知客户端转换结果呢?有几种方案:
- 上传完成后,文件服务返回一个token,后续业务系统通过token来获取转换后的URL 。此方案需要业务系统请求两次 。
- 文件服务转换完成后入库,业务系统从数据库获取 。此方案也需要业务系统请求两次,且对不同的业务需要有不同的实现 。
- 文件服务转换完成后回调业务系统 。此方案可能需要实现不同的业务回调接口 。
- 文件服务器返回一个事先生成的URL,在文件转换完成时返回特定状态码,在转换完成后,返回文件 。对于某些场景无法事先生成URL,例如office转图片,一个文档会转成多张图片,转换前无法得知图片URL
推荐阅读
- 如何设计一个高并发系统?
- 大白话告诉你Hadoop架构原理
- 华为手机这些英文文件夹到底是啥?为什么我删完瞬间多出10个G
- 从微信小程序开发者工具源码看小程序架构设计实现原理
- 怎么把电脑文件无线批量传输到iphone,不压缩不用插线,很方便
- 普通家庭装修中走廊如何设计
- 电子杂志制作工具 电子杂志设计
- 如何一步步构建大型网站架构
- 架构图解:支付宝钱包系统架构内部剖析
- 数据库软件架构,到底要设计些什么?