查看原文
其他

从1到1100万用户的架构演变

2016-01-12 Todd Hoff 云头条

你如何让系统从1个用户扩展到1100多万个用户?亚马逊网络服务(AWS)公司的解决方案架构师Joel Williams 在AWS re:Invent 2015大会上,就这个话题作了一场精彩的演讲:《扩展到你的头1000万个用户》。



如果你是资深AWS用户,那场演讲不适合你,但如果你刚接触AWS,刚接触云计算,或者无力跟上亚马逊不断推出的一大批新功能,这不失为一篇入门指南。


你可能也料到了,由于这是亚马逊人的演讲,亚马逊服务始终是解决任何问题的最主要办法。亚马逊的平台架构令人叹为观止,颇有启发性。从各部分彼此整合的情况来看,很显然,亚马逊在这方面做很到位:识别用户要求,然后确保拿出满足要求的产品。


一些值得关注的心得如下:


  • 从SQL开始入手,只在确有必要时迁移到NoSQL。

  • 一个一致的主题是,拿来组件后将它们分开来。这让那些组件可独立扩展,出现故障后不影响其他组件。这个原则适用于分解各层、构建微服务。

  • 只致力于从事为贵公司带来差异化优势的任务,不做重复性工作。

  • 可扩展性和冗余性不是两个独立的概念,这两方面常常可以同时做到。


基本概况


AWS服务全球各地的12个地区


  • 地区是指亚马逊有多个可用性区域(Availability Zones)的物理位置。地区范围覆盖:北美、南美、欧洲、中东、非洲和亚太。

  • 可用性区域(AZ)通常是单单一个数据中心,不过它们可能由多个数据中心构成。

  • 每个AZ彼此分得很开,各自有独立的电力和互联网连接。

  • AZ之间的唯一连接就是低延迟网络。比如说,两个AZ可能相隔5英里或15英里。低延迟网络的速度很快,快得应用程序运行起来如同所有AZ都在同一个数据中心。

  • 每个地区有至少2个可用性区域。总共有32个AZ。

  • 使用AZ,有可能为你的应用程序构建高可用性架构。

  • 2016年会新增至少9个可用性区域和4个地区。


AWS在全球共有53个边缘位置


  • 边缘位置被亚马逊的内容分发网络(CDN):CloudFront和亚马逊的托管DNS服务器:Route53使用。

  • 边缘位置让用户能够访问内容,延迟非常低,不管用户在世界上的什么地方。

  • 模块构建服务

  • AWS已构建了许多服务,这些服务在内部使用多个AZ,确保高可用性和高容错性。这里(https://aws.amazon.com/cn/about-aws/global-infrastructure/regional-product-services/)列出了在各地可使用什么样的服务(http://docs.aws.amazon.com/general/latest/gr/rande.html)。

  • 你可以将这些服务用在你的应用程序中,要付费,没必要为自行确保高可用性而担心。

  • AZ里面存在一些服务:CloudFront、Route 53、S3、DynamoDB、弹性负载均衡(Elastic Load Balancing)、EFS、 Lambda、SQS、SNS、SES和SWF。

  • 即便服务存在于单一AZ里面,也可以使用这些服务来构建高可用性架构。



1个用户


在这种场景下,你只有1个用户,你想让网站运行起来。


你的架构看起来就像这样:


  • 在单一实例(可能是类型t2.micro)上运行。实例类型包括:不同组合的处理器、内存、存储和网络资源,让你可以灵活地选择适合具体应用的资源组合。

  • 单一实例将运行整个Web堆栈,比如说:Web应用程序、数据库和管理等。

  • 使用亚马逊Route 53作为DNS服务器。

  • 将单一的Elastic IP地址连接到该实例。

  • 在一段时间里,运行顺畅。


纵向扩展


  • 你需要更庞大的系统。最简单的扩展方法就是选择一个更大类型的实例。比如说,可能是c4.8xlarge或m3.2xlarge。

  • 这种方法名为纵向扩展(vertical scaling)。

  • 只要停止运行实例,选择一个新的实例类型,就可以运行起来,拥有更强的处理能力。

  • 诸多组合的不同硬件配置可供选择。你可能拥有配备244GB内存的系统(2TB内存类型很快会推出),或者配备40个核心的系统。有High I/O实例、High CPU实例和High storage实例可供使用。

  • 一些亚马逊服务随带Provisioned IOPS选项,以保证性能。其想法是,你可能为自己的服务使用比较小的实例类型,充分利用能提供可扩展服务的亚马逊服务(比如DynamoDB),那样你没必要操心。

  • 纵向扩展有个大问题:没有故障切换机制,没有冗余性。如果实例有问题,你的网站就完蛋了。好比你的所有鸡蛋都放在一只篮子里。

  • 最终,单一实例支持的规模很有限。你需要采取别的做法。



用户数量> 10


把单一主机分成多个主机:


  • 一个主机用于网站。

  • 一个主机用于数据库。运行你需要的任何数据库,但是你得负责数据库管理。

  • 使用独立的主机让网站和数据库可以完全彼此独立扩展。比如说,也许数据库需要的机器比网站需要的来得庞大。

  • 你可以使用数据库服务,而不是运行自己的数据库。

  • 你是数据库管理员吗?你果真要想为备份操心吗?高可用性?补丁?操作系统?

  • 使用服务的一大优点是,只要点击一下鼠标,就能设置好一套多可用性区域数据库。没必要为复制或任何这种事务操心。你的数据库将具有高可用性和高可靠性。


正如你所料,亚马逊在出售几种全面托管的数据库服务:


  • 亚马逊RDS(关系数据库服务)。有好多选择:微软SQL Server、Oracle、MySQL、PostgreSQL、MariaDB和亚马逊Aurora。

  • 亚马逊DynamoDB:一种NoSQL托管数据库。

  • 亚马逊Redshift:PB级数据仓库系统。


亚马逊Aurora方面的详情:


  • 存储容量可自动扩展至64TB。你再也不必为数据配置存储容量。

  • 多达12个读取副本(read-replica)。

  • 持续(增量)备份到S3。

  • 横跨3个AZ的6路复制。这可以帮助你处理故障。

  • 与MySQL兼容。


从SQL数据库开始入手,而不是NoSQL数据库。


  • 建议从SQL数据库开始入手。

  • 这项技术很成熟。

  • 有许多的现成代码、社区、支持组织、图书和工具。

  • 你的头1000万个用户不会搞坏SQL数据库。根本不会(除非你的数据很庞大)。

  • 清晰的可扩展模式。


你什么时候需要从NoSQL数据库开始入手?


  • 如果你在一年内需要存储超过5 TB的数据,或者面临数据超密集型的工作负载。

  • 应用程序要求超低的延迟。

  • 需要很高的吞吐量。你需要改动在读取和写入操作方面获得的输入/输出。

  • 你没有任何关系数据。


用户> 100


  • 使用单独的主机用于Web层。

  • 将数据库存储在亚马逊RDS上。它会处理一切事务。

  • 你要做的就这些。



用户> 1000


  • 设计架构时,你的应用程序就存在可用性问题。如果用于Web服务的主机出现故障,你的网站就瘫痪。

  • 所以,你需要在另一个可用性区域的另一个Web实例。这没问题,因为AZ之间的延迟很低:只有几毫秒,就好像这些AZ几乎彼此相邻。

  • 你还需要RDS的从属数据库在另一个AZ中运行。要是主数据库出了问题,应用程序就会自动切换到从属数据库。故障切换时没有必要更改应用程序,因为应用程序始终使用同一个端点。

  • 弹性负载均衡器(ELB)被添加到配置中,在位于两个AZ的两个Web主机实例之间实现用户负载均衡。


弹性负载均衡器(ELB):


  • ELB是一种高可用性的托管负载均衡器。ELB存在于所有AZ中。它是面向你应用程序的单一DNS端点。只要把它放入到Route 53,它就会跨Web主机实例实现负载均衡。

  • ELB会进行健康检查(Health Checks),确保流量没有传送到出现故障的主机。

  • 它能自动扩展,你啥都不用做。如果它看到额外流量,会在后台进行横向扩展和纵向扩展。你没必要管理它。你的应用程序扩展时,ELB也会随之扩展。



用户> 10,000 -100,000


前一种配置在ELB后面有2个实例,实际上你可以在ELB后面有1000个实例。这是横向扩展。


你需要为数据库和RDS添加更多的读取副本。这将为写入主数据库卸掉负载。

将一部分流量移到别处,从而为你的Web层服务器减轻负载,从而提高性能和效率。将你Web应用程序中的静态内容转移到亚马逊S3和亚马逊CloudFront。CloudFront是亚马逊的CDN,负责将数据存储在全球各地的53个边缘位置。


亚马逊S3是一种基于对象的存储系统


  • 它不像EBS,也不是连接到EC2实例的存储系统,它是一种对象存储系统,不是块存储系统。

  • 它很适合存储静态内容,比如javascript、css、图像和视频。这种内容不需要放在EC2实例上。

  • 高度耐用,可用性达到99.999999999%。

  • 可无限扩展,你想添加多少数据就可以添加多少。客户将数PB数据存储在S3中。

  • 支持最大为5TB的对象。

  • 支持加密。你可以使用亚马逊的加密、你自己的加密技术或加密服务。

  • 亚马逊CloudFront缓存你的内容。

  • 它在边缘位置缓存内容,为用户提供延迟最低的访问服务。

  • 没有CDN,用户访问内容时会遇到更高的延迟。服务器也会面临更高的负载,因为它们不仅要处理Web请求,还要提供内容。

  • 一个客户需要以60 Gbps的速度提供内容。CloudFront处理一切,Web层甚至不知道发生了什么。


你还可以将会话状态从Web层转移出去,以此减轻负载。


  • 将会话状态存储在ElastiCache或DynamoDB中。

  • 这种方法还让系统可以在将来支持自动扩展。


你还可以将来自数据库的数据缓存到ElasticCache中,减轻负载。


  • 你的数据库不需要处理所有的数据获取。缓存能处理许多这方面的工作,让数据库处理更重要的流量。


亚马逊DynamoDB:托管型NoSQL数据库


  • 你配置所需的吞吐量。可以增加想要支付相应费用的读取和写入性能。

  • 支持快速、稳定的性能。

  • 完全分布式和容错。它存在于多个可用性区域中。

  • 它是键值存储系统。支持JSON。

  • 支持最大为400KB的文档。


亚马逊Elasticache:托管型Memcached或Redis


  • 管理memcached集群并不让你赚更多钱,所以让亚马逊为你做这件事。这是亚马逊的营销口号。

  • 集群自动为你扩展。它是自愈合基础设施,如果节点出现故障,就会自动启动新节点。


你还可以将动态内容转移到CloudFront,以此减轻负载。


  • 许多人知道CloudFront能处理文件之类的静态内容,但它也能处理动态内容。这个话题在本演讲中没有作进一步探讨,不过这里有个链接(https://aws.amazon.com/cloudfront/dynamic-content/)。


自动扩展


如果你配置足够的容量,以便始终处理峰值流量负载(比如黑色星期五),无异于在浪费钱财。


更明智的是,让计算能力与需求相一致。这就是自动扩展(Auto Scaling)让你能做到的事,即自动调整计算集群的大小。


你可以定义资源池的最大值和最小值。用户得决定集群中最小数量的实例和最大数量的实例分别是多少。


CloudWatch是一种嵌入到所有应用中的管理服务。


  • CloudWatch事件驱动扩展。

  • 想在处理器利用率方面进行扩展吗?想在延迟方面扩展吗?想在网络流量方面扩展吗?

  • 你还可以将自己的自定义衡量指标纳入到CloudWatch中。如果你想在针对特定应用的方面进行扩展,可以把该衡量指标纳入到CloudWatch中,然后告诉自动扩展机制你想在该衡量指标方面进行扩展。


用户> 500,000+


与前一个配置相比增添的是,自动扩展组添加到Web层。自动扩展组包括2个AZ,但可以扩展到3个AZ,不仅提供可扩展性,还提供可用性。


一个例子是在每个AZ中有3个Web层实例,但可以是数千个实例。你可以说想要最少10个实例,最多1000个实例。


ElastiCache用来卸载来自数据库的常见读取。


DynamoDB用来卸载会话数据。


你需要添加监控、衡量和日志机制。


  • 主机层衡量指标。看一下自动扩展组里面的单一处理器实例,查清楚什么出了岔子。

  • 总计衡量指标。看一下弹性负载均衡器上的衡量指标,了解整批实例的性能。

  • 日志分析。使用CloudWatch日志,看一看应用程序告诉你了什么。CloudTrail可帮助你分析和管理日志。

  • 外部站点性能。从最终用户的角度了解客户看到什么样的性能。使用New Relic或Pingdom之类的服务。


你要了解客户有什么样的评价。延迟很差劲?他们在访问网页时遇到了错误?

从你的配置获得尽量高的性能。自动扩展在这方面有所帮助。你不希望系统的处理器利用率只有20%。


自动化


基础设施变得庞大,它可以扩展到上千个实例。我们有读取副本,有横向扩展,但需要某种自动化工具来帮助管理这一切,我们可不想管理每一个实例。

自动化工具有层次结构:


  • 自己动手:亚马逊 EC2和AWS CloudFormation。

  • 更高层服务:AWS Elastic Beanstalk和AWS OpsWorks


AWS Elastic Beanstalk:为你的应用程序自动管理基础设施。它使用方便,但没有太多的控制。


AWS OpsWorks:这是一种种环境,你可以在其中构建层次化的应用程序,可使用Chef配方(recipe)来管理应用程序的层次。


  • 另外启用进行持续集成和持续部署的功能。


AWS CloudFormation:历史最久。


  • 提供最大的灵活性,因为它为你的堆栈提供了模板化视图。它可以用来构建你的整个堆栈,或者只构建堆栈的部分。

  • 如果你想更新堆栈,只要更新Cloud Formation模板,它会更新你应用程序的某一个部分。

  • 很大的控制度,但不太方便。


AWS CodeDeploy:将代码部署到一批EC2实例。


  • 可部署到1个或上千个实例。

  • Code Deploy可指向自动扩展配置,那样代码可以部署到一组实例。

  • 还可以与Chef和Puppet结合使用。


解耦/分离基础设施


使用SOA/微服务。从你的诸层拿来组件后,把它们分开来。比如将Web层与数据库层分开来时,构建独立的服务。


单个服务随后可以独立扩展。这为你在扩展方面提供了极大的灵活性,还有高可用性。


SOA是亚马逊构建的架构的一个重要部分。


松散耦合(Loose coupling)彻底解放了你。


  • 可以让组件独立扩展,出现故障后不影响其他组件。

  • 如果某个worker节点没有从SQS获取work,这严重吗?没啥关系,只要启动另一个节点。难免会出现故障,不妨构建一种可处理故障的架构。

  • 将一切设计为黑盒子。

  • 解耦/分离交互关系。

  • 偏爱内置冗余性和可扩展性的服务,而不是构建自己的服务。


不做重复性工作


只致力于从事为贵公司带来差异化优势的任务。


亚马逊有许多服务天生具有容错性,因为它们横跨多个AZ。比如说:队列、电子邮件、转码、搜索、数据库、监控、衡量、日志和计算。你没必要自行构建这些服务。


SQS:队列服务。


  • 提供的第一种亚马逊服务。

  • 它横跨多个AZ,所以具有容错性。

  • 它具有可扩展、安全又简单等优点。

  • 队列可帮助你在基础设施的不同部分之间传输消息,从而帮助基础设施。

  • 以照片内容管理系统(CMS)为例。收集并处理照片的系统应该是两个不同的系统。它们应该能够独立扩展。它们应该松散耦合。获取照片后放入到队列中,worker就能从队列中获取照片,并进行相应处理。


AWS Lambda:让你不用配置或管理服务器,就可以运行代码。


  • 让你可以解耦/分离应用程序的出色工具。

  • 在照片CMS这个例子中,Lambda可以响应S3事件,那样S3文件添加后,Lam

  • bda的处理功能就自动被触发。

  • 我们丢弃了EC2。它可以为你向外扩展,没有操作系统要管理。



用户> 1,000,000+


获得超过100万个用户需要所有上述几点:


  • 多个AZ

  • 层与层之间的弹性负载均衡。不仅仅在Web层上,还要在应用层、数据层及拥有的其他任何层上。

  • 自动扩展

  • 面向服务的架构(SOA)

  • 使用S3和CloudFront,智能化提供内容

  • 把缓存放在数据库前面

  • 从Web层移走状态


使用亚马逊SES发送电子邮件。


使用CloudWatch来监控。



用户> 10,000,000+


随着规模变得更大,我们会在数据层遇到问题。你可能会开始遇到数据库方面的问题:与负责写入的主数据库争夺资源,这基本上意味着你向一台服务器发送的写入流量很有限。


你如何解决这个问题?


  • 联合(federation)

  • 切分(sharding)

  • 把某种功能移到其他类型的数据库(NoSQL和图形数据库等)

  • 联合:根据功能分成多个数据库

  • 比如说,构建论坛数据库、用户数据库和产品数据库。之前你可能把这些功能统统都放在一个数据库中,现在将它们分开来。

  • 不同的数据库可以彼此独立扩展。

  • 缺点:你无法执行跨数据库查询;这就引出了下一个策略:切分。

  • 切分-横跨多个主机来分割一个数据集

  • 应用层更为复杂,但可扩展性方面实际上没有限制。

  • 比如说,在用户数据库中,三分之一的用户可能被派到一个分片,三分之一被派到另一个分片,剩下三分之一被派到另一个分片。


将某种功能移到其他类型的数据库


  • 开始考虑NoSQL数据库

  • 如果你的数据不需要复杂的合并,比如说选手积分榜、快速获取点击流/日志数据、临时数据、热表、元数据/查询表,那么可以考虑改用NoSQL数据库。

  • 这意味着,它们可以彼此独立地扩展。



用户> 1100万


扩展是个迭代过程。你规模变大后,总是能够做更多的事情。


对应用程序进行微调。


用更多的SOA来处理特性/功能。


从多AZ进入到多地区。


开始构建自定义解决方案,以解决你面临的、别人之前没有遇到过的特定问题。如果你需要服务于10亿个客户,就需要自定义解决方案。


深入分析整个堆栈。


回顾


使用多AZ基础设施来确保可靠性。


充分利用自扩展服务,比如ELB、S3、SQS、SNS和DynamoDB等。


在每个层面融入可靠性。可扩展性和冗余性不是两个独立的概念,这两方面常常可以同时实现。


从传统的关系SQL数据库开始入手。


基础设施内外的数据都要缓存。


在基础设施中使用自动化工具。


确保已落实了良好的衡量/监控/日志机制。确保弄清楚客户从你的应用程序得到什么样的体验。


将诸层分成单个服务(SOA),那样它们就能彼此独立地扩展,出现故障后不影响其他服务。


一旦作好准备,就使用自动扩展。


不做重复性工作,使用托管服务,而不是自行编写服务,除非绝对有必要这么做。


如果有必要的话,改用NoSQL。


补充资料:

2007年的亚马逊架构:http://highscalability.com/blog/2007/9/18/amazon-architecture.html


云头条编译|未经授权谢绝转载


欢迎加入,群主微信:aclood


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存