公司项目就是微服务,代码管理工具是Git,项目管理工具Gradle,底层用的是jpa,这里总结下对微服务一些设计思想的理解。
一、服务粒度
哪些业务可以划分为一个业务服务?什么时候就要划分?划分到什么粒度比较合适?
按照《领域驱动》中的说法,一个微服务的划分,可以参照领域驱动来划分,要兼顾技术和业务,比如:一个系统有粉丝之间关注、点赞、评论、收藏等,这些内容可以放在一个服务中,表达一种互动关系;或者系统中会用到各种第三方的东西:eg:短网址服务、定位服务、文字识别、短信服务、双因素认证、语音识别、OCR识别等技术,这些可以作为一个微服务,其他服务可以调用这个服务。
最核心的业务作为一个微服务,最核心的业务可能有多条业务线,这涉及到核心业务微服务的划分粒度问题,“颗粒”并非越小越好,粒度太小,服务过多,管理起来不方便;粒度太大,个别服务臃肿,巨大无比。
具体如何划分,还是要实战中实际操作感受,目前谈论的都是一些理论和实际观察到的例子。
二、服务之间的依赖
系统划分为多个微服务之后,服务之间如何通信?一般选择是Dubbo来负责服务之间的调用,如果是Spring Boot或者Spring cloud的话,自身就带有通信机制。除了通信之外,服务之间会存在各种依赖关系,这方面有不少处理技巧。我们这里用问题引导的方式来提解决方案。
假设系统有微服务basic 、feeds 、 access、bff.
其中basic是最基础的服务,feeds、access、bff都可以调用basic的接口,而feeds、access、bff之间都可以相互调用各自对外暴露的api.这个时候,会遇到jar包编译问题。
当bff调用了feeds对外暴露的api时候,需要编译feeds的jar包,才能确保bff引用的api的jar包已经是最新的了,否则会导致编译不过,引用的还是旧的东西;同样,如果feeds调用了bff对外暴露的api,那么需要先编译bff的api。这个时候,都需要相互编译,上线的时候,需要特别小心,先编译那个服务,后编译哪个服务,才不至于编译失败,才不至于“循环依赖”?这样是不是很心塞?团队稍微大一点,十几个人改动代码,动了哪些服务,新增了哪些依赖关系?能确保他们不重不漏?能确保根据依赖关系,准确按照依赖先后顺序发布?
很难做到吧?即便勉强做到,一定会出现很多问题。我们可以有以下解决方案:
1) 确定一个最基础的服务,它不依赖任何服务
有一个非常基础的服务,eg:base.这个服务不调用别的服务,所有的服务都调用它。而其他服务之间可以相互调用。这样可以把最核心的服务base确保是独立的;
2)事件驱动、消息监听解耦
虽说base是基础服务,要想做到不调用其他服务的api,有些场景也做不到。比如:服务初期,代码就写到了base,中间移动到别的服务代价太大,但是base又需要调用feeds服务,怎么办?
可以这么做:在base涉及到的表中,冗余一个字段,在feeds服务中监听业务发出的事件,监听到此事件后发送对应的业务消息,监听此业务消息后做业务逻辑处理,更新冗余字段。这样base的表中有了字段,是feeds通过消息驱动去主动更新的,base就可以不调用feeds的api了。实现了解耦的目的。
3)面向“前端”的服务——Backend For Fronted
简称bff服务。这个服务没有api,没有对外提供可供调用的接口,那么这个服务做什么?它就负责一些跟前端交互非常密切,更改非常频繁的的接口调用。比如有很多UI设计会经常变动,你又不得不做一些专门针对UI的逻辑代码:eg:
假设一个业务有这样几种状态:
CREATED //服务被创建
AUDIT //业务审核
REQUEST_PT_TO_CHANGE//请求平台调整
REQUEST_BS_TO_CHANGE //请求业务调整
BS_CONFIRMED //业务已确认
PT_CONFIRMED //平台已确认
BS_REJECTED //业务已拒绝
PT_CANCELED //平台已取消
后端应用层接口需要这些状态就够了,要求给运营的列表的状态是这样的:
已创建
处理中(包括:AUDIT、 REQUEST_PT_TO_CHANGE 、REQUEST_BS_TO_CHANGE)
已结束
已取消
那么这个“处理中”的状态是只是给运营用的,而且这种组合方式随时都可能发生变化,今天说处理中包含这几个状态,明天运营用起来不方便,可能就换到另一种状态中去了,难道也去更改应用层接口?
怎么做呢?对于这种 “处理中”的状态逻辑,就很适合放在BFF中。就是说你在BFF中给运营单独定义一套他们需要的状态枚举,这个枚举只是用来组织返回给前端的列表,前端感受到的是很直观的HANDLING状态,调用接口也只用传HANDLING这个状态,然后在BFF中dubbo调用提供服务的接口,这个应用层接口用到的才是业务底层真正需要的状态,这些状态基本不受UI影响。
这些跟依赖有啥关系呢?有的。因为BFF没有api包,也就是它不对外提供服务,用dubbo的术语就是,它永远都不会是Provider。所以,有的业务逻辑,你放在base中,就没法调用其他服务,放在哪里呢?
放在BFF中。BFF中可以调用任何服务,无形中就解决了服务调用问题。
文字有些多,因为这个是偏思想的多一些,技术少一点。