AmazonS3,全称AmazonSimpleStorageService,旨在通过Web服务接口提供业界领先的性能、速度、安全性、可扩展性和数据可用性。该平台由亚马逊网络服务公司(AWS)开发,于2006年3月14日首次推出,随后的S3逐渐演变成对象存储的标准。随着公司的快速发展,公司对各种图片、视频、文件等对象的存储需求也越来越强烈。目前在公司接入场景包括二维码、景点推荐视频、图片、css、js、ML培训资料等资源,约10亿+文件。都是核心业务场景。如果存储服务出现故障,影响范围会比较大,比如无法扫描入园二维码,无法访问图片等。由于历史原因,公司现提供几套类似的存储服务,包括Cephs3、FastDfs+Redis(用于元数据存储)、公有云s3代理等,几套服务存在明显问题。比如公有云s3使用成本相对较高,无法保证外网交互性能;比如Ceph需要投入大量的成本来全面维护,性价比不是很高;再比如fastdfs+redis,访问不太友好,不能支持主流的S3。因此,我们提供了一套新的对象存储服务来解决上述问题。本文将详细介绍我们新的对象存储服务(OSS)是如何工作的。01设计目标总体设计目标如下:可扩展性:至少要支持10亿+对象,具备水平扩展的能力;高可用:要实现高可用,至少要实现隔离、多租户、限流、容灾/双活等能力,核心业务甚至可以实现不同存储产品的容灾;高性能:需要足够快,类似cephrados,未来需要作为分布式文件存储的存储基础;低成本:是的,以远低于ceph的成本支持所有服务;访问简单:可支持主流对象存储S3协议的访问;无缝升级:可以在业务无感知的情况下,稳定无缝地从cephs3转移服务,将公有云s3迁移到新的oss。02系统设计简单来说,设计目标可以分为两点:需要一个非常强大的对象存储oss服务如何在架构层面解决业务无缝切换,存储无缝升级保证业务稳定下面我将从这里有2点来介绍一下我们是怎么做的。oss技术选型这几年越来越流行开源+商业的模式,以至于各个方向都有或多或少好的开源产品,比如时序存储方向的TDengine,时序存储方向的ClickHouseOLAP等。在选择对象存储模型时,我们也优先考虑开源产品,通过开源共建完成我们的产品,尽量不从头造轮子。纵观整个社区,比较流行的有minio、SeaweedFS、fastdfs、ceph。其中ceph和fastdfs没有考虑,所以重点关注minio和SeaweedFS,看看能不能满足要求。miniominio应该是目前最火的开源对象存储了,在github上的star数为3w4。minio的优势包括:UI友好,部署简单,上手容易,支持文件级自愈,节点故障时无需人工干预全EC存储,成本相对较低,中大型性能更好文件。基于文件系统设计,没有额外的minio的缺点也比较明显:只支持EC,会存在io放大的问题,尤其是在大量小文件的场景下,扩展不是很友好,并且整个集群需要停止对等扩容的服务支持文件数量受限。基于本地文件系统的设计,当对象数量增加时,查找inode会变得很耗时。Minio是一个优点和缺点都很明显的产品。在我们的需求背景下,minio不可能很好的满足,尤其是不能支撑我们10亿+的对象存储需求,而且在现有的架构设计下,不容易改造,然后才能满足我们的与社区共建海量小文件需求。SeaweedFS是一个越来越流行的对象存储开源解决方案,githubstar数1w5+,增长速度比较喜人,社区也比较活跃。SeaweedFS官方介绍有两个核心点:存储亿级文件!快速提供文件!它相对接近我们的一些核心目标。核心优势包括:相对强大的性能:核心理论基础基于Facebook的Haystack设计论文,论文的目标是解决Facebook内部图片、视频等数据的存储和查询问题。架构设计相对灵活:系统设计参考了Facebook的TectonicFilesystem,尤其是几个核心组件的设计抽象性更好,很方便扩展不同的实现,整体架构可以横向扩展,没有明显的瓶颈。功能齐全:存储更关注冷热分离、EC存储、TTL等功能。Easytosupportdeployment:部署非常简单,易于使用与优点相比,存在一些缺点。S3的适配不彻底:大部分常用的接口都实现了,一些不用的接口没有实现,比如CannedACL等项目背景:相对于minio等开源产品背后强大的商业公司,这个项目的核心作者只有chrislusf。从各方面来看,目前基于SeaweedFS开源共建构建我们的对象存储服务是比较容易的。合理解决。系统架构介绍在确定了SeaweedFS的选型之后,接下来就是如何设计整体服务来满足我们的需求。简单的架构如下:整体架构其实就是一个比较普通的架构,非常简单。代理层:适应不同的API和业务的自适应存储层:包括SeaweedFS、Cephs3、公有云s3。公有云s3的运行与Cephs3类似。本文不展开管控平台:可视化UI、权限配置、配额配置、数据列表等术语解释:公有云s3Api:公有云s3外部Api,之前封装在公司内部EfsApi:外部静态资源相关ApiS3Api:适配S3的所有ApiStoreAdapters:根据配置Request处理业务,选择存储适配Filer/s3Api:SeaweedFS用于对外暴露s3等相关Api服务DCDB:分布式数据库协-公司基于BaiKalDB构建,下面将详细介绍BlobStorage:SeaweedFS中用于实际对象存储的模块设计目标说明可扩展性目标:至少需要支持10亿+对象,水平扩展能力是必需的。Proxy是无状态的,可以水平扩展,所以我们只需要SeaweedFS能够水平扩展就可以满足我们的需求。从整体架构来看,SeaweedFS核心有2层(S3存储的核心基本就是这2层)FileStorage:用于元数据元数据存储和API适配BlobStorage:对象存储基础元数据能力是比较核心的关联。他至少需要做到:水平扩展能力、数据不丢失、读写性能好、高可用。类似的服务有:Cassandra、Tidb、YDB、totonics的ZippyDB等。结合我们公司的现状,我们选择了DCDB,这是一个与BaiKalDB共建的分布式数据库。DCDB在我们公司应用广泛,性能得到了很好的验证,可以很好的满足我们的需求。引入DCDB作为元数据服务后,测试读写请求的平均耗时在1ms以内,可以满足我们的需求。以上是dcdb实际使用的监控数据。因为可以横向扩展,所以我们的压力测试结果表明,即使数据量达到亿级,也没有性能瓶颈。比如有DCDB的加持,整个读取过程会非常简单。从DCDB获取元信息,返回数据对应的存储节点,直接与存储节点交互获取数据。存储节点之间没有直接关系,可以做水平扩展。从整体来看,整个集群没有明显的瓶颈点,所有组件都可以水平扩展,可以很好的满足我们的规模需求。高可用需要做到高可用,至少在出现单点故障(物理机故障等)、意外流量影响,甚至是单个idc故障的情况下保证服务的可用性,并实现多个之间的相互隔离租户。下面介绍一下这些场景是怎么做的:(1)Isolate业务隔离,我们在nginx上实现了拆分,不同的业务(buckets)使用不同的proxy、filer、volumeServer。实现了业务与业务之间的物理隔离,互不影响。(2)租户之间除了物理隔离和限流外,至少要实现业务层面的限流和熔断功能。对象存储与其他大数据服务最大的区别在于流量非常大。比如并发上传一个1M的文件,那么流量很容易达到几十甚至上百GB,这就会造成网络瓶颈,所以我们需要这样来为业务配置阈值,这样当某项业务出现意外流量时,可以单独对其进行限制,不会影响整体服务,甚至不会造成网络故障。关于租户的限流,我们有pr两种策略,一种是基于bucket级别的全局限流,一种是基于count+单个文件下载限速的流量控制,可以让整个集群可控。(3)高可用proxy、filer、dcdb上面都有介绍,可以做到高可用。下面我来介绍一下数据是如何做到高可用的。数据高可用通常有两种方式:多副本和EC纠删码SeaweedFS支持使用copy方式实时写入数据,后期可以转EC。两者都可以实现数据的高可用性。官方介绍的高性能SeaweedFS的特点之一就是:文件服务速度快!核心实现思路参考了Facebook的Haystack设计论文,描述的比较详细。经过工程实践,实现了最终效果,小文件顺序写入,O(1)硬盘读取。下图是我们的六块256G,12*8TBSATA硬盘。压测是1M写入,io优先级已经到了瓶颈。观点。写入3000TPS下图是我们的6块256G、10TBSSD磁盘。压测是1M写入。由于带宽限制,我们没有继续压下去,各项指标都远远没有达到瓶颈。写入、查询、删除混合场景(6:3:1)压测中写入4000TPS,1M文件3500+QPS结果只用6台机器测试,性能结果满足我们的需求,如果有更高要求,横向可以进行扩展。低成本对象存储最大的成本就是存储,数据量会非常大,几百TB、PB甚至EB都有可能。如上图所示,各个云厂商也针对不同的存储提供了不同的计费方式。简单来说,冷数据可以牺牲部分性能来降低存储成本。同样,SeaweedFS也做了类似的功能。补充一个小知识点:多备份和EC的区别,从成本角度可以清楚的看到,EC比多副本更有优势。现在我们可选的存储介质包括NVMESSD、SATASSD、HDD。可选的数据存储方式有多个副本,EC。如图所示,随着数据变冷,我们会慢慢从SSD迁移到HDD,从copy迁移到EC存储。在性能和成本之间做出了权衡。无缝升级以上介绍了SeaweedFS的部分功能,下面介绍我们如何将业务从cephs3、公有云s3、efsapi等存储无缝切换到新平台。当前场景以ceph为例:(1)流程适配业务直接通过S3操作ceph。我们要做的就是在业务没有察觉的情况下,将cephs3换成可用度更高的SeaweedFS。可能有几件事要做。全API适配代理适配了我们原有的所有外部API,包括s3api、公有云s3api、efsapi。所有的api解析后,其内部操作是完全一致的。域名解析可以调整为proxy。读取过程的适配是由于历史原因。现在cephs3和publicclouds3中有大量数百TB的未使用数据。这些数据不需要导入到新的存储中。如上图所示,我们的proxy支持一个A策略s3->S3策略。主要有两个特点:①存储层面的高可用:当新存储出现故障时,自动切换到备份存储,实现存储层面的高可用②数据自动补全:新存储没有数据,备份存储有数据,同时,我们还有一个补偿程序,读取MQ中的数据,自动将存储的数据补偿到新的存储,这样经过一段时间后,所有热点数据(有访问权限的数据))会自动备份到新存储后,cephs3/publicclouds3就可以下线了。注意:写MQ的时候需要注意。需要按照文件级别依次写入,防止出现数据问题,适配写入过程做一个权衡。为了提高性能,写入只需要一个存储就可以写入成功,然后响应业务。第二个存储数据由补偿程序完成。此过程可以使企业察觉不到任何存储故障。proxy中的所有操作都是S3标准接口操作,因此SeaweedFS与cephs3、SeaweedFS与公有云s3、SeaweedFS与SeaweedFS之间的各种容灾解决方案都可以轻松实现。比如最核心的业务场景中的二维码,景点图片等,我们会先跑SeaweedFS和公有云s3的自动容灾,防止在某个场景触发某个存储bug,造成大范围的影响。写入MQ的数据还有另外一个用途,就是用于双存的数据校验,保证两个集群最终的数据一致性。注:图中默认写入MQ成功。实际代理有一个来回策略。如果写MQ失败,还有一种来回策略,比较复杂,这里不再细说。上面介绍了两个核心场景流程,有些场景略有不同,比如listapi。(2)除了升级步骤理论上无缝衔接之外,为了稳定上线,上线过程也比较讲究。我们大概会分为几个步骤:数据对比:以s3api为例,我们在切换前会有一个对比程序订阅nginx访问日志,对比两个存储的结果。核心比对结果主要包括文件的MD5和响应头。策略调整:因为业务比较核心,为了促进稳定性,每次都只做很小的改动。推广过程分为3步:1:引入代理,保证代理功能正常2:主要引入SeaweedFS,做SeaweedFS和cephCluster的备份,这样即使SeaweedFS出现问题,我们可以快速回滚到ceph3:offlineceph,最终形态,做一个SeaweedFS的双集群备份。03落地收益得益于开源。我们只投入了2个人力。整个迭代从选型到源码、原理研究到开始落地,历时3个月左右。该项目已经运行了将近3个月。不错,达到了预期的效果。目前已接入近2000万对象、60TB数据,流量快速切换仍在进行中。以核心业务efs为例,之前使用公有云s3做存储,现在切换到第二步(SeaweedFS为主集群,公有云s3为备份集群)。切换后的好处:性能:响应时间有了质的提升,从150ms到3ms。稳定性:之前用公网访问公有云s3,性能波动很大。切换之后,耗时变得很稳定。成本:第二步,公有云s3还有写流量,读流量基本清空,成本也下降不少。04使用tipsvolumeGrowthCount:这个需要调整,让所有的volumeServer尽可能有可写的volume,否则会影响写入和查询性能。fs.configure:SeaweedFS的设计是每个bucket对应一个collection,方便生命周期管理。需要控制桶的数量,否则性能会受到很大影响。我们已经在内部修改并取消了这个绑定以达到最佳性能,但是牺牲了一些桶统计功能,完整的功能还在优化中。filer.sync:如果没有proxy,可以使用filer.sync的同步工作来做双集群容灾。05未来展望定期备份:corebucket的增量和全量定期备份可以达到类似db的效果,在误删等问题时可以回滚。开源共建:到目前为止,我们已经陆续提交了20+个PR,包括bug修复和性能优化。我们将持续关注社区,与社区共同成长。基于S3的存储分离方案:现在很多主流的存储产品都兼容S3,比如prometheus、clickhouse等。因为新oss的强大性能,我们会尝试在这些S3适配的存储上进行存储和计算分离。分布式文件存储:类似于ceph,可以基于对象存储rados创建分布式文件存储,目前流行的juicefs或curvefs也是基于s3的。后期还计划基于这个oss实现分布式文件存储。第一阶段的目标是实现除了对io延迟要求非常高的场景(mysql),为业务赋能。
