成功不可能一蹴而就,任何高性能、大规模的Web应用都是慢慢扩展而来。然而通往成功的路上从来不缺乏艰辛,这里为大家分享对扩展性影响最大的20个绊脚石以及避免之道。

Sean Hull是Heavyweight Internet Group的创始人兼高级顾问,拥有20年以上技术顾问相关经验,曾为多家知名机构提供咨询,其中包括The Hollywood Reporter、Billboard、NBC Universal、Zagats、Rent the Runway及ideeli,这些高速增长的公司每个月处理接近1亿的独立访客。Hull在Amazon EC2部署和Linux及MySQL性能上有着丰富的经验。巨大流量的处理需涉及多个方面,其中包括网站扩展性、业务连续性、安全及架构挑战等。近日,Hull分享了高性能Web应用打造的经验,剖析了扩展之路上20个最大的绊脚石。以下为译文:

1.  二阶段提交

通常情况下,当数据库中的数据发生改变时,它需要同时被写入内存和硬盘。当一个提交发生时,传统数据库需要负责数据在真实存储媒质上的持久化。牢记,内存的数据在崩溃或者重启后都会消失。即使数据已经在数据库中缓存,数据库仍然需要将其持久化到磁盘上,MySQL的二进制日志及Oracle的redo日志都符合这个要求。

通过MySQL集群或者类似DRBD(Distributed Replicated Block Device)或者Amazon Multi-AZ(Multi-Availability Zone)的分布式文件系统,提交并不仅仅是在本地发生,同时也在远端。二阶段提交意味着需要从远端得到反馈,鉴于网络及一些其它的延时,提交速度可能会被毫秒级的降低,仿佛高速公路上的所有汽车都因重载变慢。如有考虑使用Multi-AZ或者读备份,不妨查看Amazon RDS(Relational Database Service)与MySQL的比较。

同步复制同样会出现这些问题,因此MySQL解决方案是半同步的,这也可以看做是在二阶段提交上的一些让步。

2.  缓存不足

在所有层中缓存的作用都至关重要,那么什么地方最需要使用缓存:浏览器、页面、对象还是数据库存?下面不妨统统试一下。

浏览器缓存似乎遥不可及,除非你清楚浏览器是从Web Server中取出指令及其渲染的页面。因此,如果包含的对象有一个比较长的生命周期,浏览器将会缓存他们,不需要再次进行读取。这不仅会加快用户的浏览速度,同样会有益于Server对网站的托管,因为会切实的减少用户的二次读取。

猛戳这里查看更多浏览器缓存相关,确保设置了期满头文件及缓存控制。

页面缓存需要使用类似Varnish的技术,可以将它看成一个迷你的高速、低开销Web Server。它不可以支撑类似Apache可以的复杂页面,但是它可以让非常简单的页面更快。因此位于Apache之前,用于减少负载,让Apache可以处理更加复杂的页面。就像交通警察,在专注更复杂的机动车前,先给自行车放行。

对象缓存由类似memcache的组件完成,可以把它当做是应用程序的便利贴。做数据库查询时会先访问缓存寻求数据,如果发现了所需的数据,那么结果返回的时间将比访问数据库快10-100倍,这样就可以快速的构建页面,从而在眨眼间为用户呈现。如果它没有发现所需的数据,或者只发现了一部分,那么将会建立数据库请求并将返回的数据放于缓存中,让更多的后来者受益。

3.  缓慢的磁盘I/O、RAID 5、多租户存储

数据库中的一切都受到存储的限制,这里既包含了空间问题,也受设备读写的速度掣肘。

如果你使用实体服务器,那么一定要当心RAID 5,独立磁盘冗余阵列的一种,数据保护和奇偶性将严重的影响写操作。同时,如果其中一个磁盘损坏,那么这个阵列在磁盘重建时将变得非常缓慢。

这个方案一般使用RAID 10,它将为你提供独立的镜像集。这导致没有奇偶校验计算,从而不会影响重建时的速度。

云环境可能会涉及到类似于Amazon EBS(Elastic Block Store,一个类似于SAN的虚拟化磁盘)的技术。鉴于其基于网络,你必须与其它租户竞争存储的读写。因为每个存储能支撑的读写速度是固定的,所以你的邻居可能会影响到你网站及应用程序的读写速度。

最近,Amazon又公布了一个重量级产品Provisioned IOPS(每秒I/O操作)。对于技术专家来说看起来非常不错,但是对于其它人来说毫无价值。尽管如此,其依然重要,这意味着你可以锁定你数据库所需的磁盘性能。如果你想在Amazon上托管数据库,那么不妨多关注一下这个。

4.  串行处理

在超市结账时,如果有10个收银台开放,那么从事的是并行处理。如果每个收银台都在休息,只有一个登记处开放,那么从事的是串行操作。那么结账的队伍将变得非常长,不仅是结账人的心情受到影响,购物者也同样如此。这点经常发生在线路不够的大桥收费站以及许多人一起离场的体育场所。

网络应用需要严格的避免串行,因等待API调用而产生的阻塞,所有的后端节点都在等待一个搜索服务器,只要你应用程序的某处形成一个线就代表了串行化的发生,那么必须不惜一切代价去清除它。

5.  缺少Feature Flag

在给业务部门建立应用时,开发者一般从特性和功能入手。Feature Flag将至关重要,它让人们可以通过后端配置文件或管理员UI页面关闭或者打开特性。

为什么他们如此重要?如果你有早上4点的救火经验,那么你将明白启动应急计划的必要性。你需要可以关闭评级、评论以及应用程序其它的一些特性,这将不会导致整个系统崩溃。更重要的是,在新特性发布时,有些时候问题并不明显,直到一群互联网用户同时涌入。Feature Flag让你可以选择性的关闭一些功能,而不是关掉整个网站。

6.  单一的数据库副本

你必须使用一个以上的读副本或者MySQL从节点,这允许在主节点出问题时的快速故障转移。

拥有数据库的多个副本意味着横向扩展。如果你有两个,你就会看到3-4个会对你基础设施的提升。

7. 使用数据库进行排队

MySQL数据库非常适合储存表格、数据以及他们之间的关系,不幸的是,它并不适合处理应用程序的队列。尽管如此,许多开发者都习惯使用一个表格来达到这个目的。比如,让你的应用程序包含一些作业表格,或者一个状态列,拥有一些类似“in-process”、“in-queue” 及“finished”的值。

因为锁竞争、scan及 poll进程将造成更多的工作,这些解决方案会带来一些扩展性问题,它们将会显著的降低数据库速度。幸运的是这里存在很多有效的开源解决方案,比如RabbitMQ及Amazon的SQS。

8.  使用一个做全文查询的数据库

页面搜索是掣肘应用程序的另一个方面,尽管MySQL一段时间也支撑了full-text索引。但是它们只对MyISAM表格有效,其它类型表格都不买账,一直困扰着开发者。

一个解决方案是使用类似Solr的专业搜索引擎,这些技术拥有许多很好的库去支撑你的编程语言,同时会提供一个更快的搜索速度。这些方案同样易于扩展,并且不会让你的数据库成为累赘。

替代方案是Sphinx SE,一个MySQL存储引擎,将Sphinx服务器整合进数据库。此外,MySQL 5.6版本中还使用了InnoDB做全文搜索的默认搜索引擎。

9.  对象关系模型

ORM,就像毒药一样,一旦进行使用,就很难摆脱。有利的一面是ORM有益于快速原型,并且允许非专家级MySQL开发者使用对象或者内存模式进行读写访问。如果你不进行扩展,那么他们的速度将非常快,并让功能的快速交付得到保障。

然后DBA(数据库管理员)会因为缓慢且丑陋的查询来到开发团队并且说:“这个查询在应用程序什么地方,我们需要进行修复,它需要被重写。”开发团队则会说:“我们也不知道!”从而会收到来自运营组一些质疑的眼神。

有能力对bad sql进行跟踪并将其指出是非常重要的。DBA团队需要一定的指引找到bad sql的源头。如果查询是来自ORM,他们并不具备这些指引。这样你的团队将面对一个巨大的技术负债,同样也是个非常难以解决的挑战。

10.  缺少Instrumentation

Instrumentation(仪表盘)为应用程序提供了码表和油表,这是汽车不可缺少的两个部分。他们提供了应用程序的内部工作信息:他们记录了时间信息,并且提供了应用程序耗时最多的环节。

一个非常人气的网络解决方案就是New Relic,它提供了一个非常全面的可视化界面,针对各个领域工作者——项目经理、开发者、运营团队,甚至是业务部门都可以从图中发现问题所在。当然,现在已经有很多的开源Instrumentation。

11.  缺少代码仓库及版本管理

尽管现在这个问题已非常少见,但是还有有些互联网公司在没有版本控制下去建立应用程序。当然那些使用了的人,很清楚它将给团队带来的日常优势和组织控制。

如果你没有使用,随着应用程序变得更加复杂,你将被卷入技术负债的漩涡,为应用不同部分添加员工将变得异常困难。

一旦你使用版本控制,确保囊括了所有的组件,包含配置文件以及其它要素。而丢失部署时需要用到的部分,将带来额外的风险。

12.  单点故障

如果你的数据只存在一个主数据库上,这就是一个单点故障。如果你的服务器位于一个单独的磁盘上,这也是个单点故障。单点故障可以比作“阿基里斯之踵”技术用语。

不惜任何代价,单点故障都要在应用程序中移除。麻烦的是如何去认识单点故障,即使是选择单一的云供应商都可以称为单点故障,如果拥有多个供应商,或者使用Amazon不同的部分,那么AirBNB的服务将幸免Amazon 2012年10月的部分宕机。

13.  缺乏只浏览模式

如果你深夜在Yelp、Facebook或者是Tumblr上发布评论,你可能就会收到这样的信息:“该特性不可用,请稍后再试”。稍后可能是50或者60分钟,也许可能还需多试几次。对于非技术用户,他们仍然感觉网站在正常运行,只是奇怪了一点而已。

实际情况是,应用程序只允许你去浏览网站,但是不可以做任何改变。可能是主数据库或者是一些存储组件不可用了。

只浏览模式可以通过保留主数据库的多个读备份来实现,使用MySQL副本或者是Amazon读副本类似途径。这样就可以在没有主数据库情况下,保留网站全部浏览功能正常,这一点非常重要。

14.  脆弱的沟通

在扩展上谈沟通可能非常奇怪,但是应用程序技术层不可能因为团队间社交和文化上的差异分离。

强大的通信线路是必要的,队员必须要知道在错误发生时将找谁。好的交流需要自信及知识渊博的领导,广泛的听取意见并加以改善。

15.  缺少文档

当Web应用程序包含许多层时,文档至关重要。开发者需要给程序、功能、页面做文档,让后来者看代码时可以清晰的发现所需的提示及见解。当有程序发生故障时,运营程序需要在配置文件上添加评论去表明更改历史。业务流程及关系同样应该出现在公司的wiki里,让人们发现自己问题的解决方案。

文档可以在各个层次起到帮助作用,每个人都应该拥抱这个爱好。

16  缺少应急演习

应急通常情况下总会被忽视,团队可能会有“我们覆盖的地方都有备份”这类的说辞。不错备份、恢复的途径很通吃,关键是确保备份的文件万无一失。一旦在故障转移时发现备份有缺失,那么你不愿意发生的事情必然发生。

应急演习让事情发生之前有了相应的经验,公司应该将此作为运营团队工作的一部分,每年都需要进行几次。在云时代,应急演习已经变得比以前轻松许多。为保证所有组件都被备份而启动服务器是非常值得的,在这个过程中你将学到这项操作该持续多长时间,以及困难所在的地方,更知道需要小心些什么。

17.  缺少监视和指标

监视有着与版本控制同样的重要性:非常基本,缺少它工作将无法进行;然而确实有一些网站没有监视,或者是监视力度不够——有些服务器或者是核心组件并未被监视。

不间断的收集系统及服务器数据,同时,应用程序和业务级别的可用性也同等重要。如果你不想亲自动手,不妨考虑一个Web服务方案。

18.  莽撞的运营

你骑着马在街道上飞奔,明着带枪进入酒吧,你认为这是在交朋友?肯定不是,你在暴力的胁迫别人遵循,所有人都不会有归属感。强大的信心是好的,但是团队的合作是不可缺少的,团队的智慧高于任何个人。

团队需要不断的对改变做交流,用管理的角度进行,准备好应对失败等等。采取小心及规避风险的态度,永远都有备用计划,你应该有能力撤销所有改变,并且认真对待破坏性的改变,以及那些不可恢复的地方。

19.  日益增长的技术负债

随着应用不断的增长,队伍需要花越来越多的时间在老代码的维护和支持上,消除漏洞及缺陷。因此,花在新特性上的时间将越来越少。必须谨慎的维护好新特性与技术负债上投入时间的平衡。如果你发现你的技术负债增加,可能就是横下决心重写的时候了。重写可能会影响到短期新特性及客户特性的开发,但是从长远的角度上看是非常好的。

技术负债并不总是能被轻易的认知,在你建立特性或者是修复bug时,你更习惯于聚焦局部的细节,非常容易失去全局观,这也是为什么全面人才更益于Web扩展的原因。

20.  不足的日志

日志直接影响到度量及监视。你在寻找故障和排错时肯定希望得到更多的日志,但是在一个不间断运行的情况下,你同样会需要一些关键服务的日志。服务器系统日志、Apache及MySQL日志、缓存日志等,这些都需要被保存。而在日志太多时,你总是会减少一些地方的日志,或者裁剪及循环日志文件,从而丢弃旧的。

原文链接: Sean Hull's 20 Biggest Bottlenecks That Reduce And Slow Down Scalability