转于自己在公司的Blog:http://code.alibabatech.com/blog/architecture_1434/discussion-and-solution-of-service-mutiversion-problem.html
在支持Dubbo的过程中,常常会被问到:如何下线服务的一个废弃(Deprecated)的方法。
推荐的做法简单:
- 添加新的方法,把老方法Deprecated掉,推动使用方修改。
- 等完全没有人使用后(可以通过监控来观察)可以考虑把老方法删除。
如果强烈原因要一个新接口并把老接口废弃,可以使用一个新接口名,比如com.alibaba.xxx.FooService2。虽然这个做法看起来很土,但过程和实现都很简单明了。
常常有人会想到服务的多版本来解决这个问题,但就实际使用情况来看,多版本的做法成本很大好处不多,不推荐使用多版本。下面看看多版本要考虑到的问题。
Dubbo中服务是可以配置版本的:
<dubbo:service interface="com.alibaba.xxx.XxxService" version="1.0.0"/>
是否要借助版本来做这个问题?这样又引入的服务的多版本。多版本又会带来什么新的问题?
服务多版本的使用和利弊的分析Dubbo Team内有过一些讨论,这里记一下。
一、现在线上服务版本的使用方式
Dubbo已经网站已经使用了两三年,版本功能几乎没有使用。
多数用法如下:
-
服务修改保持兼容,如添加方法
不会升级版本号。这样服务修改了很多次,版本还是1.0.0。
这种使用方式实际上放弃了服务版本,版本存在反而只是增加维护的成本。
# 由于没有约束版本的使用,还是有服务升级过版本号。
线上服务绝大多数是这种情况。
-
如果使用服务不得不有不兼容的修改,则升级版本号,如1.0.1。
线上服务对应的升级流程是:
- 先一半机器Provider升级到1.0.1。
- 升级Consumer使用1.0.1。
- 升级另一半Provider到1.0.1
这种情况下,可以说并没有版本并存,一次发布后老版本服务就下线了。
在服务的升级过程中要求所有消费者都完成升级,这要求服务消费者很少,或是都在同一个大的应用中。
对于有被广泛调用的服务这样的升级方式是不实现的,所以目前广泛使用的服务(如会员信息服务)都第1种情况(保持兼容)。
二、多版本并存(接口不兼容)问题
如前面说到的,多版本并存可以为广泛使用服务的不兼容升级作保证。
由于服务广泛使用,老版本的下线会要一个过程,即并存时间可能会比较长,新老版本都会有修改,两个版本服务的工程(大部分重复)的同步修改比较麻烦,需要一个合适的方法(这里不作讨论)。
# 或者说,服务provider方面接口的版本控制本身就是一个难题,多版本支持是之后的问题。
-
多版本并存方案
讨论服务容器时说到ClassLoader的隔离可以同时运行服务的多个版本问题。
服务不同版本的实现可以放置在:
- 不同的JVM
- 不同的ClassLoader
- 不同的Class(interface)中在不同JVM放置不同的服务版本,会增加资源的Overhead。
目前一JVM一机器的情况下,并存服务版本则需要更多的机器。但调用量不会服务多版本增加,不应该消费更多的机器。
在不同的ClassLoader、Class(同一JVM中)可以避免上面的问题。
对于前两者JVM、ClassLoader,不兼容的接口可以放在相同的类(全类名)中;
如果放不同Class中,则要借助Dubbo把服务映射到不同的接口类上。
-
多版本并存的开发
- Provider实现者 需要提供多个二方库放置不同版本的接口。
- Provider实现者 实现多个版本的服务。通过上面的方案来运行的并暴露。
- Consumer实现者 引用不同的二方库来引用不同版本的接口。
上面的过程和使用的方案无关。Consumer实现者没有特别。看一下Provider:
使用相同的类名(不同JVM、ClassLoader)
- 要求Provider为不同版本服务新建工程(避免同名类编译问题),开发不便。
- 使用不同JVM增加Overhead
- 使用不同ClassLoader增加了复杂性,影响可靠性等等。
三、总结
多版本共存成本很高,无论是开发,还是上线维护。
推荐添加新的方法,把老方法Deprecated掉,推动使用方修改。
等完全没有人使用后(可以通过监控来观察)可以考虑把老方法删除。