本文原文链接
尼恩说在前面
在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如得物、阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,
最近有小伙伴面试招商银行,遇到下面的绝命 12题,狠狠被拷打了, 彻底懵了。 项目场景题太难了,不好好准备,真的答不出!
所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
当然,这些面试题 以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V171版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请关注本公众号【技术自由圈】获取,回复:领电子书
绝命12题, 尼恩将给出全部的深度答案:
1.如何让系统抗住双十一的预约抢购活动?
2.如何从零搭建10万级QPS大流量、高并发优惠券系统?
尼恩的 参考答案 , 点击查看 尼恩如何实现 1W + 的系统化、体系化作答
3.百万级别数据的 Excel 如何快速导入到数据?
尼恩的 参考答案 , 点击查看 如何实现 1W + 的系统化、体系化作答
4.如何设计一个支持万亿GB网盘实现秒传与限速的系统?
本文。
5.如何根据应用场景选择合适的消息中间件?
即将发布。
6.如何提升 RocketMQ 顺序消费性能?
即将发布。
7.使用分布式调度框架该考虑哪些问题?
即将发布。
9.如何让系统抗住双十一的预约抢购活动?
10.问 : 如何解决高并发下的库存抢购超卖少买?
即将发布。
11.为什么高并发下数据写入不推荐关系数据?
即将发布。
12.如果让你设计一个分布式链路跟踪系统?
即将发布。
本文目录
前言
网盘的主要技术挑战是海量数据的高并发读写访问。
用户上传的海量数据如何存储?
如何避免部分用户频繁读写文件,消耗太多资源,而导致其他的用户体验不佳?
尼恩从0到1 ,设计一个 NetBoxApp 技术架构,看看尼恩 如何解决这些问题。
1、亿级网盘的功能模块设计
尼恩带大家设计一个 NetBoxApp,实现网盘(云盘)功能,提供文件托管、上传下载、断点续传服务。用户能通过它保管并共享照片、视频等。另外,由于 网盘 成本高,会对普通用户上传下载流速控制,让付费用户获更多网络资源。
首先对NetBoxApp 进行功能模块划分 ,遵循高内聚低耦合原则:
一、用户管理模块:
(1)用户注册与登录:
NetBoxApp 支持用户通过多种方式进行注册,包括但不限于邮箱注册、手机号注册、第三方平台(如微信、QQ、支付宝等)授权登录注册。
(2)用户信息管理:
NetBoxApp 允许用户修改个人信息,包括用户名、头像、联系方式、个性签名等,用户可根据自身需求更新个人信息,系统将更新后的信息存储在数据库中并更新用户信息展示界面。
二、文件上传:
(1)文件上传选择:
NetBoxApp 支持多种文件类型的上传,涵盖常见的文档(如 docx、pdf、txt)、图片(如 jpg、png、gif)、音频(如 mp3、wav)、视频(如 mp4、avi、mov)、压缩文件(如 zip、rar)等。
通过直观的文件选择界面,选择文件上传。
(2) 分段上传
NetBoxApp 实现大文件上传功能,对于较大的文件(如几 GB 甚至几十 GB 的文件),采用分片上传技术,将大文件分割成多个小的文件片段进行上传,提高上传的稳定性和效率。
NetBoxApp 提供文件上传进度条,向用户实时显示文件上传的进度,包括已上传部分的比例、已上传的数据量、预计剩余时间等信息,使用户能够直观了解上传状态。
(3) 断点续传上传
NetBoxApp 支持断点续传,当文件上传中断时,系统在服务器端记录已上传的文件片段信息,在用户恢复上传操作时,自动从断点处继续上传,避免用户重新上传整个文件,节省时间和网络资源。
三、文件管理:
(1)文件目录管理:
NetBoxApp 提供文件目录管理功能,用户可创建、删除、重命名文件夹,方便用户对文件进行分类存储。用户可以将文件拖放或移动到不同的文件夹中,系统更新文件的存储位置信息并更新数据库中文件的元数据。
(2)文件元数据管理:
NetBoxApp 支持文件元数据存储,存储文件的名称、大小、类型、创建时间、修改时间、所有者等信息,以便用户查询和管理文件,同时也方便系统进行文件的检索和维护。
四、文件下载模块:
(1)文件下载选择:
NetBoxApp 支持用户从服务器端下载已存储的文件,用户可在文件列表中选择文件进行下载操作,系统将文件从存储节点传输到用户的本地设备。
(2)文件下载进度显示:
NetBoxApp 实现文件下载进度显示,向用户展示下载进度信息,包括已下载部分的比例、下载速度、预计剩余时间等,方便用户掌握下载情况。
(3) 断点续传下载
NetBoxApp 具备断点续传功能,当文件下载因网络故障、设备故障或用户主动暂停而中断时,系统可在用户恢复下载操作时,从断点处继续下载,提高下载的效率和用户体验。
五、用户权限和服务控制模块:
NetBoxApp 区分普通用户和付费用户,为不同类型的用户分配不同的权限。
(1)普通用户:
NetBoxApp 普通用户拥有基础的文件存储、下载、共享等功能,但在存储容量、文件大小限制、下载速度等方面受到一定限制。
(1)付费用户:
NetBoxApp 付费用户可根据不同的NetBoxApp 套餐等级,享受更高的存储容量、更大的文件上传和下载限制、更快的上传和下载速度等特权。系统根据用户的付费套餐信息,对用户的操作权限进行动态调整。
1.1 亿级网盘的 NetBoxApp 功能 用例图
尼恩为大家画了一个 亿级网盘的 NetBoxApp 功能 用例图分析图 , 大致如下:
2、亿级网盘NetBoxApp 非功能需求分析
2.1 总存储量的估算
一个亿的用户,每个用户平均100个文件, 100 亿个文件,每个文件平均10M ,约 多少GB ?
100亿个文件,每个文件平均10M,总大小约为97656250GB。 那么,是多少TB,多少PB?
2.2 高并发的估算
NetBoxApp 设计目标 支持 1 亿用户注册使用,免费用户最大可拥有 1TB 存储空间。
预计日活用户占总用户的 20%,即 2000 W用户。
按照尼恩的3高架构理论, 吞吐量为 2Wqps。
2.3 带宽的估算
2000 W用户,每个活跃用户平均每天上传、下载 4 个文件 假设 每次上传下载文件平均大小 100MB,
所以需要网络带宽负载 计算过程如下:
平均带宽负载为 763Gb/s。 这是一个多大的带宽规模。
2.4 高可靠存储的要求
NetBoxApp 设计目标 文件不丢失,持久存储可靠性达到 99.9999% 。
即 100 万个文件最多丢失(或损坏)1 个文件。
2.5 高可用的要求
NetBoxApp 设计目标 可用性在 99.99% 以上,即一年最多 53 分钟不可用。
最好是 99.999% 以上,即一年最多 5 分钟不可用。
尼恩架构团队,正在制作 超高可用 99.999% (5个9) 的方案和实操,非常牛逼的架构方案。
后面大家可以对照实操一下,然后写入简历, 这个绝对可以让北京、上海、深圳 的it圈 抖三抖。
3、亿级网盘NetBoxApp概要设计
网盘设计的关键是元数据与文件内容的分离存储与管理。
文件元数据就是文件所有者、文件属性、访问控制这些文件的基础信息, 而 NetBoxApp 是将元信息存储在数据库中
文件内容则使用另外专门的存储体系。
NetBoxApp 设计 成为 分布式微服务架构,通过元数据和文件内容的分离存储、API 服务器集群和数据块服务器集群的功能分离和解耦,确保系统的高并发性、高可用性和良好的用户体验。
3.1 客户端模块 设计:
- 用户界面
提供用户与 NetBoxApp 交互的界面,用户可以在此界面上进行各种操作,包括登录、文件操作、文件共享等。该界面需要具备良好的用户体验,易于操作和导航,可能会根据不同设备(如电脑、手机等)有不同的显示和操作逻辑。
- 文件上传客户端
负责从用户本地设备选择文件,并将文件发送到服务器端。在上传过程中,它要与 API 服务器集群中的文件操作 API 交互,启动文件上传操作。同时支持断点续传功能,当上传中断时,能够保存已上传进度,并在后续恢复上传时,从断点处继续上传。
- 文件下载客户端
允许用户发起文件下载请求,通过文件操作 API 从服务器端获取文件。它要显示下载进度,并且在下载中断时,能够记录下载进度,后续通过断点续传服务继续下载文件。
- 文件共享客户端
让用户可以将自己的文件共享给其他用户,包括生成共享链接、指定共享用户等操作。它会调用文件共享 API 完成文件共享操作,并在接收共享文件时,调用文件下载客户端进行文件下载。
3.2 API 服务器集群模块 设计 :
- 用户认证与授权
对用户的登录信息进行验证,确保用户的身份合法。在用户登录、注册、修改密码等操作时,处理用户的身份信息,保证只有授权用户才能使用系统。它可能会与数据库中的文件元数据存储部分交互,验证用户信息的真实性,并发放访问令牌或会话信息,以便后续操作的权限验证。
- 文件元数据管理 API
负责处理文件元数据的相关操作,包括文件的基本信息(如所有者、属性、创建时间等)的存储、更新、查询和删除。这些操作需要与数据库中的文件元数据存储部分进行交互,确保文件元数据的一致性和准确性。
- 文件操作 API
接收用户的文件操作请求,如文件的上传、下载、重命名、删除等操作请求。它会协调文件传输服务和文件元数据管理 API,完成文件的整体操作流程,确保文件操作的有序性和数据一致性。
- 用户管理 API
对用户的信息进行管理,如用户注册、用户信息修改、用户权限设置等。该部分会与数据库中的文件元数据存储部分进行交互,存储和更新用户的信息,同时会考虑用户的不同角色(如普通用户、付费用户),对不同用户的操作权限进行管理。
- 文件共享 API
实现文件的共享功能,允许用户将文件共享给其他用户,同时管理共享的权限和范围。它需要和文件元数据管理 API 协作,更新文件的元数据,反映文件的共享状态,并在用户请求下载共享文件时,协调文件传输服务完成文件的传输。
3.3 数据块服务器集群模块设计 :
- 文件传输服务
处理文件的实际传输过程,在用户发起文件上传或下载请求时,将文件在客户端和存储集群之间进行传输。它要保证文件传输的速度和稳定性,同时可能会根据用户类型(普通用户或付费用户)进行流速控制,为付费用户提供更优质的传输服务。
- 文件断点续传服务
与文件存储和文件传输服务协作,在文件上传或下载中断时,记录文件的传输进度,当用户恢复操作时,能从断点处继续传输文件。
它要和文件存储与管理部分紧密协作,确保存储的文件片段的完整性和可恢复性。
3.4 数据库模块 设计:
- 结构化数据库:存储文件元数据
存储文件的各种元数据信息,包括文件所有者、文件属性、访问控制信息等。
这些元数据对于文件的管理和操作至关重要,是文件操作的基础信息源。
在存储时,要保证元数据的完整性和可查询性,同时要支持文件元数据管理 API 的各种操作,包括添加、更新、删除和查询元数据信息。
- 非结构化数据库:存储文件内容
非结构化数据库 主要负责文件内容的存储和管理,将文件存储在专门的存储体系中。
在接收文件时,要确保文件存储的可靠性和安全性,同时在用户请求文件时,能够准确地找到并提供相应的文件内容。
它可能会使用分布式存储技术,将文件存储在多个存储节点,以实现高可用性和可扩展性。
通过这样的架构和功能模块划分,NetBoxApp 可以实现文件托管、上传、下载、共享等核心功能,并通过元数据和文件内容的分离存储、API 服务器集群和数据块服务器集群的分离管理,确保系统的安全性、高可用性和良好的用户体验。如果你还有其他需求,比如细化某个模块的功能或添加新的模块,请随时告诉我
- 文件存储与管理
主要负责文件内容的存储和管理,将文件存储在专门的存储体系中。在接收文件时,要确保文件存储的可靠性和安全性,同时在用户请求文件时,能够准确地找到并提供相应的文件内容。它可能会使用分布式存储技术,将文件存储在多个存储节点,以实现高可用性和可扩展性。
3.5 整体模块架构图
尼恩为大家画了一个 亿级网盘的 NetBoxApp 功能 模块架构图, 大致如下:
4、亿级网盘NetBoxApp核心流程设计
Transfer-Service 服务 负责 Block 上传和管理的。客户端应用程序根据 API-Service 服务器的返回指令,将文件切分成一些 Block,然后将这些 Block 分别发送给Transfer-Service服务器,Transfer-Service服务器再 调用分布式文件存储与管理器file-server集群,将 Block 存储在file-server 存储服务器中(NetBoxApp 选择 Ceph 作为file-server )。
4.1 文件上传流程设计
在文件上传过程中,首先,客户端应用程序会向 API-Service 服务器发起请求。API-Service 服务器会向客户端应用程序返回相应的指令,客户端应用程序依据此指令将需要上传的文件分割成多个 Block。
之后,客户端会将这些切分好的 Block 逐个发送至 Transfer-Service 服务器。Transfer-Service 服务承担着 Block 的上传和管理任务。
Transfer-Service 服务器收到 Block 后,会调用分布式文件存储与管理器,即 file-server 集群。
Transfer-Service 服务器会将这些 Block 存储到 file-server 存储服务器中,从而完成文件的存储过程。
在 NetBoxApp 中,选用了 Ceph 作为 file-server 。
具体的文件上传流程如下:
客户端应用程序:
- 负责与 API-Service 服务器进行交互,发送文件上传请求。
- 根据 API-Service 服务器返回的指令,将文件切分成 Block。 客户端应用程序收集文件元数据,包括文件名、文件内容 MD5、文件大小等等,并根据文件大小计算 Block 的数量(NetBoxApp 设定每个 block 大小 4MB),以及每个 Block 的 MD5 值, 发送到API-Service 服务器
- 客户端连接获取 Transfer-Service 列表后,连接 Transfer-Service 服务器,发送请求上传Block的请求 ,等待 Transfer-Service 的确认
- Transfer-Service 的确认后, 客户端切分 Block, 是将切分后的 Block 发送给 Transfer-Service 服务器。
API-Service 服务器:
- 接收客户端的文件上传请求。
- 向客户端应用程序返回文件切分指令,指导客户端如何将文件切分成 Block。
- API 服务器收到文件元数据后,为每个 Block 分配全局唯一的 BlockID(BlockID 为严格递增的 64 位正整数,总可记录数据大小 ,足以满足 NetBoxApp的应用场景)。API 服务器将文件元数据与 BlockID 记录在数据库中,并将 BlockID 列表和应用程序可以连接的 Transfer-Service 服务器 列表返回客户端
Transfer-Service 服务器:
- Transfer-Service 服务端接收客户端发送的文件 Block的请求。Transfer-Service 服务器连接 API 服务器进行权限和文件元数据验证。验证通过后,给客户端发送响应
- Transfer-Service 收到 客户端上传 的 Block 数据,Transfer-Service 服务器再次验证 Block 数据的 MD5 值,确认数据完整后,调用分布式文件存储与管理器 file-server 集群的接口 存储 Block数据, 将BlockID 和 Block 数据保存到对象存储集群 file-server 中
- 接收 file-server 存储服务器的存储确认,并将存储确认信息反馈给客户端应用程序。
file-server 存储服务器集群:
- 负责存储 Transfer-Service 服务器发送过来的文件 Block。
- 向 Transfer-Service 服务器返回存储确认信息,表明文件 Block 已存储成功。
4.2 文件上传流程的时序图:
尼恩为大家画了一个 亿级网盘的 NetBoxApp 用户上传文件的时序图 , 大致如下:
4.3 文件下载流程设计
文件下载功能流程描述:
客户端应用程序:
- 负责与 API-Service 服务器进行交互,发送文件下载请求。请求中包含所需下载文件的元数据信息,如文件名、文件id 等信息,以便 API-Service 服务器查找文件。
- 接收 API-Service 服务器返回的文件的 BlockID 列表和对应的 Transfer-Service 服务器列表。
- 依据 Transfer-Service 服务器列表,向 Transfer-Service 服务器发送下载 Block 的请求,等待 Transfer-Service 服务器的响应。
- 接收 Transfer-Service 服务器发送的 Block 数据,将其组装成完整的文件,完成文件下载。
API-Service 服务器:
- 接收客户端的文件下载请求。
- 根据客户端提供的文件元数据信息(如文件名、文件id 等信息) ,从数据库中查找文件对应的 BlockID 列表。
- 将 BlockID 列表和相应的 Transfer-Service 服务器列表返回给客户端应用程序。
Transfer-Service 服务器:
- 接收客户端应用程序 的文件下载请求,包括 BlockID 列表。
- 连接 API-Service 服务器进行文件权限和文件元数据验证,确保客户端有权限下载该文件。
- 向 file-server 存储服务器集群发送获取 Block 数据的请求。
- 接收 file-server 存储服务器集群返回的 Block 数据,并发送给客户端应用程序。
file-server 存储服务器集群:
- 接收 Transfer-Service 服务器的请求,根据 BlockID 查找并获取相应的 Block 数据。
- 将查找到的 Block 数据发送给 Transfer-Service 服务器。
4.4 文件下载流程的时序图:
尼恩为大家画了一个 亿级网盘的 NetBoxApp 用户下载文件的时序图 , 大致如下:
5、亿级网盘NetBoxApp详细设计
5.1 NetBoxApp 的类和对象设计图如下:
尼恩为大家画了一个 亿级网盘的 NetBoxApp 类和对象设计图 , 大致如下:
5.2 Client 类:
Client 类表示使用 NetBoxApp 的客户端,包含客户端的基本信息(clientId
和 username
)。
Client 类具有与文件上传、下载相关的操作方法,以及处理响应和文件块数据的方法。
Client 类通过 setTransferServiceList
和 setAPIService
方法,可以与传输服务和 API 服务建立关联。
5.3 FileMetadata 类:
FileMetadata 存储文件的元数据信息,如文件标识符、名称、大小、所有者和创建日期等。
FileMetadata 包含一个块标识符列表,因为文件可能会被拆分成多个块存储。
FileMetadata 类的核心属性:
fileId
: 文件的唯一标识符。fileName
: 文件名。fileSize
: 文件大小。owner
: 文件所有者。creationDate
: 文件创建日期。blockIds
: 存储该文件的块的标识符列表。checksum
: 文件的校验和。
5.4 Block 类:
Block 类表示文件的一部分,包含块标识符、数据内容和校验和。
Block 类提供了获取块信息和计算校验和的方法。
Block 类的核心属性:
blockId
: 块的唯一标识符。data
: 块的数据内容。size
: 块的大小。checksum
: 块的校验和。
5.5 APIService 类:
APIService提供文件上传和下载的处理接口,同时负责文件元数据的存储和检索操作。
APIService与数据库和传输服务交互,以完成文件操作和元数据的管理。
5.6 TransferService 类:
TransferService处理文件块的上传和下载操作,包括验证客户端访问权限和存储、检索文件块。
TransferService与文件服务器和数据库协同工作,确保文件块的存储和检索操作的完成。
5.7 FileServer 类:
FileServer 负责文件块的实际存储和检索操作,存储位置由 storagePath
属性表示。
5.8 NetBoxApp 的类和对象详细设计图:
尼恩为大家画了一个 亿级网盘的 NetBoxApp 类和对象详细设计图 , 大致如下:
6、 亿级网盘NetBoxApp面临的主要技术挑战
实现这样一个大规模网盘系统,面临以下几方面的技术挑战:
万亿GB/100PB级别的大规模存储挑战:
如何管理万亿GB/100PB级别存储海量数据,以及确保这些数据的高可用和可靠性。
高并发访问:
一个亿的用户,系统需要具备高2wqps并发处理能力。
秒传与去重:
如何快速判断文件是否已存在,并避免重复存储相同的文件。
普通用户限速:
根据用户 类型等因素设置灵活的限速策略。
数据一致性与安全性:
在多副本存储和分布式环境下,确保数据的一致性和传输的安全性。
7、 挑战1:万亿GB/100PB级别的大规模存储挑战
万亿GB/100PB级别数据存储的技术选型 , hdfs、 minio、 ceph
7.1 数据存储框架1:HDFS
HDFS 采用主从架构,由一个 NameNode 作为主节点和多个 DataNode 作为从节点组成。
文件被分割成固定大小的数据块,默认情况下在 Hadoop2.x 版本中数据块大小为 128MB,这些数据块会被存储在不同的 DataNode 上,并且每个数据块会有多个副本以保证数据的冗余和容错性。
HDFS优势
- 1 高容错性:
HDFS通过数据块的冗余存储,即使部分 DataNode 出现故障,也能保证数据的完整性和可用性,适合长期存储海量数据
- 2 高吞吐量:
HDFS 优化了大文件的存储和读取,能够高效地处理 TB 级甚至 PB 级的大规模数据,适用于批量数据处理的场景,如大数据分析等
- 3 硬件要求低:
可以运行在普通的低成本硬件设备上,无需高端存储设备,能够有效降低大规模存储的硬件成本.
HDFS的不足
- 1 元数据管理压力:
NameNode 需要将文件系统的元数据存储在内存中,当存储大量小文件时,元数据的数量会剧增,导致内存压力过大,限制了系统可存储的文件总数3.
- 2 不适合低延迟访问:
HDFS 的设计主要是为了处理大规模的批量数据,数据的读写操作存在一定延迟,不适合对实时性要求较高的应用场景, 作为文件存储服务,HDFS不适合。
- 3 不支持文件修改:
文件一旦写入 HDFS,就只能在文件末尾追加数据,不支持随机写入或修改操作,对于需要频繁更新数据的应用场景不太适用
7.2 数据存储框架2:MinIO
MinIO 是专注于对象存储的轻量级分布式文件系统,采用水平扩展的架构,所有智能处理均在软件层实现,用户可灵活选择硬件。
MinIO 将元数据和数据存储在一起,并采用原子提交技术,避免了独立元数据数据库导致的性能瓶颈, 这个正好是HDFS 的短板
MinIO 优势
- 高性能:
针对性能进行了深度优化,MinIO 使用 SIMD 指令和并行 I/O 技术,实现高吞吐量和低延迟,能够很好地处理大文件和高并发请求,纠删码技术进一步提高了存储效率的同时提供了数据保护
- 云原生支持:
MinIO 完全兼容 Amazon S3 API,支持 Kubernetes 原生操作器,可无缝集成到现代云原生生态中,
如与 Kubernetes、Prometheus 和 Grafana 等工具配合良好,也支持主流的大数据和 AI 工具,如 Spark 和 TensorFlow 等
易用性高:
MinIO 提供简单易用的安装方式,无需复杂配置即可快速部署,并且配备直观的管理控制台,降低了初期运维成本,适合快速上线和动态负载需求的场景扩展性强:
MinIO 支持水平扩展,可动态添加或移除节点,无需停机,能够适应从小规模部署到大规模企业级集群的需求,其架构能够灵活应对不同规模的数据存储需求
MinIO 劣势
对而言,MinIO 主要专注于对象存储,对于一些需要复杂存储类型(如块存储、文件存储等)支持的场景可能不如 Ceph 等多功能存储系统适用
对象存储和文件存储的区别:
- 对象存储: 以对象(Object)为单位存储数据,每个对象包含数据本身以及相关的元数据(Metadata)。对象存储通常使用扁平化的结构,没有目录树的概念。
- 文件存储:基于文件系统,数据以文件和目录(文件夹)的形式组织。文件存储通常有树状的目录结构。
7.3 数据存储框架3:Ceph
Ceph 是一种分布式对象存储系统,其核心组件包括 RADOS、CephFS、RBD 和 RGW 等。
- RADOS 作为底层存储层,将数据分布在多个存储设备上实现高可用性;
- CephFS 提供统一的文件系统接口;
- RBD 提供虚拟块设备的存储抽象,可与虚拟化平台集成;
- RGW 则将 Ceph 对象存储系统封装成标准对象存储接口,方便与外部交互.
Ceph整体的文件存储流程,主要分四层,File->Objects->PGs->OSDs, 具体如下图:
File: 要存储和访问的文件 ,这个是面向我们用户的,是我们直观操作的对象。
Object:这个object就是Ceph底层RADOS所看到的对象,也就是在Ceph中存储的基本单位了。object的大小由RADOS限定(通常为2m或者4m)。就跟HDFS抽象一个数据块一样,这里也是为了方便底层存储的组织管理。当File过大时,需要将File切分成大小统一的objects进行存储。
PG (Placement Group):PG是一个逻辑的概念,它的用途是对object的存储进行组织和位置的映射,通过它可以更好的分配数据和定位数据。
OSD (Object Storage Device): 它就是真正负责数据存取的服务。
PG和object是一对多的关系,一个PG里面组织若干个object,但是一个object只能被映射到一个PG中。
PG和OSD是多对多的关系,一个PG会映射到多个OSD上(大于等于2,此处即为副本机制),每个OSD也会承载大量的PG。
Ceph优势
- 高度可扩展性:
可以根据需求进行水平扩展,用户能够根据存储需求增加新节点,实现存储容量和性能的线性增长,能够轻松应对海量数据的增长和高并发访问需求
- 高度可靠性:
通过数据复制或编码等方式保证数据的可靠性和冗余,即使部分节点发生故障,数据依然可以正常访问,确保了数据的安全性和可用性
- 多种存储方式支持:
支持对象、块和文件存储等多种存储类型,能够满足不同应用场景下的存储需求,如企业级存储、虚拟化环境存储等
Ceph 劣势
- 部署和维护复杂:
Ceph 的部署和维护需要一定的技术能力和经验,涉及多个子系统的配置和管理,如 OSD、Monitor、MDS 等,对运维团队的专业要求较高.
- 性能优化难度大:
由于其多功能性和复杂的架构,在大规模集群中性能优化的难度相对较大,需要对系统有深入的了解和专业的调优知识
7.4 Spring Boot集成Ceph对象存储
Swift是由Rackspace开发,用来为云计算提供可扩展存储的项目。
Swift 专注于 对象存储 , 并提供一套REST风格的Api来访问, 与Ceph强一致性不同, Swift 是最终一致性。
Swift 也是优秀的 开源项目 , 并无明显优劣之分,在使用场景上有所不同, 如果是专注于对象存储, 那么可以选择swift即可满足需要, 如果还有 块存储 要求, 那么选择Ceph更为合适。
这里选择Ceph + Swift api, 因为通过Ceph 网关可以适配兼容swift api, 同时在数据访问上具有较强的扩展性。
在本教程中,我将向你展示如何在Spring Boot应用程序中集成Ceph对象存储Swift模式。这将帮助你更好地管理和存储大量数据,提高应用的性能和可扩展性。
流程概览
下面是通过 Swift api,集成 Spring Boot集成Ceph对象存储的 流程 步骤:
步骤 | 描述 |
---|---|
1. | 配置Ceph对象存储 |
2. | 添加Swift模块依赖 |
3. | 创建Ceph Swift配置类 |
4. | 实现上传和下载功能 |
步骤详解
- 配置Ceph对象存储
首先, 需要在Ceph中创建一个Bucket,并获取Access Key和Secret Key,以便后续Spring Boot应用程序连接到Ceph对象存储。
- 添加Swift模块依赖
在Spring Boot项目的pom.xml
文件中添加Ceph Swift模块的依赖:
<dependency>
<groupId>org.javaswift</groupId>
<artifactId>java-cloud-swift</artifactId>
<version>4.0.0</version>
</dependency>
3. 创建Ceph Swift配置类
创建一个名为CephSwiftConfig
的配置类,用于配置连接到Ceph Swift对象存储的相关信息:
@Configuration
public class CephSwiftConfig {
@Value("${ceph.swift.authUrl}")
private String authUrl;
@Value("${ceph.swift.tenantName}")
private String tenantName;
@Value("${ceph.swift.userName}")
private String userName;
@Value("${ceph.swift.password}")
private String password;
@Bean
public Swift getSwift() {
return new Swift(authUrl, tenantName, userName, password);
}
}
4. 实现上传和下载功能
在 Service或Controller中实现上传和下载功能的代码,如下所示:
@Autowired
private Swift swift;
public void uploadFile(String bucketName, String key, File file) {
SwiftObject swiftObject = swift.newStaticObject();
swiftObject.setTempFile(file);
swift.uploadObject(bucketName, swiftObject);
}
public File downloadFile(String bucketName, String key) {
SwiftObject swiftObject = swift.getObject(bucketName, key);
return swiftObject.downloadObjectAsFile();
}
8、 挑战2: 2Wqps 高并发访问
NetBoxApp 设计目标 支持 1 亿用户注册使用,免费用户最大可拥有 1TB 存储空间。
预计日活用户占总用户的 20%,即 2000 W用户。
按照尼恩的3高架构理论, 吞吐量为 2Wqps。
这里的方案比较复杂, 具体可以参考尼恩的三级缓存架构视频。
9、 挑战3:如何实现秒传?
秒传功能,即快速上传文件功能, 旨在提高用户在网盘上传文件的速度,同时减轻网盘存储负载及避免用户网络带宽浪费和长时间等待。
在网盘存储中,存在大量如电影、电子书等内容重复的文件,若重复上传会产生诸多问题。
为此,NetBoxApp 在设计上对于物理相同的文件仅保存一份。当用户上传文件时,NetBoxApp 会先在客户端计算文件的 MD5 值,之后依据该 MD5 值检查文件是否已存在于存储中。
若已存在,仅需建立用户文件与该物理文件的关联,无需用户实际上传文件,由此实现秒传。
然而,此设计存在潜在风险。
因为, MD5 算法可能出现哈希冲突,不同文件计算出的 MD5 值可能相同,这会引发 NetBoxApp 误判,带来诸多不良后果, 即上传与目标文件 MD5 值相同的文件后可下载目标文件,影响系统的安全性和用户数据的完整性。
如何解决 碰撞风险呢? 可以引入SHA-256或其他方式进行更严格的文件完整性校验。
尼恩为大家画了一个 亿级网盘的 NetBoxApp 如何实现秒传设计图 , 大致如下:
9.1 通过 SHA-256 判断文件是否存在?
秒传的核心在于判定用户上传的文件是否已经存在于系统中。
在用户上传文件时,首先计算文件的SHA-256 值,因为 SHA-256 算法 能够高效地生成文件的唯一标识。后面NetBoxApp 根据上传文件的SHA-256 值,查询是否已存在同样的文件。
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class HashCalculator {
// 计算文件的 SHA-256 哈希值
public static String calculateFileHash(String filePath) {
try (FileInputStream fis = new FileInputStream(filePath)) {
// 获取 SHA-256 算法的 MessageDigest 实例
MessageDigest md = MessageDigest.getInstance("SHA-256");
// 定义一个字节数组作为缓冲区,用于读取文件数据,这里设置为 8192 字节,可根据需要调整大小
byte[] buffer = new byte[8192];
int bytesRead;
// 循环读取文件内容,直到文件结束
while ((bytesRead = fis.read(buffer))!= -1) {
// 将读取的文件数据更新到 MessageDigest 中,每次更新一部分数据
md.update(buffer, 0, bytesRead);
}
// 完成哈希计算,生成最终的哈希值,结果是字节数组
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
// 将字节数组形式的哈希结果转换为十六进制字符串表示
for (byte b : digest) {
// 将每个字节转换为两位十六进制字符串并添加到 StringBuilder 中
sb.append(String.format("%02x", b));
}
// 返回十六进制字符串形式的哈希值
return sb.toString();
} catch (NoSuchAlgorithmException e) {
// 处理不支持的算法异常,打印异常信息
System.err.println("不支持的哈希算法: " + e.getMessage());
return null;
} catch (IOException e) {
// 处理文件读取异常,打印异常信息
System.err.println("文件读取异常: " + e.getMessage());
return null;
}
}
// 校验文件的完整性,比较两个文件的 SHA-256 哈希值是否相等
public static boolean verifyFileIntegrity(String filePath1, String filePath2) {
String hash1 = calculateFileHash(filePath1);
String hash2 = calculateFileHash(filePath2);
// 比较两个文件的哈希值是否相等
return hash1!= null && hash2!= null && hash1.equals(hash2);
}
public static void main(String[] args) {
// 要校验完整性的第一个文件路径,请替换为实际文件路径
String filePath1 = "path/to/file1.txt";
// 要校验完整性的第二个文件路径,请替换为实际文件路径
String filePath2 = "path/to/file2.txt";
// 调用 verifyFileIntegrity 方法校验文件完整性
boolean isIntegral = verifyFileIntegrity(filePath1, filePath2);
if (isIntegral) {
// 输出文件完整性校验结果
System.out.println("文件完整性校验通过");
} else {
System.out.println("文件完整性校验失败");
}
}
}
9.2 实现秒传 的执行流程
step1:客户端发起上传请求:
用户通过 NetBoxApp
的客户端 向 API服务发起文件上传请求。
这一步, NetBoxApp
调用 HashCalculator
组件,使用 SHA-256 算法计算文件的哈希值。
step2: 存储查询:NetBoxApp
将计算得到的哈希值发送API服务, API服务通过 DataSource
进行查询,看是否存在相同哈希值的文件。
step3:内容比对(仅在哈希值相同的情况下):
如果API服务通过 DataSource
进行查询后,查询到存在相同哈希值的文件,并且通过RPC 从 TransferService 查询部分内容,API服务 返回部分内容给 NetBoxApp
。
NetBoxApp
调用 ContentChecker
组件,对新文件和存储中的文件进行部分内容的比对。
API服务 可以随机选取文件的多个部分,如文件开头、中间和结尾部分进行比对,以确保文件内容一致。
step4:存储或映射建立:
如果内容比对结果显示文件相同,仅建立用户文件和物理文件的映射关系,实现秒传。
如果内容不同或存储中不存在相同哈希值的文件,与TransferService服务 传输数据,TransferService服务 将文件存储到 FileServerCluster
中,并建立用户文件和新存储文件的映射关系。
9.3 实现秒传 的执行流程 uml 图
尼恩为大家画了一个 亿级网盘的 NetBoxApp 如何实现秒传详细设计图 , 大致如下:
10、 挑战4:如何 限速设计方案?
首先,NetBoxApp 需要根据用户的付费类型和使用情况对用户进行限速。
通常有以下几种用户类型:
- 免费用户:对上传和下载速度进行严格限制,以降低系统负担。
- 付费用户:根据付费等级提供不同的上传和下载速度。
NetBoxApp 根据用户付费类型决定用户的上传、下载速度。而要控制上传、下载速度,可以通过限制并发 Block 服务器数目,以及限制TransferService 内的线程数来实现。
具体过程是,客户端程序访问 API 服务器,请求上传、下载文件的时候,API 服务器可以根据用户类型,决定分配的 TransferService数目和TransferService内的服务线程数,以及每个线程的上传、下载速率。
TransferService会根据 API 服务器的返回值,来控制客户端能够同时上传、下载的 Block 数量以及传输速率,以此对不同用户进行限速。
10.1 实现限速 的执行流程设计
尼恩为大家画了一个 亿级网盘的 NetBoxApp 如何实现限速详细设计图 , 大致如下:
时序图总结:
- 该时序图涉及四个主要参与者:用户(User)、客户端程序(Client)、API 服务器(API_Server)和传输服务(TransferService)。
- 首先,用户通过客户端程序发起文件的上传或下载请求。
- 客户端程序将该请求发送给 API 服务器。
- API 服务器会根据用户的付费类型进行判断,如区分免费用户和付费用户,对于不同类型的用户确定不同的限速策略,此策略涉及到对 TransferService 数目的分配、服务线程数以及每个线程的上传和下载速率的设定。
- API 服务器将确定好的限速信息反馈给客户端程序。
- 客户端程序将这些限速信息传递给传输服务。
- 传输服务根据收到的限速信息,控制同时上传或下载的 Block 数量和传输速率。
- 最终传输服务执行文件传输操作,完成文件传输后,将结果反馈给客户端程序,客户端程序再将结果反馈给用户。
10.2 Block服务器的并发与传输控制
TransferService接收API服务器的请求后,需要进行传输速率控制,根据用户等级和当前的网络情况来动态调整传输速率。
下面是一个参考的 带有速度限制 传输文件的方法 transferFileWithRateLimit方法。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class FileTransferWithSpeedLimit {
// 传输文件的方法,带有速度限制
public static void transferFileWithRateLimit(String sourcePath, String destinationPath, long speedLimitBytesPerSecond) throws IOException, InterruptedException {
// 创建文件输入流,从源文件读取数据
try (InputStream inputStream = new FileInputStream(sourcePath);
// 创建文件输出流,将数据写入目标文件
OutputStream outputStream = new FileOutputStream(destinationPath)) {
byte[] buffer = new byte[8192]; // 定义一个 8KB 的缓冲区
long startTime = System.currentTimeMillis(); // 记录开始时间
int bytesRead;
long bytesTransferred = 0; // 已传输的字节数
while ((bytesRead = inputStream.read(buffer))!= -1) {
// 将数据写入目标文件
outputStream.write(buffer, 0, bytesRead);
bytesTransferred += bytesRead;
// 计算已传输的时间
long elapsedTime = System.currentTimeMillis() - startTime;
// 如果传输速度超过限制,暂停一段时间
if (bytesTransferred > speedLimitBytesPerSecond * (elapsedTime / 1000)) {
long sleepTime = (bytesTransferred / speedLimitBytesPerSecond) * 1000 - elapsedTime;
if (sleepTime > 0) {
// 暂停线程,以实现限速
Thread.sleep(sleepTime);
}
}
}
}
}
public static void main(String[] args) {
try {
// 源文件路径
String sourcePath = "path/to/source/file";
// 目标文件路径
String destinationPath = "path/to/destination/file";
// 每秒限制传输 100KB
long speedLimitBytesPerSecond = 102400;
// 调用文件传输方法
transferFileWithRateLimit(sourcePath, destinationPath, speedLimitBytesPerSecond);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
11、 挑战5:5个9 高可用的要求
NetBoxApp 设计目标 可用性在 99.99% 以上,即一年最多 53 分钟不可用。
最好是 99.999% 以上,即一年最多 5 分钟不可用。
尼恩架构团队,正在制作 超高可用 99.999% 的方案和实操视频,这个非常牛逼,非常漂亮。
后面大家可以对照实操一下,然后写入简历, 这个 可以让北京、上海、深圳 的 it圈 抖三抖 。
12、 其他的挑战
万亿GB/100PB级别的 网盘系统的挑战,非常的多
大家在做架构的过程中,如果遇到了问题,可以 来尼恩的 架构师 社群 交流。
说在最后:有问题找老架构取经
回到开始的时候的面试题:招商银行的Java后端面试真题
被狠狠拷打了,问的人都懵了。 项目场景题太难了,不好好准备,真的答不出!
按照尼恩的参考答案回答,一定会 吊打面试官,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。
在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。
很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
另外,如果没有面试机会,可以找尼恩来改简历、做帮扶。前段时间,刚刚指导 一个2年经验小伙,拿到 年薪60W的 天价年薪 ,3大 offer, 实现了一本 吊打 985、211。
狠狠卷,实现 “offer自由” 很容易的, 前段时间一个武汉的跟着尼恩卷了2年的小伙伴, 在极度严寒/痛苦被裁的环境下, offer拿到手软, 实现真正的 “offer自由” 。
尼恩技术圣经系列PDF
- 《NIO圣经:一次穿透NIO、Selector、Epoll底层原理》
- 《Docker圣经:大白话说Docker底层原理,6W字实现Docker自由》
- 《K8S学习圣经:大白话说K8S底层原理,14W字实现K8S自由》
- 《SpringCloud Alibaba 学习圣经,10万字实现SpringCloud 自由》
- 《大数据HBase学习圣经:一本书实现HBase学习自由》
- 《大数据Flink学习圣经:一本书实现大数据Flink自由》
- 《响应式圣经:10W字,实现Spring响应式编程自由》
- 《Go学习圣经:Go语言实现高并发CRUD业务开发》
……完整版尼恩技术圣经PDF集群,请找尼恩领取
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓