前言:
惠农网是一家农业B2B电商平台,用户规模在国内农业垂直电商平台中领先,对比2C的平台,用户规模不算大,但电商业务功能还是比较复杂的。惠农网目前采用的是sprincloud的微服务架构,整体的微服务架构也通过几年的磨合之后,逐步形成了适用于惠农网这类中小型电商的架构。
问题分析:
随着业务的增加,微服务的个数也在逐渐增加(从十几个服务逐步增加到了近百个微服务)。目前服务端面临了每个微服务在调用其他微服务的时候都需要定义请求参数和返回参数的bean。另外,因为公司是基于springcloud作为的微服务基础框架,所以也要定义对应的feign-client以及fallback的处理逻辑。 这样就无形多了很多工作量。对于目前面临的情况, 以及后续服务进一步增加,必须要做出一些改变和优化。
项目目标:
- 能够开发一些自动化的工具和定义一些标准化的方式,来尽量减少服务的调用方的工作,从而解放开发者的部分重复的工作。
- 能够发现接口定义时存在的参数不标准的情况,以便及时进行改变
- 能够统一管理所有的定义的bean和接口,形成统一的标准
探讨过程:
针对这个问题,我们翻遍了互联网上的各种资源,有没有找到一个特别合适的方法。
所以没办法,那只能根据我们自己的实际情况触发。采用合适的方式来开发适合自己的客户端sdk
经过内部的讨论,总结出了三个派别的意见
方案一
不做任何处理,继续还是按现在的模式,毕竟已经存在这么久了,大家都适应了这种工作方式,也没有觉得特别别扭。
存在的问题
多个项目重复定义相同的bean
重复开发一样的代码,浪费工作时间
服务端提供的说明文档不清晰,需要多方进行沟通
虽然这个方式,没有任何改变,但是开发者工作量还是有一点大,所以我们既然要讨论方案,就不可能一成不变,所以我们要继续探索。
方案二
整体思路
每个服务定义一个api项目,每个服务提供者把接口的bean和feign-client写入到里面,然后做成jar包。
deploy到maven,使用方直接依赖jar包,并且使用jar中间的bean和client来进行调用。
方案优势
客户端只需要引入对应服务的api项目,并且直接使用就可以了,减少了定义的地方
实现步骤
每个微服务定义一个api项目
把接口bean定义在这个api项目里面
编写所有接口的client的定义
生成jar包,然后进行deploy到仓库
其他服务在使用的时候进行依赖写入
存在的问题
对于已经存在大几十个服务的情况下,要补充每个服务的api项目,是一个工程量巨大的过程,而且每次更新和发布都要依赖开发者进行开发。并且与现有项目进行了深度耦合和绑定,不利于扩展,并且现在有大量服务没有定义api模块,添加起来工作量巨大。
通过约定的方式,是没有统一的标准的限定的,每个人代码都需要检查
对于新人,要进行对应的培训,沟通成本很大
大部分项目都要依赖十几个服务,需要引入十几个依赖,依赖项目太多,不好进行管控
这个方法是网上的主流方法,但是针对以上的问题,感觉到明显开发和维护的成本大于带来的便利,最终还是放弃了这个实现方法。
方案三
整体思路:
学习openapi-generator项目的处理方式,通过 mustache + swagger + openapi3 的标准来生成feign和request/response的对象
方案优势:
可以通过旁路来进行生成,不依赖项目的发布和修改
统一标准,自动化生成,不再需要人肉去进行生成,提高生成效率
可以检查bean定义的规范,避免一些人用map类型进行定义
代码更新之后,重新发布也快速和方便,维护也进行统一
灵活方便,要提供的功能只要是openapi3协议支持的,都可以通过标准协议来生成
实现步骤:
通过eureka可以拿到所有服务的地址
通过统一的路径/v3/api-docs来获取标准的openapi3的文档协议
通过指定好的mustache模版,根据服务名称来生成对应的模块和包,并且包含了对应的feign-client代码
统一项目进行deploy
使用放只要引入这一个项目, 按照服务名称就可以找到对应的接口了
可能存在的问题:
多次发布定义的bean有改变,可能会导致编译时期出现错误。如果遇到问题,应该在编译期间就会出错,并不会对线上造成任何问题, 也可以进行修改之后在重新编译发布
这种方式,从利弊分析,优势大于存在的问题,而且openapi官方也是采用的这种方式,生成了各种语言的sdk,
经过讨论,最终决定,通过这种方式来进行技术落地
Doraemon项目工作大体流程
image项目结构及使用方式
image整体的项目分为了两个模块
(1)doraemon-generator 这个项目用于在eureka上面获取配置信息,根据配置信息,过滤掉一些不符合规范的服务,和排除一些不需要给服务端调用的接口地址,然后通过模版来生成代码,并且代码生成到了doraemon-api项目里面
(2)doraemon-api 这个项目用于进行deploy,给其他服务进行引用
生成的部分代码截图
image
(3)doraemon 这个项目是整体的父项目,对子项目进行管理
编译整个项目 mvn clean package
通过脚本来指定对应的服务来生成 doreamon-api 项目(如果不指定,则生成所有的项目)
deploy生成的 doreamon-api 项目到仓库
遇到的问题:
因为我们整体项目都是基于springboot和springcloud的,又因为整个spring的框架有众多注解,要生成接口定义和参数定义, 要使用到众多的判断,完全自己来利用mustache写
会有巨大的工作量,所以我们主要是基于openapi-generator包里面的SpringCodegen和DefaultGenerator作为基础类,并且使用里面的mustache变量,定义自己的模版,大大减少了
编写代码的成本
利用现在注册到eureka里面的metadata信息来判断,哪些服务是使用了openapi3的协议,来完全区分openapi2和openapi3的差异性。
利用OpenAPIV3Parser方法来直接解析openapi3的协议,来简化整体解析流程,并且配合内置的mustache变量来进行模版赋值
把项目分成了两个模块, doreamon-generator是用于生成项目的代码,这一个子项目不需要进行deploy, doreamon-api模块只生成给其他项目使用的jar,减少生成的sdk的jar包的大小
项目可以根据服务名称来指定获取信息和生成代码,有利于单独的重新生成的发布jar
项目成果和推广进度
目前这个项目用于了大概1/3的微服务了,没有发现太大的问题。也在一定程度上减少了定义的代码量,减少了大量的重复的定义。
这个项目也是 惠农网 开源的第一个开源文档和开源代码,希望这个思路有助于中等规模的公司在落地微服务的过程中少走一点弯路。
项目地址
这个项目已经同步到了github: 因为整体项目生成的代码和公司的技术框架有所耦合,所以项目仅仅是提供一个解决问题的思路,并不适用于外部的所有项目
https://github.com/cnhnkj/doraemon
转载请注明作者和出处,并添加本页链接。
原文链接: //tech.cnhnb.com/post/8
网友评论