生成时间轴:记录你的生活轨迹——facebook工程师讲述时间轴的开发始末

来源:互联网 发布:证券从业资格证软件 编辑:程序博客网 时间:2024/06/15 03:57

   时间轴对于Facebook来说不仅是一个新特性,也是这一产品中一个卓越而精彩的工程典范。我们之前的新鲜事页面展示了最近几天或几周的活动,但是从一开始我门就知道,对于时间轴这项功能,我们要从几年甚至几百年的角度来考虑。我们需要以很高的效率对日志、分享、照片、签到等信息进行遍历、聚合、排序,已呈现出这些年中你在facebook上做的最重要的事情。

  时间轴项目的开发计划非常的激进。我们开始开发这一系统的时候,优先级最高的事情是将系统设计的尽可能简单并且使用内部验证过的技术以规避技术风险。经过一些讨论,最终决定使用我们核心技术中的四项:MySQL/InnoDB作为存储和响应,Multifeed(用来支持新鲜事功能的核心技术)技术负责排序,Thrift实现不同模块的互联,memcached支持缓存。因为选择的技术都是我们熟知的,所以我们可以更准确的预估存储容量需求并且借用我们之前使用的开发工具。

  数据的反结构化(denormalization

  在做时间轴之前,我们现有的数据是高度结构化的,这需要在数据库中做很多次交互。因此我们借助缓存来使功能保持很快的速度。不在缓存中的数据在硬盘中的分布基本不会是密集的,这带来的很多潜在的低速、随机的磁盘IO。为了支持我们的排序模块,我们将不得不把所有的数据存放进chache,这其中包括了很多不会被显示出来的低价值数据。

  为了保证获取所有供排序所需的数据,且使得数据库IO请求的数量尽可能少,我们开发了一个大规模的反结构化程序。

  完成反结构化后,数据库中的每一行就都包含了用户的行为和足够用以排序的元数据,这些数据可以在方便地读取或舍弃,而无需再与数据库交互。此时数据已经按照(user,time)再磁盘上排好顺序,InnoDB在根据主键查询数据这方面功能上十分的强大,很好地支持了这项工作。

  在反结构化程序的开发中我们遇到了一些特殊的挑战:

  1.系统中各种数据在几年的调整后的结构各不相同。 Peter Ondruška,一名Fackbook的暑期实习生(暑期实习生有木有!),定义了一套专门的语言简洁的表达了我们数据格式的转换规则,并且写了一个编译器在PHP上运行。由三个熟悉数据库的员工编写了这些转换规则。

  2.相对久远的数据已经被迁移到低速存储区域。我们捣鼓出一个制度的MySQL,并且部署了几百台服务器以使之发挥最大的IO速率,使得这些本来要拷贝几个月的数据只用了几星期就拷贝完毕。

  3.大量的连接查询会带来巨量的随机IO。我们把参与链接的表整合到一个位于闪存阵列中的数据库里。一般来说,PHP一次只能在一台服务器上执行数据查询,于是我们写了一个并行查询的代理,实现了并行查询所有连接表。

  4.适应未来(高扩展性)的数据模型。我们采用完全分布式的数据模型,他更加可靠,而且对数据有诸多的语义上下文数据,并且非常有利于对代码的复用。

  时间轴聚合程序

  我们在数据库中建立时间轴聚合程序。它是一个支持“新鲜事”功能的信息聚合程序的修改版,但是现在所有数据库实例中运行,这样避免不在页面上显示的数据通过网络传输,以此实现磁盘效率的最大化。

  聚合程序有一组“故事解析器(storygenerators)”负责对某一地理区域的签到进行排序。这些解析器用C++来实现,可以在几毫秒中完成上述逻辑的分析,这比PHP快了太多。解析逻辑被拆分成很多简单操作的序列,以保证在开发新的解析器时可以很好地复用。

  缓存在任何一个Fackbook项目中都是一个重要的部分。时间轴项目的一个非常有利于实现的地方就在于,即使你执行了一个很长时间跨度的查询(例如你要排列出自己在2010年的各项活动),也只会产生很少的查询结果,这些结果可以在缓存中存储相当长的时间。一个查询结果的缓存益处多多,memcached是作为缓存的绝佳方案。

  最近时间的活动变化非常频繁,所以查询缓存也会经常失效,但是生成一个“最近活动”的摘要是非常快的。有一个行级缓存来进一步提升性能。我们在一个固态硬盘中利用InnoDB在RAM里的的缓存池和我们自己的Flashcache核心驱动来扩展操作系统的缓存机制。

  并行开发

  时间轴功能在2010年底作为一个Hackathon项目启动,项目配备了两名全职工程师和一名实习工程师,以及一名花了一晚上做出了demo的设计师。整个团队在2011年初开始高效工作,开发团队的工作被分为设计,前端工程,底层资源搭建,和数据迁移。通过分期分层的原型设计,我们开发的并行数量达到了一个很高的水平,而且很少有那一部分被其他部分阻塞。在项目的早起,我们同时进行:

  1.设计UI原型,利用了我们已有但扩展性不好的后端。

  2.在一个扩展性良好的后端上编写前端代码。

  3.利用反结构化程序原型跑出的反结构化数据构建可扩展的后端。

  4.搭建能够支持反结构化全量数据的框架。

  5.收集和复制所必需的反规范化的数据。

  6.执行模拟负载测试来验证我们的容量规划。

  现在想想,当时真的很疯狂。我们从最初的底层资源(infrastructure )清点会,到成功的完成100%后端负载测试只用了6个月时间。用另一种方式,这个项目可能需要两倍的时间,这还是乐观估计。

  时间轴功能是一个能与产品团队密切沟通的好机会。我们持续的沟通是我们能够支持他们产品要求,同时又有效的完成产品功能的关键所在。

  当几百万人都能够顺利使用时间轴这个功能,并且的到很多积极评价的时候我们很开心。而更令我们开心的是当我们看性能图表的时候,显示的结果与我们的模拟基本一致。

  Ryan Mack 底层工程师,希望能在十年后在自己的时间轴上在看到这篇文章。

 

0 0
原创粉丝点击