初步实现分布式文件存储架构IFileStorage
大石头 authored at 2025-12-14 21:08:23
3.33 KiB
Stardust
# 分布式文件存储 ## 背景 基于asp.net开发的web应用,带有文件上传功能。把文件保存到本地Uploads目录后,再写一条文件信息到附件表Attachment,业务表存储附件id。业务模块需要获取文件时,根据附件id查询并从Uploads目录读取文件。 在分布式部署场景,应用部署了ABCD四台服务器,共用MySql数据库,此时附件表共用,每个节点都可以查询到附件信息。但是文件上传时只会存储在ABCD其中一台服务器本地,业务模块请求文件时,如果负载均衡nginx刚好没有路由到那台服务器,程序将无法获取文件。 引入NAS或者OSS等集中存储的方案增加了部署维护成本,不适合轻量级项目场景。 ## 需求 现在希望在公共组件Stardust中实现分布式文件存储功能: 1. Stardust项目增加IFileStorage接口,位于Storages目录,以下的发布新文件、消费消息、发布文件请求等逻辑,都位于该接口的默认实现DefaultFileStorage中。由于Stardust项目中的逻辑代码不能操作数据库,因此DefaultFileStorage部分方法需要定义为虚实现,在最终的Stardust.Web项目中实现为StarFileStorage。本文的核心就是IFileStorage以及实现相关逻辑,上传与获取文件时,我会在恰当的地方调用该接口的方法。 2. 应用程序APP引用Stardust,部署到ABCD四台服务器,共用MySql数据库。事件总线采用`NewLife.Messaging.IEventBus`,多节点时基于Redis分发消息到各节点。 3. 用户上传文件到A节点服务器,文件保存在A节点并写入信息到附件表。 4. A节点向事件总线`IEventBus<NewFileInfo>`布新文件消息,消息包含附件Id以及所在节点服务器。整体上就是一个写扩散架构方案。 5. BCD节点从事件总线`IEventBus<NewFileInfo>`消费到新文件消息,知道该文件存储在A节点,判断本地磁盘是否存在该文件,如果不存在或者Hash哈希不正确,则请求A节点的获取文件接口,拿到文件并校验哈希通过后,保存到本地附件目录中,具体路径已经在附件表指定。 6. 经过写扩散以后,ABCD都拥有完整的附件文件存储。用户访问APP时,不管nginx路由到ABCD的哪一个节点,都可以拿到文件。为了整个系统更加健壮,我们还需要做一些增强功能。 7. 写文件扩散时,可能因为某些原因,某个节点未能处理好文件,导致文件丢失。用户访问该文件时,发现文件不存在或者Hash不正确,可以向事件总线`IEventBus<FileRequest>`发布文件请求消息。其它节点消费到文件请求消息后,查询本地存在该文件并且哈希正确,则向事件总线`IEventBus<NewFileInfo>`发送新文件消息,重用文件扩散的流程。 8. 应用程序APP增加部署EF两个节点,一共有ABCDEF六台节点服务器。此时EF节点本地没有附件文件。可以设计一个轮询附件表信息的功能,针对本地没有的文件,逐个发送文件请求,快速同步附件存储。 ## 实现要点 帮我实现代码逻辑,主要包括以下内容: 1. 设计接口 IFileStorage 2. 实现抽象类 DefaultFileStorage,根据业务流程描述,实现你能实现的代码逻辑 3. 设计 消息类 NewFileInfo、FileRequest,根据业务需要,增加所需要的属性