免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 63457 | 回复: 0
打印 上一主题 下一主题

【好书推荐】微服务与单一服务架构的拼杀,如何选? [复制链接]

论坛徽章:
59
2015七夕节徽章
日期:2015-08-24 11:17:25ChinaUnix专家徽章
日期:2015-07-20 09:19:30每周论坛发贴之星
日期:2015-07-20 09:19:42ChinaUnix元老
日期:2015-07-20 11:04:38荣誉版主
日期:2015-07-20 11:05:19巳蛇
日期:2015-07-20 11:05:26CU十二周年纪念徽章
日期:2015-07-20 11:05:27IT运维版块每日发帖之星
日期:2015-07-20 11:05:34操作系统版块每日发帖之星
日期:2015-07-20 11:05:36程序设计版块每日发帖之星
日期:2015-07-20 11:05:40数据库技术版块每日发帖之星
日期:2015-07-20 11:05:432015年辞旧岁徽章
日期:2015-07-20 11:05:44
1 [报告]
发表于 2018-07-08 17:06 |显示全部楼层
1. 如何理解微服务,简要说明您所理解的微服务是什么?
微服务架构是一项在云中部署应用和服务的新技术。大部分围绕微服务的争论都集中在容器或其他技术是否能很好的实施微服务,而红帽说API应该是重点。
微服务可以在“自己的程序”中运行,并通过“轻量级设备与HTTP型API进行沟通”。关键在于该服务可以在自己的程序中运行。通过这一点我们就可以将服务公开与微服务架构(在现有系统中分布一个API)区分开来。在服务公开中,许多服务都可以被内部独立进程所限制。如果其中任何一个服务需要增加某种功能,那么就必须缩小进程范围。在微服务架构中,只需要在特定的某种服务中增加所需功能,而不影响整体进程。
微服务不需要像普通服务那样成为一种独立的功能或者独立的资源。定义中称,微服务是需要与业务能力相匹配,这种说法完全正确。不幸的是,仍然意味着,如果能力模型粒度的设计是错误的,那么,我们就必须付出很多代价。如果你阅读了Fowler的整篇文章,你会发现,其中的指导建议是非常实用的。在决定将所有组件组合到一起时,开发人员需要非常确信这些组件都会有所改变,并且规模也会发生变化。服务粒度越粗,就越难以符合规定原则。服务粒度越细,就越能够灵活地降低变化和负载所带来的影响。然而,利弊之间的权衡过程是非常复杂的,我们要在配置和资金模型的基础上考虑到基础设施的成本问题。
微服务作为一项在云中部署应用和服务的新技术已成为当下最新的热门话题。但大部分围绕微服务的争论都集中在容器或其他技术是否能很好的实施微服务,而红帽说API应该是重点。
企业和服务提供商正在寻找更好的方法将应用程序部署在云环境中,微服务被认为是未来的方向。通过将应用和服务分解成更小的、松散耦合的组件,它们可以更加容易升级和扩展,理论上是这样。
微服务的基本思想在于考虑围绕着业务领域组件来创建应用,这些应用可独立地进行开发、管理和加速。在分散的组件中使用微服务云架构和平台,使部署、管理和服务功能交付变得更加简单。
微服务是利用组织的服务投资组合,然后基于业务领域功能分解它们,在看到服务投资组合之前,它还是一个业务领域。
微服务这一概念出现于2012年,是因软件作者Martin Fowler而流行,他承认这并没有精确地定义出这一架构形式,虽然围绕业务能力、自动化部署、终端智能以及语言和数据的分散控制有一些常见的特性。


2. 与传统单一服务架构相比,在实战环境下,各自的优劣都有哪些?

工作中使用了微服务架构,接下来的一段时间里,我会写一系列的文章来介绍微服务架构,同时我也会在github上写一个microservices的应用框架(地址会在后续文章给出)。


一、单一应用架构
1.上下文
你正在开发一个服务器端的企业级应用,它必须支持多种不同的客户端,包括桌面浏览器、手机浏览器、原生手机APP。这个应用也许还会暴露一个API,给第三方程序去调用。它也许还会与其他应用集成,通过web services或者一个消息代理。 这个应用通过运行业务逻辑、访问数据库、与别的系统交换消息、然后返回一个HTML/JSON/XML响应的方式来处理HTTP或者消息请求。对于这个应用的不同功能块, 有不同的逻辑组件与之对应。

2.问题与强制条件
问题: 这个应用的部署架构是怎样的?

强制条件:
  • 这个项目有一个开发者团队
  • 新的团队成员必须快速变得高效工作
  • 这个项目必须易于理解和修改
  • 你想要对这个项目实施持续部署
  • 你必须在多台机器上运行多个这个项目的复制品,从而达到期望的可伸缩性、可用性
  • 你想要利用新技术(框架、编程语言等)的优势

3.解决方案与例子

解决方案:

构建一个单一应用架构的应用,比如一个单一的Java War文件, 或者一个单一的Rails或者NodeJS代码的目录结构

例子:

假设你正在构建一个电子商务应用, 这个应用从客户那里收到订单,检验存货和客户的余额,然后发货。这个应用由多个组件构成,包括:前端UI,实现了用户接口; 以及一些后台服务,用来检查余额,维护存货和发货。

这个应用以一个单一应用架构部署, 比如是在Tomcat上运行的一个Java web应用。你可以在一个load balance后面运行多个应用实例,以达到提高可用性和可伸缩性的目的:





4. 这种解决方案的结果

这种解决方案有很多好处:

  • 易于开发:现在很多开发工具和IDE的目标都是支持开发单一应用结构的应用
  • 易于部署:你只要在合适的运行时环境上简单的部署一个WAR文件(或者目录结构)
  • 易于伸缩:你可以在一个load balance后面运行多个应用实例,以达到提高可用性和可伸缩性的目的

但是,一旦这个应用变得庞大,团队规模变大,这种解决方案的缺点变得越来越重大:

  • 巨大的单一应用结构的代码吓坏了开发者,尤其是团队里的新人。这个应用变得难以理解和维护。结果是,开发工作变得缓慢,而且,因为没有严格的模块界限,模块化常常会被打破。此外,因为很难去理解如何正确地实现一次变动,代码质量下降。

  • IDE负载严重:代码越多,IDE越慢,开发效率越低。

  • web容器负载严重: 项目越大,启动时间越长。这对于开发效率有很大影响,因为有很多时间都浪费在了等待web容器启动上面。这也影响了部署。

  • 持续部署很困难:一个庞大的单一应用架构的应用是频繁部署的障碍。为了更新一个组件,你需要重新部署一整个应用。这会中断后台的任务,比如Java里的Quartz job,这可能会导致问题。还有一种可能是,未更新的组件会在启动时失败,导致的结果是,重新部署的风险升高,不利于频繁更新。 这对UI开发者来说尤其是个问题,因为他们经常需要快速迭代和频繁的重新部署。

  • 伸缩这个项目变得困难:一个单一应用架构的应用只能在一个维度上伸缩。一反面,成交量上升时,可以通过运行更多实例的方法来伸缩,一些云服务甚至可以按需调节实例个数。但是在另一方面,这种架构难以根据数据量来调节。每个应用实例都会访问数据,使得缓存变得不那么有效,提高了内存消耗和I/O传输。同时,不同的组件有不同的资源需求,一个组件可能是CPU密集型,而另一个可能是内存密集型。单一应用架构下,我们很难对每个组件分别进行伸缩。

  • 对于调节开发规模是个障碍: 一旦一个单一应用架构的应用达到了一个具体的规模,把团队分别几个更小的团队,专注与不同的功能块上是有效的。比如说,我们也许想要UI团队、审计团队、仓储团队等。但是单一应用架构阻碍了各个团队之间的独立工作。团队之间必须共同合作。

  • 需要对一个技术栈有一个长期的承诺: 一个单一应用架构**你与一开始的技术栈捆绑(甚至与某一个技术的具体版本)。在单一应用架构下,很难增量应用新的技术。比如说,你选择了JVM技术,以后那些用非JVM语言写的组件在你的项目里就没有一席之地了。再比如,你选择了一个平台框架,后来这个框架过时了,那就很难去迁移到一个新的更好的框架了。很可能你为了采用新的框架,需要重写一整个应用,而这是很有风险的。




二、微服务架构


1.上下文
与上文单一应用架构相同

2.问题与强制条件
与上文单一应用架构相同



3.解决方案与例子
解决方案:
定义一个架构,使得这个应用的结构是一系列松耦合、互相合作的服务(services)。这个方法对应了伸缩立方体的Y轴。每个服务实现了一系列互相关联的功能。比如说,一个应用可能由订单管理服务、客户管理服务等构成。
服务之间用同步协议比如HTTP/REST或者异步协议比如AMQP(译者注: 实现如RabbitMQ等)来进行通信。 服务可以被独立的开发和部署。每个服务有自己独立的数据库,从而与别的服务解耦。服务之间的数据一致性通过使用事件驱动架构来维护。


例子:一个虚构的电子商务应用

假设你正在构建一个电子商务应用, 这个应用从客户那里收到订单,检验存货和客户的余额,然后发货。这个应用由多个组件构成,包括:前端UI,实现了用户接口; 以及一些后台服务,用来检查余额,维护存货和发货。这个应用由一系列服务构成:






4. 这种解决方案的结果

优点

这个解决方案有很多优点:

  • 每个微服务相对都比较小
    • 易于开发者理解
    • IDE更快
    • 应用启动更快,利于开发和部署
  • 每个服务可以独立于其他服务单独部署,利于频繁部署新版本

  • 更容易伸缩开发资源。使你可以把开发资源分成多个团队。每个团队负责一个或多个服务。

  • 提高了错误的隔离。比如说,在一个服务中产生了内容泄露,只有那一个服务会受影响。

  • 不会对一个技术栈产生长期的依赖。在开发一个新服务或者重写服务时,可以选择新的技术栈。

缺点
这个解决方案有很多缺点:


  • 开发者需要处理创建一个分布式系统时的额外的复杂度
    • 测试更复杂
    • 开发者必须实现服务间的通信机制
    • 如果不使用分布式事务,会很难实现跨多个服务的用例
    • 实现跨多个服务的用例需要团队间的更认真的合作
  • 部署复杂性。在生产环境下,部署或者管理一个微服务系统有运维方面的复杂性。
  • 更高的内存消耗。微服务架构需要N*M个实例,而单一架构只需要N个实例。如果每个服务在它自己的JVM上运行, 就需要M倍的JVM运行时。


5.问题
你有很多问题需要解决。

什么时候使用微服务架构?

使用这种方法的一个挑战是判断什么时候用它是有意义的。当开发一个应用的第一个版本时,你经常不会碰到这个方法所解决的问题。此外,使用一个精细的分布式的架构会拖慢开发进度。这对于一些初创公司来说可能是一个大问题,因为他们的挑战经常是如何快速的把业务模型实现到应用中。使用Y轴划分(译者注:这里应该指的是采用微服务架构)也许会使得快速迭代更难。但是过一段时间,当挑战变成了如何伸缩,以及你需要拆分功能块,这种紧密的依赖也许会使得拆分一个单一应用架构到一系列服务变得困难。


如何把应用拆解成多个服务?

另一个挑战是决定如何分离系统,成为一系列服务。这更像是一种艺术,但是也有很多策略可以帮到你:

  • 根据业务能力分离, 然后定义一个个服务
  • 根据子域来拆解
  • 根据用例/动词来拆解。比如说Shipping Service负责订单的输送。
  • 根据资源/名词来拆解。比如说,Account Service负责管理用户的账号。

理想情况下,每个服务应该只有一小部分的职责。(Uncle) Bob Martin 谈论过使用单一职责原则(SRP)来设计类,使用SRP来设计Service同样也是讲得通的。

另一个帮助设计Service的类比是Unix工具包的设计。Unix提供了很多工具,比如说grep, cat和find。每个工具只做一件事,然后可以和其他工具混合在一起,去做复杂的事情。


如何保持数据一致性?

为了保证松耦合,每个service有它自己的数据库。维护service之间的数据一致性是一个挑战,因为二阶段提交事务/分布式事务并不是很多应用的一个选项。相反的,一个应用必须使用事件驱动架构。一个服务在它的数据变化时,会发布一个事件。别的服务消费这个事件,然后更新自己的数据。有很多种可靠的数据更新和事件发布的方法,包括事件源事务日志跟踪


如何实现查询?

另一个挑战是实现需要从多个服务那里获取数据的查询。一个普遍的做法是使用命令查询职责分离,维护一个或多个view,它们通过订阅事件流的方式一直保持最新,事件流中的事件是别的service在数据变化时发布的。



3. 如果您考虑部署微服务,在业务部署过程中会遇到哪些关键挑战?

大家都在提微服务架构,微服务架构到底是什么?它有哪些特点和设计模式?我们在打造微服务架构过程中,这些设计模式在实战当中如何应用?数据的一致性应该如何保证?今天我将针对上述疑问分享一下我的思考。

微服务架构特点

什么是微服务架构?看下图的这段英文,这是Martin Fowler 在2014年提出来的,微服务架构是一种架构模式,既然是架构模式,那么,它就必然需要满足一些特点。他提到,微服务架构是一系列小的微服务构成的组合,那么,什么是“小的微服务”?可能每个人的理解都不一样,大家都应该都知道SOA架构,SOA架构的粒度是比较粗的,到底我们应该以什么样的粒度拆分微服务?我认为,微服务架构本质上一个业务架构,那么对业务了解的越深刻,你的微服务拆分就越合理。

比如我们做二手交易平台(转转),该平台包括用户体系、商品体系、交易体系以及搜索推荐体系。因为各个体系比较独立,那么我们就可以按照各个业务模块来拆分微服务。当然,这样做还不够,因为你的商品里面还有很多功能,但是大的思路是按照具体商品内部的逻辑来进一步拆分。

第二,围绕具体业务建模。一切脱离业务场景谈微服务架构都是耍流氓。
方法有二:首先将某一领域的模型作为独立的业务单元:比如二手交易中的商品、订单、用户等;其次将业务的行为作为独立的业务单元:比如发送邮件、单点登录验证、push服务。

第三,整个微服务都可以独立地部署,因为每一个维服务Process都是独立的,所以按照每个模块进行独立的部署也是很容易理解的。

第四,去中心化管理。打造去中心化管理意思就是微服务的每个模块和开发语言、运行平台没有关系,开发语言可以是C++,可以是go,也可以是世界上最好的语言,运行的平台是Linux,Unix、Windows等都可以。

最后一点就是轻量级通信,这点很容易理解,通信和模块语言、平台没有关系。尽可能选用轻量级的通信来做这个事情,这样实施跨平台、跨语言的时候就很容易。

讲完这些特点,我们可以看一看一个标准DEMO级的微服务架构到底是由哪些元素组成的?如下图,主要包括网关、微服务、数据存储、注册中心、配置中心。

既然是DEMO级的,和实际情况下相比肯定有所差别。那么,实际案例中,我们到底应该如何做这件事情?这个例子也是最近我在做的二手交易平台——转转。这里和DEMO有些不一样的地方。前面的第一层还是网关,下面有微服务的聚合层,作用是做各种业务逻辑的处理;聚合层下面是我们的数据原子层,主要做数据访问代理,只不过根据业务的不同垂直分开了。可以看到,网关、数据层,注册中心、配置中心都有,只不过在业务处理部分分成两层:一层是原子层,也就是整个数据访问的代理层,提供了用户的接口;另外一层就是上层的业务聚合层。

架构设计模式及实践案例

上面我大概讲了下微服务的一些特点以及DEMO级的微服务包括哪些部分以及实际案例中我们的设架构设计模式。那么,我们为什么要采用这种模式去做?除了这种架构模式之外还有哪些其它的架构模式?这里,模式还是非常多的,我会重点讲这几点:链式设计模式、聚合器设计模式和异步共享模式。

首先我们来说下链式设计模式,在这种模式下,APP前端请求首先要经过网关层,接下来连续调用两个微服务,调了微服务1之后还要调微服务2。为什么叫做链式呢?因为在调用过来以后先到微服务1,然后再同步地调用微服务2,微服务2会做一些处理,处理以后微服务2才会反馈给微服务1,微服务1再反馈给Gateway,最后反馈到APP。在实际业务场景中,涉及到交易和订单的业务场景都会用到这种模式。

接下来是聚合器设计模式,APP前端一个调用请求经过Gateway,到达聚合层,需要调用三个微服务,聚合层将三个微服务的返回结果做一些聚合处理,比如可以进行一些排序或者去重,聚合之后再反馈到Gateway和APP前端,这是一个典型的聚合器设计模式。

第三种模式是数据共享模式,这种模式相对比较简单,比如APP经过微服务网关,接下来调用微服务1和微服务2,理想情况下微服务1和微服务2都有自己独立的DB,但是有些情况下由于微服务1和微服务2的请求量和存储量较小,从资源利用率的角度来讲,这两个微服务的DB是共享的,因此这种就是数据的共享模式。

最后一种是异步消息设计模式,不管是链式设计、聚合器模式还是共享数据模式,架构模式都是同步模式。也就是说我的一个请求发出去必须等到每个环节都处理完才会给客户端。如果请求不需要关注处理结果,这时候可以异步来实施。APP更新请求经过微服务网关,持久化到MQ,写入MQ成功后马上Response给APP客户端,之后微服务根据需要从MQ里面订阅更新消息进行异步处理,我们为了提高吞吐量也会采用这种模式。

我从百度到转转这几年经历了很多业务场景,使用的无非就是聚合器、异步和数据共享的数据模式,特别是前面两个用得特别多,下面我们来看一些例子。

接下来我们看个例子,这是我们在2015年做的一个二手交易平台(转转),这个二手交易平台包括商品、分类搜索、关键词搜索、商品推荐等功能。一个用户请求过来,先经过网关,网关下面就是我们的聚合层,聚合层再去调用商品、交易、推荐以及搜索相关的,最终在聚合层把各个微服务原子层的结果汇总起来Response给到客户端。具体如下图所示:

异步消息模式的这个案例比较早了,当时我们做了Feed 流,类似现在的微信朋友圈,这是我在百度做的事情。当时,我们采用的架构模式是异步架构模式。前面是我们的APP,经过了网关,到达异步提交层,可以认为是持久化功能的MQ。用户请求经过网关到消息异步提交层后就返回了,业务处理部分从MQ里面读取数据再进行异步处理。这个时候吞吐量会增加,但是会带来一定的困惑。比如这个时候我发了一条Feed,用户再一查就直接到数据库里面查,可能异步提交消息队列有延迟,查不到,用户就困惑了,这个问题怎么解决?我们就想能不能在前端帮我们做一些事情?比如提交了MQ返回Response 200以后,前段配合插入这条Feed。用户再次刷新时候我相信已经是好几秒以后的事情了,即使有延迟,这个消息早就被你的业务处理完了。当然,我们这里是有特定场景的,社区时候可以这样去做,但是涉及到和金融相关的场景肯定不会这么去做。

数据一致性实践

微服务模块比较分散、数据也比较分散,整个系统复杂性非常高,如何进行数据一致性实践?在一个单体模块里面可以做Local Transaction,但是在微服务体系里面就不奏效。虽然难解决,但是不能不解决,不解决的话微服务架构就很难实施。我们知道微服务中做强一致性性的事情是非常难的,今天分享的更多的是解决最终一致性。因为在微服务下基于不同的数据库,Local Transaction是不可用的。大家在在分布式事务里面一定听说过两阶段提交和三阶段提交,这种场景其实在微服务架构里面也行不通,原因是因为它本质上是同步的模式,同步的模式之下做数据一致性吞吐量降低的非常多。

我们的业务场景无非是两种:第一种是异步调用,就是一个请求过来就写到消息队列里面就行,这种模式相对简单。今天主要讲下同步调用的场景之下怎么打造数据的最终一致性。既然是同步调用场景,并且不能降低业务系统的吞吐量,那么应该怎么做呢?建立一个异步的分布式事务,业务调用失败后,通过异步方式来补偿业务。我们的想法是能不能在整个业务逻辑层实现分布式事务语义策略?如何实现,无非有两种,第一是在调正常请求的时候要记录业务调用链(调用正常接口的完整参数),第二是异常时沿调用链反向补偿。

基于这个思路,我们架构设计上的关键点有三,第一是基于补偿机制,第二是记录调用链,第三是提供幂等补偿接口。架构层面,看下图,右边是聚合器架构设计模式,左边是异步补偿服务。

首先需要在聚合层引入一个Proxy。首先基于方法,在方法名加注解标注补偿方法名,比如:- @Compensable(cancelMethod=“cancelRecord”)

另外,聚合层在调用原子层之前,通过代理记录当前调用请求参数。如果业务正常,调用结束后,当前方法的调用记录存档或删除,如果业务异常,查询调用链回滚。

原子层我们做了哪些事情呢?主要是两方面,第一是提供正常的原子接口,其次是提供补偿幂等接口。

分布式事务关键是两个表(如上图),第一是事务组表,假设A->B->C三个请求是一个事务,首先针对ABC生成一个事务的ID,写在这个表里面,并且会记录这个事务的状态,默认的情况下正常的,执行失败以后我们再把状态由1(正常)变成2(异常);第二个表是事务调用组表,主要记录事务组内的每一次调用以及相关参数,所以调用原子层之前需要记录一下请求参数。如果失败的话我们需要把这个事务的状态由1变成2;第三,一旦状态从1变成2就执行补偿服务。这是我们的补偿逻辑,就是不断地扫描这个事务所处的表,比如一秒钟扫一次事务组表,看一看这个表里面有没有状态为2的,需要执行补偿的服务。这个思路对业务的侵入比较小。

具体看下我们实际的例子,比如二手交易平台里面创建订单事务组的正常流程,从锁库存到减红包再到创建订单,创建事务组完毕之后开始调用业务,首先Proxy记录锁库存调用的参数,之后开始锁库存服务调用,成功后之后又开始减红包和创建订单过程,如果都成功了直接返回。

再看一下异常的流程,前面几步都是一样的,只是在调红包服务、Proxy创建红包的时候如果失败了就会抛出异常,业务正常返回,聚合层Proxy需要把事务组的状态由1改成2,这个时候由左边的补偿服务异步地补偿调用。



您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP