Blog5-互联网公司架构

Amazon是全球商品品种最多的网上零售商和全球第2大互联网公司。而之前它仅仅是一个小小的网上书店。它开辟了让顾客来评估,审查和推荐商品的新方式。它的架构在随着规模的扩大逐步完善,下面我们就来分析它的架构。

一. 架构概述

1可伸缩性

可伸缩性到底意味着什么?对于一个服务来说,当我们增加为其分配的系统资源之后,它的性能增长能够与投入的资源按比例提升,我们就说这个服务具有可伸缩性。通常意义上的性能提升,意味着能够提供更多的服务单元,也可以为更大的工作单元提供服务,比如增长的数据集等。

2.可扩展性

Amazon的架构经历了巨大的变化,从一开始时的两层架构,转向了分布式的、去中心化的服务平台,提供许多种不同的应用。

最开始只有一个应用来和后端交互,是用C++来完成的。之后架构随着时间而演进。多年来,Amazon将增容的主要精力放在后端的数据库上,试图让其容纳更多的商品数据,更多的客户数据,更多的订单数据,并让其支持多个国际站点。到2001年,前端应用很明显不能再做任何增容方面的努力了。数据库被分为很多个小部分,围绕每个部分会创建一个服务接口,并且该接口是访问数据的唯一途径。

其中显著的变化是,数据库逐渐演变成共享资源,这样就很难再在全部业务的基础之上进行增容操作了。前端与后端处理的演进受到很大限制,因为他们被太多不同的团队和流程所共享了。

他们的架构是松散耦合的,并且围绕着服务进行构建。面向服务的架构提供给他们的隔离特性,让他们能够快速、独立地完成许多软件组件的开发。

逐渐地,Amazon拥有了数百个服务,并有若干应用服务器,从服务中聚合信息。生成http://Amazon.com站点页面的应用就位于这样的一台应用服务器之上。提供web服务接口、顾客服务应用以及卖家接口的应用也都是类似的情况。

许多第三方的技术难以适用Amazon这种网站的规模,特别是通讯基础架构技术。它们在一定范围内工作的很好,但是如果范围再扩大的话,它们就不适用了。因此,Amazon只好自己开发相应的基础技术。

3.灵活性

Amazon不在一种技术上"吊死"。它在有的地方使用jboss/java,不过只是使用servlets,并没有完全使用j2ee中所涉及到的技术。C++开发的程序被用来处理请求。Perl/Mason开发的程序用来生成页面中的内容。

Amazon不喜欢采用中间件技术,因为它看起来更像一种框架而不是一个工具。如果采用了某种中间件,那么就会被那种中间件所采用的软件模式所困扰,也就只能选用他们的软件。如果想采用不同的软件几乎是不可能的。

使用SOAP 相关的web解决方案来帮助解决所有分布式系统的问题。

Amazon提供SOAP和REST这两种Web 服务。大概有30%的用户采用SOAP这种Web Services。他们看起来似乎是Java和.NET的用户,而且使用WSDL来生成远程对象接口。大概有70%的用户使用REST。他们看起来似乎是PHP和PERL的用户。

无论采用SOAP还是REST,开发人员都可以得到访问Amazon的对象接口。开发人员想要的是把工作完成,而不需要关心网线上传输的是什么东西。

4.面向服务

Amazon想要围绕他们的服务构建一个开放的社区。他们之所以选择Web Services是因为它的简单。事实上它是一个面向服务的体系架构。简单来说,你只有通过接口才能访问到需要的数据,这些接口是用WSDL描述的,不过它们采用自己的封装和传输机制。

架构开发团队都是小规模团队,而且都是围绕不同的服务进行组织。

在Amazon服务是独立的功能交付单元。这也是Amazon如何组织他的内部团队的。如果有一个新的业务建议,或者想解决一个问题,就可以组织一个团队。由于沟通上的成本,每个团队都限制到8~10个人。他们被称为two pizza teams。因为用两个比萨饼,就可以让团队成员每个人都吃饱了。团队都是小规模的。他们被授权可以采取他们所中意的任何方式来解决一个问题或者增强一个服务。例如,他们创建了这样一个团队,其功能是在一本书中查找特有的文字和短语。这个团队为那个功能创建了一个独立的服务接口,而且有权做任何他们认为需要做的事情。

5.部署

Amazon创建了一个特殊的基础设施,来完成对依赖性的管理和对完成服务的部署。目标是让所有正确的服务可以在一个主机中部署。所有的应用代码、监控机制、许可证机制等都应该在一个“主机”中。每个人都有一个自己的系统来解决这些问题。

部署进程的输出是一个虚拟机,可以用EC2来运行他们。为了验证新服务的效果,从客户的角度去看待服务,这样做是值得的。优点有以下几个:

l  从客户的角度去看待服务,聚焦于你想交付给用户的价值。

l  强迫开发人员将关注点放在交付给客户的价值上,而不是先考虑如何构建技术再考虑如何使用技术。

l  从用户将要看到的简要特性开始,再从客户考虑的角度检查你构建的服务是否有价值。

l  以最小化的设计来结束设计过程。如果想要构建一个很大的分布式系统,简单性是关键。

6.状态管理

对于大型可伸缩系统来说状态管理是核心问题。对于内部而言,他们可以提供无限存储空间。结账的步骤是有状态的,但是并不是所有的操作是有状态的。

Amazon通过分析最近点击过的页面的SessionID,为用户提供推荐商品建议。它追踪、保存着所有的数据,所以保持状态不是一个问题。有一些分离的状态需要为一个session来保持。提供的服务们会一直保留信息,所以你只要使用这些服务就可以了。

7.系统的三个属性

Eric Brewers' CAP理论——或称为系统的三个属性:一致性,可用性,网络分区容忍度。对于任何一个共享数据的系统都至少具备这三个属性中的两个。

l  网络分区容忍度:把节点分割成一些小的分组,它们可以看到其他的分组但是无法看到其他全部节点。

l  一致性:写入一个值然后再读出来,你得到的返回值应该和写入的是同一个值。在一个分区系统中有些情况并非如此。

l  可用性:并非总是可读或者可写。系统可能会告诉你无法写入数据因为需要保持数据的一致性。

为了可伸缩性,你必须对系统进行分区,因此针对特定的系统,你要在高一致性或者高可用性之间做出选择。你必须找到可用性和一致性的恰当重叠部分。

基于服务的需要来选择特定的实现方法。比如,对于结账的过程,你总是想让更多的物品放入顾客的购物车,因为这样可以产生收入。在这种情况下你需要选择高可用性。错误对顾客是隐藏的,过后才会被拿出来分析。

   当一个顾客提交订单过来时,我们要将关注点更多的放在保持高一致性上。因为几个不同的服务——信用卡处服务、配送服务、报表功能等——在同时访问那些数据。

二. Dynamo架构

1.简介

   Dynamo是Amazon提供的一款高可用的分布式Key-Value存储系统,其满足可伸缩性、可用性、可靠性,性能也不错:读写访问中99.9%的响应时间都在300ms内。按分布式系统常用的哈希算法切分数据,分放在不同的node上。Read操作时,也是根据key的哈希值寻找对应的node。Dynamo使用了 Consistent Hashing算法,node对应的不再是一个确定的hash值,而是一个hash值范围,key的hash值落在这个范围内,则顺时针沿ring找,碰到的第一个node即为所需。

CAP原理满足:通过一致性哈希满足P,用复制满足A,用对象版本与向量时钟满足C。用牺牲C来满足高可用的A,但是最终会一致。但是,是牺牲C满足A,还是牺牲A满足C,可以根据NWR模型来调配,以达到收益成本平衡。

Dynamo内部有3个层面的概念:

l  Key-Value:Key唯一标识一个数据对象,Value标识数据对象实体,通过对Key来完成对数据对象的读写操作。

l  节点node:节点是指一个物理主机。在每个节点上,会有3个必备组件:请求协调器(request coordination)、成员与失败检测、本地持久引擎(local persistence engine),这些组件都由Java实现。本地持久引擎支持不同的存储引擎,最主要的引擎是Berkeley Database Transactional Data Store(存储数百K的对象更合适),其它还有BDBJava Edtion、MySQL以及一致性内存Cache。本地持久化引擎组件是一个可插拔的持久化组件,应用程序可以根据需要选择最合适的存储引擎,比如:如果存储对象的通常为数千字节则可以选择BDB,如果是更多尺寸则可以选择MySQL。生产中,Dynamo通常使用BDB事物数据存储。

l  实例instance:从应用的角度来看就是一个服务,提供IO功能。每个实例由一组节点组成,这些节点可能位于不同的IDC,这样IDC出现问题也不会导致数据丢失,这样会有更好的容灾和可靠性。

  Dynamo对Consistent Hashing算法的改进在于:它放在环上作为一个node的是一组机器(而不是memcached把一台机器作为node),这一组机器是通过同步机制保证数据一致的。

下图是分布式存储系统的示意图:

2.状态

l  超过5500万活动顾客帐号

l  世界范围内超过100万活动零售合作商

l  构建一个页面所需访问的服务介于100至150个之间

3.主要技术

3.1数据分区

为了达到增量可伸缩性的目地,Dynamo采用一致性哈希来完成数据分区。在一致性哈希中,哈希函数的输出范围为一个圆环,系统中每个节点映射到环中某个位置,而Key也被Hash到环中某个位置,Key从其被映射的位置开始沿顺时针方向找到第一个位置比其大的节点作为其存储节点,换个角度说,就是每个系统节点负责从其映射的位置起到逆时针方向的第一个系统节点间的区域。

一致性哈希最大的优点在于节点的扩容与缩容,只影响其直接的邻居节点,而对其它节点没有影响。这样看似很完美了,但是亚马逊没有因此而停止脚本,这是其伟大之处,其实还存在两个问题:节点数据分布不均匀和无视节点性能的异质性。为了解决这两个问题,Dynamo对一致性哈希进行了改进而引入了虚拟节点,即每个节点从逻辑上切分为多个虚拟节点,每个虚拟节点从逻辑上看像一个真实节点,这样每个节点就被分配到环上多个点而不是一个单点。

3.2数据复制

为了实现高可用,Dynamo将每个数据复制到N台主机上,其中N是每个实例(per-instance)的配置参数,建议值为3。每个Key被分配到一个协调器(coordinator)节点,协调器节点管理其负责范围内的复制数据项,其除了在本地存储其责任范围内的每个Key外,还复制这些Key到环上顺时针方向的N-1个后继节点。这样,系统中每个节点负责环上从其自己位置开始到第N个前驱节点间的一段区域。具体逻辑见图,图中节点B除了在本地存储键K外,还在节点C和D处复制键K,这样节点D将存储落在范围(A, B]、(B, C]和(C, D]上的所有键。

对于一个特定的键都有一个首选节点列表,由于虚拟节点的存在,为了解决节点故障的问题,构建首先节点列表时会跳过环上某些位置,让这些节点分别位于不同的物理节点上,以保证高可用。

3.3版本合并

由前文可知,Dynamo为了保证高可用,对每份数据都复制了多份(建议3份),在数据没有被异步复制到所有副本前,如果有get操作会取到不一致的数据,但是Dynamo提供最终一致性。在亚马逊平台中,购物车就是这种情况的典型应用,为了保证购物车永远可用,对任何一个副本的任何一次更改操作的结果都会当做一个数据版本存储起来,这样当用户get时就会取到多个版本,这样也就需要做数据版本合并了。Dynamo将合并工作推给应用程序,在这里就是购物车get时处理。

Dynamo用向量时钟来标识同一数据在不同节点上多个副本之间的因果关系。向量时钟实际上就是一个列表,列表的每个节点是一个(node, counter)对,即(节点,计数器)列表。数据版本之间的关系要么是因果关系,要么是平行关系,关系判断依赖于计数器值大小,如果第一个时钟对象的计数器小于或等于所有其它时钟对象的计数器时则是因果关系,那么因是果的祖先可以认为是旧版数据而直接忽略,否则是平行关系,那么就认为数据版本产生了冲突,需要协调并合并。

   在Dynamo中,当客户端更新一个对象时,必须指定更新哪个版本数据,更新版本依赖于早期get操作时获得的向量时钟。

 

3.4故障检测

(1)Ring Membership

每个节点启动时存储自己在环上的映射信息并持久化到磁盘上,然后每个节点每隔一秒随机选择一个对等节点,通过Gossip协议传播节点的映射i信息,最终每个节点都知道对等节点所处理范围,即每个节点都可以直接转发一个key的读/写操作到正确的数据集节点,而不需要经过中间路由或者跳。

(2)External Discovery

如果人工分别往Dynamo环中加入节点A和B,则Ring Membership不会立即检测到这一变化,而出现暂时逻辑分裂的Dynamo环(A和B都认为自己在环中,但是互相不知道对方存在)。Dynamo用External Discovery来解决这个问题,即有些Dynamo节点充当种子节点的角色,在非种子节点中配置种子节点的IP,所有非种子节点都与种子节点协调成员关系。

(3)Failure Detection

Dynamo采用类Gossip协议来实现去中心化的故障检测,使系统中的每个节点都可以了解其它节点的加入和likai

3.5故障处理

传统的Quorum,在节点故障或者网络故障情况下,系统不可用。为了提高可用性,Dynamo采用Sloppy Quorum和Hinted Handoff,即所有读写操作由首选列表中的前N个健康节点执行,而发往故障节点的数据做好标记后被发往健康节点,故障节点重新可用时恢复副本。

一个高可用的存储系统具备处理整个IDC故障(断电、自然灾害、网络故障灯)的能力是非常重要的,Dynamo就具备此能力。Dynamo可以配置成跨多个IDC复制对象,即key的首选列表由跨多个IDC的节点组成,这些IDC之间由高速专线连接,跨多个IDC的复制方案使得Dynamo能够处理整个IDC故障。

3.6扩容/缩容

(1)扩容

当一个新节点X加入到系统中时,其得到一些随机分配到环上的token,节点X会负责处理一个key range,而这些key在节点X加入前由现有的一些节点负责,当节点X加入后,这些节点将这些key传递给节点X。以图2为例,假设节点X添加到环中A和B之间的位置,当X加入到系统中后,其负责的key范围为(F, G], (G, A], (A, X],节点B、C和D都各自有一部分不再需要存储的key范围,即在X加入前,B负责(F, G], (G, A], (A, B];C负责(G, A], (A, B], (B, C];D负责(A, B], (B, C], (C, D],而在X加入后,B负责(G, A], (A, X], (X, B];C负责(A, X], (X, B], (B, C];D负责(X, B], (B, C], (C, D]。节点B、C和D在收到节点X加入的确认信号后出发这一过程。

(2)缩容

当从系统中删除一个节点时,key的重新分配情况与步骤(1)正好相反。

3.7读/写操作

读取和写入由请求协调组件执行,每个客户端请求都将导致在处理该请求的节点上创建一个状态机,每个状态机都包含以下逻辑:

l  标识负责一个key的节点;

l  发送请求;

l  等待回应;

l  可能的重试处理;

l  加工和包装返回客户端响应。

4.解决的问题

1、可用性

完全去中心化,无单点,永远可写。

2、伸缩性

带虚拟机节点的一致性hash:一致性hash解决扩容/缩容问题,虚拟节点解决机器异质性问题。

3、可靠性

数据复制多份副本,用向量时钟解决版本合并问题。

 

4、可配置

平衡性可调,即根据(N,W,R)模型平衡可用性和一致性,建议模型参数为(3,2,2)。

四. 云服务

亚马逊的云服务提供了多达几十种服务,涵盖了IaaS、PaaS、SaaS这三层。既然是亚马逊云服务,通常都叫做Amazon Web Service(AWS)。

1.云计算

下面是亚马逊云计算的架构图。

从该架构图可以看出,亚马逊云服务由7部分组成。接下来对这7部分的主要服务做一个简要的介绍。

1.1 AWS Global Infrastructure(AWS 全局基础设施)

在全局基础设施中有3个很重要的概念。

第一个是Region(区域),每个Region是相互独立的,自成一套云服务体系,分布在全球各地。目前全球有10个Region,北京的Region已经在内测当中,不久就会开放使用。

第二个是AvailabilityZone(可用区),每个Region又由数个可用区组成,每个可用区可以看做一个数据中心,相互之间通过光纤连接。

第三个是EdgeLocations(边缘节点)。全球目前有50多个边缘节点,是一个内容分发网络(CDN,Content Distrubtion Network),可以降低内容分发的延迟,保证终端用户获取资源的速度。它是实现全局DNS基础设施(Route53)和CloudFront CDN的基石。

1.2 Networking(网络)

AWS提供的网络服务主要有:

l  Direct Connect:支持企业自身的数据中心直接与AWS的数据中心直连,充分利用企业现有的资源。

l  VPN Connection:通过VPN连接AWS,保证数据的安全性。

l  Virtual Private Cloud:私有云,从AWS云资源中分一块给你使用,进一步提高安全性。

l  Route 53:亚马逊提供的高可用的可伸缩的域名解析系统。

1.3 Compute(计算)

这可是亚马逊的计算核心,包括了众多的服务。

l  EC2: Elastic Computer service,亚马逊的虚拟机,支持Windows和Linux的多个版本,支持API创建和销毁,有多种型号可供选择,按需使用。并且有auto scaling功能,有效解决应用程序性能问题。

l  ELB: Elastic Load Balancing, 亚马逊提供的负载均衡器,可以和EC2无缝配合使用,横跨多个可用区,可以自动检查实例的健康状况,自动剔除有问题的实例,保证应用程序的高可用性。

1.3 Storage(存储)

l  S3: Simple Storage Service,简单存储服务,是亚马逊对外提供的对象存储服务。不限容量,单个对象大小可达5TB,支持静态网站。其高达99.999999999%的可用性让其它竞争对手胆寒。

l  EBS: Elastic Block Storage,块级存储服务,支持普通硬盘和SSD硬盘,加载方便快速,备份非常简单。

l  Glacier:主要用于较少使用的存储存档文件和备份文件,价格便宜量又足,安全性高。

1.4 Database(数据库)

亚马逊提供关系性数据库和nosql数据库,以及一些cache等数据库服务。

l  DynamoDB: DynamoDB是亚马逊自主研发的no sql型数据库,性能高,容错性强,支持分布式,并且与Cloud Watch、EMR等其它云服务高度集成。

l  RDS: Relational Database Service,关系型数据库服务。支持MySql,SQL Server和Oracle等数据库,具有自动备份功能,IO吞吐量可按需调整。

l  Amazon ElastiCache:数据库缓存服务。

1.5 Application Service(应用程序服务)

这里的服务可就多了。

l  Cloud Search: 一个弹性的搜索引擎,可用于企业级搜索。

l  Amazon SQS:队列服务,存储和分发消息。

l  Simple Workflow:一个工作流框架。

l  CloudFront:世界范围的内容分发网络。

l  EMR: Elastic MapReduce,一个hadoop框架的实例,可用于大数据处理。

1.6 Deployment & Admin (部署和管理)

l  Elastic BeanStalk: 一键式创建各种开发环境和运行时。

l  CloudFormation:采用jason格式的模板文件来创建和管理一系列亚马逊云资源。

l  OpsWorks: OpsWorks允许用户将应用程序的部署模块化,可以实现对数据库、运行时、服务器软件等自动化设置和安装。

l  IAM: Identity & Access Management,认证和访问管理服务。用户使用云服务最担心的事情之一就是安全问题。亚马逊通过IAM提供了立体化的安全策略,保证用户在云上的资源绝对的安全。用户通过IAM可以管理对AWS资源的访问。通过IAM可以创建group和role来授权或禁止对各种云资源的访问。

2.云架构图

Amazon的云架构图如下:

以下是运行原理:

l  工作启动器——工作从网站或其它软件子系统进入,在队列服务中排队等候处理。工作不一定非是大请求,可以是整个管线中独立的一小部分。不要把状态保存到工作执行器里。把需要做的事打包进工作请求,放回到队列服务中等候处理。

l  规划服务——它是亚马逊的基础设施,允许实例根据工作负载自动伸缩。这是与自有的虚拟服务器(VPS)或典型的数据中心方案主要的不同之处。它有一套启停AMIS的API,以及自动配置、运行VM的机制。

l  工作执行器——它们从队列中取出工作,完成具体处理。对SmugMug来说,工作结果存储在S3之上,但你也可以存储在自己的数据库、SimpleDB或其它地方。

l  队列服务——队列存储工作执行器要接受的工作。SmugMug建立了自己的队列服务,你也可以直接使用亚马逊的SQS,用起来同样简单。创建一个可伸缩、分布式、高性能、高可用的队列服务并非易事,所以你可以考虑一下“Flickr——先完成必不可少的工作,其它的放进队列”中推荐的大量队列产品。

l  控制器——该组件监控工作流相关的大量变量,并以最优化一小组参数为目标,决定需要多少EC2实例。按需增减实例。

如果想查看每个云服务的详细信息,可以查看它们的官方文档https://aws.amazon.com/documentation/?nc1=h_su_dm。亚马逊的所有云服务都提供了API接口进行调用,并且提供了命令行工具Amazon CLI(Command Line Interface)来使用。

参考资料

1.《架构学习笔记—Amazon》


2.《AWS系列之一 亚马逊云服务概述》

http://www.kuqin.com/shuoit/20141213/343877.html

3.《Amazon Dynamo系统架构分析》

http://www.linuxeye.com/architecture/1679.html

4.《揭秘Amazon EC2容器服务背后的技术细节》

http://dockone.io/article/521