0 简介
Instagram,分享带有字幕的照片和视频的免费社交应用。帖子可使用标签和地理标签进行组织,使其可搜索。若标记,帖子对粉丝和公众可见。用户可将配置文件设置为私人以限制对粉丝的访问。
1 需求
1.1 功能性
- 发布照片和视频:用户可发布照片和视频
- 关注/取关用户:用户可关注/取关其他用户
- 点赞或点踩帖子:用户可以对他们关注的帐户的帖子进行点赞或不喜欢
- 搜索照片和视频:用户可根据字幕和位置搜索照片和视频
- 生成新闻馈送:用户可查看新闻馈送。包含他们关注的所有用户的照片和视频(按时间顺序)。用户还可以在其新闻馈送中查看建议的和推广的照片
1.2 非功能性
- 可扩展性:该系统在计算资源和存储方面应具有扩展性,以处理数百万用户
- 延迟:生成新闻馈送的延迟应该很低
- 可用性:系统应高度可用
- 持久性:任何上传的内容(照片和视频)都不能丢
- 一致性:可在一致性稍微妥协。若内容(照片或视频)需一段时间才能在远程区域的关注者信息流中显示,也可接受
- 可靠性:系统须能容忍硬件、软件故障
2 存储模式
2.1 实体
- 用户:存储所有与用户相关的数据,如ID、姓名、电子邮件、简介、位置、帐户创建日期、上次登录时间等。
- 关注者:存储用户关系。Instagram有个单向关系,如若用户 A 接受用户 B 的关注请求,则用户 B 可查看用户 A 的帖子,但反之不成立
- 照片:存储所有与照片相关的信息,如ID、位置、字幕、创建时间等。还需保留用户 ID 以确定哪张照片属于哪个用户。用户 ID 是来自用户表的外键
- 视频:存储所有与视频相关的信息,如ID、位置、字幕、创建时间等。还需保留用户 ID 以确定哪个视频属于哪个用户。用户 ID 来自用户表的外键
2.2 Instagram的数据模型
图片
2.3 SQL or NoSQL?
我们的数据本质是关系型,并且我们需要数据的顺序(帖子应按时间顺序出现)和即使在故障的情况下也不会丢失数据(数据持久性)。此外,我们的例子中,我们将从关系查询中受益,如根据用户 ID 获取关注者或图像。因此,基于 SQL 的数据库满足这些要求。
因此,选择关系数据库,并在该数据库存储相关数据。
3 顶层设计
图片
- 负载均衡器:平衡来自终端用户的请求负载
- 应用服务器:向终端用户托管我们的服务
- 关系数据库:存储我们的数据
- Blob 存储:存储用户上传的照片和视频
4 详细设计
4.1 上传、查看和搜索照片
客户端请求上传照片,负载均衡器将请求传递给任何一个应用服务器,后者向数据库添加一个条目。向用户发送已成功存储照片的更新。若遇到错误,也会通知用户。
查看照片的过程与上述流程类似。客户端请求查看一张照片,从数据库中获取与请求匹配的合适的照片,并显示给用户。客户端还可以提供关键字来搜索特定图像。
读请求多于写请求,并将内容上传到系统中需要时间。若分离读(上传)写服务,效率会更高。 由许多服务器操作的多个服务处理相关请求。读服 务执行为用户获取所需内容的任务,而写服务有助于将内容上传到系统。
还需缓存数据来处理数百万次读取。它通过使获取过程快速来改善用户体验。我们还将选择延迟加载,这可以最大限度地减少客户端的等待时间。它允许我们在用户滚动时加载内容,从而节省带宽,并专注于加载用户当前正在查看的内容。这改善了在 Instagram 上查看或搜索特定照片或视频的延迟。
照片上的读/写操作:
图片
4.2 生成timeline
① 拉取方式
当用户打开他们的 Instagram 时,我们发送timeline生成的请求:
- 先获取用户关注的人列表
- 获取他们最近发布的照片
- 将其存储在队列中并显示给用户
但这种方法响应***较慢***,因为每次用户打开 Instagram 时我们都会生成timeline
可通过离线生成timeline,大大减少用户感知到的延迟。如在用户打开 Instagram 前,我们定义一个服务,该服务会提前为用户获取相关数据,当该人打开 Instagram 时,它会显示timeline。这减少了显示timeline的延迟率。
② 推送方法
推送方法中,每个用户都负责将他们发布的内容推送给关注他们的人的timeline。在之前的方法中,从每个关注者那里拉取帖子,但在当前方法中,我们将帖子推送给每个关注者。
现在只需获取推送到该特定用户的的数据来生成timeline。
基于推送的方法:
图片
混合方法 — 让我们将我们的用户分为两类:
- 基于推送的用户:关注者数量为数百或数千的用户。
- 基于拉取的用户:关注者数量为数十万或数百万的名人用户。
时间轴服务从基于拉取的关注者那里拉取数据并将其添加到用户的时间轴中。基于推送的用户将他们的帖子推送到他们关注者的时间轴服务,以便时间轴服务可以将其添加到用户的时间轴中。
4.3 在哪存储时间轴?
我们针对 userID 将用户的时间表存储在键值存储中。在请求时,我们从键值存储中获取数据并显示给用户。键是 userID,而值是时间轴内容(指向照片和视频的链接)。因为值的存储大小通常限制在几兆字节内,所以当我们接近大小限制时,我们可以将时间轴数据存储在 blob 中,并将指向 blob 的链接放在键的值中。
4.4 Instagram 故事
可向我们的 Instagram 添加一个名为故事的新功能。在故事功能中,用户可以添加一张照片,该照片仅可供他人在 24 小时内查看。我们可以通过在表中维护一个选项来实现这一点,我们可以在其中存储故事的持续时间。我们可以将其设置为 24 小时,任务计划程序删除超过 24 小时限制的条目。
5 最终设计
Instagram 的最终设计:
图片
6 评估
- 可扩展性:我们可以向应用服务层添加更多服务器以使可扩展性更好并处理来自客户端的大量请求。我们还可以增加数据库的数量以存储不断增长的用户数据。
- 延迟:使用缓存和 CDN 已减少了获取内容的时间。
- 可用性:通过使用跨全球复制的存储和数据库使系统可用于用户。
- 持久性:拥有持久化存储,可维护数据的备份,因此任何上传的内容(照片和视频)都不会丢失。
- 一致性:使用了 blob 存储和数据库等存储来保持数据的全局一致性。
- 可靠性:数据库处理复制和冗余,因此我们的系统保持可靠,数据不会丢失。负载平衡层会路由绕过失败服务器的请求
参考:
- 编程严选网