一年用户从0涨到1400万,仅靠三名工程师就撑起了Instagram……

分布式实验室 2023-09-30 10:20:00

 

Instagram 在 2010 年 10 月至 2011 年 12 月的短短一年多的时间内,用户量从 0 飙升到 1400 万,而这一切的背后只有三名工程师在工作。

这个惊人的数量增长来源于三大基本原则和稳定可靠的技术栈,以下是 Instagram 的指导原则与技术栈构成分析。

 

Instagram 在技术运作上一直遵循着以下三个指导原则:

 

  • 简洁为上

  • 避免重复发明轮子

  • 尽可能使用经过验证的、稳固的技术

 

一、技术栈简要介绍

 

Instagram 早期的基础架构运行于 AWS,使用的是配备 Ubuntu Linux 的 EC2。EC2 是 Amazon 提供的服务,允许开发者租用虚拟计算机承载工作负载。

 

为了更直观地展示,我们从工程师的角度,探讨用户会话的生命周期。(以 “会话” 为标记)

 

 
1.前端

 

会话:用户启动 Instagram 应用程序。

 

2010 年,Instagram 首次作为 iOS 应用推出。考虑到 Swift 是在 2014 年发布的,我们合理猜测,Instagram 最初是使用 Objective-C 配合 UIKit 等技术编写而成。

 

图片

 

1)负载均衡

 

会话:在打开应用之后,向后端发送获取首页图片流的请求,随后到达 Instagram 的负载均衡器。

 

Instagram 采用 Amazon 的 Elastic Load Balancer服务,配置了三个 NGINX 实例,这些实例会根据其运行状况进行切换。

 

每条请求都会首先到达负载均衡器,然后被定向至真正的应用服务器。

 

图片

 

 
2.后端

 

会话:经过负载均衡器处理后,请求被传送至应用服务器,该服务器包含了处理请求的核心逻辑。

 

Instagram 的应用服务器是基于 Django 并使用 Python 语言编写,而 Gunicorn 则作为其 WSGI 服务器。补充说明,WSGI(Web Server Gateway Interface,Web 服务器网关接口)是一个协议,负责将请求从 Web 服务器转发到 Web 应用程序。

 

Instagram 采用 Fabric 工具,在多个实例上并行地执行命令,从而能够在几秒内迅速部署代码。

 

这些服务器共同运行在 25 台以上的 Amazon High-CPU Extra-Large 机型上。因为这些服务器是无状态的,所以面对更多请求时,可以灵活地增加更多机器来扩展处理能力。

 

图片

 

 

1)常规数据存储

 

会话:应用服务器发现请求需要主要的动态数据。它可能需要以下信息:

 

  • 最近相关的照片 ID

  • 对应这些照片 ID 的实际照片

  • 这些照片的用户数据

 

2)数据库:Postgres

 

会话:应用服务器从 Postgres 中提取最新相关的照片 ID。

 

应用服务器从 PostgreSQL 数据库中提取数据,其中包括大部分 Instagram 的数据,例如用户和照片的元数据。

 

Instagram 使用 Pgbouncer 对 Postgres 和 Django 之间的连接进行池化。

 

鉴于每秒收取的数据量超过 25 张照片和 90 个赞,Instagram 采用了数据分片技术,利用代码将数千个 “逻辑” 分片映射到数个物理分片。

 

Instagram 成功解决了一个有趣的挑战:如何生成可以按时间排序的 ID。最终的 ID 格式如下:

 

  • 41 位用于毫秒级时间(这为我们提供了 41 年的 ID 空间)

  • 13 位代表逻辑分片 ID

  • 10 位代表自增序列,模为 1024,意味着我们每毫秒可以为每个分片生成 1024 个 ID

 

借助Postgres 中可按时间排序的 ID,应用服务器能够成功获取最新相关的照片 ID。

 

3)照片存储:S3 和 Cloudfront

 

会话:随后,应用服务器使用快速的 CDN 链接,获取与那些照片 ID 匹配的实际照片,确保用户快速加载。

 

数以 TB 计的照片被存储在 Amazon S3 中,并通过 Amazon CloudFront 快速地提供给用户。

 

4)缓存:Redis 和 Memcached

 

会话:为了从 Postgres 中获取用户数据,应用服务器(Django)使用 Redis 将照片 ID 与用户 ID 相匹配。

 

Instagram 用 Redis 存储了大约 3 亿张照片到用户 ID 的映射,以确定在获取主要动态或其他动态时应查询哪个数据分片。为减少延迟,整个 Redis 都存储在内存中,并在多个机器上进行了分片。

 

利用精妙的哈希技术,Instagram 只需不到 5GB 的空间就可以存储 3 亿个键映射。

 

这个照片 ID 到用户 ID 的键值映射,用于确定应查询哪个 Postgres 分片。

 

会话:得益于 Memcached 的高效缓存,从 Postgres 获取的用户数据非常迅速,因为最近相应已被缓存。

 

对于常规缓存需求,Instagram 使用了 Memcached,并拥有 6 个 Memcached 实例,能够在 Django 上较为简单地进行分层。

 

有趣的是,在两年后的 2013 年,Facebook 发布了一篇论文,描述了他们如何扩展 Memcached 以应对每秒数十亿的请求。

 

会话:现在,用户可以看到其首页动态,其中填充了他关注的人的最新图片。

 

图片

 

 

5)主 - 从架构

 

Postgres 和 Redis 都采用了主 - 从架构,并使用 Amazon EBS(弹性块存储)进行频繁的系统备份。

 

二、推送通知与异步任务

 

会话:现在,假设用户关闭了应用,但随后收到了一个推送通知,告知他的朋友上传了一张新照片。

 

这个推送通知是通过 Pyapns 发送的。至今,Instagram 已经通过它发送了超过十亿的推送通知。Pyapns 是一个开源的,用于 Apple Push Notification Service(APNS)的通用提供器。

 

会话:用户非常喜欢这张照片!因此,他决定将其分享至 Twitter。

 

在后端,这项任务被推送至 Gearman,这是一个任务队列系统,可以将任务分派给更加合适的机器来处理。Instagram 拥有约 200 个 Python 工作进程来处理 Gearman 的任务队列。

 

Gearman 被用于处理多种异步任务,例如将活动(例如新发布的图片)推送给用户的所有粉丝(这个功能叫做“扇出fanout”)。

 

 

图片

 

 

三、监控

 

情景:糟糕!Instagram 应用程序因服务器出错而崩溃,这导致了一个错误的响应被发送出去。三位 Instagram 的工程师立刻收到了报警。

 

Instagram 采用了开源的Django 应用 Sentry,实时追踪 Python 的错误。

 

Munin 用于对整个系统的指标进行绘图并发出异常警告。Instagram 还定制了许多 Munin 的插件,以便追踪应用级的指标,如每秒上传的照片数。

 

Pingdom 用于监控外部服务,PagerDuty用于应对意外情况和通知发布。

 

四、架构总览

 

图片

 

 

编译丨分布式实验室(ID:DistributedLab)
来源丨engineercodex.substack.com/p/how-instagram-scaled-to-14-million
dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告