项目简介:Pastebin是一个在线的文本存储渠道,让用户能够存储和共享代码片段或许其他类型的文本。它支持多种编程和标记言语的语法高亮,用户能够挑选让他们的”paste”揭露或私有。无需注册就能够运用,但注册用户能够更方便地管理他们的”paste”。Pastebin常被开发者、体系管理员以及其他技术专业人员用于共享和协作。

现在让咱们来规划一个相似Pastebin的网络服务,用户能够在这儿贮存纯文本。用户能够输入一段文本,并获取一个随机生成的URL来拜访这段文本。

相似的产品有:pastebin.com,controlc.com,hastebin.com,privatebin.net

体系难度等级:初级

1、什么是Pastebin

Pastebin及相似服务让用户能够在网络(一般指的是互联网)上存储纯文本或图画,并生成仅有的URL来拜访上传的数据。这样的服务也被用来快速地在网络上共享数据,用户只需传递URL,其他用户就能够检查其内容。

假如你曾经没有运用过pastebin.com,主张尝试在那里创立一个新的“Paste”,并花些时刻阅读他们服务供给的不同选项。这将在了解本章时有很大帮助。

对于相似于Pastebin这样的代码或文本共享渠道,我国并未有一款特别知名或广泛运用的网站。许多开发者会运用GitHub Gist来共享代码片段,此外,国内也有一些代码保管渠道,比如Coding.net和Gitee,也供给代码共享和协作的功能。

2、体系的需求和方针

Pastebin服务需求满足以下要求:

功能需求

  1. 用户应能够上传或“张贴”他们的数据,并获得一个独特的URL来拜访它。
  2. 用户只能上传文本。
  3. 数据和链接将在特定的时刻段后自动过期;用户应能够指定过期时刻。
  4. 用户能够挑选为他们的张贴内容设置一个自定义的别号。

非功能性需求

  1. 体系必须具有高度的可靠性,上传的任何数据都不应丢掉。
  2. 体系必须一向可用。这是因为假如咱们的服务暂停,用户将无法拜访他们的张贴内容。
  3. 用户应能实时拜访他们的张贴内容,延迟要最小。
  4. 张贴的链接不能被容易猜出(不能被猜测)。

扩展需求

  1. 分析,例如,一个张贴内容被拜访了多少次?
  2. 咱们的服务也应该经过REST APIs供其他服务拜访。

3、注意事项

Pastebin与URL缩短服务(体系规划上一个事例)有一些相同的需求,可是咱们还应该考虑一些额定的规划因素。

用户每次张贴的文本量应有何束缚?咱们能够束缚用户不得张贴超越10MB10MB10MB的数据,以防止服务被乱用。

咱们是否应对自定义**URL**的巨细设置束缚?因为咱们的服务支持自定义URL,用户能够挑选他们喜欢的任何URL,可是供给自定义URL并非强制性的。然而,对自定义URL设置巨细束缚是合理的(而且一般是咱们期望的),这样咱们能够坚持一致的URL数据库。

4、容量估计与束缚

咱们的服务将是读取密集型的;比较新建Paste,读取恳求会更多。咱们能够假定读取与写入之间的份额是5:15:15:1。

流量预估:Pastebin相似的服务并不预期有如微信或今天头条那样的流量,这儿咱们假定每天有一百万个新的张贴内容增加到咱们的体系中。这样算来,咱们每天有五百万次的读取。

每秒新张贴内容

1M / (24 小时 * 3600 秒) ~= 12 张贴/秒

每秒张贴读取次数

5M / (24 小时 * 3600 秒) ~= 58 读取/秒

存储预估:用户最多能够上传10MB10MB10MB的数据;一般来说,Pastebin相似的服务用于共享源代码、配置文件或日志。这些文本并不大,所以咱们假定每个张贴内容均匀含有10KB10KB10KB。

按照这个速率,咱们每天将存储10GB10GB10GB的数据。

1M * 10KB => 10 GB/天

假如咱们想将这些数据存储十年,那咱们总共需求36TB36TB36TB的存储容量。

每天有1M1M1M的张贴内容,十年后咱们将有36亿的张贴内容。咱们需求生成并存储键来仅有地标识这些张贴内容。假如咱们运用Base64编码([A-Z, a-z, 0-9, ., -]),咱们将需求六个字符的字符串:

64^6 ~= 68.7亿个仅有字符串

假如存储一个字符需求一个字节,存储36亿个键所需的总巨细将是:

3.6B∗6=>22GB3.6B * 6 => 22 GB 3.6B∗6=>22GB

比较于36TB36TB36TB,22GB22GB22GB微不足道。为了保存一些余量,咱们将假定一个70%的容量模型(意味着咱们在任何时分都不期望运用超越总存储容量的70%),这将使咱们的存储需求增加到51.4TB51.4TB51.4TB。

带宽预估:对于写入恳求,咱们估计每秒新增12个张贴内容,导致每秒进入120KB120KB120KB的数据。

12∗10KB=>120KB/s12 * 10KB => 120 KB/s 12∗10KB=>120KB/s

至于读取恳求,咱们估计每秒58个恳求。因而,总的数据出口(发送给用户)将是0.6MB/s0.6 MB/s0.6MB/s。

58∗10KB=>0.6MB/s58 * 10KB => 0.6 MB/s 58∗10KB=>0.6MB/s

虽然总的进出口并不大,咱们在规划服务时应记住这些数字。

内存预估:咱们能够缓存一些被频频拜访的抢手张贴内容。依据80-20准则,意味着20%的抢手张贴内容发生了80%的流量,咱们期望将这20%的张贴内容进行缓存。

既然咱们每天有500万次的读取恳求,要缓存这些恳求中的20%,咱们需求:

0.2∗5M∗10KB=10GB0.2 * 5M * 10KB ~= 10 GB 0.2∗5M∗10KB=10GB

因而,咱们大约需求10GB10GB10GB的内存来缓存那些抢手的张贴内容。

5、体系API

咱们能够有SOAPREST API来揭露咱们服务的功能。以下是创立/检索/删去张贴内容的API定义:

addPaste(api_dev_key, paste_data, custom_url=None user_name=None, paste_name=None, expire_date=None)

参数

api_dev_key (字符串): 已注册帐户的API开发者密钥。这将用于依据分配的配额对用户进行限流等操作。

paste_data (字符串): 张贴的文本数据。

custom_url (字符串): 可选的自定义URL

user_name (字符串): 可选的用于生成URL的用户名。

paste_name (字符串): 张贴内容的可选名称。

expire_date (字符串): 张贴内容的可选过期日期。

回来: (字符串)

成功刺进回来能够拜访张贴内容的URL,不然,它将回来一个过错码。

相似地,咱们能够有检索和删去张贴内容的API:

getPaste(api_dev_key, api_paste_key)

其中api_paste_key是一个表明要检索的张贴内容的张贴键的字符串。这个API将回来张贴内容的文本数据。

deletePaste(api_dev_key, api_paste_key)

成功删去回来true,不然回来false

6、数据库规划

关于咱们存储的数据性质,咱们有一些观察:

  1. 咱们需求存储数十亿条记录。
  2. 咱们存储的每个元数据目标都很小(小于1KB1KB1KB)。
  3. 咱们存储的每个张贴目标巨细适中(能够到达几MB)。
  4. 记录之间没有联系,除非咱们要存储哪个用户创立了哪个张贴内容。
  5. 咱们的服务主要是读取操作。

数据库架构

咱们需求两个表,一个用于存储张贴内容的信息,另一个用于存储用户的数据。

探索Pastebin:搭建个性化的在线文本存储平台

这儿,URlHash是TinyURL的URL等效项,ContentKey是指向一个外部目标的引证,该目标存储张贴内容的内容;咱们将在本章后边评论张贴内容的外部存储。

7、顶层规划

在顶层规划上,咱们需求一个应用层来处理一切的读取和写入恳求。应用层将与存储层进行通信,以存储和检索数据。咱们能够将存储层区分为两部分,一部分数据库存储与每个张贴内容、用户等相关的元数据,另一部分将张贴内容存储在某些目标存储中(如阿里云OSS)。这种数据的区分也答应咱们单独进行扩展。

探索Pastebin:搭建个性化的在线文本存储平台

8、组件规划

A. 应用层

咱们的应用层将处理一切的进出恳求。应用服务器将与后端数据存储组件进行通信以服务这些恳求。

如何处理写入恳求?在收到写入恳求后,咱们的应用服务器将生成一个六位随机字符串,这将作为张贴的键(假如用户没有供给自定义键)。然后,应用服务器将张贴的内容和生成的键存储在数据库中。成功刺进后,服务器能够将键回来给用户。这儿或许存在的一个问题是因为键重复而导致刺进失利。因为咱们是生成一个随机键,所以新生成的键或许与现有的键相匹配。在这种状况下,咱们应该从头生成一个新的键并再试一次。咱们应该一向重试,直到咱们不再因为重复键看到失利。假如用户供给的自定义键现已在咱们的数据库中存在,咱们应该向用户回来一个过错。

上述问题的另一种解决计划或许是运转一个独立的键生成服务(KGS),它提前生成随机的六位字符串,并将它们存储在数据库中(咱们称之为key-DB)。每逢咱们想要存储一个新的张贴,咱们只需求取一个现已生成的键并运用它。这种办法将使工作变得十分简略和快速,因为咱们不会担心重复或碰撞。KGS将保证一切刺进key-DB的键都是仅有的。KGS能够运用两个表来存储键,一个用于没有运用的键,一个用于一切已运用的键。一旦KGS向应用服务器供给了一些键,它能够将这些移动到已运用的键表中。KGS能够一向在内存中坚持一些键,以便每逢服务器需求它们时,它能够快速供给。一旦KGS在内存中加载了一些键,它就能够将它们移动到已运用的键表中;这样咱们就能够保证每个服务器获取到的键都是仅有的。假如KGS在运用一切加载到内存中的键之前死掉,咱们将糟蹋这些键。咱们能够疏忽这些键,因为咱们有很多的键。

KGS会呈现单点故障吗?会的。为了解决这个问题,咱们能够有一个备用的KGS副本,每逢主服务器死掉时,它能够接收来生成和供给键。

每个应用服务器能够从**key-DB**中缓存一些键吗?是的,这必定能够加快速度。虽然在这种状况下,假如应用服务器在消费一切键之前死掉,咱们将终究丢掉那些键。这或许是能够接受的,因为咱们有68B68B68B个仅有的六位字母键,这比咱们需求的要多得多。

如何处理张贴读取恳求?在收到读取张贴恳求后,应用服务层联络数据存储。数据存储查找键,假如找到了,就回来张贴的内容。不然,回来一个过错码。

B. 数据存储层

咱们能够将咱们的数据存储层分为两部分:

  1. 元数据数据库:咱们能够运用像MySQL这样的联系数据库,或许像DynamoCassandra这样的分布式Key-Value存储。
  2. 目标存储:咱们能够将咱们的内容存储在像阿里云OSS这样的目标存储中。每逢咱们感觉到咱们的内容存储容量现已满了,咱们能够经过渠道直接扩容。

探索Pastebin:搭建个性化的在线文本存储平台

9、数据分区和仿制

为了扩展咱们的数据库,咱们需求对其进行分区,以便它能存储数十亿个URL的信息。因而,咱们需求规划一个分区计划,将咱们的数据区分并存储到不同的数据库中。

A. 依据规模的分区:咱们能够依据哈希键的第一个字母在不同的分区中存储URL。因而,咱们将一切以字母“A”(和“a”)最初的URL哈希键存储在一个分区中,将以字母“B”最初的URL存储在另一个分区中,以此类推。这种办法被称为依据规模的分区。咱们乃至能够将某些呈现频率较低的字母组合到一个数据库分区中。因而,咱们应开发一个静态分区计划,一向以可猜测的方式存储/查找URL

这种办法的主要问题是或许导致数据库服务器不平衡。例如,咱们决定将一切以字母“E”最初的URL放入一个数据库分区,但后来咱们发现以字母“E”最初的URL过多。

B. 依据哈希的分区:在这种计划中,咱们对存储的目标进行哈希。然后,咱们依据哈希值计算运用哪个分区。在咱们的状况下,咱们能够获取key或短链接的哈希值,以确定咱们存储数据目标的分区。

咱们的哈希函数将随机地将URL分配到不同的分区(例如,咱们的哈希函数能够一向将任何key映射到[1…256]之间的一个数字)。这个数字将表明咱们存储目标的分区。

这种办法仍然或许导致分区负载过大,这能够经过运用’一致性哈希’来解决。

10、缓存

咱们能够缓存频频拜访的URL。咱们能够运用任何现成的解决计划,比如Memcached,它能够存储完好的URL及其对应的哈希值。因而,应用服务器在拜访后端存储之前,能够快速检查缓存是否有所需的URL

咱们应该有多少缓存内存?咱们能够从日流量的20%开端,依据客户的运用模式,咱们能够调整需求多少缓存服务器。如上所估计,咱们需求170GB的内存来缓存日流量的20%。现在的一些服务器能够拥有256GB的内存,咱们能够轻松将一切缓存放入一台机器。或许,咱们能够运用几台小一点的服务器来存储一切这些抢手URL

哪种缓存驱赶战略最适合咱们的需求?当缓存满了,咱们想用一个新的/更抢手的URL替换一个链接,咱们应该如何挑选?最近最少运用(LRU)或许是咱们体系的一个合理战略。依据这个战略,咱们首要丢掉最近最少运用的URL。咱们能够运用Linked Hash Map或相似的数据结构来存储咱们的URL和哈希值,这也会记录最近拜访过的URL

为了进一步提高功率,咱们能够仿制咱们的缓存服务器来分配它们之间的负载。

每个缓存副本如何更新?每逢有一个缓存未命中,咱们的服务器会拜访后端数据库。当这种状况发生,咱们能够更新缓存,并将新的条目传递给一切的缓存副本。每个副本都能够经过增加新的条目来更新其缓存。假如副本现已有了该条目,它能够简略地疏忽它。

探索Pastebin:搭建个性化的在线文本存储平台

11、负载均衡(LB)

咱们能够在体系中的三个位置增加负载均衡层:

  • 客户端与应用服务器之间
  • 应用服务器与数据库服务器之间
  • 应用服务器与缓存服务器之间

最初,咱们能够运用一个简略的轮询办法,将进入的恳求均等地分配到后端服务器。这种负载均衡办法简略易行,不会引入任何额定的开销。这种办法的另一个优点是,假如一个服务器死机,负载均衡器会将其从轮询中移除,停止向其发送任何流量。

轮询负载均衡的一个问题是,咱们没有考虑到服务器的负载。假如一个服务器过载或运转缓慢,负载均衡器不会停止向该服务器发送新的恳求。为了处理这个问题,咱们能够放置一个更优的负载均衡解决计划,它定时查询后端服务器的负载,并依据负载状况调整流量。

12、铲除或数据库整理

key条目是否应永久存在,还是应该被铲除?假如到达用户设定的过期时刻,链接应该怎样处理?

假如咱们挑选持续寻觅过期链接并将其删去,这将对咱们的数据库发生很大压力。相反,咱们能够慢慢地删去过期的链接,进行懒人整理。咱们的服务将保证只删去过期的链接,虽然有些过期链接或许会存在更长时刻,但永久不会被回来给用户。

  • 每逢用户企图拜访一个已过期的链接,咱们能够删去该链接并向用户回来过错。
  • 咱们能够设置一个单独的整理服务,定时从咱们的存储和缓存中删去过期的链接。这个服务需求十分轻量,只在估计用户流量较低的时分运转。
  • 咱们能够为每个链接设定一个默认的过期时刻(例如两年)。
  • 删去过期链接后,咱们能够将该Key从头放回Key-DB,以供重复运用。
  • 咱们是否应删去一段时刻(比如说六个月)内没有被拜访过的链接?这或许有点不合适。因为存储本钱越来越低,咱们能够决定永久保存链接。

探索Pastebin:搭建个性化的在线文本存储平台

13、数据盯梢

咱们如何计算短链接被运用的次数、用户的位置等信息?咱们如何贮存这些计算信息?假如它是数据库中的一部分,每次检查都需求更新,那么当一个流行的短链接被很多并发恳求瞬间涌入时,会发生什么?

一些值得追寻的计算数据:访客的国家、拜访的日期和时刻、引导点击的网页、拜访页面的阅读器或渠道。

14、安全和权限

用户能否创立私有URL或许答应特定的用户组拜访某个URL

咱们能够在数据库中每个URL的条目里存储拜访权限级别(揭露/私有)。咱们也能够创立一个单独的表来存储有权拜访特定URL的用户的UserID。假如一个用户没有权限但企图拜访一个URL,咱们能够回来一个过错(HTTP 401)。考虑到咱们的数据贮存在一个相似CassandraNoSQL宽列数据库中,贮存权限的表的key将是‘哈希值’(或KGS生成的key)。列将贮存有权检查URL的用户的UserID