APP下载

无状态微服务架构及持续集成方法应用研究

2025-03-02鞠炜刚王佳

无线互联科技 2025年3期

摘要:随着大型软件系统的复杂度增加,传统的单体架构面临水平扩展困难、存在性能瓶颈、故障隔离不佳以及技术栈统一限制等问题,此外,单体应用构建和部署耗时较长,不利于频繁更新,影响了软件快速迭代与持续交付,微服务架构能够有效解决这些问题。文章面向一种云测试平台,采用领域驱动设计思想,设计并实现了基于Redis缓存的无状态微服务架构,应用相应的持续集成方法对该架构进行集成和部署,显著提升了平台的可扩展性、故障隔离能力和性能,支持多样化的技术栈选择并加速了软件的持续快速迭代和交付,取得了良好效果。

关键词:单体架构;微服务架构;无状态;持续集成;云测试

中图分类号:TP311" 文献标志码:A

0 引言

近年来,微服务架构(Microservice Architecture,MSA)逐渐受到越来越多人的关注。作为一种架构模式,微服务架构提倡将单体架构的应用划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。

云测试平台系统是一种测试调度执行系统。该系统采用单体架构,作为测试平台支撑大量项目使用,存在以下主要问题:(1)各模块之间耦合性强,功能扩展不方便,须要整体修改升级;(2)故障隔离性不好,某个模块的故障可能会导致系统整体不可用;(3)只能采用单一技术栈,无法发挥各语言在不同场景下的优势;(4)整体构建和部署时间比较长,不利于按需频繁部署。

为了解决以上问题,将云测试平台系统从单体架构演进到微服务架构。与传统的单体应用架构相比,微服务架构具有易于开发、技术栈多样性、扩展性强、故障可隔离性、可独立快速部署等各种优势,适合应用于大型复杂软件系统1-2。为了进一步提升系统面对大规模用户时的性能,微服务采用无状态设计支持多实例扩展。本文详细介绍了云测试系统无状态微服务架构的设计、实现以及针对微服务架构的持续集成和部署的具体方法,极大地提高了云测试平台的可扩展性、故障隔离性和性能,加快了软件持续快速迭代交付的能力。

1 单体应用架构和微服务架构

1.1 单体应用架构

传统的单体应用架构是将应用程序所有功能部署为一个单一的文件或者同一个目录下的文件合集,可以是JAR、WAR等格式,而且所有应用程序代码都运行在相同的进程中。单体应用有如下优点:(1)为人们所熟知。现有大部分工具、应用服务器、框架和脚本都是这种应用程序。(2)IDE友好。Eclipse、IntelliJ等开发环境都是针对开发、部署、调试单个应用而设计的。(3)便于共享。单个打包文件即包含所有功能,便于在团队之间以及不同的部署阶段共享。(4)易于测试和部署。单体应用一旦部署,所有服务或特性就都可以使用,没有额外依赖,每项测试都可以在部署完成后立刻开始。

截至目前,单体应用已经为人们提供了很好的服务,然而,不管如何模块化,单体应用都存在以下问题:(1)模块扩展性差。随着系统的复杂性越来越高,在单体应用中扩展业务功能模块越来越复杂。(2)故障隔离不佳。单体应用中一个模块的严重故障会导致整个应用不可用。(3)性能提升难。单体应用很难通过水平扩展来提升关键模块的性能。(4)技术栈统一限制。每个团队成员都必须使用相同的开发语言、持久化存储及消息系统,而且要使用类似工具,无法根据具体场景做出其他选择。(5)单体应用构建和部署耗时较长。单体应用可能较大,构建和部署时间也相应较长,不利于频繁部署,阻碍持续交付。

1.2 微服务架构

随着业务需求的快速发展变化,敏捷性、灵活性、可扩展性和性能需求不断增长,迫切需要一种更加快速高效的软件交付方式。微服务架构就是一种可以满足这种需求的软件架构模式,采用多个服务间互相协作的方式构建应用,每个服务独立运行在不同的进程中,服务与服务之间通过轻量级通信机制交互并且每个服务可以通过自动化方式独立部署。

1.2.1 微服务架构的特点

(1)领域驱动设计3。应用程序功能分解通过DDD中明确定义的规则实现;每个团队负责与一个领域或业务功能相关的全部开发。(2)单一职责。每个服务只负责该功能的一个单独的小的部分,也是SOLID原则之一。(3)明确发布接口。每个服务都会发布一个定义明确的接口且保持不变;服务消费者只关心接口,而对于被消费的服务没有任何运行依赖。(4)独立部署、升级、扩展和替换。每个服务都可以单独部署及重新部署而不影响整个系统,使得服务很容易升级扩展。(5)可以采用多种异构语言。每个服务的实现细节与其他服务无关,使得服务之间能够解耦,团队可以针对每个服务选择最合适的开发语言、持久化存储、工具和方法。

1.2.2 微服务架构的优点

(1)每个服务只须做好一件事,更加专注和简单,易于开发、理解、扩展和维护。(2)故障隔离好,一个服务出现问题不会影响整个应用。(3)性能水平扩展性好,可以通过对服务进行无状态设计,多实例化水平扩展来提升性能。(4)服务可以根据不同的要求选择合适的技术来做开发,不会受限于任何技术栈。(5)局部修改容易部署,有利于持续集成和持续交付4

2 基于微服务架构的云测试平台

云测试平台的核心是一个测试调度执行系统5-6,对测试环境的物理资源和用例对环境的资源需求2部分进行抽象描述,通过匹配算法达到测试用例和具体执行物理环境解耦的目的。测试人员提交测试任务,系统根据测试任务中测试用例的要求进行环境资源匹配,将用例各自分发调度到合适的测试环境并行执行,汇总结果报告输出。

2.1 单体架构

云测试系统原来的架构是经典的MasterSlave方式,一台Master服务器对应多台Slave,每个Slave管理一套测试环境,如图1所示。

该架构是单体架构,作为测试平台支撑大量项目使用时存在以下问题:(1)用户需求不断增加,模块间耦合性比较强,功能扩展起来不方便,而且需要整体修改升级;(2)故障隔离性不好,某个模块的故障可能会导致系统整体不可用,不满足稳定性的要求;(3)资源匹配算法采用Python效率较高,但是整体系统采用Go语言,只能通过脚本调用的方式,一些团队成员掌握其他技术栈却无法投入开发,浪费资源。

2.2 微服务架构

为解决以上问题,本文采用微服务架构对原有云测试系统进行改造。微服务架构采用DDD领域驱动设计的基本思想把单个应用程序根据领域业务分解为多个独立的服务,服务之间通过轻量级消息通信,形成分布式网络系统,服务间共同协作实现系统的功能。微服务架构主要有以下优点:(1)每个服务关注内容比较少,接口清晰,容易实现高内聚低耦合,功能扩展可以在服务内增加或扩展新服务,非常方便;(2)各服务的故障相互隔离,易于实现高可用系统;(3)每个服务技术选型比较灵活,只要符合消息接口即可。

本文采用DDD领域驱动设计的思想,经过对云测试系统领域业务的分析,将原系统按领域分解为以下几个主要的微服务:任务管理、用例管理、调度、匹配、环境管理、配置管理、产品管理、执行Slave等,通过它们的交互协作来对外提供价值。微服务架构如图2所示。

其中,对提供最核心的测试调度执行7,各微服务间的流程时序如图3所示。

各微服务间具体交互过程如下:

(1)Job服务向schedule服务发送activeJob请求;

(2)Schedule收到activeJob后,通知report服务,开始创建文件夹,准备接收执行报告文件;

(3)Schedule服务通知Match服务进行用例环境匹配;

(4)Match服务接收到请求后,进行匹配并返回结果;

(5)Slave空闲时向Schedule服务请求用例;

(6)Schedule服务向Slave指派匹配的用例信息请求执行;

(7)Slave执行完用例后向Report服务上传用例的报告文件;

(8)Report接收Slave传过来的用例报告文件,将这些文件放到对应目录下;

(9)Slave通知Schedule服务上传报告到Report服务完成;

(10)Schedule服务通知Report合并用例报告;

(11)Schedule服务判断Job服务中所有用例执行完毕,通知Report生成整个任务测试报告;

(12)Schedule服务通知Job服务完成整个任务测试。

2.3 无状态微服务设计

随着云测试日活测试任务数和用例数的增大,调度服务越来越成为瓶颈,主要有以下方面:

(1)调度服务已经支撑不了更大并行的测试任务调度执行,当任务达到1000时,就会有15%左右任务调度失败,导致任务执行失败,已经严重不能满足用户增长的需要。

(2)随着压力的增大,某些异常情况可能导致调度服务退出,在服务被重新拉起的时间内,系统核心调度不可用,云测试平台的高可用性受到严峻挑战。

基于上述2个主要原因,迫切须要采取相应的方法提高云测试调度服务的性能和高可用性。在对调度服务自身性能优化和异常保护后,进一步将调度服务水平扩展。云测试采用了微服务架构,调度服务是独立的服务,只须将调度服务多实例化,负载均衡,一方面可以提升调度服务的性能,支撑更多的测试任务调度执行,另一方面提升调度服务的高可用性,当一个服务异常退出后,其他服务会继续提供服务,不至于导致调度执行失败。

调度服务多实例化水平扩展的关键是对调度服务无状况化设计,将调度服务的状态数据从服务中独立出来共享存储,如图4所示。

在调度服务多实例架构中,无论哪个调度服务收到其他业务服务的消息,如果需要读写状态,均不访问自己的服务状态,而是访问共享存储中的状态,这样有以下优势:

(1)当业务需要请求调度服务处理时,可以根据负载均衡原则发给任何调度服务实例,而不须在一次业务会话中记住特定的调度服务实例,但如果调度服务存储状态数据,则必须保证一次业务会话中访问相同的调度服务实例,这样会增加系统的复杂度。

(2)当某个调度服务实例异常退出后,后续完全可以由其他调度服务实例完成相应的处理,对业务无任何影响。

为此,本文将调度中的主要状态数据等待队列移植到Redis中,以支持多个调度实例,如图5所示。

当用户提交测试任务执行时,调度执行过程如下:

(1)Job服务向调度服务请求激活测试任务,向调度实例Schd1发起;

(2)调度实例Schd1收到Active后,请求Matcher服务对用例进行预匹配;

(3)调度实例Schd1获得预匹配结果后,将匹配用例的预匹配信息加入等待队列并存储到Redis中;

(4)某个Slave1空闲,向调度实例Schd1发送消息来获取用例执行,调度实例Schd1收到请求后,访问Redis中等待队列中的用例预匹配信息,找到匹配的用例;

(5)调度实例Schd1发送用例信息指派Slave1执行;

(6)Slave1执行完毕后根据负载情况向调度实例Schd2发送了用例执行结果;

(7)调度实例Schd2获得用例测试结果后,向Redis更新用例的执行结果信息;

(8)如果Job中所有用例都执行完成,则更新Job执行状态为完成;

(9)调度实例Schd2从Redis中获取任务的执行结果信息;

(10)调度实例Schd2将任务的执行结果信息发送给Job服务。

从上面的流程可以看到,任何一个调度实例对所有任务数据可见,如某个Slave向调度实例Schd2上报用例执行结果时,不会因为对应该Slave的任务是通过另一个调度实例Schd1激活的而无法处理。另外,某一个实例异常时,其他实例仍然可以继续处理所有用例数据,仅对该异常实例正在处理中的数据有影响。

在上述流程中,等待队列基于Go中的list实现,现在须要修改为在Redis中存储(包括读和写),使用时须要现从Redis查询,所有对任务、用例属性的修改都要及时同步到Redis中,以便持久化。

3 微服务持续集成和部署

系统被分解为微服务架构后,整个云测试系统的持续集成实施方式就要跟随架构而变。持续集成和部署的目的是协作高效开发,当代码变动后尽快验证并可一键式部署到生产环境,达到快速反馈的目的。具体实施时须要考虑微服务代码库和构建部署流程2个方面。

3.1 微服务代码库

每个微服务放在一个独立的代码库中,在Jenkins中,每个Job关注一个微服务所在的仓库。如果某个微服务代码有变动,则触发相应的微服务Job运行构建,生成本微服务的Docker镜像8。这种方式的好处是,微服务之间互不影响,可以对某个微服务进行单独的功能测试,多个微服务之间可以并行实施。整个系统发布时,每个微服务可以对应不同的版本号,只须构建有改动的微服务,保证所有微服务配合通过验收测试用例即可,而不须要全部构建。

云测试的多个微服务在GitLab中被分解为独立的仓库,每个仓库中有对应的脚本,可以将本微服务制作成独立的Docker镜像。

3.2 微服务构建部署流程

从开发人员本地验证合入代码到微服务Docker镜像被部署到生产环境,须经过以下步骤9-10

(1)本地在git分支上开发代码,运行验收用例通过;(2)合入相关微服务代码至相应的GitLab仓库并提交合并请求;(3)GitLab触发对应Jenkins Job进行代码编译、镜像构建;(4)Jenkins上运行验收测试用例,通过后推送到Docker私有仓库;(5)运行Jenkins一键部署Job,调用部署脚本,将镜像部署到私有云中。

云测试系统已经基于Redis集群共享状态实现了多实例的无状态微服务滚动升级,因此,在替换镜像过程中服务不会中断,能够做到不停服升级。

4 应用实例

4.1 系统实现

4.1.1 微服务架构实现

根据业务领域,微服务架构具体拆分为如下11项微服务,如:任务调度Scheduler、资源匹配Matcher、产品管理Product、任务管理Job、用例管理Testcase,版本管理Version等。每个服务独立运行部署,按需单独配置DB,服务之间基于RESTful接口通信,如图6所示,箭头表示服务间有依赖关系。

4.1.2 无状态调度微服务实现

Redis是一个开源的高性能键值对数据库,通过提供不同的键值数据类型来满足不同场景下的存储需求,借助高层级的接口可以胜任如存储、队列系统以及缓存系统等不同角色。Redis的所有内容都存储在内存中,因此,读写速度较其他基于硬盘的数据库有明显的优势。将数据存在内存中也有问题,比如当程序退出后内存中的数据将会丢失,因此,Redis提供了对持久化的支持,即可以将内存中的数据异步写入硬盘,同时不影响继续提供服务。Redis是单线程模式,而Memcache支持多线程,然而Redis在大部分情况下性能不会成为其瓶颈。如果需要复杂的数据类型或持久化等功能时,Redis将会成为Memcache很好的代替品。

Redis采用内存存储,读写速度快,提供持久化支持,单线程模式共享不会冲突,且在大部分情况下性能不会成为瓶颈,因此,采用Redis作为服务状态共享存储,将调度服务的核心状态数据“用例等待调度队列”放到Redis中并对调度服务读写状态的处理做相应的修改。

云测试调度服务多实例化的关键是采用Redis存储状态数据,因此,Redis的高可用性就成为关键。Redis高可用有2种架构模式:集群和哨兵模式。本文采用了哨兵模式。Redis 的 Sentinel 系统用于管理多个 Redis 服务器,Sentinel 会不断地检查主服务器和从服务器是否运作正常。当被监控的某个 Redis 服务器出现问题时,Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。当一个主服务器不能正常工作时,Sentinel 会开始一次自动故障迁移操作,将失效主服务器的其中一个从服务器升级为新的主服务器,让失效主服务器的其他从服务器改为复制新的主服务器;当客户端试图连接失效的主服务器时,集群也会向客户端返回新主服务器的地址,使得集群可以使用新主服务器代替失效服务器,从而极大地提高了高可用性。

4.1.3 微服务持续集成实现

为了实现以微服务为单位的快速持续集成和部署发布,本文主要实现了以下步骤脚本:

(1)本地编译代码、制作镜像的脚本。

①build_me.sh

该脚本的作用是编译微服务代码,检验其是否可以编译通过,生成可执行文件。

②make_image.sh

该脚本的作用是制作某个微服务的Docker镜像。首先从私有仓库下载Docker镜像,该镜像预先安装了Go语言环境。接着把微服务的目录挂载到Go镜像中使用build_me.sh脚本进行编译。这样做的好处在于,在其他机器上(比如CI机器)就不须再安装Go语言环境。最后制作完整的Docker镜像。

(2)合入相关微服务代码至相应的GitLab仓库并提交合并请求。

开发人员提交合并请求后,GitLab会触发对应的Jenkins Job进行代码编译、镜像构建。其中Jenkins Job用到的脚本有:

①make_image.sh

该脚本和本地校验脚本是同一个脚本,Jenkins Job中引用它是为了在CI机器上生成镜像。

②run_ut.sh

该脚本可选,可以在这里进行该微服务的单元或功能测试。

(3)运行验收测试用例,通过后推送到Docker私有仓库,完成生产环境部署。

①start_at.sh

该脚本的作用是启动所有微服务镜像,包括仿真Slave镜像和验收用例镜像。让验收用例镜像中的Robot向云测试系统的Web发送请求的方式对系统进行验收测试。

②push.sh

如果验收测试通过,可以通过此脚本将镜像推送到Docker私有仓库。

③depoy.sh

运行Jenkins一键部署Job,将生产环境镜像替换为新版本。

4.2 效果评价

4.2.1 微服务架构实现效果

采用无状态微服务架构实现云测试平台系统后,取得了以下明显效果:

(1)系统的可扩展性得到显著增强,可以根据各种产品的测试需求增加相应的服务实现,比如针对不同的测试环境模型提供不同的资源匹配服务(MatcherXXX),针对不同的测试框架(如Robot和其他自研测试框架)开发不同的测试用例解析服务(TestcaseXXX)等。

(2)由于各个微服务都是在独立的进程中运行,故障隔离性好,例如用例管理TestCase服务发生严重异常退出,仅仅无法刷新用例,但对任务管理Job服务和任务调度Scheduler服务无任何影响,因此,测试调度执行仍然能够正常进行。

(3)各个服务采用的编程技术也可以不同,只要能满足RESTful通信接口即可。本系统中大多数业务模块采用Go实现,资源匹配服务Matcher涉及算法设计,则采用Python开发。

4.2.2 无状态微服务实现效果

云测试平台调度服务完成多实例改造后,系统调度的性能和可用性均大幅提升,本文用32C 64G的机器进行性能测试,预置条件:单任务设置50个用例,分别部署1个调度服务,2个调度服务,3个调度服务进行测试,在测试没有基本问题后,线上部署了3个调度服务实例提供正式服务,测试和线上验证结果如下:

(1)随着调度服务的扩容,系统支持的任务并行调度数也会明显增长,如表1所示。

(2)系统通过长时间稳定性测试,多实例同时出现异常退出服务的概率几乎为0,经过长时间验证,未发生调度服务异常退出导致的系统调度不可用情况,保证了云测试平台核心调度能力的高可用性。

(3)Redis采用高可用方案部署,发现曾经出现过主Redis切换的情况,但是系统的Redis对调度服务仍然是可用的,未造成影响。

4.2.3 微服务持续集成实现效果

采用容器技术针对各个微服务进行持续集成和部署,极大地提高了云测试平台持续快速迭代交付的能力。持续集成平均时间比原有时间下降了72%,集成频率由原来的每天1次大幅度提升到平均12次左右,做到了按需集成。

5 结语

云测试平台采用无状态微服务架构,具有高可扩展性、故障隔离性和高性能,选择适合的技术栈,可快速响应用户的需求。对各个微服务进行持续集成和部署,极大地提高了云测试平台持续快速迭代交付的能力。随着微服务架构及持续集成技术的不断深入应用,基于微服务的组装式应用和相应的持续集成方法是值得进一步研究的方向,从而持续提升软件系统的灵活性与敏捷性,提升研发效率和质量,降低成本。

参考文献

[1]洪华军,吴建波,冷文浩.一种基于微服务架构的业务系统设计与实现[J].计算机与数字工程,2018(1):149-154.

[2]张晶,黄小锋.一种基于微服务的应用框架[J].计算机系统应用,2016(9):265-270.

[3]埃里克·埃文斯.领域驱动设计[M].北京:人民邮电出版社,2010.

[4]杨宇,焦丽琴.基于微服务的企业应用设计与实现[J].电子科学技术,2016(5):623-625.

[5]李乔,柯栋梁,王小林.云测试研究现状综述[J].计算机应用研究,2012(12):4401-4406.

[6]李乔,郑啸.云计算研究现状综述[J].计算机科学,2011(4):32-37.

[7]左利云,曹志波.云计算中调度问题研究综述[J].计算机应用研究,2012(11):4023-4027.

[8]SAM N.Building microservices[M].California:O’Reilly Media,2014.

[9]林新党,穆加艳.基于Jenkins的持续集成系统研究[J].雷达与对抗,2014(1):58-61.

[10]陈刚,羌铃铃.软件项目开发中的持续集成研究[J].项目管理技术,2011(12):103-106.

(编辑 王雪芬)

Research on the application of stateless microservice architecture and continuous integration methods

JU" Weigang, WANG" Jia

(ZTE Corporation, Nanjing 210012, China)

Abstract: "As the complexity of largescale software systems increases, traditional monolithic architectures face challenges such as difficulty in horizontal scaling, performance bottlenecks, poor fault isolation, and limitations due to a unified technology stack. Additionally, the lengthy build and deployment processes of monolithic applications are not conducive to frequent updates, which hinders rapid iteration and continuous delivery of software. Microservice architecture can effectively address these issues. This paper focuses on a cloud testing platform and adopts the principles of domaindriven design to research, design, and implement a stateless microservice architecture based on Redis caching. It also applies appropriate continuous integration methods for the integration and deployment of this architecture. These improvements have significantly enhanced the scalability, fault isolation, and performance of the platform, supported a diversified selection of technology stacks, and accelerated the continuous and rapid iteration and delivery of software, achieving excellent results.

Key words: singleunit architecture; microservice architecture; stateless; continuous integration; cloud test