LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

微服务的正确认知和实例分析

前言

这些年经历过的公司,无论团队大小,无论成员背景,都对微服务有着错误且偏执的认知和实践。这种自以为是“微服务”的架构带来的是负面的作用:工作量多,项目混乱,服务不稳,架构臃肿等问题。

年初,几次被部门老大叫去讲如何改善架构,不善言辞的我,每次说完他都一脸蒙蔽的认同,我甚觉无趣,便写下这一篇自己过去对于微服务的总结文,希望领导和同事能有所启发。

认知

模样

这里不列出概念和定义,直接给出微服务该有的模样,,这是两个重点,个人经验而谈,在实践过程,既是疑点亦是难点。

演变

架构的演变可以大概按三个流程:

  1. 单体架构(Monolith),保罗万象,但是并非单体就没法实现模块化开发和分布式运行
  2. 面向服务架构(SOA),拆分最小功能集合,最大化复用,多用特定协议,注重高弹性,保持统一技术栈
  3. 微服务(Microservices),拆分最小完整服务,最小化调用,多用轻量协议,注重低耦合,选择各自技术栈

微服务的正确认知和实例分析演变

这里需要强调的是 Spring Cloud 是一个分布式系统套件,不是微服务框架,可以按照微服务的方式使用它,但更多场合下对它组件的使用,仅仅是 SOA 而已。

网络很多人说 SOA 是纵向拆分,微服务是横向拆分,我个人并不认同。SOA 并没有规定如何拆分,你可以按照意愿纵向、横向或者一起拆分,只要达到拆分目的即可。微服务呢,则是在 SOA 衍生出来的,他可以归为一种特殊 SOA 变体,只是横向拆分服务。

当然不管是单体,还是 SOA 或 微服务,它们都有合适自己的生存空间,如单体配上模块热插拔很适合工业定制软件,如 SOA 配上工作流适合需要流程灵活定制的行业软件等等,这里不细说。

有自治能力

自治是说一个微服务能够脱离其它服务,单独完成属于它的业务,我这里说的不仅仅是项目能独立跑起来。

如果一个服务需要依赖其他服务,那无论你采取什么策略,最终得到的都会是一团混乱。那看似容错变高,其实却不然,一个相关服务没了,不仅业务进行不下去,还得为那链式或网狀调用负责费力。

这里我需要举一个日常最常见的错误例子,订单中心。订单会有两种情况:

  • 订单是跟业务强绑定的
  • 不同业务订单都有不同的工作流

如果服务依赖,就会产生两个问题:

  • 业务服务需要其他业务服务才能走得通
  • 订单服务有太多自己本身无需了解的业务冗余

所以应该让服务独立,不相互依赖。

但是,凡是都有但是,毕竟世界混沌,这句话更好的说法是,让服务尽量独立,尽量不相互依赖。

所以上述订单的处理方式,可以直接将订单划到业务所属的 Bounded Context,然后再了解订单中心自己的存在意义和职责,通过事件驱动或者其它方式获取对应的数据,形成自己一套独立的业务服务。

能包容异构

微服务要不分种族,沟通顺畅,这里我不是套用 WiKi 上面的 lightweight,such as HTTP 来说协议,也不是在强调自主。这里我要说的是微服务的另外一个特点,拟人来说,在场双方都能无障碍沟通,不论你是中日韩还是英美法德。

日常最常见的假“微服务”,一个技术小组选定一种技术栈,其它服务的技术小组就得被限制在这个技术栈里面:

  • 你用 Java 写财务服务,我就不能用 Python 或者 PHP 写活动服务,更甚是连版本都限定
  • 你用 dubbo 沟通,我就没法用 thrift 或 grpc 跟你产生信息交换,多数时候 rpc 对语言有要求,而且需要提供接口依赖
  • 很多基础组件完全和业务项目同一类型同一物理级别的项目

微服务的正确认知和实例分析异构

对于微服务,现在流行的通用沟通方式,大抵是 HTTP 同步调用和消息队列异步消费,两种不互斥,有不同使用场景,对于 HTTP 的方式会依赖服务之间的发现管理等基础组件,这一部分可由 Service Mesh 来解决,至于是属于 DevOps 还是纯运维职责不予分说,反正不当属业务开发者。

实例分析

如果已经正确理解微服务了,那么该如何去实践,微服务并没有给出答案。

结合 DDD

实现微服务的方法有很多,其中最为流行的便是领域驱动开发(Domain Driven Design)。领域驱动开发本身并不复杂,名词概念和几种架构这里不做讲述。

微服务化一般有两个难点:

  • 业务服务拆分界限划分点
  • 业务程序设计变成面向数据库设计

DDD 是一套方法论,讲述如何理解业务,拆分业务,进行业务功能设计开发,然后再是数据库设计等。

依旧是个人经验,当你不知道拆不拆时,就不要拆,因为在以后,拆解服务在多数场合,要比合并服务更具可行性。

场景一

一个企业有几个需求:

  • 需要采购商品,并且追踪采购订单
  • 需要售卖商品,并且记录销售订单
  • 财务要根据订单来做账

常见 SOA 会大致划成:商品中心、订单中心、采购中心、销售中心和财务中心。其中调用链会随着关系网越來越长,即使现在简单的项目初始,一个采购任务,就要牵扯到采购中心、商品中心和订单中心。

我们用 DDD 的思路来拆解成微服务,则会有销售 Context,采购 Context 和财务 Context。其中对于商品这个领域对象,可见在销售和采购中都会赋予不同的属性,所以不该强行揉在一起,但是他们之间又是存在关系的,且销售的商品是源于采购的。对于订单,他们在财务、销售和采购中看到的信息和处理流程也是完全不同的。

微服务的正确认知和实例分析场景一

场景二

正因为各自的业务独立,体现在服务架构上也该是独立的,所以才能适应并跟随业务发展的变化。

例子继续,随着企业的进一步发展,发现可以卖的商品,除了自己的采购的,还可以是第三方代理的,甚至可以是自己的服务。此时我们完全是在销售的微服务做出改变,这一步的操作对于其他的业务服务应该是无感的。

微服务的正确认知和实例分析场景二

场景三

服务独立是我们最理想的情况,可是现实不一定美满,即使是微服务,也是难以完全摆脱,不管是技术服务上的,或者是实际跑业务的。

我们来设想那么一个情况,财务突然需要一个可以根据订单号来查询采购单的详情,好看看采购费用高的订单是不是给老板的惊喜。而采购服务肯定有根据采购订单号找到详情的功能了,这时候如果再冗余采购信息到财务服务,不管是出于维护困难,还是出于职责混乱,都是不合适的,所以这时候就产生直接依赖关系。

除了直接的依赖,还有非直接的依赖(不会阻碍业务流程),常规做法是通过同步或者异步的事件驱动来实现,如采购商品的变动会同步给销售自有商品,如采购订单和销售订单的状态流转都会触发事件给中间队列它们的信息,财务系统系统会捕获状态完结的订单来消费。

微服务的正确认知和实例分析场景三

服务间有依赖关系没关系,主要是要看看多少,如果太多的话,明显就是业务部门之间处理的事情本身就是拆不开的,所以技术上,服务也可以并为一起形成一个大的 context,不用拘泥于形式上的拆分。