设计Instagram

让我们设计一个像Instagram这样的照片共享服务,用户可以在其中上传照片以与其他用户共享。类似服务:Flickr,Picasa

什么是Instagram?

Instagram是一项社交网络服务,可让其用户上传和与其他用户共享他们的照片和视频。Instagram用户可以选择公开或私下共享信息。任何其他用户都可以看到公开共享的任何内容,而私有共享的内容只能由指定的一组人员访问。Instagram还允许其用户通过许多其他社交网络平台进行共享,例如Facebook,Twitter,Flickr和Tumblr。

我们计划针对此设计问题设计一个更简单的Instagram版本,以便用户可以共享照片并关注其他用户。每个用户的“新闻提要”将由该用户关注的所有人的顶照组成。

系统的要求和目标

设计Instagram时,我们将重点关注以下几组要求:

功能要求

  1. 用户应该能够上传/下载/查看照片。
  2. 用户可以根据照片/视频标题进行搜索。
  3. 用户可以关注其他用户。
  4. 系统应生成并显示用户的新闻提要,其中包含来自用户关注的所有人的热门照片。

非功能需求

  1. 服务需要高度可用
  2. 对于新闻订阅源生成,系统可接受的延迟时间为200毫秒。
  3. 如果用户有一段时间没有看到照片,一致性可能会受到一定影响(出于可用性的考虑), 但系统整体应该没问题
  4. 该系统应高度可靠;任何上传的照片或视频都不会丢失

不在范围内

  1. 在照片中添加标签,在标签中搜索照片,在照片中添加评论,在照片中为用户添加标签,关注对象等

一些设计注意事项

该系统将是繁重的读取操作,因此我们将集中精力构建一个可以快速检索照片的系统。

  1. 实际上,用户可以上传任意数量的照片;因此,有效的存储管理应该是设计该系统的关键因素。
  2. 观看照片时,期望低延迟。
  3. 数据应该是100%可靠的。如果用户上传了照片,系统将保证照片不会丢失

容量估算和约束

  • 假设我们有5亿总用户,每天有100万活跃用户。

  • 每天有200万张新照片,每秒有23张新照片。

  • 图片文件平均大小=> 200KB

  • 1天照片所需的总空间

    2M * 200KB = 400 GB

  • 10年所需的总空间:

    400GB * 365(每年的天数)* 10(年)〜= 1425TB

高级设计

在较高的层次上,我们需要支持两种方案,一种方案是上传照片,另一种方案是查看/搜索照片。我们的服务将需要一些对象存储服务器来存储照片,以及一些数据库服务器来存储有关照片的元数据信息。

数据库架构

在问题的早期阶段定义数据库模式将有助于理解各个组件之间的数据流,并在之后指导数据分区

我们需要存储有关用户,他们上传的照片以及他们关注的人的数据。“照片”表将存储与照片有关的所有数据;我们需要在(PhotoID,CreationDate)上建立索引,因为我们需要先获取最近的照片。

存储上述模式的一种直接方法是使用像MySQL这样的RDBMS,因为我们需要连接 join。但是关系数据库面临着挑战,尤其是当我们需要扩展它们时。

我们可以将照片存储在HDFS或S3之类的分布式文件存储中。

我们可以将上述架构存储在分布式键值存储中,以享受NoSQL提供的好处。与照片相关的所有元数据都可以转到一个表,其中“键”将是“ PhotoID”,“值”将是一个包含PhotoLocation,UserLocation,CreationTimestamp等的对象。

如果使用NoSQL数据库,则需要一个附加表来存储用户和照片之间的关系,以了解谁拥有哪张照片。我们将此表称为“ UserPhoto”。我们还需要存储用户关注的人员列表。我们称之为“ UserFollow”。对于这两个表,我们都可以使用像Cassandra这样的宽列数据存储。对于“ UserPhoto”表,“键”将是“ UserID”,“值”将是用户拥有的“ PhotoID”列表,存储在不同的列中。对于“ UserFollow”表,我们将有一个类似的方案。

通常,Cassandra或键值存储区始终维护一定数量的副本以提供可靠性。同样,在这样的数据存储中,删除操作不会立即生效;数据会保留几天(以支持取消删除),然后再从系统中永久删除。

数据大小估计

让我们估计一下每个表中将要存储多少数据,以及十年后我们将需要多少存储空间。

用户:假设每个“ int”和“ dateTime”为四个字节,则用户表中的每一行将为68个字节:

用户ID(4个字节)+名称(20个字节)+电子邮件(32个字节)+ DateOfBirth(4个字节)+ CreationDate(4个字节)+ LastLogin(4个字节)= 68个字节

如果我们有5亿用户,那么我们将需要32GB的总存储空间。

5亿* 68〜= 32GB

照片:“照片”表中的每一行将为284个字节:

PhotoID(4个字节)+ UserID(4个字节)+ PhotoPath(256个字节)+ PhotoLatitude(4个字节)+ PhotoLongitude(4个字节)+ UserLatitude(4个字节)+ UserLongitude(4个字节)+ CreationDate(4个字节)= 284个字节

如果每天上传200万张新照片,则一天将需要0.5GB的存储空间:

2M * 284字节〜=每天0.5GB

10年后,我们将需要1.88TB的存储空间。

UserFollow: UserFollow表中的每一行将由8个字节组成。如果我们有5亿用户,并且平均每个用户关注500个用户。UserFollow表需要1.82TB的存储空间:

5亿用户* 500位关注者* 8字节〜= 1.82TB

所有表在10年内所需的总空间将为3.7TB:

32GB + 1.88TB + 1.82TB〜= 3.7TB

组件设计

照片上传(或写入)可能会很慢,因为它们必须进入磁盘,而读取会更快(尤其是从缓存中获取照片时)。

上传用户会消耗所有可用的连接,因为上传是一个缓慢的过程。这意味着,如果系统忙于所有“写”请求,则无法提供“读”服务。我们应该记住,在设计系统之前,Web服务器具有连接限制。如果我们假设一个Web服务器在任何时候最多可以有500个连接,那么它最多不能有500个并发上载或读取。为了解决这个瓶颈,我们可以将读取和写入分为单独的服务。我们将有专用的服务器用于读取,而有不同的服务器用于写入,以确保上传不会占用系统。

分离照片的读写请求也将使我们能够分别缩放和优化这些操作。

可靠性和冗余

为了确保不丢失文件。因此,每个文件我们将存储多个副本,这样,如果一个存储服务器down,我们可以从另一台存储服务器上存在的另一副本中检索照片。

相同的原理也适用于系统的其他组件。如果我们希望系统具有高可用性,那么我们需要在系统中运行多个服务副本,以便即使有几个服务崩溃,系统也仍然可以运行。冗余消除了系统中的单点故障

如果在任何时候只需要运行一个服务的实例,我们就可以运行该服务的冗余辅助副本,该副本不提供任何流量,但是当主节点出现问题时,它可以在故障转移之后获得控制权。

例如,如果生产中正在运行同一服务的两个实例,而一个实例发生故障或降级,则系统可以故障转移到正常副本。故障转移可以自动发生或需要手动干预。

数据分区

讨论元数据分片的不同方案:

  • 基于UserID分区:基于UserID 的分区假设我们基于“ UserID”进行分片,以便我们可以将用户的所有照片保留在同一分片上。如果一个数据库分片为1TB,我们将需要四个分片来存储3.7TB的数据。假设为了获得更好的性能和可伸缩性,我们保留10个分片。

因此,我们将通过UserID%10查找分片号,然后将数据存储在那里。为了唯一地标识我们系统中的任何照片,我们可以在每个PhotoID后面附加分片号。

如何生成PhotoID?每个数据库分片都可以具有自己的PhotoID自动递增序列,并且由于我们将ShardID附加到每个PhotoID上,因此它将在整个系统中变得唯一。
此分区方案有哪些不同的问题?

  1. 我们将如何处理热门用户?有几个人关注这些热门用户,还有许多其他人看到他们上传的任何照片。
  2. 与其他用户相比,某些用户将拥有很多照片,因此存储分配不均匀。
  3. 如果我们无法将一个用户的所有图片存储在一个分片上怎么办?如果我们将用户的照片分发到多个分片上,会导致更高的延迟吗?
  4. 将用户的所有照片存储在一个分片上可能会引起问题,例如,如果该分片掉线,则无法使用该用户的所有数据;如果服务于高负载,则可能导致更高的延迟等。
  • 基于PhotoID的分区:在此方案中,如果我们可以先生成唯一的PhotoID,然后通过“ PhotoID%10”找到一个碎片号,则上述问题将得到解决。在这种情况下,我们不需要在ShardID后面附加PhotoID,因为PhotoID本身在整个系统中都是唯一的。

如何生成PhotoID?在这里,我们无法在每个分片中都有一个自动递增序列来定义PhotoID,因为我们需要首先知道PhotoID才能找到将其存储在其中的分片。一种解决方案是,我们专用一个单独的数据库实例来生成自动递增的ID。如果我们的PhotoID可以容纳64位,则可以定义一个仅包含64位ID字段的表。因此,无论何时要在系统中添加照片,我们都可以在此表中插入新行,并将该ID用作新照片的PhotoID。

生成密钥的数据库不是单点故障吗?是的,会的。一种解决方法是定义两个这样的数据库,一个数据库生成偶数ID,另一个数据库生成奇数。对于MySQL,以下脚本可以定义此类序列:

KeyGeneratingServer1:
auto-increment-increment = 2
auto-increment-offset = 1KeyGeneratingServer2:
auto-increment-increment = 2
auto-increment-offset = 2

我们可以在这两个数据库的前面放置一个负载平衡器,以便在它们之间循环轮询并处理停机时间。这两个服务器都可能不同步,其中一个服务器比另一个服务器生成更多的密钥,但这不会对我们的系统造成任何问题。我们可以通过为用户,照片注释或系统中存在的其他对象定义单独的ID表来扩展此设计。

或者,我们可以实现类似于在设计URL缩短服务(如TinyURL)中讨论的“密钥”生成方案。

我们如何计划系统的未来发展? 我们可以有大量的逻辑分区来适应将来的数据增长,这样一开始,多个逻辑分区就驻留在单个物理数据库服务器上。由于每个数据库服务器可以在其上运行多个数据库实例,因此我们可以为任何服务器上的每个逻辑分区都具有单独的数据库。因此,只要我们感觉到特定的数据库服务器具有大量数据,就可以将一些逻辑分区从该数据库迁移到另一台服务器。我们可以维护一个配置文件(或单独的数据库),该文件可以将逻辑分区映射到数据库服务器。这将使我们能够轻松移动分区。每当我们要移动分区时,我们只需更新配置文件即可宣布更改。

排名和新闻提要生成

要为任何给定的用户创建新闻提要,我们需要获取该用户关注的人的最新,最受欢迎和相关的照片。

为简单起见,假设我们需要为用户的新闻提要获取前100张照片。我们的应用程序服务器将首先获取用户关注的人员列表,然后获取每个用户最新100张照片的元数据信息。在最后一步,服务器会将所有这些照片提交给我们的排名算法,该算法将确定前100张照片(基于新近度,相似度等)并将其返回给用户。这种方法可能出现的问题是更高的延迟,因为我们必须查询多个表并对结果执行排序/合并/排序。为了提高效率,我们可以预先生成News Feed,并将其存储在单独的表格中。

预先生成新闻提要:我们可以拥有专用的服务器,这些服务器可以连续生成用户的新闻提要并将其存储在“ UserNewsFeed”表中。因此,只要任何用户需要最新的照片作为他们的News-Feed,我们都将简单地查询该表并将结果返回给用户。

每当这些服务器需要生成用户的新闻提要时,它们将首先查询UserNewsFeed表以查找上一次为该用户生成新闻提要的时间。然后,从那时起将生成新的News-Feed数据(遵循上述步骤)。

将新闻摘要内容发送给用户的方法有哪些?

  1. 拉取:客户端可以定期或从需要时手动从服务器拉取News-Feed内容。这种方法可能出现的问题是:a)在客户端发出拉取请求之前,可能不会向用户显示新数据。b)在大多数情况下,如果没有新数据,则拉取请求将导致响应为空。
  2. 推送:服务器可以在可用时立即将新数据推送给用户。为了有效管理此问题,用户必须与服务器维护长轮询请求以接收更新。这种方法可能出现的问题是关注很多人的用户或拥有数百万关注者的名人用户。在这种情况下,服务器必须非常频繁地推送更新。
  3. 混合:我们可以采用混合方法。我们可以将拥有大量关注者的所有用户转移到基于拉动的模型,而仅将数据推送给拥有数百(或数千)关注者的用户。另一种方法可能是服务器将更新推送给所有用户的频率不超过某个特定频率,并允许具有大量关注者/更新的用户定期提取数据。

使用分片数据创建新闻提要

为任何给定用户创建新闻提要的最重要的要求之一就是从该用户关注的所有人那里获取最新照片。为此,我们需要一种机制来对照片的创建时间进行排序。为了有效地做到这一点,我们可以将照片创建时间作为PhotoID的一部分。由于我们将在PhotoID上拥有一个主要索引,因此可以很快找到最新的PhotoID。

我们可以为此使用纪元时间。假设我们的PhotoID有两个部分;第一部分代表纪元时间,第二部分代表自动递增序列。因此,要制作一个新的PhotoID,我们可以采用当前的时间,并从生成密钥的数据库中添加一个自动递增的ID。我们可以从此PhotoID(PhotoID%10)中找出分片号,并将照片存储在此处。

PhotoID的大小可能是多少?假设我们的时代从今天开始;在接下来的50年中,我们需要多少位来存储秒数?

86400秒/天* 365(一年中的天数)* 50(年)=> 16亿秒

我们将需要31位存储该数字。由于平均而言,我们期望每秒能拍摄23张新照片,因此我们可以分配9个额外的位来存储自动递增的序列。所以每一秒钟,我们可以存储(292^929=> 512)新照片。我们为序列号分配了9位,这超出了我们的要求;我们这样做是为了获得完整的字节数(因为40位= 5字节)。我们可以每秒重置一次自动递增序列。

缓存和负载平衡器

我们的服务将需要一个大规模的照片传送系统来为全球分布的用户提供服务。我们的服务应该使用大量按地理位置分布的照片缓存服务器使用CDN来将其内容更接近用户。

我们可以为元数据服务器引入缓存,以缓存热数据库行。我们可以使用Memcache来缓存数据,而应用程序服务器在访问数据库之前可以快速检查缓存是否具有所需的行。对于我们的系统,最近最少使用(LRU)可能是合理的缓存逐出策略。在此政策下,我们将首先丢弃最近浏览最少的行。

我们如何建立更智能的缓存?如果我们遵循八十二条规则,即照片的每日阅读量的20%产生了80%的访问量,这意味着某些照片非常受欢迎,以至于大多数人都会阅读它们。这表明我们可以尝试缓存每日读取的照片和元数据的20%。

设计Instagram相关推荐

  1. 系统设计(四) 设计Instagram

    让我们设计一个像Instagram这样的照片分享服务,用户可以上传照片与其他用户分享. 类似服务:Flickr,Picasa 难度级别:中等 1.什么是Instagram? Instagram是一项社 ...

  2. 系统设计面试题 之 如何设计Instagram

    本文翻译自https://www.educative.io/collection/page/5668639101419520/5649050225344512/5673385510043648 1.什 ...

  3. 面试题|设计instagram

    目录 题目 Use Cases 约束 High Level DB Design DB schema 容量预估 详细设计 扩展 可靠性 高并发 扩展性 信息流设计 题目 用户可以上传照片,分享照片:关注 ...

  4. 0098 系统设计——Instagram设计

    设计Instagram 让我们设计一个像Instagram这样的照片共享服务,用户可以在其中上传照片以与其他用户共享.类似服务:Flickr,Picasa难度级别:中 1.什么是Instagram?# ...

  5. 华为技术面试编码题_最佳技术编码面试准备书

    华为技术面试编码题 Technical coding interviews are notoriously difficult - almost borderline quiz-like for th ...

  6. 软件工程师面试学习指南

    本文列出了一个涵盖许多热门面试题的清单,相信会对你有所裨益. 作者 | Ben Rogojan 译者 | 谭开朗,责编 | 郭芮 出品 | CSDN(ID:CSDNnews) 以下为译文: 与其他技术 ...

  7. 年入200万的华人程序员,过了30岁就成傻逼了?

    来源 | https://www.zhihu.com/question/494603100 今天逛知乎的时候,看到一个问题: "湾区年薪30万美元,是不是日子过不下去很贫困?" 这 ...

  8. 你离互联网大公司的距离只有三个月:算法小白的面试成长之旅之路线图

    写在前面的话,如果大家购买本文提到的任何课程,都可以使用折扣码 awesome-developer-20 享受额外八折的优惠,本文中所有课程都适用,网站上其他课程一样适用. 这篇文章翻译自educat ...

  9. 我如何在1年内转行成了一名软件工程师

    作者 | Amanda Bullington 翻译 | Mika 本文为 CDA 数据分析师原创作品,转载需授权 在决定转行前,我是科技公司的一名营销人员.我尝试过很多类型的营销工作,具备活动.公关. ...

  10. 耗时一个月,前端开发之小程序实战-----虎牙小程序

    文章目录 前言 一.小程序是什么? 二.知识储备 1.CSS 声明 基础知识 2.JavaScript 3.React React简介 React概述 React框架的优点 我谈React React ...

最新文章

  1. 数据库中日期大小的判断
  2. Oracle的连接与会话
  3. Number Theory Problem(The 2016 ACM-ICPC Asia China-Final Contest 找规律)
  4. Pandas条件筛选 | Python技能树征题
  5. 代码签名证书,让软件真正拥有姓名!
  6. 实现tree系统命令
  7. HDU6736 F.Forest Program(dfs找环)
  8. BSTR、char* 和 CString 之间的转换 (转)
  9. 996!007!同是敲了2万行代码,为什么他却晋升了?
  10. 作者:钱卫宁(1976-),男,华东师范大学数据科学与工程研究院教授、博士生导师...
  11. 将byte数组写进文件,指定buffer size
  12. 吴恩达机器学习作业 1线性回归
  13. jenkins手把手教你从入门到放弃03-安装Jenkins时web界面出现该jenkins实例似乎已离线
  14. 深入机械制造业供应链关键节点,SCM供应链管理系统全面防控企业供应链风险
  15. 维刻柠檬鲜果冰怎么样?
  16. matlab gpa排名,GPA如何决定申请排名多少的大学?(附TOP100大学要求)
  17. 16天记住7000考研单词
  18. 海思SDK学习(11)海思媒体处理软件平台MMP(10)VGS视频图形子系统
  19. 欢迎来到魔法的未来~
  20. 实战技法 - 短线操盘 (9)

热门文章

  1. C语言基础视频教程-欧阳坚-专题视频课程
  2. 计算机专业能当电子厂技术员,我在一个机械工厂从事电气技术员的工作,谁能告诉..._电气工程师_帮考网...
  3. 客户信息管理系统4—客户信息的查询
  4. 医院建筑综合布线方案特点
  5. 详细名单:Google的581个域名
  6. openv Mat 之 forEach 操作
  7. wap4410n 服务器上限修改,cisco wap4410n设置方法
  8. AIDA64 Business Edition(系统检测)多国语言绿色特别
  9. micropython透明屏:esp32驱动透明屏幕通过aida64显示硬件信息
  10. JS实现弹性漂浮广告代码