设计 DropBox 及类似的云文件存储系统

设计 DropBox

让我们设计一个文件托管服务,例如Dropbox或Google Drive。云文件存储使用户可以将其数据存储在远程服务器上。通常,这些服务器由云存储提供商维护,并通过网络供用户使用。用户每月支付其云数据存储费用。类似服务:OneDrive,Google Drive

为什么要使用云存储?

云文件存储服务最近变得非常流行,因为它们简化了多个设备之间数字资源的存储和交换。人们认为,从使用单个个人计算机转变为使用具有不同平台和操作系统的多个设备(例如智能手机和平板电脑)可以随时随地从不同地理位置进行便携式访问的转变是云存储服务的巨大普及的原因。以下是此类服务的一些主要优点:

  1. 可用性 Availability:云存储服务的座右铭是随时随地具有数据可用性。用户可以随时随地从任何设备访问其文件/照片。
  2. 可靠性和持久性 Reliability and Durability:云存储的另一个好处是,它提供了100%的数据可靠性和持久性。云存储通过将数据的多个副本保存在不同地理位置的服务器上,确保用户永远不会丢失其数据。
  3. 可扩展性 Scalability:用户将永远不必担心会耗尽存储空间。有了云存储,只要您准备为此付费,便可以拥有无​​限的存储空间。

系统的要求和目标

我们希望从云存储系统中实现什么?以下是我们系统的最高要求:

  1. 用户应该能够从任何设备上载和下载他们的文件/照片。
  2. 用户应该能够与其他用户共享文件或文件夹。
  3. 我们的服务应支持设备之间的自动同步,即,在一台设备上更新文件后,该文件应在所有设备上同步。
  4. 系统应支持存储最大为GB的大文件。
  5. 必须提供ACID-ity。所有文件操作的原子性 Atomicity,一致性 Consistency,隔离性 Isolation和持久性 Durability 都应得到保证。
  6. 我们的系统应支持离线编辑。用户应该能够在脱机时添加/删除/修改文件,并且一旦他们上线,他们的所有更改都应该同步到远程服务器和其他在线设备。

扩展要求
系统应支持数据快照,以便用户可以返回到任何版本的文件。

一些设计注意事项

  • 我们应该期望巨大的读写量。
  • 读写比率预计将几乎相同。
  • 在内部,文件可以存储为小块或小块(例如4MB)。这可以带来很多好处,即所有失败的操作仅应针对文件的较小部分进行重试。如果用户未能上传文件,则仅重试失败的块。
  • 我们可以仅通过传输更新的块来减少数据交换的数量。
  • 通过删除重复的块,我们可以节省存储空间和带宽使用。
  • 与客户端一起保留元数据的本地副本(文件名,大小等)可以为我们节省许多往返服务器的行程。
  • 对于较小的更改,客户端可以智能地上传差异而不是整个块。

容量估算和约束

  • 假设我们有5亿总用户,每天有1亿活跃用户(DAU)。
  • 假设平均每个用户从三个不同的设备进行连接。
  • 如果一个用户平均拥有200张文件/照片,则我们总共将拥有1000亿个文件。
  • 假设平均文件大小为100KB,这将为我们提供10 PB的总存储量。
    100B * 100KB => 10PB
  • 我们还假设每分钟将有100万个活动连接。

高级设计

用户将在其设备上指定一个文件夹作为工作区。放置在此文件夹中的任何文件/照片/文件夹都将上传到云中,并且无论何时修改或删除文件,它都将以相同的方式反映在云存储中。用户可以在其所有设备上指定相似的工作空间,并且在一个设备上进行的任何修改都将传播到所有其他设备,以使各处的工作空间视图相同。

在较高级别,我们需要存储文件及其元数据信息,例如文件名,文件大小,目录等,以及与谁共享文件。因此,我们需要一些可以帮助客户端将文件上传/下载到Cloud Storage的服务器,以及一些可以帮助更新有关文件和用户的元数据的服务器。我们还需要某种机制来在发生更新时通知所有客户端,以便它们可以同步其文件。

如下图所示,块服务器 (Block Server) 将与客户端 (client) 一起从云存储上载/下载文件,而元数据服务器 (Metadata Server) 将在SQL或NoSQL数据库中更新文件的元数据。同步服务器 (Synchronization servers) 将处理通知所有客户端有关同步的不同更改的工作流。

组件设计

客户端

客户端应用程序监视用户计算机上的工作区文件夹,并将其中的所有文件/文件夹与远程Cloud Storage同步。客户端应用程序将与存储服务器一起使用,以上传,下载和修改实际文件到后端Cloud Storage。客户端还与远程同步服务进行交互,以处理任何文件元数据更新,例如,文件名,大小,修改日期等的更改。

这是客户端的一些基本操作:

  1. 上传和下载文件。
  2. 检测工作区文件夹中的文件更改。
  3. 处理由于脱机或并发更新而引起的冲突。

我们如何有效地处理文件传输?如上所述,我们可以将每个文件分成较小的块,以便仅传输那些已修改的块,而不传输整个文件。假设我们将每个文件分成固定大小的4MB块。我们可以基于
1)在云中使用的存储设备来静态计算最佳块大小,以优化空间利用率和每秒的输入/输出操作(IOPS)
2)网络带宽
3)存储中的平均文件大小等。在我们的元数据中,我们还应该记录每个文件以及组成该文件的块。

我们应该与客户一起保留元数据的副本吗?保留元数据的本地副本不仅使我们能够进行脱机更新,而且还节省了许多往返以更新远程元数据。

客户如何才能有效地聆听与其他客户一起发生的变化? 一种解决方案是客户端定期与服务器核对是否有任何更改。这种方法的问题在于,与服务器在有任何更改时通知的情况相比,客户端将定期检查更改,因此我们将延迟本地反映更改的时间。如果客户端经常检查服务器的更改,则不仅浪费带宽,因为服务器大多数时候必须返回空响应,而且还会使服务器繁忙。以这种方式提取信息是不可扩展的。

解决上述问题的方法可能是使用HTTP长轮询。使用长轮询时,客户端会期望服务器可能不会立即响应,从而从服务器请求信息。如果在收到轮询时服务器没有客户端的新数据,则服务器将打开请求并等待响应信息变为可用,而不是发送空响应。一旦收到新信息,服务器将立即向客户端发送HTTP / S响应,从而完成打开的HTTP / S请求。收到服务器响应后,客户端可以立即发出另一个服务器请求以进行将来的更新。

基于以上考虑,我们可以将客户分为四个部分:

  1. 内部元数据数据库 Internal Metadata Database:将跟踪所有文件,块,它们的版本以及它们在文件系统中的位置。
  2. 分块者 Chunker :会将文件分成称为块的小块。它还将负责从文件块中重建文件。我们的分块算法将检测用户已修改的文件部分,并将这些部分仅传输到Cloud Storage;这将节省我们的带宽和同步时间。
  3. 观察者 Watcher:将监视本地工作区文件夹,并将用户执行的任何操作通知索引器(如下所述),例如,当用户创建,删除或更新文件或文件夹时。监视程序还侦听同步服务广播的其他客户端上发生的任何更改。
  4. 索引器 Indexer: 将处理从监视程序收到的事件,并使用有关已修改文件的块的信息来更新内部元数据数据库。一旦将块成功提交/下载到Cloud Storage,索引器将与远程同步服务进行通信,以将更改广播到其他客户端并更新远程元数据数据库。
    在这里插入图片描述

客户端应如何处理速度较慢的服务器? 如果服务器忙/无响应,客户端应按指数方式退缩。这意味着,如果服务器响应太慢,客户端应延迟重试,并且此延迟将成倍增加。

移动客户端是否应该立即同步远程更改?与台式机或Web客户端不同,移动客户端通常按需同步,以节省用户的带宽和空间。

元数据库

元数据数据库负责维护有关文件/块,用户和工作区的版本控制和元数据信息。元数据数据库可以是关系数据库(例如MySQL)或NoSQL数据库服务(例如DynamoDB)。无论数据库的类型如何,同步服务都应该能够使用数据库提供文件的一致视图,尤其是当多个用户同时使用同一文件时。由于NoSQL数据存储区不支持ACID属性以支持可伸缩性和性能,因此,如果我们选择这种数据库,则需要以编程方式将对ACID属性的支持合并到我们的同步服务的逻辑中。然而,

元数据数据库应存储有关以下对象的信息:

  1. 大块
  2. 档案文件
  3. 用户
  4. 设备
  5. 工作区(同步文件夹)

同步服务

同步服务 Synchronization Service 是处理客户端所做的文件更新并将这些更改应用于其他订阅的客户端的组件。它还将客户端的本地数据库与存储在远程元数据DB中的信息同步。同步服务是系统架构中最重要的部分,因为它在管理元数据和同步用户文件中起着至关重要的作用。桌面客户端与同步服务进行通信,以从Cloud Storage获取更新或将文件和更新发送到Cloud Storage以及潜在的其他用户。如果客户端离线一段时间,它将在新的更新联机时轮询系统。当同步服务收到更新请求时,它将与元数据数据库进行一致性检查,然后继续进行更新。

同步服务应设计为在客户端和Cloud Storage之间传输较少的数据,以实现更好的响应时间。为了达到此设计目标,同步服务可以采用差分算法 differencing algorithm来减少需要同步的数据量。无需将整个文件从客户端传输到服务器,反之亦然,我们只需传输文件两个版本之间的差异即可。因此,仅传输文件中已更改的部分。这也为最终用户减少了带宽消耗和云数据存储。如上所述,我们将文件划分为4MB的块,并且仅传输修改后的块。服务器和客户端可以计算哈希(例如SHA-256)以查看是否更新块的本地副本。在服务器上,如果我们已经有一个具有相似哈希值的块(即使来自另一个用户),则不需要创建另一个副本;我们可以使用相同的块。稍后将在重复数据删除中对此进行详细讨论。

为了能够提供有效且可扩展的同步协议,我们可以考虑在客户端和同步服务之间使用通信中间件。消息传递中间件应提供可伸缩的消息队列和更改通知,以使用拉或推策略来支持大量客户端。这样,多个Synchronization Service实例可以从全局请求Queue接收请求,并且通信中间件将能够平衡其负载。

消息队列服务 Message Queuing Service

An important part of our architecture is a messaging middleware that should be able to handle a substantial number of requests. A scalable Message Queuing Service that supports asynchronous message-based communication between clients and the Synchronization Service best fits the requirements of our application. The Message Queuing Service supports asynchronous and loosely coupled message-based communication between distributed components of the system. The Message Queuing Service should be able to efficiently store any number of messages in a highly available, reliable, and scalable queue.

The Message Queuing Service will implement two types of queues in our system. The Request Queue is a global queue and all clients will share it. Clients’ requests to update the Metadata Database will be sent to the Request Queue first; from there, the Synchronization Service will take it to update metadata. The Response Queues that correspond to individual subscribed clients are responsible for delivering the update messages to each client. Since a message will be deleted from the queue once received by a client, we need to create separate Response Queues for each subscribed client to share update messages.

我们的体系结构的重要组成部分是消息传递中间件,它应该能够处理大量请求。一个可扩展的消息队列服务,它支持客户端与同步服务之间基于异步消息的通信,这最适合我们应用程序的要求。A scalable Message Queuing Service that supports asynchronous message-based communication between clients and the Synchronization Service best fits the requirements of our application. 消息队列服务支持系统分布式组件之间的异步和松散耦合的基于消息的通信。消息队列服务应该能够在高度可用,可靠和可伸缩的队列中有效存储任意数量的消息。

消息队列服务将在我们的系统中实现两种类型的队列。请求队列是一个全局队列,所有客户端都将共享它。客户更新元数据数据库的请求将首先发送到请求队列;从那里,同步服务将使用它来更新元数据。对应于各个已订阅客户端的响应队列负责将更新消息传递给每个客户端。由于一旦客户端接收到消息,消息将从队列中删除,因此我们需要为每个订阅的客户端创建单独的响应队列以共享更新消息
在这里插入图片描述

云/块存储

云/块存储 Cloud/Block Storage 存储用户上传的文件块。客户端直接与存储进行交互以从存储发送和接收对象。将元数据与存储区分开来,使我们能够使用云中或内部的任何存储。
在这里插入图片描述

文件处理工作流程

下面的序列显示了当客户端A更新与客户端B和C共享的文件时,方案中应用程序各组件之间的交互,因此它们也应接收更新。如果其他客户端在更新时未处于联机状态,则消息队列服务会将更新通知保留在单独的响应队列中,直到它们稍后联机。

  1. 客户端A将块上传到云存储。
  2. 客户端A更新元数据并提交更改
  3. 客户端A得到确认,并将有关更改的通知发送到客户端B和C。
  4. 客户端B和C接收元数据更改并下载更新的块。

重复数据删除 Data Deduplication

重复数据删除是一种用于消除重复数据副本以提高存储利用率的技术。它还可以应用于网络数据传输,以减少必须发送的字节数。对于每个新传入的块,我们可以计算它的哈希值,并将该哈希值与现有块的所有哈希值进行比较,以查看存储中是否已经存在相同的块

我们可以在系统中以两种方式实现重复数据删除:

a. 流程后重复数据删除 Post-process deduplication
借助流程后重复数据删除,新数据块首先存储在存储设备上,然后某些流程会分析数据以查找重复数据。这样做的好处是,客户端在存储数据之前无需等待哈希计算或查找完成,从而确保存储性能不会降低。这种方法的缺点是:1)我们将不必要地存储重复数据,尽管在很短的时间内,2)重复数据将被占用带宽。

b. 在线重复数据删除 In-line deduplication
另外,当客户端在其设备上输入数据时,可以实时完成重复数据删除哈希计算。如果我们的系统识别出已经存储的块,则只会在元数据中添加对现有块的引用,而不是该块的完整副本。这种方法将为我们提供最佳的网络和存储使用率。

元数据分区 Metadata Partitioning

为了扩展元数据数据库,我们需要对其进行分区,以便它可以存储有关数百万用户和数十亿文件/块的信息。我们需要提出一种分区方案,该方案可以将数据划分并存储在不同的DB服务器中。

  1. 垂直分区 Vertical Partitioning:我们可以对数据库进行分区,以便在一个服务器上存储与一个特定功能相关的表。例如,我们可以将所有与用户相关的表存储在一个数据库中,并将所有与文件/块相关的表存储在另一个数据库中。尽管此方法易于实现,但存在一些问题:

我们还会遇到规模问题吗?如果我们要存储数万亿个数据块,而我们的数据库不支持存储如此大量的记录,该怎么办?我们将如何进一步划分此类表?
在两个单独的数据库中联接两个表可能会导致性能和一致性问题。我们必须多久连接一次用户表和文件表?

  1. 基于范围的分区 Range Based Partitioning:如果我们基于文件路径的首字母将文件/块存储在单独的分区中,该怎么办?在这种情况下,我们将所有以字母“ A”开头的文件和以字母“ B”开头的文件保存在另一个分区中,依此类推。这种方法称为基于范围的分区。我们甚至可以将某些不经常出现的字母组合到一个数据库分区中。我们应该静态地提出这种分区方案,以便我们始终可以以可预测的方式存储/查找文件。

这种方法的主要问题是,它可能导致服务器不平衡。例如,如果我们决定将所有以字母“ E”开头的文件放入数据库分区,然后我们意识到我们有太多以字母“ E”开头的文件,以至于无法容纳它们进入一个数据库分区。

  1. 基于散列的分区 Hash-Based Partitioning:在此方案中,我们对要存储的对象进行散列,并基于此散列确定该对象应进入的数据库分区。在我们的例子中,我们可以使用要存储的File对象的’FileID’的哈希值来确定文件将要存储的分区。我们的哈希函数会将对象随机分配到不同的分区,例如,我们的哈希函数始终可以将任何ID映射到[1…256]之间的数字,而该数字将是我们将存储对象的分区。

这种方法仍然会导致分区过载,这可以通过使用Consistent Hashing解决。

缓存 Caching

We can have two kinds of caches in our system. To deal with hot files/chunks we can introduce a cache for Block storage. We can use an off-the-shelf solution like Memcached that can store whole chunks with its respective IDs/Hashes and Block servers before hitting Block storage can quickly check if the cache has desired chunk. Based on clients’ usage patterns we can determine how many cache servers we need. A high-end commercial server can have 144GB of memory; one such server can cache 36K chunks.

Which cache replacement policy would best fit our needs? When the cache is full, and we want to replace a chunk with a newer/hotter chunk, how would we choose? Least Recently Used (LRU) can be a reasonable policy for our system. Under this policy, we discard the least recently used chunk first. Similarly, we can have a cache for Metadata DB.

我们的系统中可以有两种缓存。为了处理热门文件/块,我们可以引入用于块存储的缓存。我们可以使用像Memcached这样的现成解决方案,该解决方案可以存储带有其各自的ID /哈希和块服务器的整个块,然后再访问块存储可以快速检查缓存是否具有所需的块。根据客户的使用模式,我们可以确定我们需要多少个缓存服务器。高端商用服务器可以具有144GB的内存。一台这样的服务器可以缓存36K块。

哪种缓存替换策略最适合我们的需求?当缓存已满,并且我们想用更新/更热的块替换块时,我们将如何选择?对于我们的系统,最近最少使用(LRU)是合理的策略。在此政策下,我们将首先丢弃最近最少使用的块。同样,我们可以为元数据数据库提供一个缓存。

负载平衡器

我们可以在系统中的两个位置添加负载均衡层:

  1. 在客户端和块服务器之间.
  2. 在客户端和元数据服务器之间。

最初,可以采用简单的Round Robin方法,该方法在后端服务器之间平均分配传入请求。该LB易于实现,不会带来任何开销。这种方法的另一个好处是,如果服务器死了,则LB会将其从循环中移出,并停止向其发送任何流量。Round Robin LB的问题是,它不会考虑服务器负载。如果服务器过载或运行缓慢,则LB不会停止向该服务器发送新请求。为了解决这个问题,可以放置一个更智能的LB解决方案,该解决方案定期向后端服务器查询其负载,并根据此负载调整流量。

安全性,权限和文件共享 Security, Permissions and File Sharing

用户在将文件存储到云中时将要关注的主要问题之一是其数据的隐私性和安全性,尤其是因为在我们的系统中,用户可以与其他用户共享文件,甚至可以将其公开以与所有人共享。为了解决这个问题,我们将每个文件的权限存储在元数据数据库中,以反映任何用户可见或可修改的文件。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
介绍 文件存储系统是目前越来越流行的一种服务,它可以使用户将文件存储在端,并随时随地访问和分享这些文件。本文将介绍一个基于QT的文件存储系统,该系统可以实现以下功能: 1.用户注册与登录,包括用户名和密码的验证。 2.用户上传、下载、删除文件,支持多文件同时上传下载。 3.文件分享,用户可以将自己的文件分享给其他用户,也可以接收其他用户的文件分享。 4.网络断开重连,用户在上传或下载文件的过程中,如果网络中断,系统会自动重连,保障文件上传下载的顺利进行。 开发环境 1.QT 5.9(或者更高版本) 2.MYSQL 数据库 3.DROPBOX存储服务 4.远程服务器(用于部署系统) 实现步骤 1.设计数据库 系统需要一个数据库存储用户信息和文件信息。设计数据库时,需要考虑以下几个方面: 1)用户注册和登录需要存储用户名、密码、邮箱等基本信息。 2)文件信息需要存储文件名、文件路径、文件大小等基本信息。 3)共享文件需要存储分享者和接收者的用户ID、文件ID等关联信息。 设计数据库时,考虑各个表之间的关联关系,以便实现查询和编辑操作。 2.实现用户注册和登录 用户注册和登录是系统的基础功能,需要验证用户的用户名和密码。使用QT提供的QTcpSocket类和QTcpServer类,实现客户端和服务器之间的通信。在服务器端,使用QT提供的QSqlDatabase类和QSqlQuery类,实现数据库操作,保存和验证用户信息。 3.实现文件上传和下载 文件上传和下载是文件存储系统的核心功能。使用QT提供的QFile类,实现文件的读写操作。使用QT提供的QTcpSocket类和QTcpServer类,实现客户端和服务器之间的通信。在服务器端,使用QT提供的QSqlDatabase类和QSqlQuery类,实现文件信息的存储和查询。 4.实现文件分享 文件分享是文件存储系统的一个扩展功能,允许用户将自己的文件分享给其他用户。使用QT提供的QTcpSocket类和QTcpServer类,实现客户端和服务器之间的通信。在服务器端,使用QT提供的QSqlDatabase类和QSqlQuery类,实现共享文件信息的存储和查询。 5.实现网络断开重连 考虑用户在上传或下载文件的过程中,如果网络中断,系统需要自动重连,保障文件上传下载的顺利进行。使用QT提供的QTcpSocket类和QTcpServer类,实现网络通信,并设置一定的重连机制。 6.远程部署 完成上述步骤后,需要将系统部署到一个远程服务器上,以便用户可以随时随地访问系统。在远程服务器上安装必备的环境和软件,如MYSQL数据库、QT运行库、DROPBOX存储服务等。将系统打包,并上传到远程服务器,解压后即可运行。 总结 基于QT的文件存储系统是一个完整的系统,实现了用户注册和登录、文件上传下载、文件分享等核心功能。通过对该系统的开发和部署,可以更好地理解QT网络编程和MYSQL数据库操作,对于服务开发有较好的参考价值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值