大家好,我是小❤,一个漂泊江湖多年的 985 非科班程序员,曾混迹于国企、互联网大厂和创业公司的后台开发攻城狮。
小❤最近发现,以前初高中时代喜欢的很多歌手,各大曲库平台的歌曲都开始收费了。
比如以前喜欢的音乐才子 VAE,无论是江南夜色下的小桥屋檐,还是烟火绝、客怎眠的关外野店,亦或是紫烟留香、翩若绝影的惊鸿一面。
那些动人的旋律都会在某个午睡后的黄昏,或大雨后的清晨突然萦绕脑海,久久无法散去。
不知道是怀念曾经一起听歌的人,还是怀念那些青春的回忆。
无论怀念与否,歌是要听的,会员是不可能充的 🐶
于是,机智(pinqiong)的我开始在各大平台寻找免费的资源。不得不说,互联网真是一个伟大的发明,只要通电上网,就没有找不到的资源。
特别是网盘系统,真是资源共享的一把好手!
PS:有喜欢 VAE 歌曲的,文末可从网盘里获取免费的歌曲资源,自取不谢。
相信大家都用过网盘,从存储照片到分享工作文档,它已经成为了我们生活中不可或缺的一部分。
但你是否好奇过,背后是怎么样的系统设计在支撑着这些功能?今天,我们就来探讨一下,网盘系统的架构设计。
百度网盘是一个备受欢迎的云存储和文件分享平台,拥有 8 亿多用户和高达 10w+PB 的存储容量。
在这篇文章中,我们将深入探讨百度网盘系统的核心功能,以及如何应对高并发和海量存储可能引发的挑战。
百度网盘的系统设计采用分布式架构,以应对用户庞大的数量和海量的存储需求。核心组件包括:
对于像网盘这样的存储系统,每天都有大量的数据产生和传输。
以百度网盘为例,在 2022 年底用户就已经突破了 8 亿,存储量更是早已超过了 10w+PB(即 1000+亿 GB)。
所以,设计一个网盘系统有如下挑战。
百度网盘目前有 8 亿多用户,普通用户最大存储量为 1 TB,存储量就按 1000亿GB 来算,每个用户差不多 100+GB【1000GB/8】的存储量,存储空间的平均使用率为 10%。
以百度网盘每天日活量为 2 亿,日活用户占比约 25%,每个用户平均访问 4 次网盘。
所以网盘系统的 QPS 约为 1 万【2亿用户*4次/(24*3600秒) 】,高峰期为平均 QPS 的两倍,即 2 万。
假设用户每次上次下载的文件平均大小为 2MB,网络带宽负载约为 18GB/s(2亿*4*2M/(24*3600*1024G)),即 144Gb/s。高峰流量带宽约为平均的 2 倍,约为 288Gb/s。
通用的功能有以下几点:
当前设计的网盘系统需要有以下要求:
用户通过网盘客户端或网页界面上传文件,上传请求经过客户端应用层后,为了确保大文件上传的可靠性,我们可以根据文件大小,对文件进行切片上传。
然后客户端调用应用微服务处理文件基础数据(元数据)和文件内容,分别对元数据和文件内容数据进行异步上传。
用户请求下载文件时,客户端层将请求发送到应用微服务。
为了提高下载速度,可将文件块并发从服务器下载,然后在客户端进行文件组装,再返回给用户设备。
用户可以分享文件或文件夹给好友,分享时可以指定好友只读、或者存储权限,并且可指定文件共享的时间期限。
用户可以将文件或文件夹通过链接分享出去,通过链接分享的权限默认为转存权限,分享范围可以设定为公开、私密或者仅限特定用户访问。
由于 MySQL 这类关系型数据库不适合存储大数据文件,而像 HDFS、Ceph 这类文件系统在数据查询时又非常缓慢。
所以我们将文件数据分为元数据和文件内容,将它们分开进行存储,其中:
而负责响应元数据和文件内容的请求,也分成文件元数据管理系统(File Metadata Management,简称 FMM)和文件内容管理系统(File Content Management,简称 FCM)两个系统。
架构图如下:
由于用户文件可能包括视频、音频等大文件,但是 Ceph 不适合存储过大文件,所以我们对上传文件内容进行拆分,把大文件分成很多个小块(block),以便更好地上传下载大文件。
这样做还有一个好处,当大文件分块上传下载时,可以并发处理这些文件块,然后在 SDK 端进行文件组装,加快文件的传输速度。并且,当用户网络断连以后,我们只需要重传剩余的文件块即可,实现断点续传功能。
文件上传的时序图如下:
用户上传文件后,客户端应用根据用户上传的文件大小,将文件分成一个个 block,假设每 8M 生成一个 block,然后将 block 对应的 MD5 值信息上传到元数据管理系统(FMM)。
FMM 通过上传的 block 列表,判断 MD5 值是否有重复。如果是新的 MD5 文件块,则为它们分配 id,并存储到每个文件元数据表中。
然后 FMM 生成一个访问 Token,结合 blockId 列表以及可用的 FMM 服务器列表一起返回给客户端。
当客户端收到 FMM 的响应时,会对比 MD5 值,判断哪些是需要上传的文件块信息。然后带着 Token 以及需要上传的文件块 ID 和文件块内容,并发传入 FMM 的各可用节点,将真实的文件块存到对象存储系统 Ceph 中。
当客户端带着 blockId 列表请求 FCM 时,为了保证 blockId 来自 FMM 而非用户伪造,一般 FCM 需要再调用一次 FMM 做用户鉴权。
但是我们为了整体的架构简洁性考虑,用缓存 Token 的方式来替代内部 API 的调用,一方面减少了系统的交互,另一方面提升了整体的响应速度。
文件下载的时序图如下:
当用户下载文件时,客户端传入文件名、用户等信息,以获取 FMM 获取文件的元数据。
接着,FMM 服务器从 MySQL 中查询对应用户的文件 blockId 列表,分别从 ZK 获取可访问的 FMM 服务器列表、从 Redis 生成访问 Token,然后返回给客户端。
由客户端根据 FCM 的服务器列表和响应的 blockId 列表信息,并发调用 FCM 服务器下载文件 block,当下载完成所有的文件 block 后,客户端将文件 block 组装成一个完整的文件,返回给用户设备。
在设计网盘时,考虑到系统的用户量和存储量比较大,我们将应用系统和存储服务器都加入集群,并集成负载均衡、服务网关等基础设施,以提供故障转移、高可用和弹性伸缩等能力。
而基于内存、网络带宽的成本考虑,我们不可能一味加机器来保证用户的上传下载速率,并且基于商业化考量,我们可以对非会员的普通用户进行限速。
具体实现为:当客户端请求 FMM 系统进行上传或下载任务时,我们先获取用户的用户类型,如果是平民用户,我们在返回客户端可用的 FCM 节点列表时,可将服务器数量适当降低。
比如,VIP 用户可以享受 50 台服务器同时上传下载,而普通用户只分配 5 台服务器来进行上传下载文件。
由于网盘的文件共享是可以实时修改状态的,所以我们采用 RBAC(Role-Based Access Control,基于角色的权限访问控制)的思想来控制用户访问文件的权限。
权限相关的表设计如下:
通过 RBAC 的机制,我们可以轻松管理用户对资源的权限,根据角色分配权限,并在需要时回收权限。
有了 RBAC 来进行权限控制,我们注册账号并上传文件,给好友分享的业务流程如下:
整体流程和好友共享类似,唯一不同在于将记录插入到 Permission 表时,可以将文件的权限设置为公开访问,对应的用户置为 NULL,默认所有用户可访问和转存文件。
insert into permission (file_id, role_id, user_id) values ('被共享的文件ID', '公开角色的ID', NULL)
这样,当用户在访问该文件时,判断出该文件的权限为公开访问,就可以访问或转存共享文件了。
当资源所有者或管理员决定回收某个用户或角色对资源的权限时,系统会删除相关的权限记录。
具体实现为在 Permission 表新增一个过期时间字段,当用户共享文件给好友、或生成链接分享时,需要设置具体的过期时间。
文件系统可以开启定时任务,定期清理已经过期的权限,确保文件只能在有效期内被用户访问。
若设置链接为无限期访问,则可以设置过期时间为过去的某个时间点。
当用户删除文件时,我们首先需要通过 FMM 的接口获取文件块列表,然后删除元数据信息,释放用户的存储空间,同时通过消息队列将已删除的文件块列表传输至 FCM,删除文件内容。
为了保证文件元数据和文件内容的事务一致性,我们采用了分布式事务中的最大努力通知思想。
具体实现为:新增一个监控告警系统,当文件内容删除失败时,可以采用短信或邮件的方式通知管理员来手动处理不同步数据。
对用户来说,文件元数据已经看不到了,所以文件内容和文件元数据只需要保证最终一致性即可。
不明白分布式、最终一致性的同学可以看我之前的这篇文章,深入浅出:分布式、CAP和BASE理论
目前,互联网市场竞争激烈,网盘领域也不例外。
国内有很多网盘供应商,如百度网盘、腾讯微云、360 云盘等,但百度网盘依旧一家独大,市场份额占比超过了 80%。
数据来源:观研报告网
目前,个人网盘使用痛点集中在速度、安全、分享和价格四个层面。用户为优质服务和体验付费的意愿显著提升,因此做好VIP付费会员的经营与变现,成为个人网盘商业化的主流。
但是,作为一个很少充值网盘 VIP 的人来说,我相信普通用户才是大群体,所以更希望网盘应用们在商业变现时,也可以考虑下平民用户的使用体验。