1 开篇
微服务现如今已经是一个被绝大多数开发人员都熟知的概念了。
网上各种微服务开发系列层出不穷,各类的微服务框架也多如牛毛。
但是,在这样一种仿佛没什么必要介绍微服务的时间点,我还是要给出一系列我对于微服务开发的理解。
这些理解并不深奥,这些做法你可能每天都在做,某些地方你可能认为非常基础。
但是在我的理解中,这些很重要,并没有花里胡哨的实现方式,技术的目的,不是为了用繁琐的方法实现简单的目的,而是为了用简单的方法,实现一切目的。
因此我想介绍的框架,一切都是为了方便,方便排查,方便部署,方便开发,它只是一个方便的系统。
这些简单的技巧,朴实的做法,不仅仅为微服务框架提供有益的设计方式,还对一些开发人员的开发习惯和对开发的理解上,也能够有着一些助力。
2 源码地址
great-microservice-gradle-kotlin
上面的项目源码,是笔者自己亲手搭建并不断完善的,后续所有的《微服务框架系列》都是基于此写出。
源码使用 kotlin 开发,但是可以无缝转为 java。
后续我会单独写一篇我为什么要使用 kotlin。
3 系统结构
这是一个基于 gradle 构建微服务架构。
\--- server
+---framework
+---gateway
\---business
+---business-foundation
+---business-web
其中拥有子节点的项目,是一个没有代码的管理项目,管理下面子项目的构建,依赖等。
4 各个模块的作用
4.1 server
整个微服务架构中的顶层项目,本身不包含任何代码,是所有项目的顶层项目。
拥有下面的功能:
- 管理项目都需要用到的依赖版本
- 定义了所有项目必须拥有的依赖,比如所有项目都需要依赖
framework
,hutool
,spring-security
,spring-cloud
,spring-admin-client
,spring-redisson
,spring-alibaba-nacos-config
,spring-alibaba-nacos-discovery
,caffeine
- 定义打包中需要包含或者排除的文件
- 定义各个项目的构建方式
- gradle 依赖仓库
- 依赖的 gradle 插件
- 设置其它一些共用参数
4.2 server:framework
基础模块,项目中所有的模块都需要依赖该模块,在 server
中已经设置好,拥有下面的功能:
- 所有项目共同需要使用类和 spring boot starter 自动装载的 bean。
- 包括了 http 请求中,项目所需使用的共用类
- jackson 封装
- redisson 基于 jackson 的序列化配置
- spring 数据统一序列化
4.3 server:gateway
网关模块,作用类似于 nginx,拥有下面的功能:
- 网关转发
- 跨域设置
- spring security 鉴权、验证码
- 请求响应中 content 的拦截打印
- 全局请求日志打印、采集
- 为所有请求的 response 中加上 cost 耗时监控,
- 为所有请求的 response 中加上 request-id 请求唯一 id,并且传递到下游,能够在下游追踪日志
- knif4j swagger 服务中心
有一些功能项目到了一定规模需要做的,目前未实现
- 请求限流
- 熔断
该模块使用了 webflux,是 spring cloud gateway 使用的 web 框架,有别于传统的 servlet。
4.4 server:business
业务模块,是一个小型的顶层模块,能够掌控所有的业务模块拥有的依赖,构建方式等,因为系统中大部分相同的功能都已经被 server
定义,所以这个模块不需要再做过多的配置,只需要专心处理与下面子业务模块相关的依赖或者配置。
4.5 server:business:business-foundation
是一个类似于 framework
但是仅服务于业务模块的业务基础模块,随着系统的发展,能够不断扩充功能,例如某个组件是需要所有业务模块设置的,那么就可以在该模块下,做一个统一的配置。
目前拥有的功能:
提供所有业务模块需要共同依赖的业务类,比如业务对象、rpc 远程调用接口类。扩充的原则是
- 共享的代码范围必须限制在
business
下 - 代码共享范围必须至少是两个或者以上的项目
- 尽量剥离业务逻辑,不能把本来应该放在业务模块中的代码,不加思考的放在这里
- 共享的代码范围必须限制在
- spring mvc security、跨域、日志、全局异常、http session 配置
- 一些业务共用参数例如封装的分页参数对象、分页结果对象
- mybatis plus 配置
4.6 server:business:business-web
一个系统的核心业务模块,这类模块为系统提供业务能力,是和外接环境交互最多的模块,这类模块可以分为多个,当业务过于复杂的时候,就可以考虑剥离开来,减少一个模块的复杂度。
但是剥离为多个时又需要考虑好每个业务模块之间的连接如何设计,需要考虑包含但不仅限于下面这些问题:
- 共用业务类如何剥离
- 系统间服务如何相互调用
- fegin 的使用该如何设计
这些问题不仅要在开发前思考,在开发和需求不断变化的过程中也要不断思考,以求其能够快速的适应新的开发方式。
相比于思考上层,开发反而是最简单的事情,只要上层结构定义好了,剥离与合并都是十分方便的事情。
这个微服务框架这样设计,就是为了在小中型系统中尽量获取更多的灵活性。
5 架构中使用到的第三方服务
在架构用采用一些第三方服务,应该要仔细思考引入的服务将会带来什么样的影响,在应用过程中,应该要不断地对服务本身的优缺点进行考量。
怎么样使用第三方服务,才是合理的、正确的,我在使用到下面的这些服务时,或多或少都会有一些问题,不断地磨合,寻找合适的解决方法,是一个不断进步的过程。
系统中引用过的第三方服务有下列这些,后面的一些章节,会详细说明一些服务为什么要这样用,更重要的是为什么不要这样用。
5.1 mysql
目前使用的 orm 是 mybatis plus,mp 虽然好用,但是需要有一些限制,后面会介绍到。
5.2 redis
使用的客户端是 redisson,对于 redisson 的序列化后面会介绍。
5.3 nacos
作为注册中心和配置中心,其本身功能不错,但是也有一些问题和额外的配置。
5.4 elasticsearch
使用原生的 RestHighLevelClient,不考虑 spring data
。
不使用 spring data 的原因主要有两个
- elasticsearch 的版本升级太快,spring data 有点跟不上节奏
- spring data 的使用,需要三个版本一致,spring data 本身的版本,spring boot 的版本,elasticsearch 的版本,使用条件太苛刻
6 总结
这个微服务架构,由顶至下设计了整个项目的结构,尽可能的利用一些能够利用到的特性,把项目中与业务无关的代码全部剥离开来,让所有的模块都能享受到在一个整体架构中的优势,明确各个模块各自的职能,找到自身模块的定位。
这些职能并不是唯一不变的,每个系统都可以根据自身的实际情况去调整这个结构,架构也不是一成不变的,完全可以根据实际情况去做改变,但是尽量要遵循最大解耦的原则,并在任何情况中考量改变的影响,以方便开发人员开发的同时,也能维护框架本身的稳定性。
这个框架只是适合一些中型的系统,中型的系统体量上不会过于庞大,如果在这个架构中出现了十几个甚至几十个模块的时候,就要考虑到这个架构是否合适了,可能需要更加适合的架构去开发了,可能会产生多个中型项目相互配合的情况,甚至可能出现与业务结合紧密的网关模块。
同样也不适合一些小型项目,因为没有这个必要,简单开发一些业务功能,并且随后很难在扩充的情况下,只需要一个单独 spring boot 就可以完成所有功能。
因此没有一个框架是唯一的,能解决任何问题的。
这一系列的文章,是为了能够描述出一个理想的框架,是如何在不断思考的过程中,与各种服务不合理的地方做斗争,与各种开发习惯相互磨合,又如何做出妥协,不断进化的过程,从而能够帮助更多的开发者加深对框架的理解,在面对任何第三方服务时,都能够游刃有余的做出合理的选择。
本文参与了思否技术征文,欢迎正在阅读的你也加入。