有哪些循环依赖场景?
场景1:
服务A 对外提供了接口 a1,a1 内部会调用 服务B 的接口 b1。 服务B 对外提供了接口 b2,b2 内部会调用 服务A 的接口 a2。
即:
A.a1 -> B.b1
B.b2 -> A.a2
这种依赖是 A 和 B 之间的循环依赖。
从某个角度来说,把 A、B 看做类,a1、b1、a2、b2 看做方法也是可以的。
场景2:
服务A 对外提供了接口 a1,a1 内部会调用 服务B 的接口 b1。 服务B 对外提供了接口 b1,b1 内部会调用 服务A 的接口 a2。
即:
A.a1 -> B.b1
B.b1 -> A.a2
这种依赖是 A 和 B 之间的依赖。与场景1不同的是,对A.a1的调用的路径是:
A -请求-> B -请求-> A -响应-> B -响应-> A
场景3:
服务A 对外提供了接口 a1,a1 内部会调用 服务B 的接口 b1。 服务B 对外提供了接口 b1,b1 内部会调用 服务A 的接口 a1。
即:
A.a1 -> B.b1
B.b1 -> A.a1
这种就是死循环了。服务上线就会一堆超时。
循环依赖可能带来的问题和解决方案
服务上线流程变的复杂
以 Dubbo 为例,Dubbo 中需要将协议以打包的形式暴露出去,让需要该服务的其他服务引用协议。
在有循环依赖的情况下,要考虑谁先打正式包,要不要引入临时包,谁先被引入,哪个服务先上线。
解决方案:
重新梳理,去除循环依赖,比如不需要循环依赖也能解决问题;也可以增加第3个服务来解除循环依赖。
数据库事务操作中可能引入脏数据
在实际业务中,事务的隔离级别是读已提交
或者可重复读
。
以场景2为例子:
A.a1 -> B.b1
B.b1 -> A.a2
A.a1是一个MySQL事务操作,会将某个表中某个记录的某个字段值从 value1 修改 value2,然后调用 B.b1 ,B.b1 再通过 A.a2 查数据,因为事务还没提交,所以读到的数据是 value1。
但,B.b1 想要的是是 value2 ,那么这种实现就会有问题。
解决方案:
具体情况具体分析,比如分析能否去掉事务,能否让事务粒度变小,B能否异步延时调用A?