当前位置 博文首页 > odirus:项目中对象存储的实践经验
七牛云存储、阿里云OSS、腾讯云COS等都是典型的对象存储服务,本篇文章会依次介绍一下我们在最近几年使用过程中遇到的问题,同时也介绍一下目前为止我们在项目中的一些实践经验(爬坑记录),或许对你有一些帮助。
由于同一个程序需要多机部署,从14年开始我们的项目就不再把文件保存到服务器磁盘上了,而是统一上传到对象存储服务中,然后把拼接后的HTTP地址保存到数据中。因为当时连运维都没有,嫌麻烦所以直接使用的是七牛云给的域名,地址类似于这样的 "https://7xicvf.com1.z0.glb.clouddn.com/xxx.ext"。
除了域名很丑之外,很长一段时间内都没出现问题,直到有一天早上我们的用户都在群里面反馈APP中的资源无法下载,我们一看原来是七牛云给的这个域名被停止解析了(后面了解到因为对应的一级域名涉及到“儿童涩情”,在全球范围内被停止解析),当时我们就懵了,数据库那么多URL太多了,涉及到很多表、很多字段,看来快速在数据库中替换URL不现实了,还好我们用的是PHP框架,有一个统一的入口和出口,我们就在出口处进行了string replace替换,暂时解决了这个问题。
经过这件事情后七牛云也强烈建议我们绑定自己的业务域名,而且在控制台也声明提供的域名只供测试,并且还做了一些措施来防止误使用,例如会限制资源下载带宽、浏览器中访问资源地址是直接当成附件下载而不在浏览器中显示等手段。我们随后也就绑定了业务域名,并且在数据中进行了资源替换,但因为涉及到很多表、很多列,所以替换起来很费力气,这也在我心里埋下了一个种子,希望有一天能够给出一个比较完美的方案来解决遇到的这些问题。
随着公司业务规模的扩大,为了折扣或者进行一些资源互换所以就得接入更多的服务商,虽然内心是抵触的,但还是得提供对应的支持才行,所以我在这个时候就接入了阿里云OSS存储。使用的方式还是一样,新建一个资源桶,然后绑定公司自己的业务域名,上传资源后就把拼接起来的URL(域名 + 路径)放到数据库中。
随着团队的不断扩大,存储的资源场景就越来越多,有私有读的场景、也有公开读的场景,甚至很多时候干脆会为某个业务分配一个全新的桶,让大家爱怎么折腾就怎么折腾。如果大家的资源都放一个桶的话,当时又做不到在程序中对路径前缀强制隔离,有些操作就不方便,例如想备份某种非常重要的资源那就得把整个存储桶内容都备份才行,因为不容易区分哪些资源属于哪个业务的(让业务同学从数据库导出资源更麻烦,同样因为资源会放到很多表、不同列中)。另外由于涉及到很多桶,会绑定很多个业务域名,那前端对接的时候可能就要在后端设置很多跨域的域名配置(除非是设置为*,允许所有域名的跨域请求,但这会出现安全性的问题)。
针对上面的一些场景,总结此时遇到的问题:
针对上述的问题,我们进行尝试通过中间件的方式来解决,因此诞生了第一个版本的存储中间件,虽然后面也收到了很多吐槽,不过没关系,有了吐槽才会有后面不断完善的解决方案,存储中间件设计详情请看下文。
其实中间件所有的内容都是围绕着我们自定义的存储协议展开的,存储协议的资源地址是这样的:oss://spaceKey/fileKey.ext,分为三部分内容:
针对上面的协议,我们的中间件需要包含以下部分内容:
其中核心数据结构设计如案例如下,与我们实际业务代码不同,这里主要是表达含义即可:
针对上面的数据结构相关的解释:
针对上面的架构相关的解释:
当然我们的业务系统会更加复杂一些,例如通过processor参数来适配不同云存储的数据处理功能,无论使用哪家云存储都可以提供一致的图片处理方案(例如裁剪、水印、旋转等)。而且也遇到了一些比较尴尬的坑,有各端配合上的、有知识短板导致方面的,这些坑不方便在这里写下来,如有需要后面我会单独脱敏后记录下来。