微服务化架构理解及应用实例分析

背景

服务化架构是当前最火的概念,当我们一谈到服务化第一时间联想到的就是互联网应用中,采用服务与服务之间进行互联调用的架构模式。RESTful、Json、Webservice,一定是绕不开这些词汇。但是从我个人理解,服务化应该是一种架构设计的理念。相对于之前非常流程的模块化设计思路,服务化是模块化的演进。从原来大颗粒的模块,转变为专注于特定业务、功能的服务(单元)。

         任何一个模块都是一个相对完整独立的系统,从前端view、到业务处理、数据模型处理、数据存储。相互独立,互不干扰,是独立的烟囱。而服务化架构思想,改变了烟囱的结构。已横切的思路,将原来的烟囱进行了切面。对于切面上的功能,统一由服务提供功能实现。

相应的,在任何一个系统或模块中,都可以借鉴这种横切的思路,将模块进行横切,以按功能划分服务。

总体设计思路

架构微服务化设计

从架构的构架上,依照微服务化的思路,首先明确服务的概念,并进行服务的分层。每层均由提供不同功能的服务组成,从原来模块化的理解转变为服务化的理念。

另外,这里特别强调微服务的概念应用。从传统模块化的设计风格到服务化的设计风格,是一种转变。而从服务到微服务则是另一种架构风格的转变,也是一种开发模式的转变。微服务强调一个微,相同的都是服务,微服务更强调细粒度化的服务。从功能的规模、开发的投入,到实际交付的周期过程。微就体现了更快,同时也意味着更多的微服务进行并行的开发和交付。从开发管道上看,有利于多管道化的运作模式。

通过管道化的运作,提升服务的交付效率,同时也进一步达到功能解耦。这里,笔者试着根据一个Eclipse插件工程的开发设计来说明微服务化理念的应用过程。

下图是该插件工程基于模块化的设计level0的设计图:

level0 架构设计图

​​​​​​​​​​​​这是一个非常常见的基于功能模块的系统设计方式,按照不同的功能划分到相应的功能模块。在该插件工程中,应用数据都是存储在XML文件中。因此,存储模块直接利用了第三方开源的xml处理模块。而在数据模型处理模块,则是根据业务view的视图需要,以前端view的功能进行模块的划分。不同的视图,需要提供不同模型的数据。在数据模型处理模块,既会有单一模型的数据处理,也会涉及到多数据模型的处理。而这些功能都是按照前端的需求进行涉及和划分,是一种自前而后的设计。从展示需求端入手,设计底层的实现往往是一种较快捷,也较容易理解的一种设计思考方式。

但是,随着业务功能的深入,对数据模型处理的功能复杂度也在不断上升。尤其是因为模型的设计会随着功能的深入而不断的被修改,也就导致了数据模型处理模块不断的变更。而且,由于模型没有被单独的封装到一个处理模块中,导致变更的修改会有多出。

例如,该项目的xml模型的依赖关系如下图:

XML模型

Offering模型的实例化数据的处理,会附带着对ProductPlan的数据处理。在原有模块化的划分方式下,设计并提供一个Offering模型的处理是合理的。但是也存在一定的隐患,就是对ProductPlan,甚至是Property的数据处理都包含Offering的模型处理中。因此,当存在ProductPlan甚至是Property的模型变更、功能调整都会引起Offering模型处理模块的变动,也就是说Offering模型处理的功能不够“单一”。Offering模型“本身”没有调整,却因为它包含的模型调整而变更。

因此,一种可行的微服务化得设计思路(注,这里所谓的服务并不是特指web服务。而是从本质上来说,它们的设计思想是相通的),就是按照模型独立来拆分“微服务”:

微服务架构   Offering ModelService 将会只对“ Offering ”模型定义的实例数据进行处理,而对于包含的 Product 模型实例的处理,则交由 Product Model Service 进行处理。包括数据实例的创建、删除、更新和查询,甚至基于模型定义的实例数据的创建也可以在这里提供。 Offering Model Service 在需要使用 Product Model 的实例数据时,调用该服务的创建实例数据的服务接口即可。

将原来的数据模型处理层进行重新的设计和划分,一部分拆分为细粒度的模型服务,一部分拆分为细粒度服务组合后的业务功能服务。也就是说,会有组合服务和原子服务(相对而言)。展示层View则保持不变,微服务化尽量保持原有接口兼容,不会引起对上层的变动。

由于,原有模块化提供的功能接口保持不变。而服务接口又势必会引起对这些接口的冲击,这里可以借助Proxy设计模式,通过代理封装内部变化,并且同时发布新的业务服务接口,并标记原有的功能接口过期。

服务接口和实现的设计思路

从本质上来说,模块化的设计进一步发展就是服务化,而发展到极致(追求功能单一)就是微服务化。在本例中,按照服务化的设计思想,对服务设计主要分为接口设计和实现设计。服务的接口定义表明了该服务对外的契约,应该是相对稳定的。但是随着业务的深入发展,接口也会进行变动,为了避免接口变动对外部造成的影响。接口也需要有版本定义,而接口的实现则更是如此。实现更加的灵活多变,通过不同的实现类来避免这种情况的发生。如下的java package包的设计就是这种思路的一种体现:

​​例如:

ModelServiceLayer.OfferingModelService.v1 :表示为模型服务层的Offering模型服务的v1版本定义。

ModelServiceLayer.OfferingModelService.v1.impl: 表示为Offering模型服务的v1版本的实现。

ModelServiceLayer.OfferingModelService.v2 :表示为模型服务层的Offering模型服务的v2版本定义。

ModelServiceLayer.OfferingModelService.v2.impl: 表示为Offering模型服务的v2版本的实现。

         注:对于package的划分在实际开发中存在很多的方式,例如:微服务层名.版本.微服务名,这种方式是以版本为维度,将同一版本下的微服务集中在一起。这种方式的好处的,管理直接。如果是按照版本运作,则更适合这种模式。不同的版本由不同的团队独立负责。

         对于接口版本的定义,完全可以实现向前兼容。而兼容的做法是在新版本接口中保留原有版本接口的定义,而新版本接口定义的实现可以通过代理方式直接调用之前版本的实现。

如上图,对于v2版本接口定义中来自v1版本的,在v2版本接口的实现直接委托v1版本接口定义的实现。

         如此,版本和实现可以随需求和功能一并演进。按照微服务化得思路,在开发和构建时,每天可以根据当前微服务的开发进度进行版本功能合并和出包。外部的对微服务只依赖于具体的接口实现,当微服务构建完成后,既可以直接进行集成。同时,利用IoC容器(成熟的spring即可),服务的实现可以注册到IoC容器中,并提供服务接口的不同实现。同时,也就把IoC容器作为一种服务中心来使用。在当前项目的需求背景下,把IoC容器作为服务控制和注册的中心,并且已经满足当前的需求。后续可以在根据情况,对服务的控制和注册能力的提升。

如下例,OfferingModelService依赖于StoreService的服务接口,而StoreServiceXmlImpl和StoreServiceDBImpl则分别实现了StoreService的接口定义,通过Spring的配置可以表示为:

 

 

          在接口定义好之后,实现可以先注册一个Mock的实现,对外不提供任何的功能实现。随着实现的不断完善,在完成impl1之后,可以替换原先的注册。这时可以提供部分的功能实现,未提供的功能对外仍然是调用失败的。Impl2可以是另外一部分实现,可以通过委托调用impl1中已经实现的功能。如此,就可以提供一种并行开发的模式,从而提升开发的效率。

         在这种思路下,更进一步。一个接口的定义实现就可以被拆分成不同的Function实现类,分别实现不同的Function,最后统一由impl进行集成。如下图:

其他思考

         在有了微服务化的思路后,对现有工程重构后,如何对这些微服务,以及它们之间的依赖关系进行管理,就变得很重要了。以微服务作为最基本的单元进行跟踪:需求拆分、开发、测试、验证、发布,最后统一进行集成验证和打包发布,就是一个具有挑战性的任务。尤其是跟踪微服务的进度、集成后的功能进度等。这里,可以构建一个微服务看板的视图,通过这个看板视图了解到以上信息。

         首先明确,一个微服务是可以进行独立开发、测试、验证和发布的。微服务的测试,可以由使用该微服务的开发人员提供测试的元素代码,由测试人员通过进一步的架构完善。最后,作为微服务在构建环境上的测试用例。通过微服务看板,每天可以跟踪微服务的当前进展(开发、测试、发布的状态),跟踪开发进度。

微服务看板

猜你喜欢

转载自lottons88.iteye.com/blog/2365896