教你设计一个最简单的微服务
原题:《枚举常量数据字典微服务设计》
作者:汪照辉 王作敬 中国银河证券股份有限公司 信息技术部IT研发中心
枚举常量数据字典微服务,是一个基础的相对简单的微服务,算是一个起手式。
前面我们讨论了《微服务实施从数据梳理开始》(点击标题可回顾),最简单的微服务可以从枚举常量数据字典微服务开始,这是也是我们在数据库设计和数据定义绕不开的一个部分。一些字段的取值是枚举值,这些值是整个系统通用的。推广一下,如果这些枚举值标准化,扩展到整个部门、整个公司甚至整个行业,是不是在共享和互连互通方面就简单很多?大家标准是一样的,不需要转来转去,这也是微服务架构实现唯一数据来源的必须做的前提:数据标准化。
数据标准化之后,基于这些标准化数据就可以方便地快速地构建服务、组件和应用系统。鉴于每个系统都少不了很多枚举常量值,所以我们把枚举枚举值进行梳理,实现一个枚举值数据字典微服务,它是一个基础的相对简单的微服务,算是一个起手式。
一、数据梳理
第一步就是要对这些枚举常量进行梳理,一个单体系统梳理起来可能很简单,但如果多个系统放在一起,同时支持多个系统的枚举数据字典,就复杂很多。前面我们也提到过,简单的性别字段,其取值在不同的系统中就可能有多种,更别说其他复杂的字段取值了。数据梳理可以采用主数据实施的方法,以一个核心系统数据为基础,比如说CRM,逐步扩展支持其他系统。枚举常量数据字典的设计相对简单很多,把所有字段的枚举值都找出来,然后根据实体含义和业务场景进行分析梳理,先实体后元素再取值,主-枝-叶逐步梳理。字段枚举取值数据梳理中几个常见问题需要考虑。
二、字段名相同,含义不同
在不同系统中,你可能发现,一个相同的字段名分别在两个系统中代表不同的含义。比如客户类型,在不同的系统中可能完全不是一回事。可能是个人客户、机构客户等,也可能是普通客户、金卡客户等,或者是境内客户、境外客户等。这是由于不同场景数据代表的含义不同,有一定的适用范围。在做数据标准化规范化时,也不能简单的合并了之。需要考虑其数据域,也就是使用范围。比如客户实体在每个域都会存在,但其元素可能会不同,所以即便是相同的元素名称,其代表的含义可能不同,取值也不同。这样的问题一般通过域前缀来区分,明确其数据含义。
三、字段名不同,含义相同
还有就是不同的字段名却代表相同的含义,比如Currency和MoneyType都表示货币类型,含义和取值都是一样的,但是却是两个不同的命名字段。我们甚至在同一个系统提供的接口中发现有这样的命名,给我们的系统服务集成带来一些小麻烦。相同含义不同命名的字段需要标准化,映射为统一的标准化名称。我们做数据梳理、数据标准化不仅仅是为了标准化,更多的应该是一种意识、一种习惯。
四、取值范围不同
数据域确定,梳理同一域内的数据,你也可能发现,元素相同、含义相同,取值可能不同,就像我们提到的性别,有取(男、女),也有(男、女、其他),或者(男、女、未知)等,这就需要把这些不同的取值基于实际业务实现标准化。但我们基于一个系统要兼容其他系统的标准化字典定义取值范围可能面临着几个问题:
取值范围小
基准系统的字段取值范围可能没有其他系统的取值那么多,这种情况下就需要根据实际各系统的取值扩展字段标准取值范围。比如基准系统性别是(男、女),另一个系统是(男、女、未知),这就需要将“未知”这个取值添加到“性别”字段的取值范围内。中文不同词汇意思是不一样的,有差别的,“未知”和“其他”所表示的意思是不一样的。如果性别取值中还需要表示其他意思,也可以把“其他”添加到“性别”字段的取值范围内(不建议这么做)。取值范围大
取值范围大,这倒相对简单些,不需要扩展,也就不涉及代码、配置等的修改。以基准系统的字段取值范围作为标准取值范围就可以了。取值范围交叉
取值范围交叉,这种情况呢是上面两种情况的结合,基准系统多的可以不管它,少的扩展以支持需要兼容的系统字段的取值。
五、键值编号不一致
键值编号不一致倒是也很正常,毕竟不同系统是由不同的人员来开发的,枚举值键值编号没有统一的标准可以参考,基本上都是开发人员自己来定义,还有不少是硬编码到代码中的。我们既要兼容不同的系统,又要标准化,这处理起来稍微麻烦点。不同系统和标准的字典取值需要建立对应的映射关系,根据系统代码来实现源系统和标准字典之间的转换。一旦这些旧的历史遗留系统都被替换,那么就只有标准字典定义了。
六、编码不同
还有就是不同系统编码可能不同,这也是我们需要考虑的一个方面。当然更多是的需要在集成系统的Adapter中来实现转换。但要实现标准化时,一个公司也需要考虑数据的标准编码格式。
七、字段可取多值
最麻烦的可能是枚举类型在系统中可以同时取多个值,存储时以分割符分割作为一个String存储。可能这个字段是多选的,可以同时取多一个或多个值,这种情况可能连取值范围都比较难以确定。有时候系统需要先跑起来再说,文档也不全,或者忘记了,整理起来就比较麻烦些。比如产品的销售渠道,可以是网站、app、柜台等多个渠道。这在转换时需要根据分割符进行处理。
八、定义数据模型
数据梳理过程中可以逐步定义数据模型,数据字典是全局公用的服务,相对来说也时比较简单的基础服务。我们可以定义枚举值数据字典和字典详情两个实体和源系统枚举值数据字典和字典详情映射关系模型。
九、确认接口需求
标准化之后,所有新的业务需求都按照标准的字典定义来使用。旧的历史遗留系统,还需要继续它们的使命。跟这些系统的集成可以按照ESB的集成方式实现。对枚举值数据字典服务的接口存在查询和维护需求,以及源系统字典和标准字典之间查询和映射转换需求。因此我们:
1、至少需要提供枚举值的查询和标准字典值和源系统字典值之间的转换服务。
2、提供维护更新操作,可以对数据字典进行添加更新删除。通常可以提供一个UI来实现;如果存储在文件中(比如XML文件),可以直接编辑文件。
3、考虑到频繁操作数据库或文件不是一种比较好的方式,我们把这些基础数据在应用服务启动时加载内存中,如果这些数据发生了变化,需要实现主动更新通知。在数据字典更新后,通知所有的应用服务,更新缓存在内存中的数据字典内容。这样以client/server的方式实现,类似于配置中心的设计。
十、定义接口API
根据接口需求,我们定义了查询所有枚举值数据字典API 和按照sysCode查询某一系统的枚举值数据字典的API,按照ID查询的API,示例如下:
标准字典值和源字典值之间的映射转换在应用服务中集成数据字典Client模块实现。
十一、加载内存
数据字典服务是基础的服务,可以说每个微服务都会用到,这就面临着频繁的操作需求。不管使用HTTP restful或者其他方式通信,我们觉得都不是一种很好的方式。从性能方面考虑,为了支撑这样高频度的操作,减少不必要的服务调用,可以把数据在启动时加载内存。实现方式和配置中心数据配置的实现类似。系统初始化时,把相应的系统数据字典信息按照业务应用的需求统一加载到内存,在内存中实现数据字典的查询和转换。
十二、自动更新管理
数据字典值发生改变,在不影响运行时服务的情况下,能够自动更新数据字典枚举值也可能是一个潜在的需求。其实我们采用配置中心的设计方式来实现枚举值数据字典服务,也是为了满足这样的需求。这样可以很方便的集成其他系统,或者在旧系统被替换之后方便的从枚举值数据字典中把过期的信息移除。我们使用的文件来存储枚举值数据字典的影射关系,采用配置中心配置更新的设计,由一个任务来监控这个文件的变化,一旦文件改变了,触发通知机制,通知所有的服务更新其内存中的数据内容。
自动加载内存和自动更新管理都在数据字典client模块中实现,应用服务仅引用该模块,使用其提供的数据转换函数,专注于实现业务应用功能即可。
十三、建立OpenAPI文档中心
服务实现之后,需要对外开放接口。不管是面向公司内部团队之间的API,或者面向公司外部的OpenAPI, 都需要提供实现的API文档说明,以帮助其他团队成员快速的查找和理解我们公开的API接口用途用法。API描述自身结构的能力是OpenAPI魅力的所在。
互联网的思维越来越普及,现在项目基本上也都采用互联网项目的前后端合作的开发形式,后端开发好接口API供前端使用。API接口是标准化的,所以后端也不需要知道这个API接口被谁使用,什么时候使用。当API接口发布出去,前端的应用基于API文档描述和API测试来使用API。 前端和后端的联系也变成了标准化的API接口。API文档变得越来越重要,它变成了前后端开发人员联系的纽带。采用微服务,建立OpenAPI文档中心,对外提供统一的API文档服务,也是一个需要考虑的问题。
目前Swagger框架一个很强大的OpenAPI文档管理工具,它是由一系列核心工具支持,用于设计、构建、归档RESTful APIs。包括Swagger Editor、SwaggerUI、Swagger CodeGen等工具。它只支持restful API接口。一些API的实现也不一定都是Restful的,其实也没必要,就像我们前面提到的,枚举值数据字典也可以在应用初始化是加载内存,这样更合适。也可能会用到Java API接口或者JMS API接口。根据实际情况来决定就是了。当然要想使用Swagger,必须使用restful API。
到后面你会发现,很多API都已经Deprecated了,这也说明微服务体系已经成熟了。就像蝴蝶,总要经历从虫到茧到蝶蜕变,才能成为漂亮的蝴蝶。当然在这个过程并不是一帆风顺的,需要做好各项管理和治理工作,最后才能蜕变为蝴蝶而不是成为笨重的蛾子。
十四、最后
我们讨论的枚举常量数据字典微服务只是个相对简单独立的一个基础服务,也可以使用配置中心的思想来实现,不用单独建立枚举值数据字典微服务,但我们觉得这是一个理解微服务和尝试微服务的比较好的切入点。我们ESB实施时实现了一个枚举常量数据字典服务,但基于性能方面的考虑,数据字典映射转换的实现是在内存中实现的,毕竟枚举值数据字典和系统关联比较大,使用的地方比较多,转换频繁,所以我们采用配置中心的设计,在应用初始化时加载内存中,并提供相应的方法来供服务来使用,避免频繁的远程调用。
更多相关内容,请点击阅读原文
长按二维码关注公众号