当前位置: 首页 > 科技观察

应用程序不能很好地扩展?让我们看看基于Java的云应用程序

时间:2023-03-23 11:00:41 科技观察

我们最近的任务是开发用于分析大数据的软件即服务(SaaS)应用程序。对于数据挖掘,系统需要在数据库中存储和分类数十亿个公共帖子。在此环境中进行分类是一个缓慢、资源密集且痛苦的过程,需要为数据库中的任何记录分配主题或情绪。对我们的测试数据进行分类的过程持续了长达24小时。为了满足这些要求,摆在我们面前的显而易见的选择是在AmazonWebServices(AWS)上构建云应用程序。在接手这个项目一段时间后,我想分享一下我在开发基于Java的云应用程序方面的经验、知识和方法。什么是云计算?我们先看看维基百科给出的定义:“云计算涉及网络上的分布式计算。一个程序或应用软件可以同时运行在多台相连的计算机上。”这个定义可能有点模糊,但可以理解,因为云计算本身更像是一个营销术语而不是技术术语。对于初学者来说,如果我们以更实际的方式定义云计算,就更容易理解:传统Web应用程序和云Web应用程序之间的唯一区别是完美的可扩展功能。鉴于无限的硬件,云应用程序应该能够处理无限的工作负载。今天云应用的流行是由于对现代应用提出了更高的要求。过去,Google以开发高度可扩展的应用程序而闻名,这些应用程序几乎包含Internet上的所有可用信息。今天,许多其他企业需要开发能够处理类似规模的数据和计算的应用程序(Facebook、Youtube、LinkedIn、Twitter,以及像我们这样搜索和处理数据的人)。使用传统的应用程序开发方式,不可能处理如此庞大的数据量。这促使我们采取完全不同的方法并开发可扩展的应用程序。那就是云应用。#p#为什么传统的网络应用开发方式不够可扩展?开发Web应用程序的传统方法让我们来看看为什么传统应用程序无法处理大规模数据。如果您曾经开发过传统的Web应用程序,它应该与上图非常相似。还有其他细微差别,例如组合应用程序服务器和Web服务器或多个企业服务器。但大多数时候,数据库是关系数据库。Web服务器通常是有状态服务器,而企业服务器可以同时提供无状态和有状态服务。有一些明显的缺点使该体系结构的可扩展性不够。让我们从定义完美的可扩展性开始。给定双倍的带宽和双倍的硬件数量,系统始终可以为双倍的工作量提供相同的响应时间,从而实现完美的可扩展性。在真实环境中无法实现完美的可扩展性。相反,开发人员的目标是近乎完美的可扩展性。例如,DNS服务器不在我们的控制范围内。因此,理论上,我们无法处理比DNS服务器更多的请求。这是任何系统的上限,即使是谷歌。SQL回到上图,最大的弱点在于数据库的可扩展性。请求数量和数据大小都足够小,以至于开发人员在负载增加时不会注意到任何性能下降。继续进一步增加负载,如果处理器使用率达到100%或者内存被占满,影响可能会非常明显。这时,最实用的方法就是为数据库系统提供更多的内存和处理器资源。之后,系统可能会再次顺利运行。不幸的是,只要问题出现,这种方法就不能永远重复。总有一个限制:无论你有多少内存和处理器资源,性能总是会随着时间的推移越来越差。这是意料之中的,因为会有许多创建、读取、更新和删除(CRUD)某些记录的请求。无论你决定缓存记录,将它们存储在内存中,还是采取任何其他方式,它们都是单台机器上存在的唯一记录,并且对某个内存地址可以发送多少访问请求是有限制的。这又是一个不可避免的限制,因为SQL是为完整性而开发的。为确保完整性,SQLServer中的任何信息都必须是唯一的。即使在数据隔离或复制之后,此功能仍然适用(至少对于主实例而言)。相比之下,NoSQL不会尝试规范化数据。相反,它选择存储聚合对象,其中可能包含重复信息。因此,NoSQL仅适用于对数据完整性没有要求的情况。以上来自couchbase.com的示例显示了数据如何存储在文档数据库中以及如何存储在关系数据库中。如果一个家庭有多个成员,关系数据库只为所有家庭成员存储一个地址,而NoSQL数据库只是简单地复制地址。家庭成员搬家后,一次交易可能不会更新所有家庭成员的地址,这违反了数据完整性。但是,对于我们的应用程序和许多其他应用程序,这种暂时的违规行为是可以接受的。例如,您可能不需要您的社交网络页面浏览量或社交网站上的公开帖子计数是100%准确的。数据复制实际上消除了我们上面提到的对单个内存地址的并发访问,允许开发人员选择将数据存储在他们想要的任何地方,只要一个节点的变化可以慢慢同步到其他节点即可。这种架构更具可扩展性。有状态下一个问题是有状态服务。有状态服务需要相同的硬件来为来自相同客户端的请求提供服务。客户端数量增加后,最明智的做法是在系统中部署更多的应用服务器和Web服务器。然而,就有状态服务而言,资源分配无法得到充分优化。就传统应用而言,负载均衡系统没有任何关于系统负载的信息,通常采用RoundRobin的方式将请求分发到不同的服务器。这里的问题是并不是所有的请求都是一样的,也不是所有的客户端发送相同数量的请求。这将不可避免地导致一些服务器不堪重负,而另一些服务器则处于闲置状态。混合数据检索和数据处理对于传统应用程序,从数据库检索数据的服务器最终会处理数据。处理数据和检索数据之间没有明确的区分。这两项任务都会在系统中造成瓶颈。如果瓶颈是数据检索,那么数据处理自然就没有得到充分利用,反之亦然。#p#重新思考开发可扩展应用程序的最佳方法看看我们最近在IT中采用的方法,我发现它们根本不是新发明。相反,IT世界只是简单地采用已在现实生活中成功使用的方法来解决可伸缩性问题。为了说明这一点,想象一下处理可伸缩性问题的真实情况。医院假设我们有一家小医院。就这家医院而言,我们的服务对象主要是本地客户。每个忠诚的客户都有自己喜欢的医生,医生会跟踪病人的病历。正因为如此,客户只需出示IC病历卡,其首选的医生就会处理病历。使情况变得具有挑战性的是,我们医院在互联网时代之前就开始运作了。有状态与无状态上面的描述看起来是否与有状态服务足够相似?现在,您的医院开始名声大噪,客户数量突然暴增。假设你有足够的硬件基础设施,一个明显的选择是雇佣更多的医生和护士。尽管如此,客户仍不愿更换新医生。这导致新的医护人员非常空虚,而原有的医护人员非常忙碌。为确保优化,您决定更改医院政策,以便客户必须保留他们的医疗记录,并且医院会将它们分配给任何可用的医生。这种新方法有助于解决医院的所有难题,使其能够部署更多季节性员工来应对突然激增的客户。这个策略可能不会让客户满意,但对于IT世界来说,有状态服务和无状态服务提供相同的结果。数据复制假设客户数量持续激增,您开始考虑开设更多分支机构。与此同时,一个新的问题出现了:客户不断抱怨医院要求看病时必须带病历。为了解决这个问题,您恢复了在医院存储病历的旧政策。但是,当您有多个分支机构时,每个分支机构都需要存储一份用户的病历副本。一天或一周后,记录的任何更改都需要同步到每个分支机构。在服务分离医院运营几个月后,您会发现资源分配并未达到最佳状态。比如你在A分行和B分行都有一个验血科和一个X光科,但是很多客户在A分行验血,很多在B分行做X光,导致客户在排队等候一根树枝,而另一根则空手而归。为了优化资源,您关闭了未充分利用的部门,并建立了独特的血液检测中心和X光中心。客户从这些分支机构分配到提供专门服务的特设中心。特定资源由于季节性疾病仅在一年中的特定时间发生,因此很难为医院制定资源计划。此外,灾难随时可能发生。它们导致病房患者在短时间内突然激增。为应对这种情况,您可能需要与市政当局达成协议,以便可以临时租用设施和空间,并在需要时雇用更多兼职员工。将这些想法应用到开发云应用程序现在,在分析了上面的示例之后,您可能会觉得大部分想法都说得通了。开发人员可以立即开始应用这些想法来开发Web应用程序。然后,我们进入了云应用时代。#p#如何开发云应用?为了开发云应用,我们不得不想方设法利用上面的思路来开发应用。这是我推荐的方法。基础设施如果您开始考虑开发云应用程序,那么首先要关注的是基础设施。如果您的平台不支持特定资源(动态增加现有服务器的硬件规格或启动新实例),则很难开发应用程序。现在,我们选择AWS,因为它是目前最成熟的平台。由于AWS具有的一些巨大优势,我们在一年前从本地迁移到AWS托管模型。多个地点:我们的客户来自五大洲;使用AmazonRegions,我们能够将实例部署到更靠近客户位置的位置;这导致更快的响应时间。监控和自动缩放:亚马逊为其平台提供相当有效的监控服务。面对服务器负载,可以实现自动扩容。内容交付网络:AmazonCloudFront为我们提供了从主要部署环境卸载静态内容的选项,这将缩短页面加载时间。与普通实例一样,静态内容从最近的实例提供给客户端。同步缓存与分布式缓存:多年来,MemCache一直是我们最喜欢的缓存解决方案。但是,一个大问题是缺乏对节点间同步的支持。AmazonElasticCache(亚马逊弹性缓存)为我们提供了使用MemCache的选项,而不必担心节点同步问题。托管API:这是一个很大的优势。我们最近开始广泛使用管理API来在短时间内启动实例以运行集成测试。数据库假设您已经选择了一个用于开发云应用程序的平台,下一步应该是为您的系统选择合适的数据库。您需要做出的第一个决定是哪个适合您的系统,SQL还是NoSQL?如果系统不是数据密集型的,SQL应该没问题;如果系统是数据密集型的,那么你应该考虑NoSQL。有时,多个数据库可以一起使用。例如,如果我们想要实现像Facebook这样的社交网络应用程序,我们可以将系统设置甚至用户配置文件存储在SQL数据库中。相比之下,由于数据量巨大,用户帖子必须存储在NoSQL数据库中。此外,我们可以选择具有强大搜索功能的SOLR来存储公共帖子,并选择MongoDB来存储用户活动。如果可能,请务必选择支持集群、数据隔离和负载平衡等特性的数据库系统。否则,您最终可能会自己实现所有这些功能。比如SOLR应该是比Lucene更合适的选择,除非我们想自己隔离数据。计算密集型还是数据密集型如果我们知道系统是数据密集型还是计算密集型,那就太好了。例如,Facebook等社交网络几乎完全是数据密集型的,而我们的大数据分析既是数据密集型又是计算密集型的。就数据密集型系统而言,我们可以让云端的任何节点检索数据并同时处理数据。在计算密集型节点的情况下,最好还是将数据检索与数据处理分开。数据密集型系统通常处理实时数据,而计算密集型系统运行后台任务来处理数据。在同一环境中结合这两项繁重的任务可能最终会降低系统的有效性。对于计算云来说,最好有一个框架来监控负载,分发任务,计算完成后收集结果。如果不需要实时处理,Hadoop是市面上最好的选择。如果需要实时计算,可以考虑ApacheStorm。云应用程序的设计模式要开发成功的云应用程序,我们应该牢记以下几个方面。1.无状态你所有的服务和服务器都必须是无状态的。如果服务需要用户数据,请将它们作为参数添加到API。值得注意的是,如果我们要在Web服务器上实现无状态会话(StatelessSession),我们有几种方案可以考虑:基于Cookie的会话分布式缓存会话数据库会话以上方案从上到下排列,分别是更具可扩展性较差,但易于管理。2.幂等性就云应用而言,大多数API调用将通过网络进行,而不是通过内部方法调用。因此,如果我们可以使方法调用安全,那就太好了。如果您坚持上述无状态原则,那么您实现的服务就已经是幂等的了。3.远程外观远程外观不同于外观模式。它们实际上看起来相同,但旨在解决不同的问题。由于大多数API调用都是通过网络进行的,因此网络延迟会对响应时间产生很大影响。使用RemoteFacade模式,开发人员应该能够构建可减少调用次数的粗粒度API。通俗地说,去超市一次买10件比去超市20次每次买1件更明智。4.数据访问对象当你传输数据时,你应该注意传输的数据量。最好只传输所需的最少数据。5.谨慎行事这不是一种设计模式,但你以后小心行事会很幸运。由于分布式计算的特性,一旦出现问题,很难找出是哪一部分出了问题。在可能的情况下,为系统的每个部分实施健康检查、ping检测、综合日志记录、调试模式等安全机制。结束语希望这种开发云应用程序的方法对您有所帮助。如果您还有其他的看法或经验,欢迎留言交流。https://weblogs.java.net/blog/sgdev-blog/archive/2014/05/20/how-build-java-based-cloud-application英文原文链接:http://sgdev-blog.blogspot.com/2014/05/how-to-build-java-based-cloud.html