提到对象存储。业界唯一的是AWSSimpleStorageService(S3)。写意是现成的,任何不敢支持s3写意的厂商都会被现实打脸,纯属开卷考试。对于公司来说,无论是多云架构还是自建IDC,对象存储选择只能支持S3协议,比如探探选择的Minio,以及基于SeaweedFS的改造。强制选项是agreement。业务上也有很多基于S3的创业项目,比如基于Fuse的juicefs分布式文件系统,目前在大数据领域用的比较多。听说这两年收支平衡了。当然,收入来自国外^^还有一个olap数据库databend等。基础设施S3已经是IT的基础设施了。没有S3的自建成本是难以想象的。作为程序员,自造轮子飞,技术实现上没有什么秘诀,都是开放锻炼技术的。就看谁能把稳定性做好,降低成本。以上截图来自aws官网。大数据分析、日志存储、应用数据、视频图像、备份都围绕着S3。对于应用,屏蔽底层细节,没有容量限制。而且大部分aws产品也是建立在s3之上,围绕着对象存储基础设施构建了一个庞大的生态。这也是为什么独立的云存储厂商无法存储和盈利的原因……比如七牛,如果你使用阿里云的大数据平台,访问七牛对象存储需要跨公网,没有人能接受这。在成本上,这家公司已经半死不活,沦为某云厂商cdn的二线流量商。大家也可以想象一下,如果我们公司自建IDC,现有的infra团队至少会增加一倍。在这里羡慕国外的infra创业公司,可以买saas服务,从不造轮子。从财务到办公软件,从监控系统到数据库,都是购买的服务。刚毕业工作的时候,数据库的备份只能写到磁盘上,然后磁盘存放在保险箱里。别无选择。当时国内公有云厂商的接受度不高。成本与选型S3好用,但价格确实贵。您需要根据实际使用选择不同的类型:Standard、Intelligent-Tiering和Glacier。标准的最贵,默认的适合经常看。如果数据很少被读取,可以选择Intelligent-Tiering智能存储:FrequentAccessTier、InfrequentAccessTier、ArchiveInstantAccessTier。对于不追求多活的,可以选择one-zone,去掉versioning多版本存储,进一步降低成本。对于大量的历史审计数据,选择Glacier冰川类型。缺点是后面无法读取,需要手动恢复为正常类型。当然,AWS也不是仁慈之人。冰川式接入是要钱的,一次性转换成本很高。对于大量的小对象,不能使用Intellint-Tiering类型。最小对象大小需要128KB,每个对象还有40KB的额外开销用于维护对象元数据信息。我们服务10%的成本来自于这块开销,不出意外,不出意外……至于技术实现细节,估计是多份离线转换成EC纠删码,不过aws机器巨规模和大量过度保护机器也处于闲置状态。这里我推荐美团对象存储系统[1],工作量大,涵盖了所有的技术点。小对象合并这里我们介绍一下我们的场景。当订单完成或退回时,必须拍照以生成用于后续审核的证明凭据。订单完成后,也会生成发票和收据。这些都是以图片的形式存储在S3中,大量的小物件成本非常高。为了降低成本,选择了智能存储和冰川类型,但这还不够。这类场景有一个前提:访问历史图片的概率很低,一周前的图片基本不看。图像本身是无用的,它们只有在绑定到订单时才有意义。经过研究,我们可以将图片压缩合并成大文件,按照历史时间存储。优点是我们可以充分利用智能类型并使用廉价层。同时,压缩后的图片只有原来的一半大小。原来的逻辑,后端服务会生成一个临时的预签名s3公网URL,客户端可以通过公网访问,那么如何读取历史订单数据呢?此处使用了s3的工艺对象accesspoint[2]和selectapi[3]。简单来说就是将历史数据合并成一个parquet格式的大文件上传到S3。当用户访问编码后的s3url时,访问点调用lambda解析url,定位parquet文件位置,然后使用S3SelectAPI查询图像数据。消息对象{需要int64ID;必需的int64DriverID;需要int64CityID;必需的int64索引;requiredbinaryPayload;}你可以把parquet想象成一张数据库表,预先定义schema,使用SQL查询数据。Object是thriftIDL定义的,Payload是我们的历史图片二进制数据。selectPayloadfromS3ObjectwhereID=XXXlimit1这是selectapi定义的查询SQL。至于AWS底层如何存储parquet文件,目前还是一个黑盒子。limit1算子好像不能条件下推到底层存储,不能提前返回。也就是说加不加limit1的效果可能是一样的。func(impl*implDecoder)Decode(bucket,keystring,filtersmap[string]string)([]byte,error){sql:=fmt.Sprintf("selectPayloadfromS3Objectwhere%slimit1",strings.Join(clauses,"and"))logger.Info(logTag,"Decodebucket%skey%sfilters%vsql:%s",bucket,key,filters,sql)//小对象默认50KBwriter:=bytes.NewBuffer(make([]byte,0,50*1024))iferr:=selectFromObjects(context.Background(),impl.selector,writer,bucket,key,sql);err!=nil{returnnil,err}returnwriter.Bytes(),nil}以上是lambda回调的伪代码示例,是不是很像读取数据库?理想情况下,aws应该将数据按照RowGroup分别存储在parquet中,使用parquet索引加速查询,或者自建O??bject索引,类似于mysql表。或者加bloomfilter,简单来说就是减少数据扫描,一是减少accessPoint查询时间,一是降低成本,aws奸商是按照扫描数据的大小收费的!!!目前aws应该没有实现算子下推,知道的朋友可以告诉我^^再次感慨aws生态强大,收费真的很贵。总结推荐大家阅读minio或者seaweedfs的源码。本文分享的优化思路,灵感来源于minio的源码。阅读更多有关行业实施的信息并没有坏处,也许这会带来灵感。参考文献[1]https://www.bilibili.com/video/BV1za4y1v7Tb:《美团对象存储系统》,[2]AWS对象访问点:《https://aws.amazon.com/blogs/aws/introducing-amazon-s3-object-lambda-use-your-code-to-process-data-as-it-is-being-retrieved-from-s3/",[3]S3SelectAPI:"https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html”
