Instagram 在 2010 年 10 月至 2011 年 12 月的短短一年多的时间内,用户量从 0 飙升到 1400 万,而这一切的背后只有三名工程师在工作。
这个惊人的数量增长来源于三大基本原则和稳定可靠的技术栈,以下是 Instagram 的指导原则与技术栈构成分析。
Instagram 在技术运作上一直遵循着以下三个指导原则:
- 简洁为上
- 避免重复发明轮子
- 尽可能使用经过验证的、稳固的技术
一、技术栈简要介绍
Instagram 早期的基础架构运行于 AWS,使用的是配备 Ubuntu Linux 的 EC2。EC2 是 Amazon 提供的服务,允许开发者租用虚拟计算机承载工作负载。
为了更直观地展示,我们从工程师的角度,探讨用户会话的生命周期。(以 “会话” 为标记)
2010 年,Instagram 首次作为 iOS 应用推出。考虑到 Swift 是在 2014 年发布的,我们合理猜测,Instagram 最初是使用 Objective-C 配合 UIKit 等技术编写而成。
1)负载均衡
会话:在打开应用之后,向后端发送获取首页图片流的请求,随后到达 Instagram 的负载均衡器。
Instagram 采用 Amazon 的 Elastic Load Balancer服务,配置了三个 NGINX 实例,这些实例会根据其运行状况进行切换。
每条请求都会首先到达负载均衡器,然后被定向至真正的应用服务器。
会话:经过负载均衡器处理后,请求被传送至应用服务器,该服务器包含了处理请求的核心逻辑。
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用于应对意外情况和通知发布。
四、架构总览
转载请注明出处:https://stgod.com/5365/