作者:vivo 互联网平台产品研发团队 - He Zhichuang、Han Lei
手机云服务目前作为每家手机厂商必备的一项基础服务,其服务能力和服务质量对用户来说可以说是非常重要。用户将自己大量的信息数据存储在云端,那我们的云端服务如何保证服务的稳定和数据的安全,以及如何应对越来越多用户群体的使用?本文将主要介绍 vivo 手机云服务系统的建设历程。
几乎每家手机厂商都为用户提供了信息存储的云服务能力。通过一个账号,用户可以将手机系统中的各种常用的信息备份到云端,以便后续在合适的时间点查看或恢复自身的数据。然而由于用户量级巨大,服务在设计系统的时候需要考虑的因素特别多,比如如何保证服务的稳定性,如何保证大文件的传输效率,以及如何保证用户文件的数据持久性等等。
除此之外,随着越来越多的终端用户开始使用vivo云服务,存储和计算的成本也与日俱增。可能有部分人了解,某些手机厂商的云服务产品年度亏损数亿级别,而主要成本之处来自用户私人文件的存储成本。
另外,在安全方面,云服务在这块需要承担的使命更是重中之重。某些厂商的云服务曾经出现过用户数据泄露,居然可以通过搜索引擎直接查询到用户的私人文件,这种事件一旦出现,对企业品牌的打击和影响可以说是非常巨大。
如上所述,云服务在建设过程中可以说是困难重重,那么vivo云服务在建设过程中,又是如何兼顾产品功能、资源成本、服务稳定性、数据安全等等诸多因素而进行设计的?且听后文细细分解。
当今智能设备发展迅速,各个手机厂商相继推出了PAD、智能手表等设备。因此不同设备之间的数据互通诉求也随之而来,一个帐号实现数据互通。
拿vivo为例,vivo帐号可以同时在vivo手机、vivo PAD、PC上登录,用户可以在手机、PAD、PC上同时对联系人、日历等内容进行编辑,一端编辑,多端可见。
这种多设备数据同步互通就是云服务的一项核心功能。当前云服务支持同步的数据项:联系人、日历、便签、书签、黑名单、蓝牙、WLAN,后续会支持更多的数据项。
手机行业功能更新迭代很快,新的亮点功能会吸引用户购买新机。但是新机购买回来后,各种数据的设置、新增对用户来说是个繁琐、头疼的事情。
为了方便用户将旧手机的数据迁移到新手机上来,手机厂商提供了一些数据迁移工具。如我司的互传,新老手机放在一起通过蓝牙可以方便的将数据导入新手机上。但是互传必须要求2个手机在一起,如果用户旧手机不在身边呢?
此场景下,云服务提供的整机打包功能很好的解决了此痛点。用户在使用旧手机期间,可以打开云服务的整机备份开关,云服务会自动将用户手机数据打成数据包备份至云端。
在用户购买新手机换机时,可以通过云服务快速选择老手机的打包数据进行恢复,方便快捷。
云盘是一种专业的互联网存储工具,是互联网云技术的产物,它通过互联网为企业和个人提供信息的储存,读取,下载等服务。具有安全稳定、海量存储的特点。
在vivo云服务中,除了诸如联系人、短信等数据类型内容的备份恢复能力之外,文件类型的云端存储能力,即云盘的能力同样重要。
用户可以将自己本地重要的图片、视频、文档等重要文件备份到云端,以便后续可以在云端后者在其他设备上可以访问到该文件,同时借助于云盘的能力,用户也可以方便快捷的释放整理本地空间。
除此之外,云盘还提供了丰富的文件周边功能,例如压缩文件的在线解压,视频的在线播放,以及文档在线协作等等。
云服务数据同步的方案采用的是类似于Git版本管理的概念,主要涉及2个行为:
推数据:将本地设备增量数据推送至云端。
拉数据:将云端增量数据拉取至本地。
主要需要了解的有以下2点:
增量数据识别;
数据冲突处理。
(1)增量数据识别
云服务采用的是基于数据版本的识别方案:云端每条数据都有自身的版本号,版本号逐步递增。
主要同步流程如下图:
如图可见,增量数据同步过程并不复杂,整个流程总结如下:
客户端获取云端当前最大的数据版本sv;
若客户端本地数据最大版本lv < sv,则证明云端数据有更新,客户端需要拉取云端增量数据;
若lv = sv,则客户端判断本地是否存在增量更新数据,若有则将本地增量数据推送到云端。
(2)数据冲突处理
数据冲突出现在多设备同时使用的过程中,同时对同一条数据进行操作,造成数据冲突的情况。
因此同步数据流程需要考虑数据冲突的场景。
常见的冲突解决方案有2种:a、自动为用户解决冲突。b、用户手动自行解决冲突。
自动为用户解决冲突一般有以下方案:
以最新的数据修改时间为准,以修改时间最迟的设备的数据为准。(多设备时钟无法统一问题,后面上报的数据可能并不是用户实际上最后修改的)
2条数据都保留。(会给用户造成数据重复的错觉,影响体验)
用户手动自行解决冲突:
参照git的冲突处理方式,冲突数据展示给用户,由用户自行选择内容的存留,最后将最终数据推送到云端。
由于云服务对接了很多不同模块的数据:联系人、日程、浏览器书签,不同数据的特性不一样,每种数据的冲突处理的规则也不一样。因此云服务采用了将冲突数据返回给业务模块,供业务模块自行解决的策略,于业务方采用上述哪种解决方式,由业务方自行决策。
云服务采用的是将本地不同模块的数据打包成文件,上传至云盘的方案。
通过树形结构,将整个包、不同模块、不同模块的数据文件进行关联,恢复数据时,通过父包parentId即可获取到所有的数据文件的metaId,进行恢复即可。
此方案的优点:方便快速扩展备份手机其他模块的数据,服务器基本上不需要进行改造。
当然此方案也存在劣势:设备不同模块的数据格式对服务器属于黑盒,服务器难以针对模块的数据做实时的解析和展示。
相对于数据项目的同步备份,云盘模块主要聚焦的是文件类型的云端存取。
和普通业务模型相比,云盘业务的显著特点是逻辑复杂,需要考虑的细节很多:例如空间占用、数据安全、大文件传输效率等等,因此整个的系统设计更加复杂。
1、对象存储简介
《对象存储》是由云存储供应商提供的一套基于对象的海量存储服务,一般可以为用户可以提供海量、安全、高可靠、低成本的数据存储能力。
在vivo云服务的存储逻辑中,用户的图片、视频、音频等文件目前均存储在对象存储服务中。
由于早期vivo内部并无自建的对象存储能力,故一开始这部分数据均存放在公有云,随着近两年vivo自建对象存储能力的完善,目前公有云数据已完全迁移到了自建存储。
2、云盘系统架构
如上图所示,云盘涉及到的周边模块众多,但是最核心的还是元数据模块、空间管理模块、文件处理这三个模块,概述如下:
元数据模块:主要用来描述文件的属性,例如文件的名称,文件的大小,媒体文件的长宽高等等。更抽象的,元数据模块保存了除了文件实体内容之外的所有信息。
但是,为了系统后续的可扩展性,我们针对元数据模块还进行了“动静”分离。
具体如下:
不同的业务所关注的元数据信息不尽相同,比如除了一些名称大小这些公共属性外,云相册业务还会关注诸如文件拍摄时间,exif中的特定字段等等,而这些字段在别的业务中却不会使用。
所以我们继续将静态的不会变化的公共信息继续进行了一层沉降,即上图中的公用元数据层。这一层存放了文件的大小、状态、文件摘要值,存储在对象存储的路劲等核心内容。
空间模块:和大部分手机厂商一样,云服务默认会允许每个用户免费使用的5G空间,如果存储总量级超出了5G,那么用户则需要购买VIP以提升空间容量。
那么关于用户空间信息的管理,我们有一个统一的空间模块进行收纳管控。
文件处理模块:此模块主要提供用户文件数据的上下行能力。比如文件的断点上传下载能力,媒体文件的缩略图处理能力,压缩包文件的在线解压能力等等,都由该服务承载。
下面,我们主要来了解下最核心的文件上传流程,如下图所示。
在实际的业务处理中,文件上传的整个流程其实远远不止上述时序图这么简单,比如文件缩略图的处理,比如用户身份的校验,或者是风险文件的识别,加密的处理等等。
由于云服务业务使用用户量级巨大,所以在关系型数据库的设计上,也要考虑后续频繁扩容的场景。
关于云服务的分库分表实践,这里不再展开描述,感兴趣的可以参考这篇文章:你分库分表的姿势对么?——详谈水平分库分表
和普通的业务数据交互相比,文件的上下行动作就显得特别"笨重",因为每次处理都要传输大量的文件报文。
那试想,如果用户在上传一个上G的文件,突然遇到了弱网环境而中断了链接,那下次恢复链接之后,还需要从头开始上传,这样无非会对整体文件的传输体验带来非常大的影响。
在客户端进行文件上传时,我们会约定一个分片大小阈值。我们会将文件切割成一组组大小不超过阈值的文件片段,然后对每个片段进行传输。
这样如果端上遇到了弱网环境,那么我们也只要对失败的分片进行重传即可,大大提升了整体文件传输的性能。
同样,客户端进行文件下载时,如果下载一半网络断开了,那么下次又需要对整个文件进行重新下载。
所以,vivo云盘在对文件下载时,也使用了断点下载能力,主要基于HTTP的Range头信息,对需要的文件资源进行定位截取。
因为前文描述了文件在上传的时候通过分片技术将文件进行了拆分,那么在断点下载的时候,可以通过Range中的范围计算得到具体涉及的存储路劲,无需进行多余的IO操作。
当前云服务用户数据规模颇大,诸如元数据类存储在数据库中的数据总条数已经超过了5000亿、而文件类总占用空间也超过了百PB。
如此海量数据的存储,每年耗费的磁盘成本和数据库成本都是一笔不小的数目,因此云服务在节省成本上也做了不少动作。
随着在网用户的量级越来越大,用户每天需要备份的文件数量也呈日趋增大,那么如何从技术层级进行降本呢?
我们这边主要进行了以下几个方面的探索和挖掘。
在vivo对象存储自建完成之前,云盘也是将数据存放在公有云的对象存储上。
存储分级技术主要是将不同的数据采取不同的存储方式分别存储在不同性能的存储设备上。
一般来说,公有云将对象存储的存储分成三种类型(部分公有云会有四层或更多),即标准存储,低频存储,归档存储。
以下为某公有云的存储分级报价情况:
在标准存储和低频存储的选择方面,我们假设:S为当前存储总量,G为每月取回总大小,那么经过数据计算,我们可以推导出:
即如果每月的文件取出率小于123%,则使用标准能有更优的成本,而如果大于123%,则应该使用低频存储。
然而对于用户行为进行分析,用户对文件进行存储后,后续访问源文件的概率非常小,但是用户可能会经常到云端去查看自己的文件,这个时候展示的大部分是缩略图。
于是我们将源文件和缩略图进行分离,将源文件使用低频存储,将缩略图进行标准存储,获得了比纯低频更优的最终成本。
和大部分其他厂商技术实现可能存在不同,在vivo云盘的文件上传流程中,有一个非常重要的一环,即文件的预上传。
在进行实际文件二进制流的上传之前,云盘客户端会读取文件的各项属性,诸如文件名,大小,长宽、照片的拍摄时间等信息,将这部分数据传输给服务器,我们把这一步叫做预上传。
而服务器则会进行用户剩余空间大小的逻辑计算,如果剩余空间不足以存放该文件,则会直接终止上传流程。
如果空间足够,此时服务器在此时就会扣减用户空间,然后才会进行下一步的文件体传输。而大部分其他友商只有当文件完成整个上传流程时才进行空间扣减。
该逻辑能保证同一个用户在进行多线程上传,或者多个设备同时上传时,不会出现空间超用的情形。
不知道大家平时在使用一些云盘类似工具的时候有没有发现,自己明明上传了一个很大的文件,但是却很快就完成了。
那么这种快速进行文件上传的能力,我们这边就成为"秒传",形象的释义就是仿佛在秒级完成了一个大文件的传输。
"秒传"不仅对用户体验有一定的提升,而且也能节省比较可观的存储成本。
在vivo云盘的设计中,秒传又分为用户级秒传和全局秒传,分叙如下:
用户级秒传:用户上传自己之前曾经上传过的文件时,触发秒传动作。
全局秒传:用户上传的文件之前有其他人上传过,触发秒传动作。
秒传的设计思路较为简单,用户进行预上传时,将文件摘要告知服务器,服务器查询该摘要值是否已经存储,若存在就告知客户端无需进行文件实体的传输。
云服务用户的非文件类数据主要还是存储在MySQL数据库里。海量的数据存储随着带来的是MySQL的硬件成本的提升。当前云服务MySQL数据库实例就有将近30+。
为了尽可能降低MySQL的存储成本,云服务对MySQL的数据做了相应的数据压缩。
云服务采用的是MySQL官方提供的innodb压缩方案:
云服务通过线上实践,对联系人数据库进行压缩验证:压缩之前磁盘占用空间2.75T,压缩后空间1.3T,压缩率可达50%。
说明:压缩效果取决于表的字段的类型,典型数据通常具有重复值,因此能够有效压缩。CHAR,VARCHAR,TEXT、BLOB这类字符串类型的数据通常能够很好地压缩。而二进制数据(整数或浮点数字)、已经经过压缩的数据(JPEG 或 PNG 图像)通常起不到压缩效果。
矛盾加密
目前客户端和服务器之间的通讯统一通过HTTPS进行传输,然而有了HTTPS一定就安全了么?
考虑以下场景:
客户端HTTPS的相关校验均是系统库实现的,那么作为攻击者可以改写这些系统库的执行逻辑使得相关校验“失效”,从而发起“中间人攻击”
若APK被Hook,也可使得HTTPS的相关校验失效,从而发起“中间人攻击”。
所以,为了更高的安全性考虑,我们除了基于HTTPS的文件传输,云盘在核心接口上还是用了公司内部自研的矛盾SDK加密。
这使得就算HTTPS被诸如中间人代理方式获取了明文数据后,还是无法对消息体的敏感信息进行提取。
文件存储安全有两个重要部分组成:
用户可以在以后任意时间点访问到存储在云端的完整文件,需要保证文件的安全存储永不丢失。
用户的文件存储是私密的,不该有非预期的人或物能非预期的读取到这些私密文件。
我们把上述的1称作为数据的持久性安全,2称作为数据的隐私安全。
一般来说,第三方公有云提供的对象存储都能保证11个9的数据持久性,即99.999999999%,开启异地备份后,能达到12个9,能满足文件在存储上的持久性要求。所以下面我们主要聊下用户的隐私安全。
早在2019年,就有某大牌手机厂商,其云端的用户私人照片竟然全部泄露,个人的隐私照片竟然能在搜索引擎中查询到,这个就是典型的用户私人文件未被授权即被非法读取使用。
该事件一旦发生,非常容易被舆论发酵,进而迅速影响企业的口碑,所以,这块安全方面的设计就显得重中之重。
存储加密
我们能通过很多技术手段保证自身服务的足够安全,但由于用户文件最终存储在公有云的对象存储中,而各家公有云的技术实现细节我们并不知悉,是否真正具备了足够高的安全性,我们并不能得知。
所以,我们针对存放在第三方公有云的用户数据全部进行了加密, 这样,连存储方也无法获取我们用户的明文文件,我们只需要保证自身业务足够的安全,而无需关注第三方对象存储泄露文件的可能性。
在对文件的加密时,我们更是使用了最为严格的加密手段:每个用户的每个文件均使用不同的密钥进行了加密。这样即便"黑客"通过某种技术手段拿到了某一个文件的密钥,他也无法对大量的其他文件进行解密。
该方案虽然大大提升了文件的安全性,但是由于文件在业务方存在了加密解密动作,除了对性能有一定的损耗,一些媒体能力也受到了限制。比如我们没法直接使用第三方的内容审核、图片处理等服务。
不使用CDN
众所周知,CDN技术的成熟发展,使得终端用户可以就近获取各种网络资源。但是由于CDN的本质是对内容进行了缓存,如果我们将用户的私人文件通过CDN的方案进行访问,那么这些文件被CDN运营商以明文方式缓存在了各个边缘节点上,存在被非法获取的风险。
和其他网盘形式不同,vivo云盘主要以存放用户私人文件为主,目前并没有开放文件的传播分享行为。在这种业务场景下,使用CDN的效率并不高,缓存的资源并不会被多次重复利用。所以vivo云服务不会对用户的私人文件使用CDN技术以提升性能。
令牌有效期设计
云盘的文件以链接的方式暴露给各客户端进行下载。在链接的设计上,云盘携带了下载令牌,该令牌在一定有效期内会自动过期。
vivo云服务的用户量级目前还在持续增加,从用户体验方面着想,目前云服务的功能完备性还可以有不少发掘的点,未来我们还将构筑以下能力:
离线下载能力:用户可以使用云端的下载功能将文件存储到用户的云盘中。
文档协同编辑:随着vivo pad产品的发布,后续用户可以在不同端基于云服务完成文档的协同编辑。
无缝换机体验:推动手机100+数据项接入,为用户打造无缝的换机体验。