Jul31

【转载】大规模服务设计部署经验谈

Author: 赖翥翔  Click: 7001   Comments: 2 Category: 架构  Tag: 大规模服务设计部署

大规模服务设计部署经验谈

本文中提出的最佳实践,来自于作者多年大规模服务设计和部署的经验,为设计、开发对运营友好的服务提供了一系列良好的解决方案。
■ 文/James Hamilton 译/赖翥翔
1               引言

本文就设计和开发运营友好的服务的话题进行总结,得出一系列最佳实践。设计和部署大规模服务是一个高速发展的领域,因而随着时间的流逝,任何最佳实践集合都可能成熟并完善。我们的目的是为了帮助人们:
l          快速交付运营友好的服务;
l          避免清早电话铃声的骚扰,帮助备受运营不友好的服务侵扰的客户尽量摆脱窘境。
这篇论文是我们在过去的20年中在大规模以数据为中心的软件系统和互联网级大规模服务的智慧结晶,包括Exchange Hosted Services 团队、Microsoft Global Foundation Services
Operations团队以及Windows Live! 平台多个团队的经验。这些贡献经验的服务中,有不少规模已经增长到拥有超过二亿五千万名用户。同时,本论文也大量吸取了加州大学伯克利分校
在面向恢复计算(Recovery Oriented Computing)方面取得的成果和斯坦福大学在只崩溃软件(Crash-Only Software)方面的研究经验。
Bill Hoffman为本论文贡献许多最佳实践。此外,他还提出三条简单原则,值得大家在进入正题之前进行考量:
1. 做好发生故障的心理准备。
2. 保持简单化。
3. 将所有的工作自动化。
这三条原则形成了贯穿后续讨论的主轴。
本文的十个小节涵盖了设计和部署运营友好服务所必须做到的各个方面。它们是:整体服务设计;以自动化和预置(Provisioning)为目标进行设计;依赖关系管理;发布周期及测试;硬件的选择和标准化;运营和容量规划;审核、监控和警报;体面降级和管理控制;客户及媒体沟通计划;以及客户自我预置和自我帮助。
2               整体服务设计

一直以来,人们都相信80%的运营问题源于设计和开发,因此本节关于整体服务设计的内容篇幅最长,也最重要。系统出故障时,人们很自然倾向于首先去审视运营工作,因为这是问题实际产生的地方。不过,绝大多数运营问题都可以归因于设计和开发,或者最适合在设计和开发中解决。随后的内容凸显一个共识,即在服务领域,将开发、测试和运营严格分离不是最有效的方式。在环顾众多服务之后, 我们发现了这样一个趋势——管理的低成本与开发、测试和运营团队间协作的紧密程度密切相关。
除了在这里讨论的服务设计最佳实践以外,随后一节“以自动化管理和预置为目标进行设计”对服务设计也有实质性的影响。有效的自动化管理和预置通常以一个受限的服务模型来实现。简单是高效率运营的关键,
这是贯穿本文重复出现的主题。在硬件选择、服务设计和部署模型上的理性约束,是降低管理成本和提高服务可靠性的强心针。
在运营友好的基础原则中,为整体服务设计带来最大影响的几条包括:
2.1               设计时为故障做好准备(Design for failure)。

在开发包含多个协同运作的组件的大型服务时,这是一条核心概念。这些组件会有故障发生, 而且故障的产生很频繁。它们之间不会总是稳定地协作,也不会单独出现故障。一旦服务的规模达到10,000台以上的服务器和50,000块以上的磁盘,每天就会有多次故障发生。如果一有硬件故障产生就得采取紧急措施来应对,那么服务就无法以合理的成本可靠地伸缩。整个服务必须有承受故障而无须人工干预的能力。故障恢复的步骤必须非常简单,而且这些步骤应当进行频繁测试。斯坦福大学的Armando Fox 主张说,对故障恢复步骤进行测试的最佳方法,就是绝对不要用正常方式使服务停机,用粗暴的方式让它停转就可以了。乍听起来怎么做是违背直觉的,但是如果没有频繁使用故障步骤,那么它们在真正临阵时就可能溃不成军 。
2.2               冗余和错误恢复(Redundancy and fault recovery)。

大型机模型是指购买一台价高块头大的服务器。大型机拥有冗余的电源供应,CPU可以热交换,而且总线架构也超乎寻常,使得这样一个紧密耦合的系统能够有可观的I/O吞吐量。这样的系统,最明显的问题就是它们的成本;而且即便有了所有这些费用高昂的设计,它们仍然不够可靠。为了达到99.999%的可靠性,冗余是必须存在的。实际上,在一台机器上实现4个9的可靠性都是相当困难的。这个概念在整个业界都耳熟能详,不过,将服务构建在脆弱而又非冗余的数据层之上的现象,到目前为止都屡见不鲜。要保证设计的服务其中的任何系统可以随时崩溃(或者因为服务原因被停止)但又仍然能符合服务水平协定(Service Level Agreement, 简称SLA),是需要非常仔细的设计的。保证完全遵守这项设计原则的严格测试(acid test) 步骤如下:首先, 运营团队是否有意愿并且有能力随时让任意一台服务器停机并且不会让负载被榨干?如果答案是确定的,那么肯定存在同步冗余(无数据丢失)、故障侦测和自动接管。我们推荐一条普遍使用的设计方法,用于查找和纠正潜在的服务安全问题:安全威胁建模(Security Threat Modeling)。在安全威胁建模中,我们要考虑每一条潜在的安全威胁,并且相应实现恰当的缓和方案。同样的方法也适用于以错误适应和恢复为目标的设计。
将所有可以想象到的组件故障模式及其相应组合用文档记录下来。要保证服务在每个故障发生后都能继续运行,且不会在服务质量上出现不可接受的损失;或者判断这样的故障风险对于这样一个特定的服务是否可以接受(例如,在非地理冗余的服务中损失掉整个数据中心)。我们可能会认定某些非常罕见的故障组合出现的可能性微乎其微,从而得出确保系统在发生这种故障之后还能继续运行并不经济的结论。但是,在做这样的决定时请谨慎从事。在运行数以千计的服务器的情况下,每天都会有几百万种组件故障产生的可能,这时那些事件的“罕见”组合亮相的频繁程度,足以让我们瞠目结舌。小概率组合可能变成普遍现象。
2.3               廉价硬件切片(Commodity hardware slice)。

服务的所有组件都应当以廉价硬件切片为目标。例如,存储量轻的服务器可以是双插槽的2至4 核的系统,带有启动磁盘,价格在1,000 至2,500 美元之间;存储量大的服务器则可以是带有16至24个磁盘的类似服务器。主要的观察结果如下:
l          大型的廉价服务器集群要比它们替代的少数大型服务器便宜得多;
l          服务器性能的增长速度依然要比I/O性能的增长速度快很多,这样一来,对于给定容量的磁盘,小型的服务器就成为了更为稳定的系统;
l          电量损耗根据服务器的数量呈线性变化,但随系统时钟频率按立方级别变化,这样一来性能越高的机器运营成本也越高;
l          小型的服务器在故障转移(Fail over)时只影响整体服务工作负荷的一小部分。
2.4               单版本软件(Single-version software)。

使某些服务比多数打包产品开发费用更低且发展速度更快的两个因素是:
l          软件只需针对一次性的内部部署。
l          先前的版本无须得到十年的支持——针对企业的产品正是如此。相对而言,单版本软件更容易实现,附带客户服务,特别是无须费用的客户服务。但是在向非客户人员销售以订阅为基础的服务时,单版本软件也是同样重要的。企业通常习惯在面对他们的软件提供商时拥有重要的影响力,并且在部署新版本时(通常是个缓慢的过程),他们会习惯性想去掌握全部的控制权。这样做会导致他们的运营成本和支持成本急剧上升,因为软件有许多版本需要得到支持。最经济型的服务是不会把对客户运行的版本的控制权交给他们的,并且通常只提供一个版本。要把握好单一版本软件的产品线,必须:
l          注意在每次发布之间不要产生重大的用户体验变更。
l          愿意让需要相应级别控制能力的客户可以在内部托管,或者允许他们转向愿意提供这类人员密集型支持服务的应用服务提供商。
2.5               多重租赁(Multi-tenancy)。

多重租赁是指在同一个服务中为该服务的所有公司或最终用户提供主机服务,且没有物理上的隔离;而单一租赁(Single-tenancy)则是将不同组别的用户分离在一个隔离的集群中。主张多重租赁的理由基本上和主张单版本支持的理由一致,且它的基础论点在于提供从根本上成本更低、构建在自动化和大规模的基础之上的服务。
回顾起来,上面我们所展示的基本设计原则和思考如下:
l          设计时为故障做好准备
l          实现冗余和错误恢复
l          依靠廉价硬件切片
l          支持单一版本软件
l          实现多重租赁
我们约束服务设计和运营的模型,以此最大化自动化的能力,并且减少服务的总体成本。在这些目标和应用服务提供商或IT 外包商的目标之间,我们要划一道清楚的界限。应用服务提供商和IT外包商往往人员更加密集,并且更乐于运行面向客户的复杂配置。
2.6               设计运营友好的服务的实践

设计运营友好的服务更具体的最佳实践包括:
2.6.1             快速服务健康测试。

这是构建验证测试的服务版本。这是一个嗅探型测试,可以快速在开发者的系统上运行,以保证服务不会以独立方式出错。要保证所有的边界条件都被测试到,是不可能的,但如果快速健康测试通过的话,那么代码就可以检入了。
2.6.2             在完整的环境中开发。

开发人员不但应当对他们的组件进行单元测试,而且还要对出现组件变更的整个服务进行测试。要高效实现这个目标,必须得有单服务器的部署,以及前一条最佳实践——快速的服务健康测试。
2.6.3             对下层组件的零信任。

设想下层组件会出现故障,并且确保组件会有能力恢复并继续提供服务。恢复的技巧和服务相关,但常见的技巧包括:
l          在只读模式中依靠缓存的数据继续运转;
l          在服务访问故障组件的冗余拷贝的短暂时间内,继续向用户群一小部分的所有人提供服务。
2.6.4             不要把同一个功能构建在多个组件中。

预见未来的交互是一件极其困难的事情,如果不慎引入冗余的代码,那么将来就不得不在系统的多处做修复。服务的增长和发展是很快的,稍不留神代码的质量就会很快恶化。
2.6.5             不同的集群之间不能互相影响。

大多数服务由小型集合或者系统的子集群组成,它们之间相互协作,共同提供服务,其中每个小型集合都可以相对独立地运作。每个小型集合应达到接近100%的独立程度,且不会有跨群的故障。全局服务,甚至包括冗余,是故障的中心点。有时候,这样的问题是不可避免的,但还是要设法保证每个集群都拥有各自所需的资源。
2.6.6             允许(少量)在紧急情况的人工干预

见场景是在灾难性事件或者其他紧急情况下移动用户数据。把系统设计成完全无须人工交互,但也要清楚小概率事件可能会发生,其中组合的故障或者未预期的故障都会需要人工交互。这些事件是会发生的,而在这些情况下,操作员的错误往往是导致灾难性数据丢失的常见来源。一名在半夜2点顶压工作的运营工程师可能会犯错误。将系统设计成一开始在多数情况下无须运营干预,但请和运营团队协作制定在他们需要进行干预时的恢复计划。比起将这些计划写进文档,变成多步骤易出错的过程,更好的办法是把这些规则写成脚本,并在生产环境中进行测试,以确保它们正常工作。没有经过产品环境试验的代码是不可行的,因此运营团队应当定时指挥使用这些工具进行“防火演习”。如果演习的服务可用性风险非常高,那么可以认为之前在工具的设计、开发和测试上的投资不足。
2.6.7             保持一切简单健壮。

复杂的算法和组件交互会给调试和部署带来成倍困难。简单到近乎傻瓜式的结构在大规模服务中几乎总是更胜一筹, 因为在复杂的优化工作交付之前, 交互中故障模式的数量早就足以磨灭人们的信心。通常我们的惯例是, 能够带来一个数量级以上改善的优化工作才值得考虑, 而只有百分之几或者甚至于只是低系数级别的提升,就不值得了。
2.6.8             全面推进准入控制。

所有良好的系统会在设计时开门见山地引入许可控制,这样符合一条长期以来为人们所认可的原则,那就是避免将更多的工作引入一个已经过载的系统,要比持续接受工作然后开始翻来覆去地检查好一些。在服务入口引入某些形式的节流或者准入控制是很常见的做法,但在所有的主要组件边界上都应该有准入控制。工作性质的变更最终会导致子组件的过载,即使整体服务仍然运行在可接受的负载级别。总体的惯例就是尝试采用优雅降级的方式,而不用在统一给所有用户低质量服务之前进行硬停机并阻断服务的入口。
2.6.9             给服务分区。

分区应当可以无限调整,并且高度细粒度化,并且不受任何现实实体(人、集合等)的限制。如果按公司分区,那么对于大的公司,就有可能超过单个分区的规模;而如
果按名称前缀进行分区,那么例如所有以P打头的最终一台服务器就可能会装不下。我们推荐在中间层使用一张查询表,将细粒度的实体,通常是在设计大规模服务的目标和应用服务提供商或IT外包商的目标之间,要划一道清楚的界限。应用服务提供商和IT 外包商往往人员更加密集,并且更乐于运行面向客户的复杂配置。
用户,映射到其数据相应被管理的系统上。这些细粒度的分区随后就可以自由在服务器之间移动。
2.6.10         理解网络的设计。

提早进行测试,了解机柜内的服务器之间、跨柜的服务器之间以及跨数据中心之间有哪些负载。应用程序开发人员必须理解网络的设计,且设计应当尽早交给来自运营团队的网络专员审核。
2.7               对吞吐量和延迟进行分析。

应当对核心服务的用户交互进行吞吐量和延迟的分析,从而了解它们的影响。结合其他运营操作,比如定期数据库维护、运营配置(加入新用户,用户迁移)和服务调试等,进行吞吐量和延迟的分析。这样做对于捕捉由周期性管理任务所带动的问题是颇有裨益的。对于每个服务,都应当形成一个度量标准,用于性能规划,比如每个系统的每秒用户访问数,每个系统的并发在线人数,或者某些将关联工作负载映射到资源需求的相关度量标准。
2.8               把运营的实用工具作为服务的一部分对待。

把运营的实用工具作为服务的一部分对待。由开发、测试、项目管理和运营所产生的运营实用工具应当交给开发团队进行代码审查,提交到主源码树上,用同一套进度表跟踪,进行同样的测试。最频繁出现的现象是,这样的实用工具对于任务有至关重要的影响,但几乎都没有经过测试。
2.9               理解访问模式。

理解访问模式。在规划新特性时,一定要记得考虑它们会给后端存储带来哪些负载。通常,服务模型和服务开发人员与存储抽象得非常开,以至于他们全然忘记了它们会给后端数据库带来的额外负载。对此的最佳实践把它作为规范建立起来,里面可以有这样的内容:“这项功能会给基础结构的其他部分带来什么样的影响?”然后在这项特性上线之后,对它进行负载的测量和验证。
2.10           让所有工作版本化。

做好在混合版本的环境中运行的准备。我们的目标是运行单版本的软件,但是多个版本可能会在首次展示和生产环境测试的过程中并存。所有组件的n 版和n+1版都应当能够和平共存。
2.10.1         保持最新发布版的单元/功能测试。

这些测试是验证n - 1 版本的功能是否被破坏的重要方法。我们推荐大家更进一步,定期在生产环境中运行服务验证(后面会详细介绍)。
2.10.2         避免单点故障。

单点故障的产生会导致整个服务或者服务的某些部分停工。请选择无状态的实现。不要将请求或者客户端绑定在特定的服务器上,相反,将它们负载均衡在一组有能力处理这样负载的服务器上。静态哈希或者任何静态的服务器负载分配都会时不时遭受数据和/ 或查询倾斜问题的困扰。在一组机器可以互换时,要做到横向伸展是非常容易的。数据库通常会发生单点故障,而数据库伸缩仍然是互联网级大规模服务的设计中最为困难的事情之一。良好的设计一般会使用细粒度的分区,且不支持跨分区操作,以在多台数据库服务器之间进行高效伸展。所有的数据库状态都会进行冗余存储(至少在一台)完全冗余的热待机服务器上,并且在生产环境中会频繁进行故障转移测试。
3               自动管理和预置

许多服务编写的目的是为了在故障时向运营部门发出警报,以得到人工干预完成恢复。这种模式凸显出在24 x 7 小时运营人员上的开支问题;更重要的是,如果运营工程师被要求在充满压力的情况下做出艰难的决定,那么有20%的可能他们会犯错误。这种模式的代价高昂,容易引入错误,而且还会降低服务的整体可靠性。然而,注重自动化的设计会引入明显的服务模型约束。比如说,当前某些大型服务依靠的数据库系统,会以异步方式复制到次级备份服务器,因为复制以异步方式完成,在主数据库无法服务请求后,故障转移到次级数据库会引起部分客户数据丢失。然而,不把故障转移到次级数据库,则会引起数据被储存在故障服务器上的用户面临服务停工。在这种情况下,要自动化故障转移的决策就很困难了,因为这个决策依赖于人为判断,以及对数据损失量和停机大致时长相比的准确估计。注重自动化设计出的系统会在延迟和同步复制的吞吐量开销上付出代价。在做到这一步以后,故障转移变成了一个很简单的决策:如果主服务器宕机,将请求转到次服务器上。这种方式更适用于自动化,而且被认为更不容易产生错误。在设计和部署后将服务的管理过程自动化可能是一件相当具有难度的工作。成功的自动化必须保证简单性,以及清晰并易于确定的运营决策;这又要依靠对服务的谨慎设计,甚至在必要时以一定的延迟和吞吐量为代价作出牺牲,让自动化变得简单。通常这样的折中方案并不容易确定,但是对于大规模服务来说在管理方面的节约可能不止数量级。事实上,目前根据我们的观察,在人员成本方面,完全手动管理的服务和完全自动化的服务之间的差别足足有两个数量级。注重自动化的设计包含以下最佳实践:
3.1               可以重启动,并保持冗余。

可以重启动,并保持冗余。所有的操作都必须可以重新启动,并且所有持久化状态也必须冗余存储。
3.2               支持地理分布

支持地理分布。所有大规模服务都应当支持在多个托管数据中心运行。我们所描述的自动化和绝大多数功效在无地理分布的情况下仍是可行的。但缺乏对多服务中心部署方式的支持, 会引起运营成本显著提升。没有了地理分布, 很难使用一个数据中心的空闲容量来减缓另外一个数据中心所托管的服务的负载。缺乏地理分布是一项会导致成本提高的运营约束。
3.3               自动预置与安装。

自动预置与安装。手动进行预置和安装是相当劳民伤财的,故障太多,而且微小的配置差异会慢慢在整个服务中蔓延开来,导致问题的确定越来越困难。
3.4               将配置和代码作为整体。

将配置和代码作为整体。请确保做到:
l          开发团队以整体单元的形式交付代码和配置;
l          该单元经过测试部门的部署,并严格按照运营部门将会部署的方式;
l          运营部门也按照整体单元的方式部署。通常说,将配置和代码作为一整个单元处理并且只把它们放在一起修改的服务会更可靠。
3.5               生成环境的变更必须审核和记录

如果配置必须在生产环境中变更,那么请保证所有的变更都要产生审核日志记录,这样什么东西被修改,在什么时候被谁修改,哪些服务器受到影响,就一目了然了。频繁扫描所有的服务器,确保它们当前的状态与预期状态相符。这样做对捕获安装和配置故障颇有裨益,而且能在早期侦测到服务器的错误配置,还能找到未经审核的服务器配置变更。
3.6               管理服务器的角色或者性质,而不是服务器本身

管理服务器的角色或者性质,而不是服务器本身。每个系统的角色或性质都应当按需要支持尽可能多或少的服务器。
3.7               多系统故障是常见的。

多系统故障是常见的。请做好多台主机同时发生故障的准备(电源、网络切换和首次上线)。遗憾的是,带有状态的服务必须得注意它们的拓扑分布。有相互联系的故障一直以来都是不可避免的。
3.8               在服务级别上进行恢复。

在服务级别上进行恢复。在服务级别处理故障,相比软件底层来说,其中的服务执行上下文更加完整。例如,将冗余纳入服务当中,而不是依靠较低的软件层来恢复。
3.9               对于不可恢复的信息,绝对不要依赖于本地存储。

对于不可恢复的信息,绝对不要依赖于本地存储。保证总是复制所有的非瞬时服务状态。
3.10           保持部署的简单性

保持部署的简单性。文件复制是最理想的方式,因为这样能带来最大的部署灵活性。最小化外部依赖性;避免复杂的安装脚本;避免任何阻止不同组件或者同一个组件不同版本在同一台机器运行的情况。
3.11           定期使服务停转

定期使服务停转。停掉数据中心,关闭柜式服务器,断掉服务器电源。定期进行受控的关闭操作,能够主动暴露出服务器、系统和网络的缺陷。没有意愿在生产环境中测试的人,实际上是还没有信心保证服务在经历故障时仍能继续运转。此外,若不进行生产测试,在真正出事时,恢复不一定能派上用场。■
 
4               依赖管理

在大规模服务中,依赖管理这个话题通常得不到应有的关注。一般的准则是,对于小型组件和服务的依赖关系,对于判断管理它们的复杂性来说,并不足以节约成本。在以下情况中,依赖关系存在重要意义:
1. 被依赖的组件在大小和复杂度上有重要价值;
2. 被依赖的服务在作为单一的中央实例时存在价值。
第一类的例子有存储和一致性算法(consensus algorithm) 的实现。
第二类的例子包括身份和群组管理系统。这些系统的整体价值在于它们是一个单一且共享的实力,因此使用多实例来避免依赖关系就不是可选方案。假定要根据上面的标准判断依赖关系,那么用来管理它们的最佳实践有:
4.1               为延迟做好准备。

为延迟做好准备。对外部组件的调用可能需要很长时间才能完成。不要让一个组件或者服务中的延迟在完全不相关的领域中引发延迟;确保所有的交互都存在长度合适的超时时长,避免资源阻塞更长的时间。运营等幂性允许请求在超时后重启,即便这些请求可能已经部分或完全完成。确保所有的重启操作都得到报告,并给重启操作设定界限,从而避免反复故障的请求消耗更多的系统资源。
4.2               隔离故障。

网站的架构必须能防止层叠的故障,要总是“快速失败(fail fast)”。当依赖服务出现故障时,把这些服务标注为停机,并停止使用这些服务,以避免线程因等待故障组件而阻塞。
4.3               使用已经交付的历经考验的组件。

使用已经交付的历经考验的组件。历经考验的技术通常总是要比大胆前卫地走在潮流尖端运行要好很多。稳定的软件要优于新版本的早期,不管新特性如何有价值。这条原则也适用于硬件。批量生产的稳定硬件,往往要比从早期发布的硬件所获得的些许性能提升要有价值得多。
4.4               实现跨服务的监控和警报。

实现跨服务的监控和警报。如果服务中有一个附属服务过载,那么被依赖的服务就必须了解这个情况,并且如果服务无法自动备份,那么必须发送警报。如果运营部门无法快速地解决这个问题,那么服务就得设计得能容易迅速地联系到两个团队的工程师。所有相关的团队都应当在附属团队中安排工程联络人。
4.5               附属服务需要同一个设计点。

附属服务需要同一个设计点。附属的服务和附属组件的生产者至少必须遵循与所属服务相同的SLA(服务水平协议)。
4.6               对组件解耦。

对组件解耦。在所有可能的地方保证在其他组件故障时,组件可以继续运行,可能在一个降级的模式中。例如,比起在每一个连接上重新验证,维护一个Session键值,并且无论连接状况如何,每过N小时就刷新这个键值会更好些。在重新建立连接时,只使用现有的Session 键值。这样的话在验证服务器上的负载就会更加一致,而且也不会在临时网络故障和相关事件之后的重新连接过程中出现登录高峰期的情况。
5               发布周期及测试

在生产环境中进行测试是一件很现实的事情,必须成为所有Internet 级服务所必须的质量保证方式之一。在尽可能( 可以掏得起钱)的情况下,绝大多数服务都应当有至少一个与生产环境相似的测试实验室,并且所有优秀的工程师团队应当使用生产级的负载,以反映现实的方式测试服务器。不过,我们的经验是,这些测试实验室即便模拟得再好,也绝不可能百分之百的逼真;它们至少总是会在一些细微的方式上和生产环境有所差别。由于这些实验室在真实性上接近生产系统,因此相应的费用也呈渐进趋势,在部署互联网级大规模服务时,有关依赖管理和发布周期及测试方面的经验和最佳实践在本文中得以体现。新的服务发布版本可以顺着标准单元测试、功能测试和生产测试实验室测试一路走下来,一直进入受限的生产环境作为最后的测试阶段。
快速逼近生产系统的开支。与此不同,我们推荐让新的服务发布版本顺着标准单元测试、功能测试和生产测试实验室测试一路走下来,一直进入受限的生产环境作为最后的测试阶段。显然,我们不想让无法正常工作并给数据一致性带来风险的软件进入生产环境,因此这就不得不小心翼翼地实施。下面的原则一定要遵守:
1. 生产系统必须有足够的冗余,以保证在灾难性的新服务故障发生时,能够快速地恢复到原来的状态;
2. 必须让数据损坏或者状态相关的故障极难发生(一定要首先通过功能测试);
3. 故障一定要能检测得到,并且开发团队(而不是运营团队)必须监控受测代码的系统健康度;
4. 必须可以实现对所有变更的回滚操作,并且回滚必须在进入生产环境之前经过测试。这听起来有点让人心惊胆战。不过我们发现,使用这个技术实际上能够在新服务发布时提升客户体验。与尽可能快地进行部署的做法不同,我们在一个数据中心中将一个系统放到生产环境数天。随后在每个数据中心内把新系统引入生产环境。接着,我们会将整个数据中心带入生产环境。最后,如果达到了质量和性能的目标,我们就进行全局部署。这种方式可以在服务面临风险之前发现问题,事实上还可以通过版本过渡提供更优秀的客户体验。一锤定音的部署是非常危险的。我们青睐的另一种可能违反直觉的方式是,在每天正午而不是半夜部署。在晚上部署,出现错误的风险更高,而且在半夜部署时如果有异常情况突然发生,那么能处理这些问题的工程师肯定会少些。这样做的目标是
为了使开发和运营团队与整体系统的互动最小化,尤其在普通的工作日之外,使得费用得到削减的同时,质量得到提高。对于发布周期和测试的最佳实践包括:
5.1               经常性地交付。

经常性地交付。直觉上讲,人们会认为更频繁地交付难度要更大,而且会错误频出。然而我们发现,频繁的交付中突兀的变更数量很少,从而使得发布的质量变得更高,并且客户体验更棒。对一次良好的发布所进行的酸性测试,用户提供可能会有所变化,但是关于可用性和延迟的运营
问题的数量应当在发布周期中不受改变。我们会喜欢三个月一次的交付,但也可以有支持其他时长的论调。我们从心底认为,标准最终会比三个月更少,并且有许多服务已经是按周交付的了。比三个月更长的周期是很危险的。
5.2               使用生产数据来发现问题。

使用生产数据来发现问题。在大规模系统中的质量保证,是个数据挖掘和可视化的问题,而不是一个测试问题。每个人都必须专注于从生产环境的海量数据中获得尽可能多的信息。这方面的策略有:
l          可度量的发布标准。定义出符合预期用户体验的具体标准, 并且对其进行持续监控。如果可用性应当为99%, 那么衡量可用性是否达到目标。如果没有达到, 发出警报并且进行诊断。
l          实时对目标进行调优。不要停顿下来考虑到底目标应当是99%、99.9%还是任何其他目标,设定一个可以接受的目标,然后随着系统在生产环境中稳定性的建立,让目标渐进式地增长。
l          一直收集实际数据。收集实际的度量,而不是那些红红绿绿的或者其他的报表。总结报表和图像很有用,不过还是需要原始数据用来诊断。
l          最小化“ 假阳性(falsepositive)”现象。在数据不正确时,人们很快就不再关注它们。不要过度警报,真是很重要的,否则运营人员会慢慢习惯于忽略这些警报。这非常重要,以至于把真正的问题隐藏成间接损害常常是可以接受的。
l          分析趋势。这个可以用来预测问题。例如,当系统中数据移动的速度有异于往常的时候,常常能够预测出更大的问题。这时就要研究可用的数据。
l          使系统健康程度保持高度透明。要求整个组织必须有一个全局可用且实时显示的系统健康报告。在内部安置一个网站,让大家可以在任意时间查看并了解当前服务的状态。
l          持续监控。值得一提的是,人们必须每天查看所有数据。每个人都应当这么做,不过可以把这项工作明确给团队的一部分人专职去做。
5.3               在设计开发上加大投入。

在设计开发上加大投入。良好的设计开发可以使运营需求降到最小,还能在问题变成实际运营矛盾之前解决它们。非常常见的一个现象就是组织不断给运营部门增加投入,处理伸缩问题,却从没花时间设计一套伸缩的可靠架构。如果服务一开始没有进行过宏伟的构思,那么以后就得手忙脚乱地追赶了。
5.4               支持版本回滚。

支持版本回滚。版本回滚是强制的,而且必须在发布之前进行测试和验证。如果没有回滚,那么任何形式的产品级测试都会存在非常高的风险。回复到先前的版本应该是一个可以在任意部署过程中随时打开的降落伞扣。
5.5               保持前后版本的兼容性

保持前后版本的兼容性。这一点也是至关紧要的,而且也前面一点关系也非常密切。在组件之间更改文件类型、接口、日志/ 调试、检测(instrumentation)、监控和联系点,都是潜在的风险来源。除非今后没有机会回滚到之前的老版本的可能,否则不要放弃对于老版本文件的支持。
5.6               单服务器部署。

单服务器部署。这既是测试的需求也是开发的需求,整个服务必须很容易被托管到单一的系统中。在对于某些组件单服务器无法实现的地方(比如说一个对于外部、非单箱的可部署服务),编写模拟器来使单服务器测试成为可能。没有这个的话,单元测试会的难度会很大,而且不会完全覆盖到实际条件。而且,如果运行完整的系统很困难的话,开发人员会倾向于接受从组件的角度看问题,而不是从系统的角度。
5.7               针对负载进行压力测试。

针对负载进行压力测试。使用两倍(或者更多倍的)负载来运行生产系统的某些小部分,以确保系统在高于预期负载情况下的行为得到了解,同时也确保系统不会随着负载的增加而瓦解。
5.8               在新发布版本之前进行功能和性能测试。

在新发布版本之前进行功能和性能测试。在服务的级别上这么做,并针对每个组件这么做,因为工作负载的特征会一直改变。系统内部的问题和降级现象必须在早期捕获。
5.9               表象性且迭代地进行构建和部署。

表象性且迭代地进行构建和部署。在开发周期中早早地把完整服务的骨架先搭建起来。这个完整服务可能几乎做不了什么,也可能在某些地方出现偏差,但是它可以允许测试人员和开发人员更有效率,而且也能让整个团队在一开始就从用户的角度进行思考。在构建任何一个软件系统时,这都是一个好方法。不对,对于服务来说这尤为重要。
5.10           使用真实数据测试。

使用真实数据测试。将用户请求和工作量从生产到测试环境分门别类。选择生产数据并把它放到测试环境中。产品形形色色的用户,在发现bug 的时候总是显得创意无穷。显然,隐私承诺必须保持,使得这样的数据永远不会泄漏回到产品环境中,这是至关紧要的。
5.11           运行系统级的验收测试。

运行系统级的验收测试。在本地运行的测试提供可以加速迭代开发的健康测试。要避免大量维护费用,这些测试应当放在系统级别。
5.12           在完全环境中做测试和开发

在完全环境中做测试和开发。把硬件放在一边,在专注的范围内测试。作重要的是,使用和在这些环境中的生产条件下同样的数据集合和挖掘技术,以保证投资的最大化。■(中结束)
 
6               运营和功能计划

要高效地运营服务,关键在于让构建的系统有效地消除运营团队的绝大部分管理交互。这样做的目标,是让一个高度可靠的24 x 7 小时运行的服务,由一个8 x 5小时工作的运营团队就足以维护起来。
不过世事难料,一组或者多组系统救火不成,无法恢复上线的事情是时有发生的。在熟知这些可能性的情况下,实现把损坏的系统标为当机这个过程的自动化。依赖运营团队手动更新SQL 表或者使用特别的技术移动数据,都会招致灾难。与故障交战正酣时,往往错误也容易迭出。先预估运营团队需要采取的补救措施,然后预先编写和测试这些过程。一般来说,开发团队必须将紧急恢复措施自动化,而且他们必须对之进行测试。显然,百密一疏,并非所有故障都能预估到,但通常一小组恢复措施就可以用来恢复多种类型的故障。从根本上说,要构建并测试可以根据灾难的范围和性质以不同方式使用及结合的“恢复内核”。
恢复脚本应当在生产环境中进行测试。这里有一条普适规则,即如果没经过频繁测试,什么程序都无法正常工作,因此不要实现团队没勇气使用的任何东西。如果在生活环境中测试风险过高,那么脚本就没有达到能在紧急情况下使用的标准,或者说在紧急情况下不安全。这里很关键的一点是,灾难总是可能发生的,由无法按预期结果运行的恢复步骤所导致的小问题酿成大灾难的例子是屡见不鲜的。要预见到这样的事件,设计出自动化措施,让服务回复正常状态,而不至于丢失更多数据或损耗更多正常运行时间。
6.1               让开发团队承担责任。

让开发团队承担责任。Amazon也许是沿着这条道路贯彻得最坚定最矢志不渝的公司了——他们的口号是“你创建就该你管”。这样的立场也许要比我们会选择的更坚定一些,但这显然是一个正确的大方向。如果不得不频繁在深更半夜给开发团队打电话,那么你就得做出一套自动化方案。如果需要频繁给运营团队打电话,那么通常的反应就是要增加运营团队的人手。
6.2               只进行软删除。

只进行软删除。绝不要删除任何东西,只可以把这些东西标记成删除状态。在有新数据进入时,即时将请求记录下来。每两周(或者更长时间)保存一份所有操作的历史记录,可以有助于从软件或者管理上的错误进行恢复。如果有谁犯了错误,忘记在delete 语句加上where 子句(这样的错误以前发生过,以后也可能再犯),那么数据的所有逻辑拷贝都会被删除。不管是RAID还是镜像都无法防止这样的错误。具备数据恢复的能力,可以让原来会十分令人窘迫难堪的大问题转化为一个小到甚至可以忽略不计的小障碍。对于那些已经做过离线备份的系统,只需要从上次备份开始记录进入服务的附加数据就可以了。不过谨慎起见,不管怎么说我们还是推荐进行更进一步的备份。
6.3               跟踪资源分配。

跟踪资源分配。了解性能规划的额外负载所带来的开销。每个服务都需要开发出一些使用的度量标准,例如并发在线用户数量、每秒用户访问数或者其它合适的标准。不管度量标准是什么,在这个负载度量和所需的硬件资源之间肯定存在一个已知的直接相互关系。估算的负载数字应当由销售和营销部门提供,并在性能规划过程中为运营团队所使用。不同的服务会拥有不同的变更速率,也要求不同的订购周期。在我们开发过的服务中,我们每90天更新一次市场预报,每30天更新一次性能规划和订购一次设备。
6.4               每次变更一样东西

每次变更一样东西。在出现麻烦时,应当每次只向环境应用一个变更。这条准则看起来显而易见,但我们也看见过许多场合里出现多个变更,导致起因和效果不能吻合。
6.5               使所有资源都可以配置。

使所有资源都可以配置。在生产环境中,任何存在变更需求的资源,都应无需经过任何代码改变,就能在生产环境中进行配置和调优。即使你没什么好理由说明为什么某个值会有必要在生产环境中更改,只要实现起来没什么难度,还是让它可变更好些。不应在生产环境中随意更改这些开关,而应该使用为生产环境所规划的配置对整个系统进行彻底测试。不过,在出现生产环境问题时,比起编码、编译、测试再部署代码变更的过程,进行简单的配置变更永远是更加简单、安全和快速的。
7               审核、监控和预警

运营团队不能在部署环境中装配服务。要在部署过程中付出实质性的努力,以确保系统中的每个组件都可以生成性能数据、健康数据和吞吐量数据等。
在任何有配置变更发生的时候,都必须在审核日志中记录详细变更内容、变更人和变更时间。在生产环境出现异常时,第一个要回答的问题就是最近到底进行过哪些变更。离开了审核跟踪,那么这个答案就是“什么都没被改过”,而且情况往往会是,被人们忘掉的就是引发问题的变更。预警是一门艺术。人们总是倾向于对所有事件都做警报,因为开发人员认为这些事件可能值得关注。正是如此,多数服务的第一版通常都会产生长篇累牍的无用预警,结果再也没
有人去理睬。要提高效率,每个警报都得说明一个问题,否则运营团队会慢慢学会对这些警报置之不理。进行互动慢慢跳出需要警报的条件,保证所有关键性事件得到预警,以及在无需采取应对措施时没有警报。除此之外,要实现正确的预警别无灵丹妙药。要得到正确的预警标准,有两条度量标准很有用,也值得尝试:
一、警报和实际故障比(同时要设定一个较为接近的目标);
二、没有相应警报的系统健康问题数量(并设定一个近于0的目标)。
7.1               对所有资源进行检测。

对所有资源进行检测。测量通过系统的每一次用户交互或事务,报告异常情况。尝试“运行器(人为的工作负载,用来模拟生产环境中用户和服务的交互)”也是可以的,不过这还远远不够。如果只是单独使用运行器,我们发现需要花费数日才能检测到一个严重错误,因为运行器的标准工作负载也会被继续良好地处理,接下来还要再花几天才能查出原因。
7.2               数据是最有价值的资产。

数据是最有价值的资产。如果没有充分理解正常的操作行为,那么要对非正常行为做出响应就不是件容易的事情。我们需要汇集许多系统内发生的事件信息,才能知道系统是否真的正常运行。许多服务都经历过灾难性故障,而只有电话铃响起的时候,人们才意识到故障的发生。
7.3               从客户的角度看服务。

从客户的角度看服务。进行端到端的测试。虽然单有运行器不够,但还是需要它们来保证服务器的完整运行。保证例如新用户登录这样重要的复杂过程经过运行器的测试。避免误警,如果在某个运行器上的故障没被当作重要故障,那么变更测试对象,换到是重要故障的运行器上。重申一下,一旦人们开始对数据视而不见,真正的损失就会让人们措手不及。
7.4               检测是生产环境测试所必不可少的。

检测是生产环境测试所必不可少的。检测是生产环境测试所必不可少的。要在生产环境中实现安全的测试,就有必要进行全面监控和预警。如果某个组件开始出现故障,就必须快速检测出来。
7.5               延迟是最棘手的问题。

延迟是最棘手的问题。缓慢的I/O,以及尚未出现故障但处理缓慢的现象,都是很好的例子。这些问题发现起来很困难,所以一定要仔细检测,保证这样的现象可以检测出来。
7.6               要有足够的生产环境数据

要有足够的生产环境数据。为了发现问题,数据是不可或缺的。在早期就要建立细粒度的监控机制,否则放到后面再翻新成本就高得多了。
我们所依赖的数据中最重要的包括:
l          对所有操作使用性能计数器。至少记录操作的延迟和每秒钟的操作次数。这些数值突然出现的此消彼长现象,是一个十分危险的信号。
l          审核所有操作。每次有人进行操作之后,尤其是那些明显的操作,一定要记入日志。这样做有两个目的:首先,可以对日志进行挖掘,找出用采取的操作类型(在我们的例子里是用户查询的种类);其次,一旦发现问题,这样做有助于调试问题。相关视点:如果每个人使用相同的账号管理系统的话,这么做带来不了多少好处。相反这是一个非常糟的办法,不过这种情况不多。
l          跟踪所有容错机制。容错机制会把故障隐藏起来。每次出现重试、某个数据被一处复制到另一处,以及机器或者服务重启这类现象时,都要进行跟踪。要了解容错机制在何时隐藏了小故障,这样就可以对这些小故障进行追溯,以防其变成大面积故障。我们曾经碰到过这样一个问题:一个跨2000台机器的服务在几天内慢慢地瘫痪,最后只剩400 台机器可用,而一开始这个问题却没有发现。
l          跟踪对重要实体的操作。为某个特殊实体的所有重要操作记录一份“审核日志”,不管这个实体是一个文档,或者一组文档。在运行数据分析时,常常能在数据中发现异常现象。要了解数据的来源及其经历的处理过程。到了后期才往项目加入这样的功能是非常困难的。
l          断言(asserts)。不要吝惜断言的使用,而且要贯彻在整个产品中。收集因此产生的日志或者崩溃转储(crashdump),并进行调查研究。对于在同一个进程边界内运行不同服务并且无法使用断言的系统,要写下跟踪记录。不管哪种实现,都要能够对错误进行标记,频繁挖掘不同问题的频率。
l          保留历史记录。历史性能和日志数据对于趋势的总结和问题的诊断都是非常必要的。
7.7               可配置的日志功能。

可配置的日志功能。对可配置的日志功能提供支持,这些日志记录可以有选择性开启或关闭,以便进行错误调试。在故障过程中,如果不得不部署带额外监控功能的新构建版本是非常危险的。
7.8               外部化健康信息,用于监控

外部化健康信息,用于监控。考虑能实现外部监控服务健康程度的方式,并使对生产环境进行监控容易实现。
7.9               保证所有报告的错误可以应对

保证所有报告的错误可以应对。问题总会发生,系统也总会出错。如果在代码中检测到无法恢复的错误,并且在日志或者报告中归为错误,那么错误信息应当指出错误可能发生的原因,并提供修复的建议。无法采取应对措施的错误报告毫无用处,而且时间一久这些错误报告会像“狼来了”一样被人们忽略,那时候真正的错误就可能被错过。
7.10           启用生产环境问题的快速诊断。

启用生产环境问题的快速诊断。
为诊断提供足够信息。当问题被标出时,要提供足够的信息,人们才可以对其进行诊断;否则门槛会非常高,标注也会被忽略。例如,不要只说“10个查询都没返回结果”,还得补上“列表在这里,还有问题出现的次数”。
证据链。保证存在一条贯穿始终的路径,可供开发人员诊断之用。通常这都是由日志实现的。
在生产环境中的调试。我们偏爱这样的一种模式:系统没有被包括运营团队在内的任何人触碰过,并且调试是通过镜像快照、内存转储并将所得数据发送到生产环境之外来实现的。当生产环境成为唯一选择是,开发人员就是最好的选择。要确保开发人员得到良好的培训,知晓生产环境的操作限制。我们的经验是,系统在生产环境中动的次数越少,客户通常也越开心。因此我们推荐,一定要多努一把力,尽量避免接触生产环境中的系统。
◇ 记录所有重要的操作。每次系统执行了重要的操作,特别是对网络请求和数据修改上,要进行记录。这既包括用户发送命令的事件,也包括系统内部的行为。有了这样的记录,调试问题的时候就会获益无穷。更重要的是,还可以开发出相应的挖掘工具,用来找出有用的集合,比如用户的查询都是什么样的(也就是说,用了哪些关键字,有多少关键字等等)。
8               优雅降级和许可控制

当发生DoS攻击或者由于用户使用模式变化而带来的负载激增时,服务器需要能实现优雅降级和管理控制。例如,911恐怖袭击发生后,大多数的新闻服务都发生瘫痪,无法向所有用户群体提供任何可用的服务。与此相比,如果能够将一部分文章可靠地提供给用户,总比什么都不能提供好。最佳实践有两种:“大红开关(big red switch)”和许可控制,如果能够针对服务进行量身定制,作用将会十分强大。
8.1               支持“大红开关”。

支持“大红开关”。这个概念最初来源于Windows Live Search,它拥有很大的权力。我们对这个概念进行了一定程度的推广,更事务性的服务与搜索差别迥异。不过这个想法非常有效,而且可以应用于任何地方。一般来说,“大红开关”是当服务已经或者即将无法满足SLA时,采用的一个经过精心设计和测试的措施。将优雅降级比喻成“大红开关”稍微有些不恰当,但核心意思是指在紧急时刻卸掉非关键的负载。“大红开关”的主要思想是保证关键任务的运行,同时卸掉或者延迟非关键的负载。从设计角度来说,这种情况应该不会发生,但在发生紧急情况时不失为一个好的救火办法。在紧急情况已经发生之后再来考虑这些问题是十分危险的。如果有哪个负载可以被加入队列并延后处理,或者在关掉高级查询后仍能继续运行事务系统,那么这都是作为“大红开关”的理想对象。关键在于,判断在整个系统出现问题时有哪些任务是必不可少的,然后实现并测试在问题出现时关闭非关键服务的选项。切记“大红开关”必须是可逆的,也就是说当紧急情况解除后,必须保证开关能正确地让所有的批处理工作和先前被停止的非关键任务恢复原状,这是应当经过测试的。
8.2               控制许可

控制许可。许可控制是另外一个重要的概念。如果都无法对当前的任务进行处理,向系统引入更多的工作负载只会将不好的体验扩散到更大的用户群中。这要如何实现和系统有关,有些系统实现很容易,有些则比较困难。拿我们上次的邮件处理服务作为例子,如果系统超过负荷,开始排队列的话,我们最好是拒绝接受后续邮件进入系统,然后让这些邮件在来源处列队等候。这样做很有意义并实际上减少了整体服务延迟,主要原因在于一旦队列在我方形成,系统会处理得更慢。如果我们拒绝形成队列,吞吐量也会得以提升。另外一个诀窍是:重要客户优先于非重要用户,注册用户优先于访客(但如果是以吸引新访客作为商业模式的,另当别论)。
8.3               对许可进行计量

对许可进行计量。还有一个无比重要的概念,就是前面所说的许可控制观点的修改方案。如果系统故障并当机,必须能够实现逐步恢复用户使用,并确保系统运行正常。比如先允许1 个用户进入,然后允许每秒进入10 个用户,随后再逐渐放宽限制。对于重新上线或者从严重错误中恢复过来的系统,应该确保每项服务都有一个细粒度的开关,来实现用户的缓慢增加,这是至关紧要的。大多数系统的初始版本中很少有包括这项功能。
对于有客户端的系统,一定会存在一种方式,用来通知客户端服务器当机,并且告知可能的恢复时间。这样一方面使客户端尽可能继续基于本地数据来运行,另一方面也可以避免客户端打扰服务器,以便后者更快恢复。这样同时也给了服务拥有者一个直接和用户沟通的机会( 见下节),用来调整用户的期望值。另外一个关于客户端的技巧是刻意设置扰动(jitter),和自动备份来防止客户端在同一时刻“扑向”脆弱的服务器。客户和媒体沟通计划当系统出错时需要就发生的延误和其它相关事项与客户进行沟通。沟通应当能以可选的方式通过多个渠道完成 :RSS、Web,还有即时消息等等。另外,对于拥有客户端的系统,通过客户端来进行和用户的沟通也是很有效的。可以告诉客户端在一定时间内或者特定时间点之前避免访问服务器,或者如果支持的话,可以告诉客户端在离线和缓存的方式运行。客户端可以把系统状态告诉用户,并说明可以预计完整的功能在何时恢复。即使在没有客户端的情况下,比如用户通过网页来和系统交互,仍然可以告知用户系统当前的状态。当用户了解发生的状况并对系统的恢复时间有一个合理的期望值,他们的满意度会大大提高。系统管理员常常会不自觉地倾向于隐藏系统发生的问题,但是跟据我们的经验,我们确信,将系统的状态告知用户会极大地提高其满意度。即便是非付费系统,如果人们知道系统发生了状况并被告知其何时会恢复,他们放弃使用这项服务的可能性也会减小。某些事件会引发媒体报导。如果这样的场景有预先备好的应对方案,那么会更加真实地反应服务的情况。大量数据丢失或损坏、安全遭到破坏、违反隐私以及服务器长时间当机,这样的情况都可能引起媒体的关注。事先准备好一份沟通计划。清楚电话通知谁,并能主导谈话。沟通方案的框架应当事先搭好。应针对每一种事故制定一份沟通方案,内容包括该给谁电话通知、电话时间,还有如何掌控沟通过程。客户自预置及自助服务客户自己进行预置可以大幅度降低成本,同时还能提升客户满意度。如果客户可以访问网站,输入所需数据,然后就可以开始使用服务,那么他们要比不得不在电话处理队列中浪费时间开心得多。我们一直认为,主流移动运营商因为没为那些不想致电客户支持组的用户提供自助服务,错过了一次拯救并提升客户满意度的好机会。
9               结语

要降低大规模互联网服务的运营成本并改善服务的可靠性,一切从编写服务时注重运营友好开始。在这篇论文中,我们为“运营友好”做了诠释,并根

Aug20

【转载】Linux服务器群集技术总结

Author: Mr_JBean  Click: 8024   Comments: 0 Category: 架构  Tag: linux,cluster

1. 引言
在制作电影《泰坦尼克号》所用的160台Alpha图形工作站中,有105台运行的是Linux操作系统,这160台Alpha工作站是做图形处理。图形处理中有一项重要的任务—计算。这些计算机是被利用群集技术(Cluster)组织到一起的。这就是cluster中的一种—“并行计算”。

2. Cluster概况
Cluster只是一个笼统的概念,刚才提到的“并行计算”只是cluster的一个方面,这方面的主要应用就是用低成本的“低档”电脑去做super computer的工作。

Cluster分为下面几方面

l 高可用性,High-Availability (HA)

l 负载平衡,Load Balance

l 科学计算,即并行计算,Scientific Computing

1. HA:用在不允许中断服务的场合。实际上是两台(或更多台)计算机通过一定方式互相监听,实现热备份。当其中的主服务器(primary server)出现问题时,备份服务器(standby backup server or secondary server)能够自动立即接替工作,使用户感觉不出停机。在primary server恢复正常之后,backup server又会把工作还给primary server。

2. Load Balance:在web server上的应用比较多(尽管它支持很多别的协议如ftp, telnet, sendmail等,但用处最多的还是http服务)。用户访问一个地址,但实际上后台是有若干台服务器在提供服务。而当服务请求达到饱和时,还可以很容易地再添加新的节点而不用停掉整个cluster,实现所谓的“热插拔”,这也就是Cluster中的一个概念—Scalability (易扩展性)。而且,cluster还会查询真实节点的情况,当某台真实节点没有响应时,就不再把任务分配到那里,直到这台节点恢复正常。

3. Scientific,主要用于计算量大的场合。比如刚才提到的图象处理,或一些海量计算的科学实验,以及国防应用。

那么什么是cluster呢?

1.Clustering是用两个(或更多)的系统(节点)在一起工作,来提供相同服务或实现相同目的;

2.在外面看来,整个体系结构象一个完整的系统;

3.Clustering用来提高服务的稳定性和/或核心网络服务的性能。

2.1 HA (heartbeat)
在HA方面,heartbeat(心跳)是代表技术。Heartbeat的工作方式属于Server Monitor(服务器监控)方式,即备份服务器和主服务器互相监听的一种技术。这种方式的特点是

l 提供了可用性(availability),但没有提供可扩展性(Scalability)。

l 只限两台节点

l 两台节点执行相同的服务,但只有主节点与外界通讯

l 当主节点出问题时,备份节点马上接替工作  
 
Server Mirror解决方案的例子有:

Novel SFT III

Vinca Standby Server

Compaq Standby Server

下图为Compaq Standby Server的应用示例:

还有另外两种方式—Application Failover,Fault Tolerant

l 应用程序故障接管技术(Application Failover)

采用这种方式的例子有:

Microsoft Cluster Server

Digital Clusters

Sun Clusters

下图为Microsoft Cluster Server的一种配置示例:

下图为Digital Clusters的一种配置示例

l 容错技术(Fault Tolerant)

这种技术的优点也很多,特别是可以作到不间断客户端的连接就可以接替服务,但价格较贵,一般都在$1,000,000以上。

代表产品有:

Tandem (Compaq) NonStop Cluster

前几届的师兄们所做的广东省自然科学基金项目:基于Unix容错技术的研究,就属于这方面的范畴。

2.2 Load Balance(LVS, TurboCluster)
负载均衡的群集技术主要应用于Web服务器群中,解决Web服务器在高访问量时的负载分流问题。

下面是一种成熟的商业Load Balance方案,主要采用了DNS的域名轮换指向技术,即在DNS服务器上使来在用户浏览器的请求平均分配给不同的Web服务器。 


这种属于单一的可扩展群集技术(Scalability-only Clustering),Web服务器群仅仅具有可扩展性,应付突发的高访问量。

例子有:

Round Robin DNS

F5 BigIP/LB

Other older HW solutions

新的解决方案是高可用性可扩展技术/高可用性负载均衡技术(HAScalability/HA Load Balancing Clusters),加入了故障处理机制。

它同时提供可扩展性和高可靠性,一般用来提供核心网络服务:Web, mail, news, 等等。大的ISP和企业会用到,起价$25,000到$50,000之间,随着价格下降,更多用户会对此产生兴趣。采用这种方案的有:

Resonate Central Dispatch

F5 BigIP

Cisco LocalDirector

TurboCluster Server

Linux Virtual Server(Piranha, UltraMonkey等)

而这些方案中,最具价格优势的是TurboCluster 和Linux Virtual Server(LVS)。TurboCluster软件目前约20,000人民币,而LVS则加入了GPL公约,是免费的。

2.3 Scientific (Beowulf, MOSIX, PVM, MPI)
和刚才说的两种cluster的目的不同,这种cluster的主要目的是为了提高计算机处理任务的速度。应用程序需要被写成一种分布式应用程序,在运行时被分成分布式处理的进程,同时运行在多个节点上。例子:

Beowulf Cluster

Supercomputer Architectures

MPI(Message Passing Interface)

MOSIX

PVM(Parallel Virtual Mation)

2.4小节
从上面可以看出,Cluster并不是什么新的思想,Cluster思想已经发展多年,比较成熟。但原来都需要专业的软/硬件设备才能实现。所以只有少数公司才有能力用的起。但随的linux的流行,出现了许多基于linux,基于PC的cluster解决方案,使更多的人有机会构建自己的cluster。而且这些基于linux的软件大多都是遵循GPL协议的,是Open Source的。从而更推动了cluster技术的发展。

3. Heartbeat
3.1设计思想
Heartbeat顾名思义,就是心跳。两台计算机通过某种途径向对方发送“heartbeat”,同时也在监听对方的“heartbeat”。从而知道对方的状态。这种途径可以是串口线,也可以是网卡。可以同时使用。但如果只用一块网卡,则会发生单故障点SPOF[Single Point of Failure: a part which renders an entire system unusable when if fails (SPOF)]

Heartbeat除了在互相发送消息外,另外一项重要的工作就是接替和释放资源。比如:

假设系统主服务器为192.168.2.49,副服务器为192.168.2.47。平时主服务器虚拟192.168.2.48这个IP,当主服务器出问题时(比如关机),192.168.2.47自动虚拟192.168.2.48这个IP。

3.2 安装
Heartbeat属于应用程序级别的程序,所以不需要修改内核。只要取得其源代码。在任意目录下释放(/tmp),然后编译安装即可

tar xzvf heartbeat-0.4.6.tar.gz

cd heartbeat-0.4.6

make

make install

3.3 配置
Heartbeat的安装很容易,关键步骤是配置,第一个需要配置的文件为/etc/ha.d/ha.cf,具体配置选项在里面都有注释,下面是一个例子:

logfacility local0

keepalive 1

deadtime 3

serial /dev/ttyS0

nice_failback off

node tst_sd5_svr9

node tst_sd5_svr7

这里表示主节点为tst_sd5_svr9(192.168.2.49), 副节点为tst_sd5_svr7(192.168.2.47)

第二个需要配置的文件为/etc/ha.d/haresources,具体配置选项在里面都有注释,下面是一个例子:

tst_sd5_svr9 IPaddr::192.168.2.48/24 httpd

这个告诉系统主节点是tst_sd5_svr9,当heartbeat启动时,虚拟192.168.2.48这个IP。并且启动/etc/rc.d/init.d/httpd start这个命令。

第三个需要配置的文件是/etc/ha.d/authkeys,下面是一个例子:

auth 2

2 sha1 ultramonkey

注意,这个文件的属性一定要是600,所以要用chmod 600 authkeys设一下。然后就可以用/etc/rc.d/init.d/heartbeat start启动heartbeat服务了。还可以设为系统启动时自动启动:

cd /etc/rc.d/rc0.d ; ln -s ../init.d/heartbeat K01heartbeat

cd /etc/rc.d/rc3.d ; ln -s ../init.d/heartbeat S99heartbeat

cd /etc/rc.d/rc5.d ; ln -s ../init.d/heartbeat S99heartbeat

cd /etc/rc.d/rc6.d ; ln -s ../init.d/heartbeat K01heartbeat

至此,heartbeat就可以工作了,log文件在/var/log/ha-log中。

3.4 特点
前面基本已经说过,heartbeat能提供HA,但不能提供扩展性。也就是说cluster的性能就是一台server的性能。所以heartbeat一般都是和load balance结合起来使用。下面的load balance就是结合heartbeat的例子,因为单纯的load balance如果没有HA,则当负责分配任务的router(switcher)出问题时,整个cluster都会不工作。

4. Load-Balance
4.1设计思想
Load balance是通过router(switcher)把任务分派到真实节点上来提高整个cluster的性能,整个cluster的性能是由真实节点的性能和真实节点的数量决定的。所以,同一个cluster中的各个真实节点的内容都是一样的。是完全相同的镜象。当整个cluster的能力不够是,可以增加真实节点来提高性能。而增加真实节点只是在网络里增加几台计算机,所以不用关掉其他机器,只需在router上的真实节点表里增加几条记录就可以了。

4.2和传统方式的比较
有用其他方式实现类似功能的解决方案,比如前面提到的修改DNS,让一个域名对应多个IP,这样也可以把任务分派到多台机器上去。或者在路由器上把任务分给多台机器。第一做法是完全随机的,第二种做法是固定的,两者都不会根剧当时情况调整分配到真实节点上的任务量。而LVS提供了4中分配方法(Load-balancing Methods)和3种转发机制(Traffic Forward Mechanism)。具体情况在后面介绍

4.3 LVS
l 设计思想及特点

LVS提供了4种负载平衡的分配方法(Load-balancing Methods)和3种转发机制(Traffic Forward Mechanism)。

负载平衡方法: 名称
 简介
 
Round robin
 在实际服务器间平均分配负载
 
Leastconnections
 最少活动连接数的服务器分配较多的负载 (The IPVS table stores active connections.)
 
Weighted round robin
 根据动态负载权重和服务器的处理能力,在实际服务器中平均分配负载
 
Weighted leastconnections
 根据服务器的权重,为最少连接数的服务器分配负载。
 


LVS提供了3种转发机制(Traffic Forward Mechanism)

分别为VS-NAT,VS-TUN 和VS-DR   VS-NAT
 VS-TUN
 VS-DR
 
Server
 any
 tunneling
 non-arp device
 
server network
 private
 LAN/WAN
 LAN
 
server number
 low (10~20)
 high
 High
 
server gateway
 load balancer
 own router
 own router
 


3种转发机制中。常用的是VS-NAT。这种方式只需要几个公有IP,真实节点都在内部使用私有IP。而且真实节点可以是任何系统(包括NT),缺点是router(switcher)是整个系统的瓶颈,因为所有的数据都会通过router。一般真实节点数为20台左右。但这个问题可以解决,一种方法是混合途径,即设多个cluster组,然后通过DNS指向这几个router。另一种方法就是用VS-TUN或VS-DR

l 安装

所谓安装只需要在router上进行,真实节点不需要安装,特别是VS-NAT方式。这是节点唯一需要做的就是把设定一下缺省网关。安装LVS需要重新编译linux内核。在安装LVS时,需要下载相应版本的内核补丁。比如我们实验用的内核为2.2.14,相应补丁为ipvs-0.9.12-2.2.14.tar.gz

假设内核在/usr/src/linux中。ipvs-0.9.12-2.2.14.tar.gz被释放在/root/ipvs-0.9.12-2.2.14中。

1.先给内核做patch

cd /usr/src/linux

cat /root/ipvs-0.9.12-2.2.14/ipvs-0.9.12-2.2.14.patch | patch -p1

2.然后配置内核选项

make xconfig

Kernel Compile Options:

Code maturity level options ---

[*] Prompt for development and/or incomplete code/drivers

Networking options ---

[*] Network firewalls

....

[*] IP: firewalling

....

[*] IP: masquerading

....

[*] IP: masquerading virtual server support

(12) IP masquerading table size (the Nth power of 2)

IPVS: round-robin scheduling

IPVS: weighted round-robin scheduling

IPVS: least-connection scheduling

IPVS: weighted least-connection scheduling

....

[*] IP: aliasing support

其他选项根据需要选如网卡驱动程序

3.编译内核并用新内核启动

4.编译ipvsadm管理程序

cd /root/ipvs-0.9.12-2.2.14/ipvsadm

make install

重新启动系统就可以用ipvsadm来配置和管理cluster了

l 设置

具体设置方法在讲Piranha(水虎鱼)与Ultra Monkey文挡里有讲述。LVS的安装相对来说比较麻烦,但如果选用Piranha(这是RedHat公司基于LVS开发的产品,遵守GPL的),则只要正常安装RH6.1或RH6.2就免去了安装过程,而Ultra Monkey则提供了编译好的内核,而且是以rpm格式提供的,安装也非常简单。

5. MOSIX
5.1 Beowulf
一谈到并行计算,研究cluster的人第一个提到的就是Beowulf。Beowulf是目前最有名的基于廉价PC并行计算的cluster。但是Beowulf对硬件有特殊的要求。它需要千兆级速度的网卡,我们现在自己使用的网卡都是10M速度的。如果要研究Beowulf,需要在硬件上额外投资,这些时我们暂时所不能负担的,所以没有采用Beowulf方案

5.2 MOSIX是什么
MOSIX (The Multicomputer OS for UNIX)在底层实现了进程在处理器之间的迁移,对于用户和程序来说这种迁移的过程是透明的,用户不需要加以干涉(当然也能够干涉)。所有迁移过程都是根据一定的算法自动进行的,可以充分利用CPU和内存资源。尽管MOSIX在文挡重称自己进行负载均衡(load balance)运算,但它不同与其它的load balance(LVS,TurboCluster等),它不能处理象web server或ftp server这样的I/O紧张的程序,MOSIX做的还是超级计算(super computering)方面的工作。它可以同时使很多人在服务器上运行程序,作为一个多用户的分时环境(Multi-user, time sharing environment),也可以做科学计算(需要用并行通信机制PVM/MPI把程序预先编成可以并行计算的)

关于MOSIX更详细的介绍。在MOSIX网站上有一篇Slide Show “MOSIX Scalable Cluster Computing for Linux” 介绍得很详细。

MOSIX提供了内核级的接口,相对于内核级接口的是用户级接口。下面是用户级接口的图示:

下面是内核级接口的图示  
 
 

比较起来,内核级的优点是对用户来将是透明的。用户不必和各个节点打交道。在用户看来,所有的节点就象一台机器。在MOSIX上运行的进程被分为两部分:

而上面的部分可以在cluster节点中移动,根据当时节点的负载情况。所以,MOSIX可以更有效的使用各节点的CPU资源和内存资源。

5.3 MOSIX与PVM的关系
PVM是Parallel Virtual Machine的缩写。PVM实际上提供了一组API。用这种API,用户可以开发并行应用程序。并行应用程序在运行时会并发的产生多个进程同时执行。这些进程同时在多台机器上运行以缩短整个程序所需的运行时间。

PVM在不需要MOSIX的情况下可以正常执行。但在基于MOSIX的平台上运行PVM。会提高性能。PVM是用来写并行程序并运行,MOSIX是负责各个节点的资源调度。这就是PVM与MOSIX之间的关系

5.4安装MOSIX
MOSIX需要重新编译内核,使内核支持上面提到的进程迁移机制。所以,需要linux内核源代码以及MOSIX补丁。MOSIX提供了安装脚本,根据此安装脚本,用户可以很容易的完成安装过程(当然,在配置内核选项时,用户需要有基本的配置内核的知识)。

一、安装

1. 首先在/tmp下解开MOSIX软件包。

2. 运行安装脚本

cd /tmp

./mosix.install

这个安装脚本将指导下面的安装过程。

3.在配置内核时,有4项要选

CONFIG_MOSIX (YES)

CONFIG_BINFMT_ELF (YES)

CONFIG_PROC_FS (YES)

CONFIG_KMOD (YES)

4.整个安装过程结束,重起系统,就可以配置系统了,MOSIX的自动安装过程中完成了配置过程,它在安装过程中修改了以下文件:

/etc/inittab

/etc/inetd.conf

/etc/lilo.conf

/etc/rc.d/init.d/atd

/etc/cron.daily/slocate.cron

二.节点配置

节点配置是通过修改/etc/mosix.map这个文件来实现的。示例配置文件如下(不跨网段):

# MOSIX CONFIGURATION

# ===================

#

# Each line should contain 3 fields, mapping IP addresses to MOSIX node-numbers:

# 1) first MOSIX node-number in range.

# 2) IP address of the above node (or node-name from /etc/hosts).

# 3) number of nodes in this range.

#

# MOSIX-# IP number-of-nodes

# ============================

1 192.168.2.42 1

2 192.168.2.47 1

3 192.168.2.49 1

#或空格开头的是注释。每行配置有3个栏位

1. MOSIX节点号

2. IP地址(必须在/etc/hosts里指定IP-hostname的对应关系)

3. 节点数目

刚才是IP都不连续的的情况,所以节点数目都是1,假如我们有192.168.2.100-192.168.2.200这100台节点,则可以写成

1 192.168.2.100 100

更复杂的配置方法可以参照man mosix。与mosix.map相关的文件有/etc/hosts、/etc/mospe和/etc/mosgates (后两个文件都是在跨网段时会用到,我们目前的配置中不需要)

关于MOSIX的管理,MOSIX基本上不需要人为干涉,但如果用户希望干涉进程的运行状况,MOSIX提供了一套管理程序。MOSIX的管理主要是通过对/proc/mosix/下的文件进行操作来完成的。

5.5安装PVM
PVM的安装不需要修改内核,它只需要普通用户的权限就可以安装。比如用户cluster在3台机器上都有用户,则可以利用这三台机器的资源进行并行计算。安装工作需要在用户的主目录$HOME下进行。经过解包,生成$HOME/pvm3目录;设置一些环境变量;编译,安装就完成了。在PVM设置好以后,就可以用pvm命令进入pvm虚拟机环境。在上面可以运行并行应用程序。也可以不进入虚拟机环境,直接在命令行上提交任务。这些只是PVM的运行环境,PVM的另一部分是其提供的开发环境。在pvm里有c和fortran语言的接口,用户使用这些接口(Interface)用c语言或fortran语言就可以写出并行应用程序然后在pvm运行环境上运行。在其主页上还看到其他的一些语言接口,比如

java,perl,c++

PVM有NT版和UNIX版,由于PVM有虚拟机的概念,所以协同工作的节点可以是NT,linux和其他系统的混合构架,之间只要通过tcp/ip协议连接就可以。(但MOSIX没有NT版的)

6. 结论
以上对服务器群集技术(Server Cluster)做出了简单的介绍。现在正在进行的cluster的项目很多(有遵守GPL公约的,也有商业化的),这些只是cluster中的一小部分。不过这些Cluster方式基本上都是我们目前实际具有的软硬件情况所能够实现的技术。这些技术即具有各自的应用价值,分别适用于Cluster的三个方面,又有各自的不足之处。从这些技术的思路出发,借助自由软件的免费及技术公开的优势,开发出自己的Cluster系统是完全可行的。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/Mr_JBean/archive/2008/10/08/3033128.aspx

Jul9

深入了解Web站点数据库的分布式存储【转】

Author: leeon  Click: 6507   Comments: 0 Category: 架构  Tag: 数据库

在Web 2.0时代,网站将会经常面临着快速增加的访问量,但是我们的应用如何满足用户的访问需求,而且基本上我们看到的情况都是性能瓶颈都是在数据库上,这个不怪数据库,毕竟要满足很大访问量确实对于任何一款数据库都是很大的压力,不论是商业数据库Oracle、MS sql Server、DB2之类,还是开源的MySQL、PostgreSQL,都是很大的挑战,解决的方法很简单,就是把数据分散在不同的数据库上(可以是硬 件上的,也可以是逻辑上的),本文就是主要讨论如何数据库分散存储的的问题。

目前主要分布存储的方式都是按照一定的方式进行切分,主要是垂直切分(纵向)和水平切分(横向)两种方式,当然,也有两种结合的方式,达到更贴切的切分粒度。

1. 垂直切分(纵向)数据是数据库切分按照网站业务、产品进行切分,比如用户数据、博客文章数据、照片数据、标签数据、群组数据等等每个业务一个独立的数据库或者数据库服务器。

2. 水平切分(横向)数据是把所有数据当作一个大产品,但是把所有的平面数据按照某些Key(比如用户名)分散在不同数据库或者数据库服务器上,分散对数据访问的压力,这种方式也是本文主要要探讨的。

本文主要针对的的 MySQL/PostgreSQL 类的开源数据库,同时平台是在 linux/FreeBSD,使用 php/Perl/Ruby/Python 等脚本语言,搭配 Apache/Lighttpd 等Web服务器 的平台下面的Web应用,不讨论静态文件的存储,比如视频、图片、CSS、JS,那是另外一个话题。

说明:下面将会反复提到的一个名次“节点”(Node),指的是一个数据库节点,可能是物理的一台数据库服务器,也可能是一个数据库,一般情况是指一台数据库服务器,并且是具有 Master/Slave 结构的数据库服务器,我们查看一下图片,了解这样节点的架构:

一、基于散列的分布方式

1. 散列方式介绍

基于散列(Hash)的分布存储方式,主要是依赖主要Key和散列算法,比如以用户为主的应用主要的角色就是用户,那么做Key的就可以是用户ID或者是用 户名、邮件地址之类(该值必须在站点中随处传递),使用这个唯一值作为Key,通过对这个Key进行散列算法,把不同的用户数据分散在不同的数据库节点 (Node)上。

我们通过简单的实例来描述这个问题:比如有一个应用,Key是用户ID,拥有10个数据库节点,最简单的散列算法是我们 用户ID数模以我们所有节点数,余数就是对应的节点机器,算法:所在节点 = 用户ID % 总节点数,那么,用户ID为125的用户所在节点:125 % 10 = 5,那么应该在名字为5的节点上。同样的,可以构造更为强大合理的Hash算法来更均匀的分配用户到不同的节点上。

2. 散列分布存储方式的扩容

我们知道既然定义了一个散列算法,那么这些Key就会按部就班的分散到指定节点上,但是如果目前的所有节点不够满足要求怎么办?这就存在一个扩容的问题,扩容首当其冲的就是要修改散列算法,同时数据也要根据散列算法进修迁移或者修改。

(1) 迁移方式扩容:修 改散列算法以后,比如之前是10个节点,现在增加到20个节点,那么Hash算法就是[模20],相应的存在一个以前的节点被分配的数据会比较多,但是新 加入的节点数据少的不平衡的状态,那么可以考虑使用把以前数据中的数据按照Key使用新的Hash算法进行运算出新节点,把数据迁移到新节点,缺点但是这 个成本相应比较大,不稳定性增加;好处是数据比较均匀,并且能够充分利用新旧节点。

(2) 充分利用新节点:增 加新节点以后,Hash算法把新加入的数据全部Hash到新节点上,不再往旧节点上分配数据,这样不存在迁移数据的成本。优点是只需要修改Hash算法, 无须迁移数据就能够简单的增加节点,但是在查询数据的时候,必须使用考虑到旧Key使用旧Hash算法,新增加的Key使用新的Hash算法,不然无法查 找到数据所在节点。缺点很明显,一个是Hash算法复杂度增加,如果频繁的增加新节点,算法将非常复杂,无法维护,另外一个方面是旧节点无法充分利用资源 了,因为旧节点只是单纯的保留旧Key数据,当然了,这个也有合适的解决方案。

总结来说,散列方式分布数据,要新增节点比较困难和繁琐,但是也有很多适合的场合,特别适合能够预计到未来数据量大小的应用,但是普遍 Web2.0 网站都无法预计到数据量。

二、基于全局节点分配方式

1. 全局节点分配方式介绍

就是把所有Key信息与数据库节点之间的映射关系记录下来,保存到全局表中,当需要访问某个节点的时候,首先去全局表中查找,找到以后再定位到相应节点。全局表的存储方式一般两种:

(1) 采用节点数据库本身(MySQL/PostgreSQL)存储节点信息,能够远程访问,为了保证性能,同时配合使用 Heap(MEMORY) 内存表,或者是使用 Memcached 缓存方式来缓存,加速节点查找

(2) 采用 BDB(BerkeleyDB)、DBM/GDBM/NDBM 这类本地文件数据库,基于 key=>value 哈希数据库,查找性能比较高,同时结合 APC、Memcached 之类的缓存加速。

第 一种存储方式是容易查询(包括远程查询),缺点是性能不太好(这个是所有关系型数据库的通病);第二种方式的有点是本地查询速度很快(特别是hash型数 据库,时间复杂度是O(1),比较快),缺点是无法远程使用,并且无法在多台机器中间同步共享数据,存在数据一致的情况。

我们来描述实施 大概结构:假如我们有10个数据库节点,一个全局数据库用于存储Key到节点的映射信息,假设全局数据库有一个表叫做 AllNode ,包含两个字段,Key 和 NodeID,假设我们继续按照上面的案例,用户ID是Key,并且有一个用户ID为125的用户,它对应的节点,我们查询表获得:

Key NodeID
13 2
148 5
22 9
125 6

可以确认这个用户ID为125的用户,所在的节点是6,那么就可以迅速定位到该节点,进行数据的处理。

我们来查看一下分布存储结构图:

2. 全局节点分布方式的扩容

全局节点分配方式同样存在扩容的问题,不过它早就考虑到这个问题,并且这么设计就是为了便于扩容,主要的扩容方式是两种:

(1) 通过节点自然增加来分配Key到节点的映射扩容

这 种是最典型、最简单、最节约机器资源的扩容方式,大致就是按照每个节点分配指定的数据量,比如一个节点存储10万用户数据,第一个节点存储0-10w用户 数据,第二个节点存储10w-20w用户数据,第三个节点存储20w-30w用户信息,依此类推,用户增加到一定数据量就增加节点服务器,同时把Key分 配到新增加的节点上,映射关系记录到全局表中,这样可以无限的增加节点。存在的问题是,如果早期的节点用户访问频率比较低,而后期增加的节点用户访问频率 比较高,则存在节点服务器负载不均衡的现象,这个也是可以想方案解决的。

(2) 通过概率算法来映射Key到节点的的扩容

这种方式是在既然有的节点基础上,给每个节点设定一个被分配到Key的概率,然后分配Key的时候,按照每个节点被指定的概率进行分配,如果每个节点平均的数据容量超过了指定的百分比,比如50%,那么这时候就考虑增加新节点,那么新节点增加Key的概率要大于旧节点。

一般情况下,对于节点的被分配的概率也是记录在数据库中的,比如我们把所有的概率为100,共有10个节点,那么设定每个节点被分配的数据的概率为10,我们查看数据表结构:

NodeID Weight
1 10
2 10
3 10

现在新加入了一个 节点,新加入的节点,被分配Key的几率要大于旧节点,那么就必须对这个新加入的节点进行概率计算,计算公式:10х+у=100, у>х,得出:у{10...90},х{1...9},x是单个旧节点的概率,旧节点的每个节点的概率是一样的,y是新节点的概率,按照这个计算 公式,推算出新节点y的概率的范围,具体按照具体不同应用的概率公式进行计算。

三、存在的问题

现在我们来分析和解决一下我们上面两种分布存储方式的存在的问题,便于在实际考虑架构的时候能够避免或者是融合一些问题和缺点。

1. 散列和全局分配方式都存在问题

(1) 散列方式扩容不是很方便,必须修改散列算法,同时可能还需要对数据进行迁移,它的优点是从Key定位一个节点非常快,O(1)的时间复杂度,而且基本不需要查询数据库,节约响应时间。

(2) 全局分配方式存在的问题最明显的是单点故障,全局数据库down掉将影响所有应用。另外一个问题是查询量大,对每个Key节点的操作都必须经过全局数据库,压力很大,优点是扩容方便,增加节点简单。

2. 分布存储带来的搜索和统计问题

(1) 一般搜索或统计都是对所有数据进行处理,但因为拆分以后,数据分散在不同节点机器上,无法进行全局查找和统计。解决方案一是对主要的基础数据存储在全局表中,便于查找和统计,但这类数据不宜太多,部分核心数据。

(2) 采用站内搜索引擎来索引和记录全部数据,比如采用 Lucene 等开源索引系统进行所有数据的索引,便于搜索。 对于统计操作可以采用后台非实时统计,可采用遍历所有节点的方式,但效率低下。

3. 性能优化问题

(1) 散列算法,节点概率和分配等为了提高性能都可以使用编译语言开发,做成lib或者是所有php扩展形式。

(2) 对于采用 MySQL 的情况,可以采用自定义的数据库连接池,采用 Apache Module 形式加载,能够自由定制的采用各种连接方式。

(3) 对于全局数据或都频繁访问的数据,可以采用APC、Memcache、DBM、BDB、共享内存、文件系统等各种方式进行缓存,减少数据库的访问压力。

(4) 采用数据本身的强大处理机制,比如 MySQL5 的表分区或者是 MySQL5 的Cluster 。另外建议在实际架构中采用InnoDB表引擎作为主要存储引擎,MyISAM作为一些日志、统计数据等场合,不论在安全、可靠性、速度都有保障

Jul6

Nginx的upstream的四种设置方式

Author: leeon  Click: 7350   Comments: 0 Category: 架构  Tag: nginx

Nginx的upstream的四种设置方式

1、轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器 ,如果后端服务器down掉,能自动剔除。

2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。 
例如:
[code="plain"]
upstream bakend {
server 192.168.0.14 weight=10;
server 192.168.0.15 weight=10;
}
[/code]

2、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session 的问题。
例如:
[code="plain"]
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
[/code]

3、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
[code="plain"]
upstream backend {
server server1;
server server2;
fair;
}
[/code]

4、url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

例:在upstream中加入hash语句,server语句中不能写入weight等其他的参数,hash_method是使用的hash算法

[code="plain"]
upstream backend {
server squid1:3128;
server squid2:3128;
hash $request_uri;
hash_method crc32;
}
[/code]

Nginx负载均衡设置:

[code="plain"]
upstream bakend{
ip_hash;
#定义负载均衡 设备的Ip及设备状态
server 127.0.0.1:9090 down;
server 127.0.0.1:8080 weight=2;
server 127.0.0.1:6060;
server 127.0.0.1:7070 backup;
}
[/code]
在需要使用负载均衡的server中增加
[code="plain"]
proxy_pass http://bakend/ ;
[/code]

每个设备的状态设置为:
1.down 表示单前的server暂时不参与负载
2.weight 默认为1.weight越大,负载的权重就越大。
3.max_fails :允许请求失败的次数默认为1.当超过最大次数时,返proxy_next_upstream 模块定义的错误
4.fail_timeout:max_fails次失败后,暂停的时间。
5.backup: 其它所有的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻。nginx支持同时设置多组的负载均衡,用来给不用的server来使用。

分类

标签

归档

最新评论

Abyss在00:04:28评论了
Linux中ramdisk,tmpfs,ramfs的介绍与性能测试
shallwe99在10:21:17评论了
【原创】如何在微信小程序开发中正确的使用vant ui组件
默一在09:04:53评论了
Berkeley DB 由浅入深【转自架构师杨建】
Memory在14:09:22评论了
【原创】最佳PHP框架选择(phalcon,yaf,laravel,thinkphp,yii)
leo在17:57:04评论了
shell中使用while循环ssh的注意事项

我看过的书

链接

其他

访问本站种子 本站平均热度:8823 c° 本站链接数:1 个 本站标签数:464 个 本站被评论次数:94 次