面向Spring的热点代码在线部署方法研究

2023-05-19 07:51万嘉龙况立群熊风光薛红新
计算机技术与发展 2023年5期
关键词:复杂度代码容器

万嘉龙,况立群,熊风光,薛红新,韩 燮

(中北大学 大数据学院,山西 太原 030051)

0 引 言

随着业务不断变更和功能持续迭代,人们对软件更新方式的要求越来越高。个人的开发经验、团体的技术积累以及需求的不断变化,都会增加软件部署的复杂度和风险。在实际开发中,项目集成以及组件的更新会消耗大量的时间,并且存在众多潜在风险,往往等到项目开发结束的时候,才可能发现这些问题,最终可能导致项目延期。持续集成与部署可以使项目实施过程透明化,进而完善开发结构,改进开发质量,降低交付风险[1]。随着国家数字化进程的推进,越来越多的项目采用这种开发方式,持续集成在应用系统中发挥着越来越重要的作用[2]。

传统上通常使用人工干预的持续化部署模式,通过各种交互式手段完成自动化流程,以此实现对应的代码部署以及功能上线。Jenkins是一款持续集成和持续交付的开源软件,常用于项目部署,不仅提供了直观友好的用户界面,而且可减少由于人工直接部署导致项目出现的系统兼容和版本冲突等问题[3]。但是这种方式不适用于部署频繁改动的热点代码,因为这将导致频繁的对整个应用程序进行重新打包以及手工部署,由此产生较高的学习成本,且效率相对较低。

目前主流的部署方式大多采用Docker等虚拟容器,其本质上是一个内部封装Jenkins或与Jenkins同类插件的系统[4-5]。虚拟化的持续化部署方式可以减少系统开销,同时增加容器化的可移植性[6-8]。如果直接将应用部署到系统中,一旦系统环境发生变化,会引发应用程序的运行风险。虚拟容器的部署方式降低了部署难度和部署风险,并且在代码频繁改动的环境下,可以提高部署效率。但是,该方式仍然需要打包部署全部应用程序,无法仅针对局部热点代码进行部分编译部署,因此没有从根本上解决热点代码部署效率低下的问题。

针对热点代码部署效率低下的问题,该文借鉴低代码设计思想,提出一种面向Spring的热点代码在线部署方式,为专业计算机从业人员提供新颖的软件开发部署模式,提升代码质量及部署效率[9-10]。该方法根据Bean容器找到对应的算法代码段进行数据抽取,利用在线部署的方式对代码进行编译、注册及替换等操作,实现局部业务功能的在线更新。该方法应用于新型智慧城市评估系统,通过测试热点代码的频繁更新迭代,验证了在线部署模式的高效性。

1 在线编译的容器化加载机制

Java的编译分两个部分,首先将源文件编译成字节码文件,然后字节码文件被虚拟机加载以后变成机器码[11]。对于开发者来讲,主要的关注点在第一部分。在Spring的在线编译中,应用内设置锚点,应用外编译代码,再将指定的功能加入到应用程序,这种在线编译的加载机制可将代码信息按照自定义格式加载到对应的环境中。而容器化的机制是将编译好的对应代码加入到Spring容器管理目录,其关键思想是将新增的功能代码直接加载到应用,无需拉取所有代码进行编译发布[12]。

在线编译的容器化加载机制如图 1所示。前台将代码与类名称传入服务端,构成输入参数,将其连同程序构建的编译参数、输出参数以及程序错误输出参数一起传入到JavaCompiler编译工具类。待JavaCompiler执行成功输出对应类的class文件,如果执行失败将在程序错误输出中写入失败信息。容器化过程将类名称转化成相应的Bean名称并构成Bean定义,连同class文件一起传入Bean工厂,由Bean工厂生成相应的Bean容器并添加至Spring容器列表。

图1 在线编译的容器化加载机制

2 热点代码在线部署方法

2.1 在线部署流程

在线部署模块是由容器配置模块、热点代码编译模块和容器装载模块组成。用户按照定义好的格式在容器化管理列表的代码编辑功能页面下进行代码编辑,并通过代码检查。前端将代码信息传输至在线部署模块的服务端,服务端对获取的信息进行解析,确定符合容器定义规范后,再对代码进行编译并生成编译文件。在线部署模块将对应的文件传输到系统指定的目录下,通过Spring将文件注册到Bean列表,并交由Spring进行管理,具体流程如图 2所示。

当应用系统新增功能时,应用系统首先要调用API实例化容器,然后提取相应的属性信息,最后由在线部署模块将应用数据装入执行单元,完成功能的调用。系统维护的过程中,如果目标执行功能有变动,需要对目标执行功能进行卸载再由在线部署模块完成功能的新增。而在执行功能卸载时,应用系统需要通过容器化管理列表查询Bean容器的信息,在Spring中将该容器卸载,在线部署模块通过查找元信息中存储的类名来删除对应的编译文件,同时删除存放的Bean信息和类文件。

2.2 容器配置模块

容器配置模块是基于当前流行的React框架并使用NodeJs进行编译的前端平台。该平台使用React语言主要基于两方面的原因,一方面是React使用虚拟Dom对页面进行渲染,这种方法比直接操作Dom树速度更快,另一方面React可以对功能细粒度进行封装,从而提升组件的复用,且手动优化性能更加便利,所以大型项目往往都会选择React作为基础框架[13]。

图2 热点代码在线部署方法

如图3所示,容器配置模块是由容器化管理列表与对外提供服务两个部分组成,其功能是为系统提供应用管理、代码编辑以及对外服务的API。其中应用管理的功能是为在线部署模块展示注入的应用功能状态,以及对应用功能进行基本操作。而代码编辑模块为容器化管理列表提供代码编辑和代码检查的功能,方便使用者能够摒弃繁琐的配置,专注于指定功能的代码编辑。为了使系统更加方便地调用容器配置模块所构建的功能,在容器配置模块中加入了对外服务的API,使应用系统能够依靠简单的配置就可以完成对注入功能的测试,同时也能为容器化管理列表提供对应的功能索引,方便进行应用功能的基本操作。

图3 容器配置模块结构

2.3 代码编译模块

代码编译模块使用了Java软件开发包中自带的java-tools动态编译模块,可以对字符串构成的代码进行编译,并能提供丰富的编译接口。该模块将从前端传输来的代码和元信息存储到数据库,并将数据库中的对应状态标记为传输完成。随后,代码在该模块进行编译,如果编译成功,模块生成编译文件,并将生成的文件放到指定位置,然后把编译成功的状态传输到容器装载模块,接着执行后续操作。反之将编译失败的信息,连同对应的元信息一起传输到数据库中,并将数据库中的对应状态标记为编译失败。

常规采用的重新编译部署方式如图4的上部分所示,重新编译部署方式在功能修改时,由用户开发好相应的功能代码,并将代码上传至代码管理平台。用户要完成应用的部署还需使用持续集成工具Jenkins,将代码拉取至服务端,Jenkins在服务端对代码进行编译,然后编译生成Jenkins构件,启动构件即完成部署。该文采用基于在线部署的编译方式(见图4下半部分),用户是在在线部署模块中进行编码,服务端仅负责接收和编译由在线部署模块传输过来的代码,之后将生成的文件通过Spring的环境直接注入到系统中,进而完成项目的部署。与重新编译部署方法相比,在线部署编译方式减少了代码拉取以及构件启动的时间。在应用功能未确定时,功能的改变会引发频繁部署,采用在线部署方法可以节省很多的时间。

图4 重新编译部署与在线部署的编译方式对比

2.4 容器装载模块

容器装载流程如图5所示。

图5 容器装载流程

容器装载模块将Spring应用环境的上下文实例化,通过加载具有复合注解的代码,将应用功能注入到Spring环境。该模块从编译模块获取编译成功的文件和元信息并加入到Bean处理单元,然后将新生成的Bean容器注册到Spring环境。如果注册成功,则依据元信息在数据库中找到指定记录,并将其状态更新为部署成功,然后把对应的状态写入到日志管理器,反之,注册失败则标记部署失败。

容器注册的核心是将热点代码转化成Bean容器。对所需功能注册时,将类名与Bean的ID进行绑定,保证在Bean注册机制下,注册的容器是唯一有效的。容器是整个Spring环境的重要组成部分,在应用系统中,Bean的实例化获取与销毁都由Spring进行管理。如图6所示,当在线部署某一应用程序时,采用不停机的工作模式,事先定义好该程序的计算接口和数据信息接口,然后在代码编辑模块中实现上述两个接口。其中,计算接口用于实现具体的应用功能,而数据信息接口用于实现容器配置模块对应用功能的管理。接口代码完成编译后,Spring调用Bean管理器将转化好的容器注册到容器列表,为代码无侵入做准备。应用在停机部署时,卸载在线部署模块不会影响系统的使用。依据不同开发阶段的要求,在线部署模块可以灵活制定相应的部署策略,降低开发与运维的工作难度,保障系统的稳定,降低项目管理成本。

图6 运行与停机状态下的容器注册方法

3 性能测试与分析

3.1 实验环境

实验的硬件环境是Intel(R)Corn(TM)i7-7700HQ CPU @ 2.8 Hz 2.81 GHz,内存为8 GB,软件环境为windows tomcat idea2022。实验在Spring官网下生成空白的项目,添加相应的功能构建不同复杂度的系统,以便对比不同部署方式的部署效率。

3.2 评价标准

为了评估应用在不同软件复杂度下的在线部署方法与重新编译部署方法的效率,采用不同维度下的软件复杂度进行实验,衡量软件复杂度的常用度量方法,包括代码行数度量法和Halstead度量法。其具体构建如下:

代码行数度量法在空白项目中写入100行代码形成一个请求单元,标识系统拥有100的复杂度,将代码请求单元扩增至10个请求单元,可以使代码行数复杂度增加10倍,变为1 000的复杂度,以此类推,构建10 000、100 000的代码行数复杂度的测试项目。同理,使用Halstead度量法构建不同复杂度的项目,向空白项目中写入定义好的度量单位为100的模块,以此为模板扩增,与代码行数复杂度一致,分别增加至10 000和100 000的复杂度。度量单个单元复杂度的Halstead公式如下所示:

Mcount=0.05(N+N1)

其中,N为程序词汇表的长度,N1为程序长度,为了与代码行数度量法的对比更加直观,设定了0.05的系数。

3.3 实验结果

对重新编译部署与在线部署两种方法在时间效率上进行对比,从程序开始编译计时,到实际应用部署为止,得出各自所需的时间。实验中选择不同度量法下的不同系统复杂度,在进行10次相对独立的实验后取平均值。其中T1表示在线部署的时间,T2表示重新编译部署的时间,T1/T2是两种部署模式下的时间比值。

表1 两种部署方式在代码行数复杂度下的对比

表2 两种部署方式在Halstead复杂度下的对比

如表1和图7所示,随着代码行数复杂度的增加,在线部署的时间明显小于重新编译部署的时间,并随着代码行数复杂度的增加,时间比值在逐渐下降。如表2和图8所示,Halstead复杂度和代码行数复杂度的结果基本一致。结果表明,在线部署比重新编译部署效果更好,推广到现在大规模、复杂性高的系统中,运用该热部署方法部署代码更有利于节约时间和资源。

图7 两种部署方式在代码行数复杂度下的对比

图8 两种部署方式在Halstead复杂度下的对比

4 系统应用

该文提出的在线部署方法应用于新型智慧城市评估系统的评估体系构建模块。随着城市的不断发展,城市评价的指标体系也在不断地进步,指标计算也越来越复杂。在系统业务开发的过程中,对城市评估的评估体系往往考虑得不够全面,所以在系统运行初期,会不断地调整指标中的评估算法,与之相对应的测试环境以及预生产环境的应用也需要频繁地部署。针对这种情况,系统为其设计了可在线编辑的指标计算模块,该模块通过在线操作完成新指标的部署。

当用户对指标计算模块编辑时,先在指标编辑的模块中对指标计算的算法进行编辑,之后系统根据算法的名称和配置构建元信息,将代码连同元信息一起传输到系统后台,并在后台对算法进行编译,然后将编译后的文件通过Spring注入到容器列表,即可完成对应指标的部署。在对城市评估的时候,评估系统使用元信息查找到对应的算法,完成指标的计算。该在线部署方法为在线评估系统的指标拓展计算提供了思路,同时很好地解决了频繁部署热点代码的问题。

5 结束语

研究了基于Spring的在线热点代码部署方法,并在新型智慧城市评估系统进行了验证。在系统部署的过程中,运维人员会将所有的代码拉取到服务器中,对应用重新部署。功能应用在频繁改动的时候,重复拉取代码后进行部署,很容易导致一些问题出现。该方法能够使应用系统集成的在线部署模块在不停机的状态下,稳定地增加功能,并以较快的速度部署,同时在应用必须停机时,卸载在线部署模块,零配置重新部署功能 。该文设计的在线部署方法有望在紧急上线、预生产环境调试等环境下发挥作用[14-15]。

同时,该部署方案还有进一步完善的空间。在应用过程中热点的代码只能修改单独的类,只能在线单独改变其中一个功能,这种方法免去了代码的整包构建,提升了速率。但是这种方案仅仅只能在热点代码中使用,不适合大范围的修改代码,此外对于复杂环境的分布式系统,还需要考虑各个层级的依赖问题。

猜你喜欢
复杂度代码容器
Different Containers不同的容器
难以置信的事情
一种低复杂度的惯性/GNSS矢量深组合方法
创世代码
创世代码
创世代码
创世代码
求图上广探树的时间复杂度
某雷达导51 头中心控制软件圈复杂度分析与改进
取米