自身服务的变动,需要其他依赖服务跟着升级变更,这就叫服务耦合,比如数据库换了一个ip,此时往往连接此数据库的上游需要修改配置重启,明明换ip的是你,凭什么配合重启的却是我?这就是一种典型的架构设计上“反向依赖”的问题。

常规方案

我们在架构设计的时候就要将服务进行解耦,解决反向依赖带来的各种问题。

公共库导致耦合

三个服务s1/s2/s3,通过一个公共的库biz.jar来实现一段业务逻辑,s1/s2/s3其实间接通过biz.jar耦合在了一起,一个业务s1修改一块公共的代码,导致影响其他业务s2/s3,架构上是不合理的。

业务垂直拆分

如果公共的库biz.jar中实现的逻辑“业务特性”很强,可以拆分为biz1.jar/biz2.jar/biz3.jar,来对s1/s2/s3进行解耦。这样的话,任何业务的改动,影响范围只是自己,不会影响其他人。

服务化

如果biz.jar中实现的逻辑“业务共性”很强,可以将biz.jar优化为biz.service服务,来对s1/s2/s3进行解耦。服务化之后,兼容性能更好的通过接口自动化回归测试来保证。

基础服务的抽象,本身是一种共性聚焦,是系统解耦常见的方案。

服务化不彻底导致耦合

服务化是解决“业务共性”组件库导致系统耦合的常见方案之一,但如果服务化不彻底,service本身也容易成为业务耦合点。典型的服务化不彻底导致的业务耦合的特征是,共性服务中,包含大量“根据不同业务,执行不同个性分支”的代码。

switch (biz-type)
case biz-1 : exec1
case biz-2 : exec2
case biz-3 : exec3
…

在这种架构下,biz-1/biz-2/biz-3有个性的业务需求,可能导致修改代码的是共性的biz-service,使其成为研发瓶颈,架构上也是不合理的。

业务特性代码上浮,业务共性代码下沉,彻底解耦

把swithc case中业务特性代码放到业务层实现,这样biz-1/biz-2/biz-3有个性的业务需求,升级的是自己的业务系统。

notify的不合理实现导致的耦合

消息发送方不关注消息接收方的执行结果,如果采用调用的方式来实现通知,会导消息发送方和消息接收方耦合。比如如何新增消息接收方biz-4,会发现修改代码的是消息发送方,新增一个对biz-4的调用,极不合理。

通过MQ实现解耦

消息发送方upper将消息发布给MQ,消息接收方从MQ去订阅,任何新增对消息的消费,upper都不需要修改代码。

配置中的ip导致上下游耦合

下游服务换ip,可能导致多个服务调用方修改配置重启。上下游间接的通过ip这个配置耦合在了一起,架构不合理。

通过内网域名而不是ip来进行下游连接

如果在配置中使用内网域名来进行下游连接,当下游服务或者数据库更换ip时,只需要运维层面将内网域名指向新的ip,然后统一切断原有旧的连接,连接就能够自动切换到新的ip上来。这个过程不需要所有上游配合,非常帅气,强烈推荐!这也是我们常用的vip的架构设计,也可以新增服务发现服务来解决这个问题,用于解决下游集群扩容等问题。