APP下载

一种基于有限状态机的分布式框架配置属性校验方法

2022-01-17刘怡然谢鹏飞邓雪峰

关键词:配置文件校验容器

刘怡然,谢鹏飞,邓雪峰

(1.山西农业大学 信息科学与工程学院,山西 太谷 030801;2.北京微梦创科网络技术有限公司,北京 100080)

随着软件模块化技术的发展和软件编程工具的日益丰富,各种编程框架简化了系统的开发过程,通过对现有的框架进行配置可以构建出软件的基本结构,把软件开发者从复杂的环境配置中解放出来.动态配置技术支持软件的在线演化,能实现多样的服务质量(quality of service,QoS)控制,是目前许多软件系统和构件都支持的一种配置方式,在分布式系统和实时系统配置中尤为重要[1].然而,动态配置的加载流程在使服务更加灵活的同时,也存在配置错误导致系统崩溃的风险.修改配置文件可能会引发一系列潜在的问题,在测试阶段无法被发现,一段时间后可能会因为网络环境的改变导致系统的崩溃[2].另一方面,一些框架没有回退(fallback)机制,一旦配置的数据类型出了问题,会导致服务不可用.即使框架支持了回退机制,软件的容错机制会使配置修改后不生效,也并不符合用户的期望.基于此,文中拟提出一种模型驱动的动态配置校验方法,解决软件动态重配过程中配置格式错误导致的问题.

为了给用户提供不间断的服务,动态地进行资源分配,许多当前流行的分布式系统框架都提供了配置管理支持,用于管理应用程序的外部属性配置,如Spring Cloud Config、Spring Cloud Consul、Apollo和Nacos等[3].国内外学者一直对分布式系统的配置管理问题保持关注,配置管理主要包含权限管控、灰度发布、版本管理、格式校验和安全配置等流程[4].如M.ZNIGA-PRIETO等[5]提出了一种动态和增量架构的云服务重配方法,该方法允许开发人员将新服务指定为软件增量,并实现了生成服务集成逻辑,作为服务部署和重构架构脚本的工具.尤其针对分布式框架的配置格式校验,S.KIKUCHI等[6]开发了一种利用UML/OCL验证从现有基础设施的配置信息中提取参数配置策略的方法.这些方法实现了配置的动态管理,但缺少对属性数据类型的正确性校验,在数据类型配置错误时会产生报错.

为了确保服务能够正常执行并满足其预期目标,其属性必须在正式执行之前进行验证.文中拟基于有限状态机实现配置格式校验逻辑,将配置提取出来,通过对属性数据类型的转换验证其正确性,以期使用户修改的配置正确.

1 分布式框架配置校验方法

当前主流分布式框架常见的配置文件格式主要有.properties、.json、.xml、.yml等,如Spring Cloud支持采用.properties和.yml格式进行配置,Hadoop和Spark支持采用.xml格式进行配置.通过研究当前主流分布式框架的环境配置过程,设计了一种分布式框架配置校验方法.

1.1 总体设计

配置文件格式错误会导致客户端解析配置失败引起生产故障,对配置的格式校验能够有效防止人为错误操作的发生,是配置管理中非常核心的功能.为了实现配置文件的格式校验和数据类型校验,系统的主要功能包括以下3个方面:① 配置文件解析,即解析各种类型的配置文件,将配置内容提取出来,转换成容易处理的键值类型;② 配置属性解析,即对抽取出的key进行解析,获取目标数据类型;③ 数据类型校验,即校验并转换value的数据类型.

因此,该校验方法主要功能由配置文件解析器、配置属性解析器和数据类型校验器3个部分完成,其流程见图1.

图1 总体设计图

1.2 配置属性解析设计

为了获取正确的目标数据类型,对常见数据类型的表示进行统一约定,如表1所示.约定原则如下:① 对简单数据类型如String、int、Double等,使用类型的首字母替代,如果有冲突,用该数据类型的第2个字母替代;② 对于容器数据类型如List、Map、Set等,使用2个首字母分别标志容器的开始和闭合;③ 支持容器数据类型的嵌套.

表1 常见数据类型的表示举例

1.3 有限状态机的状态拆分

有限状态机又称有限状态自动机(finite-state automation,FSA),简称状态机,是表示有限个数的状态以及在这些状态之间的转移和动作等行为的数学计算模型[7].它可以用来对对象行为建模,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件[8].有限状态机模型由一个5元组构成,记作M=(S,E,f,S0,Z),其中:S表示状态;E表示条件(输入);f表示状态转换函数;S0是S的一个子集,表示初态;Z表示次态(终态)[9].构建有限状态自动机的5个元组,并将状态和事件进行解耦,主要步骤如下:

1)确定状态.文中定义了Start、SetStart、SetEle等9种状态,由于一次只解析一个数据类型,容器闭合就代表着解析结束,所以没有对各个容器设置结束状态.End为结束状态.9种状态代表的含义见表2.

表2 状态名称及其代表的含义

2)拆分事件.事件是扫描到的每一个字符,由于字符种类较多,而int和Double、String和Long的处理非常相似,文中将事件类型抽象为原始类型元素(PRIMITIVE_ELE)、包装类型元素(WRAPPED_ELE)、Map、List和Set类型5个事件,每个事件代表的含义见表3.

表3 事件名称及其代表的含义

3)绘制状态转换图(表).状态转换图(表)能够清晰地表示各个状态和事件之间的转换关系.用于数据类型校验的状态转换图见图2.

图2 状态转换图

1.4 基于FAM的数据类型校验器设计

借助栈结构后进先出的特性,基于有限状态机设计了数据类型校验器校验的总体流程,如图3所示.

图3 数据类型校验器处理流程图

2 基于FAM的校验方法实现

Spring Cloud是一个完整的微服务解决方案,它提供分布式情况下的各种解决方案合集,其中的Spring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持[10-11].文中基于有限状态机在Spring Cloud Config框架中实现了所设计的配置校验方法.

2.1 基于Spring Cloud的校验方法

在Spring Cloud框架下实现配置校验方法的总体思路如下:在服务外通过 ApplicationContext 类重新启动了新的Java进程,并在新进程里实例化构造出来的Java类;如果类实例化过程中出现问题,即可说明配置是有问题的,捕获新进程的报错可以识别错误信息.然而,把各个字段解析完成后放到类模板中时,所生成的Java类需要动态编译成字节码.JavaCompiler的默认实现都是通过文件进行的,输入和输出都在内存中进行,所以需要修改JavaCompiler的实现,以实现不中断的服务.

2.1.1Spring Cloud的动态配置流程

Spring Cloud进行动态配置时,先将动态配置通过@Value注入到一个动态配置Bean,并将这个Bean用注解标记为@RefreshScope.在配置变更后,这些动态配置Bean会被统一销毁,之后Spring Cloud的ContextRefresher会将变更后的配置作为一个新的Spring Environment加载到ApplicationContext对象中,由于Scoped Bean都是懒加载(Lazy Init)的,它们会在下一次使用时被使用新的Environment重新创建.

2.1.2动态编译和Spring Bean实例化

JavaCompiler通过JavaFileManager管理输入和输出文件,使用时通过getTask()方法提交一个异步CompilationTask进行代码编译,代码编译时,JavaCompiler通过getCharContent()从传入的compilation-Units获取到 .java 文件内容,把编译后的结果调用CompiledByteCode的openOutputStream()方法写到CompiledByteCode对象里.

JavaCompiler的默认实现都是通过文件进行的,为了避免不必要的文件读写,对JavaCompiler进行了改进,让编译过程的输入和输出都在内存进行,如图4所示.JavaCompiler、JavaFileManager、Java-FileObject(Input/Output)等分别使用委托模式实现.

因为新编译的字节码是懒加载的,所以要显示获取.要让Spring能够加载到这些编译好的字节码,需要类加载器的配合,可以新加一个ClassLoader来实现,如图4所示.

图4 对JavaCompiler的改进

2.2 有限状态机实现

为了转变解析状态并将结构结果保存起来,将事件整体抽象为一个事件处理器接口.该接口的定义如下:

public interface StateHandler{

/**

* @param event要处理的事件

* @param states系统整体状态

* @param result解析的结果

*/

void handle(Event event,Stackstates,StringBuilder result);

}

将状态机的各个要素都抽出来之后,再分别完善每个StateHandler的处理逻辑.为了处理容器的开启和闭合,可以考虑使用栈来保存预期的下一个字符类型,再对比栈顶字符类型和当前处理字符,决定解析的结果.还要注意类型嵌套的情况下,内层嵌套的容器作为外层容器的元素被解析完成时,需要修改外层容器的预期字符.有别于对Set容器和List容器的处理,Map容器还要处理它的左右元素.同时还不能忘记处理各种异常,如未知字符、容器内是原始类型、容器未正确闭合等.例如,MapLeftHandler的处理流程见图5.

图5 MapLeftHandler处理流程图

3 测试和分析

为了证明该方法的有效性,基于Spring Cloud Config框架对配置校验功能进行测试,设计了各种数据类型的测试用例,几种典型的测试用例见表4.目标数据类型指的是配置文件要求的数据类型.

表4 测试用例示例

由表4可见,在实现了该配置校验的系统中,如果配置文件所有属性数据类型正确,则配置文件可以正常生效,不提示错误;如果存在错误,则会产生错误提示.可以检测的错误类型包括简单数据类型不匹配、数据溢出、容器类型未闭合、容器类型内数据类型错误、容器类型嵌套错误等.

4 结 论

1)文中提出了一种分布式框架动态配置属性数据类型校验方法,提供了一种比较清晰的配置属性数据类型校验逻辑,能够通过动态编译实现对配置文件数据类型的校验,为实现框架配置管理的校验功能提供了参考.

2)由于基于状态机的实现逻辑拆分清晰,在添加或删除一种状态时比较方便,使系统有较高的可维护性.相比常见的IF-ELSE结构,实现了代码解耦.

3)改进了Java编译器的实现,避免了不必要的文件读写,提高了执行效率.

4)在实际开发环境中使用该分布式框架配置校验器,能够解决实际配置过程中可能出现的配置校验问题,具有较高的实用性.

猜你喜欢

配置文件校验容器
基于Docker的实时数据处理系统配置文件管理软件的设计与实现
复杂多耦合仿真模型校验工具研究
使用Excel朗读功能校验工作表中的数据
电能表在线不停电校验技术
从Windows 10中删除所有网络配置文件
用软件处理Windows沙盒配置文件
难以置信的事情
互不干涉混用Chromium Edge
精通文件校验的“门道”
液体对容器底及容器对桌面的压力和压强