我于2007年四月加入了Facebook,在结束了几周的课程之后,我的经理Robert Johnson来找我。我们谈了很久,不过内容可以归结为:

Bobby: “那么,Jason,我们要在2008年之前在弗吉尼亚开一个新的数据中心。你能去帮点忙吗?”
Me: “呃…. 可以?”
Bobby: “很好!”

我在Facebook的第一个项目上投入的要比我预期的多一点点,但是我认为这是为何我们拥有如此一个非常强大的工程组织的原因;我们还有很多难题 有待解决,这里每个人都迫不及待要立刻去解决他们。我开始了解为何我们需要建造一个新的数据中心以及我们需要解决什么问题才能让他正常工作。

有何必要?

在东海岸建造一个新的数据中心的主要原因就是“延迟”。在一个高速连接上发送一个包横穿大陆需要大概70微秒的时间,而对于普通的互联网用户而言,可能会需要的时间就长得多。通过将服务器放在弗吉尼亚,我们可以大大减少给东海岸和欧洲的用户传送网页的时间。

第二个关注点是空间、能源和灾难恢复。在我们位于加利福尼亚的主数据中心中已经没有多少物理空间了,而弗吉尼亚的点可以给我们充分的空间添加东西。 我们还有一个类似问题就是要给予充足的电能驱动所有的服务器。最后,如果把我们限制在某个单独的地方,意味着如果出现灾难事件(断电、地震、怪兽),可能 会导致Facebook长时间无法访问。

开始构建!

在我们能处理应用级的问题之前,我们的小组在弗吉尼亚投入了大量的心血构建服务器和物理空间。他们还完成了数据中心之间的网络和低延迟光线通道连接。这些工作是非常巨大的工程,然而我们顶尖的团队使之看上去像是小菜一碟。

网络和硬件都到位后,我们搭建了标准的3层架构:Web服务器,memcache服务器和MySQL数据库。在弗吉尼亚的MySQL数据库作为西海 岸的数据库的从数据库(Slave)运行,所以我们花了几周的时间复制所有的数据,然后建立同步复制流(replication stream)。

现在硬件、网络和基础的设备都已经建立好,那现在就要面对两个主要的应用级的挑战:缓存一致性(Cache Consistency)和流量路径选择(traffic routing)。

缓存一致性

先说一下我们的缓存模型:当一个用户修改了数据对象后,我们的底层设施会向数据库写入新的值,并且从memcache中删除旧的值(如果存在)。下 一次用户请求该用户对象的时候,我们从数据库中取出新的结果并写入memcache。后续的请求就会直接从从memcache中取出数据直到缓存过期或者 被另外一次更新删除。

这种设置在只有一套数据库的时候运行得很好,因为我们只有当数据库完成了新值的写操作之后才删除memcache中的值。这种方式保证了我们能够从数据库中获得新值并且放入memcache中。然而,当在东海岸有一个从数据库后,情况就有些棘手了。

当我们在西海岸的主数据库中更新了一些数据之后,在东海岸的从数据库能正确反映这些新数值之前,中间有一个同步复制的延迟。通常这个延迟小于一秒钟,但是在高峰时期,它可能会延长到20秒。

现在我们假设在更新了加利福尼亚的主数据库的同时,我们从弗吉尼亚的memcache层中删除了旧值。然后有一个对弗吉尼亚的从数据库的读操作可能 由于复制延迟还是看到的旧数值。然后弗吉尼亚的memcache可能会更新为旧的(不正确)的数值,然后它可能被“困住”直到被删除。如你所见,最差的情 况是弗吉尼亚的memcache层可能总是同一个版本而非正确的数据。

考虑下面的例子:

  1. 我将我的名字从“Jason”改成了“Monkey”
  2. 我们把“Monkey”写入了加利福尼亚的主数据库并且从加利福尼亚和弗吉尼亚的memcache中删除了原来的名字
  3. 有个人在弗吉尼亚访问我的信息
  4. 在memcache中没有找到我的姓名信息,所哟我们从弗吉尼亚的从数据库中读取,由于复制的延迟获得了“Jason”
  5. 我们将姓名“Jason”存入弗吉尼亚的memcache
  6. 同步复制上来了,我们将名字信息在从数据库中更新为“Monkey”
  7. 另一个人在弗吉尼亚访问我的信息
  8. 我们在memcache中找到了名字并返回“Jason”。

在我再更新我的名字或者数据过期需要再访问数据库之前,我的名字在弗吉尼亚会一直显示为“Jason”,在加利福尼亚显示为“Monkey”。混乱吧?确实。欢迎来到分布式系统的世界,在这里一致性确实是一个难题。

幸好,解决方案要比问题容易解释。我们对MySQL做了一个小小的改动,让MySQL能在同步复制流中附加一个额外的信息。我们利用这个功能将要变更的所有数据对象追加到给定查询上,然后当从数据库“看到”这些对象后,要负责在进行了数据库更新后将这些值从缓存中删除。

我们是怎么做到的呢?MySQL是用了一个词法解析器和yacc语法来定义查询的结构然后对其进行解析。为了解释方便,我对其进行了简化,这个语法最顶层差不多如下:

query:statement END_OF_INPUT {};

statement:alter| analyze| backup| call... (insert, replace, select, 等.)

很直观吧?一个query(查询)是一个能分解成某种我们熟知的MySQL表达式的statement(语句)。我们将这个语法修改为允许在任意查询后追加memcache键,如下:

query:statement mc_dirty END_OF_INPUT {};

mc_dirty:{}| MEMCACHE_DIRTY mc_key_list;

mc_key_list: mc_key_list ',' text_string { Lex->mc_key_list.push_back
($3); }
| text_string { Lex->mc_key_list.push_back($1); };

查询现在可以有一个额外的组件;在语句statement之后有mc_dirty可以为空或者为一个关键词MEMCACHE_DIRTY后面跟着一个mc_key_list。一个mc_key_list只是一个逗号隔开的字符串列表,该规则会告诉解析器将所有字符串一个接一个存入某个叫做mc_key_list向量中,这个向量将被存入每查询解析器对象中。

看个例子,某个老式的查询看上去像:
REPLACE INTO profile (`first_name`) VALUES ('Monkey') WHERE `user_id`='jsobel'
在新语法下会变成:a
REPLACE INTO profile (`first_name`) VALUES ('Monkey') WHERE `user_id`='jsobel' MEMCACHE_DIRTY 'jsobel:first_name'

新的查询会告诉MySQL,除了要将我的名字更改为Monkey外,它还需要将一个对应的memcache键设脏。这很容易实现。由于每对象解析器对象现在储存了所有的memcache键,我们在mysql_execute_command最后添加了一小段代码——如果查询成功了,就设脏这些键。看看,我们成功地按照我们的目的——缓存一致性——劫持了MySQL同步复制流。

新的工作流变成了(更改的内容为粗体):

  1. 我将我的名字从“Jason”改为“Monkey”。
  2. 我将“Monkey”写入加利福尼亚的主数据库并从加利福尼亚的memcache中删除我的名字,但不包括弗吉尼亚的memcache
  3. 某个人在弗吉尼亚访问了我信息。
  4. 在memcache中找到了我的名字,并返回“Jason”。
  5. 同步复制到了之后,将从数据库中我的名字更新为“Monkey”。还需要从弗吉尼亚的memcache中删除我的名字因为缓存对象出现在同步复制流中了。
  6. 另一个人在弗吉尼亚访问了我的信息
  7. 没有在memcache中找到我的名字,所以从从数据库读出名字,得到了“Monkey”。

页面路径选择

我们还需要解决的另一个主要的问题是只有在加利福尼亚州的主数据库才可能接受写操作。这个情况就是说我们需要避免在弗吉尼亚服务那些需要进行数据库 写操作的页面,因为他们都需要穿越整个大陆访问我们在加利福尼亚的主数据库。幸好,我们最频繁访问的页面(首页、档案、照片页面)在正常情况下都不会进行 写操作。这样这个问题就归结于,当一个用户请求某个页面时,我们怎么判断它是否可以被“安全”地送到弗吉尼亚,或者它必须被引导到加利福尼亚?

这个问题最后有一个比较直观的答案。某个用户请求Facebook时,命中了第一批服务器其中的一个,这个服务器称之为负载均衡器;该机器的主要职 责是选择一个Web服务器来处理该请求,不过它也进行一些其他目的的服务:防御拒绝服务攻击,多路复用用户连接等。这个负载均衡器拥有可以在第7层模式运 行的能力,这样他可以检查用户请求的URI并根据这个信息进行路由选择决定。这个特性意味着,我们可以很容易地告诉负载均衡器哪些是“安全”页面,然后可 以根据页面的名字和用户的位置决定是否要将请求发送到弗吉尼亚或者是加利福尼亚。

不过,这里还有一点问题。假设你访问editprofile.php来更改家乡信息。该页面没有被标记为安全所以他被引导到了加利福尼亚,并且进行 了更改。然后你访问你的档案页面,同时由于这个页面是安全页面,所以被引导到了弗吉尼亚。然而因为前面提到的同步复制延迟,你可能不能立刻看到你刚刚做过 的改动!这种体验会令用户感到非常混乱,同时会导致双重提交。我们通过在浏览器中设置一个包含(有过写入数据库操作的)当前时间cookie来绕开这个问 题。负载均衡器会查看该cookie,如果它注意到20秒内你写入了些东西,将无条件地传送到加利福尼亚。过了20秒之后,我们确保数据已经同步到弗吉尼 亚,这时便允许你回来访问安全页面。

回顾

从我们第一个用户在弗吉尼亚数据中心访问页面后的九个月中我们一直在运行同样架构获得了很好的效果。当然,一路上还有挫折;在头一两个月中,缓存一 致性的框架非常地不稳定,逼我们在诊断和修复错误的时候每隔一段时间就要把流量从弗吉尼亚转移出去。当然,过了一段时间,我们消灭了这个问题,现在这个数 据中心在Facebook的流量中占了很大的比重。

这个架构中主要的伸缩方面的挑战很明显:所有的写操作必须在同一个地方发生。更进一步我们对开发新的可以让我们在任何位置进行写操作的技术非常感兴 趣。我们也在思考如何将新的数据中心做成一个灾难恢复点,以防怪兽要进攻加利福尼亚!想来帮帮我们吗?www.facebook.com/jobs!

http://shiningray.cn/facebook-scaling-out.html

转载于:https://www.cnblogs.com/in-loading/archive/2012/02/17/2356552.html

Facebook 数据的横向扩展相关推荐

  1. 数据中心基础设施是应该纵向扩展还是横向扩展?

    导读:如今数据量越来越大,数据中心需求也会越来越高,当数据中心需要扩容时,那么问题来了,我们需要可伸缩的数据中心资源,那数据中心应该是纵向扩展好?还是横向扩展好呢?如何兼顾成本,效率,性能等多方因素呢 ...

  2. 关系型数据库横向扩展的三种方法

    本文是 Oracle Coherence 3.5一书,第一章: Achieving Performance, Scalability, and Availability Objectives,第二节: ...

  3. 横向扩展你的ASP.NET Core SignalR 应用

    前言 最近项目要用signalr来做实时通信,在研究asp.netcore signalr 应用横向扩展时候发现了这篇国外的博客,和大家分享一下 原文连接地址 负载均衡 当你把你的应用部署到生产环境时 ...

  4. mysql 横向分表合并_MySQL横向扩展-分库分表解决方案总结

    从业务场景看分库分表 互联网行业中,业务场景通常写少读多的情况居多,在MySQL的使用前期,读性能大多可以通过SQL优化来解决,但随着业务的持续发展,单纯依靠SQL的查询优化会越来越难以达到业务服务要 ...

  5. mysql的纵向扩展方案_SQL Server横向扩展方案-SODA

    SQL Server横向扩展方案-SODA 每次在提到SQL Server扩展性问题的时候,似乎很多的SQL Server DBA或者使用微软技术开发的朋友心里总是一整痛:SQL Server只能纵向 ...

  6. NAS实现类型对比:统一式、网关式和横向扩展式(Scale-out)

    作者将本文同时发布到:EMC中文支持论坛 https://community.emc.com/docs/DOC-28457 介绍 NAS主要有三种类型的实现:统一式.网关式和横向扩展式(Scale-o ...

  7. mysql横向扩展_高可用MySQL学习笔记-面向横向扩展的MYSQL复制

    负载增加时,有两个解决办法.一个是购买更加强大的服务器来应对增加的负载,称为"纵向扩展"(scale up):二是添加更多的服务器,称为"横向扩展"(scale ...

  8. GB28181系统设计(四)-横向扩展和纵向扩展

    横向扩展 横向扩展是增加更多的服务器来实现的,那么如何自动发现服务器呢?需要中心节点吗?当然这和设计有关,和具体应用有关, 提高计算能力,显然需要把任务分解到不同的服务器上,并行完成,客户端有可能连上 ...

  9. 【转】横向扩展与纵向扩展

    谈到系统的可伸缩性,Scale-up(纵向扩展)和Scale-out(横向扩展)是两个常见的术语. 鱼缸的启示:Scale-out和Scale-up架构 其实我认为Scale-out和Scale-up ...

最新文章

  1. shell脚本将本地docker镜像push到阿里云镜像仓库
  2. python3 数组大小_python3从零学习-5.1.8、高效的数值数组array
  3. android gridview显示本地图片大小,在Android上的GridView中调整图像大小
  4. 程序员食品营养(2)-日式乳酪酱和巧克力酱
  5. ps自定义形状工具_PS教程——用PS绘制虚线的三种方法
  6. java幂等性的控制(技术论坛上整理成文)
  7. 关系数据库——并发控制
  8. vue 项目安装axios报错
  9. Windows10下下载安装ideaIU
  10. 【毕设资料】 Web版RSS阅读器(一)——dom4j读取xml(opml)文件
  11. Mybatis根据经度、纬度查询距离最近一个位置(Mysql )
  12. css实现点点点效果
  13. linux notifier chains机制
  14. 修改Textview内图片文字间距和图片大小
  15. 【Python】列表排序,用 sort() 还是 sorted()?
  16. 全局gin对象如何在子模块中修改Logger
  17. Win10系统Chrome浏览器启用独立显卡提升3D程序渲染性能
  18. cs224w(图机器学习)2021冬季课程学习笔记20 Advanced Topics on GNNs
  19. UG4.0高级塑胶模具设计视频教程-陈工73G
  20. 快捷方式病毒的解决方法

热门文章

  1. python 枚举类型_Python枚举类
  2. 巴特沃斯滤波器 python_巴特沃斯、切比雪夫、贝塞尔滤波器的区别
  3. linux 配置 java tomcat,Linux配置Tomcat和JDK
  4. gps天线拆解图片_飞宇稳定器拆解:握杆的手,不怕颤抖
  5. svm matlab 画图,matlab 画图
  6. java pdf转为png_java-使用icepdf实现pdf转换成png
  7. Python编程基础21:GUI编程
  8. Scala学习笔记05:函数
  9. 漫谈OI中的群论入门
  10. 【BZOJ2120】数颜色,带修莫队