微服务分解应用程序以实现可部署性与可扩展性(下)

  在上篇 微服务分解应用程序以实现可部署性与可扩展性(上)中了解了为什么要将应用程序分解为服务以及微服务架构的优缺点,现在我们来看一下在微服务架构中几个关键的设计问题,首先是应用内部以及应用与客户端之间的通信机制。

  微服务架构中的通信机制

  在微服务架构中,客户端和应用之间以及应用组件之间的通信机制与整体应用有所不同。我们首先看一下应用的客户端与微服务交互的问题;随后是应用内部的通信机制。

  API网关模式

  在一个整体架构中应用的客户端,如Web浏览器和原生的应用,会发起HTTP请求,负载均衡器将请求转发到N个完全相同的应用实例中的某一个上面。但是在微服务架构中庞大的应用被替换为一组服务,所造成的结果就是,我们需要回答客户端到底与谁交互的问题。

  应用的客户端,如原生的移动应用,可以对单个服务发起RESTful HTTP请求,如图4所示。

  图4——直接调用服务

  表面上这看起来很吸引人,但单个服务的API和客户所需的数据之间的粒度可能极其不匹配。例如,显示一个网页可能需要调用大量的服务。以Amazon.com为例,它描述了一些网页是如何调用100多个服务的。发出这么多的请求,即使使用的是高速互联网,效率也会很低,并将导致很差的用户体验,更不用说低宽带、延迟性较高的手机网络了。

  一个较好的方法是让客户端针对每个页面发出较少数量(可能少至一个)的请求,这些请求通过互联网进入前端服务器,也就是API网关,如图5所示。

  图5——API网关

  API网关位于应用客户端和微服务之间,为客户提供量身定做的API。API网关为手机客户端提供粗粒度的API,为使用高性能网络的桌面客户端提供细粒度的API。在本例中,桌面客户端可发出多条请求,对产品的信息进行检索,而手机用户仅可发出一条请求。

  API网关通过高性能LAN向一定数目的微服务发出请求,以处理传入的请求。例如,Netflix描述了各个请求是如何平均分散至六个后端服务的。在本例中,仅桌面客户发出的细粒度请求被代理到匹配的服务上,而手机用户发出的各个粗粒度请求则是通过聚合调用多重服务的结果而进行处理。

  API网关不但优化了客户端和应用之间的通信,而且还囊括了微服务的详细信息。这便使微服务可在不影响客户端的情况下不断发展。例如,可合并两个微服务,一个微服务也可被划分为两个或多个服务。仅需对API网关进行更新,便可反应这些变化,同时,客户端不受任何影响。

  既然我们明白了API网关是如何在应用和客户端之间进行协调的,接下来看一看微服务之间的通信是如何实现的。

  服务间通信机制

  微服务架构另一个主要差异是应用的不同组件如何进行交互。在整体架构的应用中,其组件可通过常规的方法调用另一个组件。而在微服务架构中,不同的服务运行在不同的进程中,因此服务必须使用进程间通信(IPC),从而实现通信。

  同步HTTP

  微服务架构中的进程间通信有两种方式。一种是基于HTTP的同步机制,如REST或SOAP。这是一种较简单且常见的IPC机制。由于支持防火墙,所以它能够通过互联网进行工作,执行请求/回复式的通信就变得容易了。HTTP的缺点是它不支持其他模式的通信,如发布-订阅。

  另一个限制是要求客户端和服务器都必须同时在线,但这一点无法一直保证,因为分布式系统易于出现部分失效的现象。此外,HTTP客户还需知晓服务器主机和端口。这听起来很简单,但其实不然,尤其是在采用自动扩展的云部署中,服务实例的生命周期是很短暂的。应用需使用服务发现机制。一些应用采用服务注册,如Apache ZooKeeper或Netflix Eureka,而对于其他应用,必须使用负载平衡器进行服务注册,如亚马逊虚拟私有云(VPC)上的内部弹性负载均衡器(ELB)。

  异步消息

  同步HTTP的一个替代方案就是基于消息的异步机制,如基于AMQP的消息代理。该种方式具有诸多优点。它解耦了消息的生产者和使用者,通过消息代理将对消息进行缓冲,直到使用者能够进行消息处理为止。生产者完全意识不到使用者,因为他们只与消息代理进行对话,根本无需使用服务发现机制。同时,基于消息的通信还支持各种通信模式,其中包括单向请求和发布-订阅。使用消息的一个缺点是需具备一个消息代理--另一个运行时部件—这就增加了系统的复杂性。另一个缺点是它不适用于请求/回复式的通信。

  两种机制各有利弊。应用可混合使用这两种机制。在下一节中,我们将要讨论如何解决架构拆分中的数据管理的难题,进而看一看HTTP和消息传递是如何同时使用的。

  去中心化的数据管理

  将应用拆分为服务,其结果是对数据库进行了拆分。为确保低耦合,各项服务应具有自己的数据库(模式)。此外,不同的服务可能使用不同类型的数据库——这就是所谓的多种类持久化架构。例如,一项需进行ACID事务的服务可能使用关系数据库。因此说对数据库进行拆分是必要的,但这里出现了一个新的问题:如何处理那些访问多个服务的数据的请求呢。首先让我们看一下如何处理读请求,然后再看更新请求。

  处理读请求

  例如,网上商店需对每位顾客的信用卡额度进行管理。当顾客想要下单时,系统必须进行核实,证实所有未结订单的金额不得超过他们的信用卡额度。虽然在整体架构应用中执行这条业务规则轻而易举,但在顾客和订单分别由CustomerService和OrderService进行管理的系统中执行起来却困难得多,因为不管怎样,OrderService都必须访问由CustomerService维持的信用卡额度。

  OrderService可通过向CustomerService 申请RPC调用来对信用卡额度进行检索。这种方法操作简单,并保证OrderService每次获取的都是最新的信用卡额度。但缺点是减低了系统的可用性,因为CustomerService必须保持在线,客户才能下订单,同时进行了额外的RPC调用,所以也增加了响应的时间。

  还有一种处理方式是,在OrderService中存放一份信用卡额度的副本,这样就无需向CustomerService发起请求,这既提高了可用性,又缩短了响应时间。但是还需要一种机制保证:每当Customer Service中的信用卡额度发生变化时,都要及时更新存放在Order Service中的副本。

  处理更新请求

  发出请求,对多重服务持有的数据进行更新。如何保持Order Service中的信用卡额度为最新的信用卡额度则是处理这些请求过程中较为常见的问题。

  分布式事务

  使用分布式事务是一个非常直观的解决方案。例如,当对顾客的信用卡额度进行更新时,CustomerService可使用公布式事务对其上的信用卡额度以及OrderService上的相应信用卡额度进行更新。使用分布式事务能够保证数据一致,但是会降低系统的可用性,因为所有相关的服务必须始终在线,才能进行事务的操作。而且,很多现代的技术并不支持分布式事务,如REST、NoSQL数据库等。

  基于事件的异步更新

  另一种方法是使用基于事件的异步更新。服务公布说明某些数据已改变的事件。其他服务订阅这些事件,并对数据进行更新。例如,当CustomerService对其中一个顾客的信用卡额度进行更新时,它将发布一个顾客信用卡更新事件,该事件包含顾客ID以及新的信用卡额度。OrderService订阅这些事件,并对其上的信用卡额度进行更新。事件流如图6所示。

  图6——使用事件复制信用卡额度

  该种方法的主要优势在于事件的生产者和使用者均被解耦了。这不但简化了开发,还提高了系统的可用性(与分布式事务相比)。如果使用者不能对事件进行处理,则消息代理将把该事件存入列队,直到能够处理该事件时为止。该方法的主要缺点是这种方式的主要缺点在于它为了可用性牺牲了一致性。应用的编写方式必须能够容忍最终一致性数据,同时,发开人员也可能执行补偿事务,以实现符合逻辑的回滚。尽管存在这些缺点,但该方法仍然是诸多应用首选的方法。

  重构整体架构

  在实际工作中,我们很少有机会参与一个全新的、尚未进行开发的项目。需要处理的差不多都是存在这样那样问题的复杂、大型的应用。每天都需要处理本文开头所提到的问题,但好消息是可采用一些技术将整体架构的应用拆分为一组服务。

  首先不要让事情变得更糟糕,不要继续在这个庞大的应用上增加代码而执行重要的新的功能。相反,应该以某种方式将功能实现为一项独立的服务,如图7所示。这可能并不容易做到。你需要编写凌乱复杂的胶水代码来实现服务与这个庞大应用的集成。但对于拆分整体架构的应用来说,这是很好的第一步。

  图7—抽取服务

  第二,识别整体整体架构的应用中的一个组件,然后将其转换为内聚且独立的服务。要进行抽取时,比较好的可选组件包括那些经常变化的或具备不一致资源需求的组件,如需要大量内存缓存或CPU密集型操作。展现层也是一个很好的可选项。你将组件转换为服务,并编写胶水代码使其能够与应用的其他部分进行集成。再次强调一遍,这可能会比较痛苦,但是能够让你渐进式地迁移到微服务架构上。

  总结

  在构建企业级应用时,单片集成架构模式是一种常用的模式。对小型应用来说,它的确运行的很不错:开发、测试以及部署小的单片集成应用相对很简单。但对于大型的复杂应用,单片集成架构就成为开发和部署的障碍了。很难做到持续交付,并且通常会长期局限于最初所作出的技术选择。对于大型的应用使用微服务架构会更好,这种架构会将应用拆分为一组服务。

  微服务架构有很多的优势。例如,单个服务更易于理解,可以独立于其他服务进行开发和部署,更易于使用新的语言和框架,因为你可以每次在服务中尝试新的技术。微服务架构也有一些明显的不足。尤其是应用要复杂得多,会有更多的运行时组件,你需要高度的自动化,如PaaS,才能有效地使用微服务。在开发微服务时,你还要处理一些复杂的分布式数据管理问题。尽管有这些不足,但是对于快速演化的大型复杂应用,尤其是SaaS风格的应用来讲,微服务架构是很有意义的。

  要将现有的单片集成应用增量式地演进为微服务架构,可采用多种策略。开发人员应该将新功能作为一项单独的服务进行实现,并编写胶水代码将服务与巨石型应用进行集成。另外一种很好的办法就是迭代式地识别组件并将其从巨石型应用中抽取出来,然后将其转换为服务。尽管演进过程并不简单,但是总比开发和维护笨重的单片集成应用要强得多。



  本文由寄云科技编译,未经授权谢绝转载。欢迎关注寄云科技订阅号(neuclouddy),这里有最新云服务行业资讯,更有与PaaS、运维相关的技术干货!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值