Instagram的技术探索

2019-03-27 01:01|来源: 网路

原文:http://instagram-engineering.tumblr.com/post/13649370142/what-powers-instagram-hundreds-of-instances-dozens-of

banner

当我们与其他工程师偶遇和交流的时候,有一个问题经常被问及,“你们的技术架构(technology stack)是怎么样的”?我们觉得从较高的层次来描述Instagram的所有构成系统是一件有趣的事情;未来你可能期待更深入的描述这些系统。这就是我们的系统,仅仅1年时间,并且我们活了下来,其中有一部分我们一直在修改。一个小型团队的初创公司,可以在一年多一点时间发展到1400多万用户规模。我们选择一种技术的核心原则是:

     尽量保持简单

     不重复发明轮子

尽量用被验证的可靠的技术

我们将自顶向下进行介绍:

操作系统 / 主机

我们在亚马逊的 EC2上跑Ubuntu Linux 11.04 (“Natty Narwhal”)。我们发现之前的版本在EC2上高流量的时候都会出现各种不可预测的问题( freezing episodes)。我们只有3名工程师,我们的需求依然在不断的变化中,因此自托管主机不是我们的选择,也许未来当用户量空前增长的时候,我们会考虑。

负载均衡

每一个对Instagram 服务器的访问都会通过负载均衡服务器;我们使用2台nginx机器做DNS轮询。这种方案的缺点是当其中一台退役时,需要花时间更新DNS。最近,我们转而使用亚马逊的Elastic 负载均衡器,使用3个NGINX 实例可以实现调入调出(and are automatically taken out of rotation if they fail a health check);我们同时在 ELB 层停掉了 SSL , 以缓解nginx的 CPU 压力。我们使用亚马逊的Route53服务 作为DNS服务,他们最近在AWS控制台上增加了一套很好的GUI工具。

应用服务器

接下来是应用服务器用来处理我们的请求。我们在亚马逊的High-CPU Extra-Large机器上运行了Django ,随着用户的增长,我们已经在上面跑了25个Django实例了(幸运地,因为是无状态的,所以非常便于水平扩展)。我们发现我们的个别工作负载是属于计算密集型而非IO密集型,因此High-CPU Extra-Large类型的实例刚好提供了合适的比重(CPU和内存)。

我们曾经使用 http://gunicorn.org/ 作为我们的WSGI服务器;我们使用mod_wsgi 和Apache,但是发现Gunicorn 更容易配置,且对CPU的要求更低。为了 一次在多个实例上执行命令(像部署代码),我们使用FabricFabric最近增加了并行模式,因此部署只需要花费几秒钟。

数据存储

我们大部分数据(用户信息,照片的元数据、标签等)存储在PostgreSQL中;我们 之前已经说了关于如何基于不同的Postgres 实例进行切分的。我们的主要分片集群包含12个四倍超大内存云主机(且12个副本在不同的区域);

我们发现亚马逊的网络磁盘系统(EBS)每秒的寻道能力不够,因此,将我们所有工作放到内存中就变得尤为重要。为了获得合理的性能,创建了软 RAID 以提升 IO 能力,使用的 Mdadm 工具进行 RAID 管理;

顺便提一下,我们发现vmtouch用来管理内存数据是个极好的工具,尤其是在故障转移时,从一台机器到另一台机器,甚至没有活动的内存概要文件的情况。这里是脚本,用来解析运行于一台机器上的vmtouch 输出并打印出相应vmtouch命令,在另一台机器上执行,用于匹配他当前的内存状态;

我们所有的PostgreSQL实例都是运行于主-备模式,基于流复制,并且我们使用EBS快照经常备份我们的系统。为了保证我们的快照的一致性(原始灵感来源于ec2-consistent-snapshot)我们使用XFS作为我们的文件系统,通过XFS,当进行快照时,我们可以冻结&解冻RAID阵列。为了进行流复制,我们最爱的工具是repmgr

对于从我们的应用服务器连接到数据,我们很早就使用了Pgbouncer做 连接池,此举对性能有巨大的影响。我们发现Christophe Pettus的博客 有大量的关于Django、PostgreSQL 和Pgbouncer 秘诀的资源。

照片直接存储在亚马逊的S3,当前已经存储了几T的照片数据。我们使用亚马逊的CloudFront 作为我们的CDN,这加快了全世界用户的照片加载时间(像日本,我们第二最受欢迎的国家)

我们也广泛的使用了Redis ; 我们的main feed、activity feed、sessions系统(这里是我们的Django session backend),和其他 相关系统 都使用了Redis。因为所有的Redis数据都需要放在内存中,因此我们最后使用了几个四倍超大内存云主机用于跑Redis。我们的Redis也是运行于主-备模式,并且经常将DB保存到磁盘,最后使用EBS快照备份这些数据(我们发现在主机上进行导出太费劲了)。由于Redis 允许写入备份,使得在线故障转移非常方便,转移到一台新的Redis 机器,而不需要停机。

为了我们的geo-search API,我们一直使用PostgreSQL了很多个月,不过后来迁移到了Apache Solr.他有一套简单的JSON接口,这样我们的应用程序相关的,只是另一套API而已。

最后,和任何现代Web服务一样,我们使用了Memcached 做缓存,并且当前已经使用了6个Memcached 实例,我们使用pylibmc & libmemcached进行连接。亚马逊最近启用了一个灵活的缓存服务,但是它并不比运行我们自己的实例便宜,因此我们并没有切换上去;

任务队列&推送通知

当一个用户决定分享一张Instagram 的照片到Twitter 或Facebook,或者是当我们需要通知一个 实时订阅者有一张新的照片贴出,我们将这个任务推到 Gearman,一个任务队列系统能够写于Danga。这样做的任务队列异步通过意味着媒体上传可以尽快完成,而“重担”可以在后台运行。我们大概有200个工作实例(都用Python写的)在给定的时间内对队列中的任务进行消费,并分发给不同的服务。我们的feed feed fan-out也使用了Gearman,这样posting就会响应新用户,因为他有很多followers。

对于消息推送,我们找到的最划算的方案是https://github.com/samuraisam/pyapns,一个开源的Twisted 服务,已经为我们处理了超过10亿条通知,并且绝对可靠。

监视

对于100多个实例,监控变得非常重要。我们使用Munin进行图形化度量。我们基于 Python-Munin,也写了很多Munin 插件。用于图形化度量非系统级的东西(例如,每秒的签入人数,每条照片发布数等)我们使用Pingdom作为外部监控服务,PagerDuty 用于事件通知。

Python错误报告,我们使用Sentry,一个Disqus的工程师写的令人敬畏的开源的Django app。在任何时间,我们可以开始工作,并查看我们的系统发生了什么错误,实时的。

是你吗?

如果你对我们系统的这篇描述感兴趣,或者你正跃跃欲试的想告诉我们关于系统你有什么不同的见解,我们都静候佳音。We’re looking for a DevOps person to join us and help us tame our EC2 instance herd.


转自:http://www.cnblogs.com/xiekeli/archive/2012/05/23/2514108

相关问答

更多
  • 现在软件开发专业还是很不错的,我们学校就是专门培训这方面的课程的,我是石家庄国立电脑学校的老师,现在企业很需要软件开发方面的人才,如果你真对这方面感兴趣,可以详细了解下这方面,看看学校的课程适合不适合你。
  • 在国内被屏蔽了,你要在手机上面设置VPN,把IP换成香港或是国外的才可以打开 下载分享给你的51vpn ,这是软件的唯一官网:www.51vpnn.com.cn/ 装上软件后,来到主页面,点击网络加速按钮,变成加速中。 再从网络加速点击进去,选择你想x墙的APP。 这样就可以啦
  • 有啊 有‘’添加到照片地图‘’ 选择之后就出现了 ‘’为此位置命名‘’ 就可以加位置了
  • 与此同时,我发现了自己: Instagram.process_subscription(request.body.string) do |handler| handler.on_geography_changed do |object_id| # object_id tells you what subscribed geography-object has been updated end end In the meantime I've found it ou ...
  • Instagram限制了为Instagram喜欢和提供API返回的图像数量,它实际上不是300,它可能会少于此。 没有其他方法可以得到所有。 Instagram limits the number of images returned for instagram likes and feed API, its not really 300 always, it can be less than that. No other way to get all.
  • 好的,我找到了一种方法: 单击后,此函数将使用模板中使用的类。 var allTagFeed = new Instafeed({ target: 'inst1all', get: 'tagged', tagName: 'mongolia', clientId:'xxxxxxxxxxxxxxx', accessToken: 'xxxxxxxxxxxxxx', limit:'32', template: '
    < ...
  • 很久以前有人问。 但明确的答案不在这里。 这就是为什么,我也想回答。 我一直在使用下面的代码,它的工作。 它直接重定向到裁剪instagram的屏幕。 (当然,Instagram应用程序必须安装在设备上。) ... Intent intent = createInstagramIntent("file://" + filePath); startActivity(intent); ... 和 private Intent createInstagramIntent(String uriString) { ...
  • 你可能想要一个像https://github.com/Instagram/python-instagram这样的模块, 该网站的一个例子 from instagram.client import InstagramAPI api = InstagramAPI(client_id='YOUR_CLIENT_ID', client_secret='YOUR_CLIENT_SECRET') popular_media = api.media_popular(count=20) for media in popu ...
  • 您可以将图像设置为背景图像并使用background-size: cover; 以获得您正在寻找的效果( DEMO )。 这有缺点,您的用户将无法右键单击或拖动图像(以保存它们等),因为他们可能会这样做。 示例图像的HTML:
    CSS ...
  • 您无法从其他应用程序将图像发布到Instagram。 以下是最底层的一些文字: http : //instagram.com/developer/endpoints/media/ 目前,无法通过API上传。 我们有意识地选择不添加此内容,原因如下: Instagram是关于你在旅途中的生活 - 我们希望鼓励应用程序内的照片。 但是,将来我们可能会根据具体情况授予白名单访问个人应用程序的权限。 我们想要打击垃圾邮件和低质量的照片。 一旦我们允许从其他来源上传,就很难控制Instagram生态系统中的内容。 所 ...