云计算是任何架构师工具包中的重要工具。 它可以让您原型设计和启动新项目,而不必担心服务器配置,它可以降低成本并降低管理服务器的风险,并且可以轻松扩展,并能够在您每次启动时增加额外的实例。需要他们。
但是,在开始为云开发应用程序时,需要考虑许多架构问题。 本文重点介绍了在构建第一个基于云的应用程序时的一些注意事项。
在提出有关为云进行架构设计的建议之前,值得花一些时间重新审视基于云的架构可以提供的好处:
对于许多架构师而言,基于云的应用程序是他们有效地进行规模设计的介绍,因为即使在较小规模的应用程序中也有充分的理由使用云。 扩展应用程序时,有很多注意事项,这对于习惯于最大化单个服务器性能的架构师来说可能并不直观。
首次开发流行的应用程序时,通常会首先扩大规模。 添加更多的RAM。 提高处理器速度。 升级到更快的硬盘。 为慢速查询或常用计算实现缓存。 这些都是合理的技术,但是如果您的应用程序要扩展到某个特定点之外,那么您将不仅需要扩展和设计以在多个服务器上进行扩展。 这样做通常需要对应用程序的体系结构进行重大更改。 云应用程序的本质意味着您应该从一开始就进行扩展设计。
同样,在为云架构师时,重要的是不要专注于性能微优化。 与其进行大量复杂的缓存和性能调整,不如保持设计简单并确保可以扩展应用程序,这是更好的选择。 服务器通常比开发人员便宜得多,性能微优化通常不值得在开发时间和降低应用程序可维护性上付出代价。
当必须扩展应用程序时,请关注五种体系结构方法:
在云中增加水平可伸缩性的最重要模式可能是可变状态的最小化。 这是函数式编程语言变得如此流行,以及事件来源(请参阅参考资料获得更多信息的链接)之类的模式被更频繁地使用的原因。 共享的可变状态(即,跨应用程序共享并且可以随时间更改的变量)的问题在于,它对可伸缩性造成了严重破坏。 试图同时更新相同变量的多个服务器和进程会导致死锁,超时和失败的事务。 Web服务器,应用程序以及(可能甚至是)数据库中的三个位置,您将希望最小化或消除应用程序中的可变状态。
对于云应用程序,不能保证任何给定实例都是持久的。 如果您有三个均处理请求的Web服务器实例,则任何给定实例都可能随时关闭。 鉴于此,您只想将信息存储在服务器实例发生故障时可能丢失的本地文件系统上。
如果用户正在上传文件(个人资料图片或TPS报告),则要确保将它们上传到冗余的远程文件系统,而不仅仅是上传到他们正在访问的Web服务器的硬盘上。 如果要记录即使服务器实例出现故障也确实需要访问的信息,则可能希望将其保存到Cassandra之类的NoSQL存储中,而不是将其持久保存到任何给定Web服务器上的本地硬盘上。
共享的可变状态在面向对象的编程中特别有用,但是在扩展基于云的应用程序时,最小化可变状态的数量并仔细考虑其含义很重要。
Eric Evans在域驱动设计中包括了一些很棒的代码级模式,以最大程度地减少可变状态,例如使(可变的)实体尽可能的薄,并为尽可能多的应用程序状态使用(不可变的)值对象。 例如,用户是一个可变的实体,但是您可以使用不可变值对象来表示用户的地址,只是在用户移动时更改指向用户的地址。 通常,优先使用值对象和不可变值而不是可变状态,尤其是对于可能需要由基于云的应用程序的许多部分定期更新的状态。
另外,请仔细考虑您的缓存策略。 如果信息是特定于单个实例的,则可以使用本地缓存,因为如果实例停止运行,您始终可以重新创建它。 但是,如果访问另一台Web服务器的用户可能需要该信息,则您要么希望每次从共享的持久性存储中提取信息,要么使用分布式缓存来处理跨多个Web服务器实例的缓存更新。
最初,这听起来像是矛盾的话题,但是采用事件源影响的方法为基于云的应用程序进行数据库设计可能会带来真正的好处。 尝试扩展应用程序时的常见问题是数据库中的写入争用。 采购订单的更改可能会影响数百个订单项目以及供应商的关联采购订单。 自然,任何此类更改都必须包装在事务中,以确保数据库仅在进行了一部分更改后才不会处于无效状态。 但是,随着越来越多的用户更新影响相关订单的交易,您很快就会发现所有交易由于乐观的锁定冲突而失败。
解决此问题的一种方法是最小化数据库中的可变状态。 在数据库中只有一条记录具有唯一标识符(例如,ID,电子邮件地址,UUID),但是没有其他状态,而不是让用户的名字,姓氏和其他配置文件字段的值可变。 然后,您为ProfileUpdateEvent
拥有一个单独的表,其中为每个更新存储了一个不可变的事件,并带有相关的时间戳。 因此,如果用户更新了他或她的家乡城市,将有一个ProfileUpdateEvent
,其中的字段为home_city
并存储新值和更新的日期/时间。 要获取用户的家乡,您只需遍历所有ProfileUpdateEvent
直到找到更新该字段的最新时间戳。 此过程为您提供了一个系统,在该系统中,写入争用消失了,您可以按读取或自动计划解决所有冲突,从而在应用程序中提供更大的写入可伸缩性。
当然,您现在对读取性能有疑问。 仅要获取单个实体的状态就必须对大量事件执行操作效率不高,特别是对于那些涉及读取可伸缩性的应用程序而言。 但这是一个很容易解决的问题:在用户表中重新创建其他字段,但这些字段不是用户状态的单一权威性引用,而是在特定点上只是用户状态的缓存及时。 然后,根据您的业务规则,您可以编写脚本以基于ProfileUpdateEvent
来更新用户表中的状态缓存, ProfileUpdateEvent
根据业务规则解决任何写入冲突。 如果您拥有写争用可能成为扩展基于云的应用程序的真正障碍的应用程序,则值得考虑事件源。
管理数据库中写争用的另一种方法是评估对部分或全部应用程序数据使用NoSQL数据存储的可能性。 例如,Cassandra专门设计用于在多个节点之间提供线性写入可伸缩性,以存储大量数据。 CouchDB在多个节点之间具有出色的主到主同步,而MongoDB具有“计数器”字段的概念,允许对计数器字段进行异步触发并忘记更新,因此您不必担心写入争用只是定期更新帖子的观看次数。
许多NoSQL存储还提供MapReduce功能,从而可以有效地访问预定义的查询。 如果您要对大量数据运行已知查询,则随着您使用的数据量的增长,它们可以提供可扩展的解决方案。
另一个重要的体系结构方法是通过创建单独的异步服务来从主应用程序服务器上分担工作。 无需阻塞线程,也无需等待同步发送电子邮件或运行报告的站点访问者等待响应。 最好将这些任务分解成可以在云中不同服务器上运行的单独服务。 这样,您可以从主应用程序中独立扩展它们。 您不必在等待任务完成时阻止Web服务器上的线程,您的用户也不必等待这些进程完成即可获得响应,表明您正在使用该线程并会通知他们。该过程完成后。
通常,您使用具有一定程度的保证传递能力的传输机制(例如消息队列)连接到异步服务。 使用网络而不是进程间通信也很重要。 通常,在单独的服务器上运行这些服务。 如果您愿意,您当然希望能够在单独的服务器上运行它们。 您还可以使用其他体系结构方法,例如将数据库当作黑板,以便在主应用程序和执行单独的异步服务的各种服务之间共享信息。
最后,自动化云部署过程非常重要。 您需要具有用于各种角色(Web服务器,电子邮件服务器,数据库服务器等)的基础机器映像,并需要使用Chef或Puppet之类的工具来自动配置实例。 您还将要使用某种构建系统来自动部署代码。
监视基于云的应用程序也是一个重要的问题。 设置监视,以便知道实例何时发生故障或负载过重,从而可以根据应用程序的执行情况来自动进行增加或减少实例的过程。
确保对IP地址进行脚本化的自动重新映射,以处理数据中心发生故障时的情况。 另外,研究您的云提供商如何支持SSL连接,并将它们映射到各种实例。 通常,仅在绝对需要协议提供的传输安全性的页面上使用SSL才是好习惯。 SSL请求会产生开销,因此您只想在支付溢价时增加业务价值。
要了解更多有关自动化部署和不断增长的DevOps运动,看看优秀的书上连续传递由Jez的谦逊和大卫·法利的相关主题 。
考虑基于云的应用程序的故障设计尤其重要。 您应该仔细考虑世界末日的情况,查看您的单点故障以及在故障发生时应采取的措施。
但是,决定可接受的故障级别同样重要。 如果数据中心发生故障,则仅在几分钟之内只能提供对服务器的“读取”访问权限,直到将另一个数据库提升为“主”数据库,这可能就可以了。 也许还可以,如果服务器发生故障,则用户将不得不再次登录,否则将失去他或她的偏好或购物车。 重要的是,将容错技术的工程成本与该容错技术的业务价值进行比较,以确保您不会过度投资于为对您的业务不足够重要的信息提供冗余。
基于云的应用程序具有许多好处,包括更快地进入市场和更容易扩展。 此外,初始成本较低,并且架构良好的基于云的解决方案通常可提供更好的灾难恢复功能。 但是,要利用基于云的部署的优势,您必须以与云一致的方式进行架构设计,通常假设您将使用只读本地文件系统并将任何重要数据存储在数据库或数据库中。共享的持久性文件系统。 此外,请最小化应用程序中的可变状态,并考虑使用NoSQL数据存储来提高应用程序的可伸缩性。 看一下如何将繁重的处理工作卸载到可以转移到单独服务器的异步服务上。 最后,自动化部署过程并设计故障应用程序,以确保从基于云的应用程序获得可接受的故障性能特征。
翻译自: https://www.ibm.com/developerworks/cloud/library/cl-cloudappdevelop/index.html