服务多版本并存的问题的讨论

Posted on May 23, 2012

转于自己在公司的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. 服务修改保持兼容,如添加方法

不会升级版本号。这样服务修改了很多次,版本还是1.0.0。

这种使用方式实际上放弃了服务版本,版本存在反而只是增加维护的成本。
# 由于没有约束版本的使用,还是有服务升级过版本号。

线上服务绝大多数是这种情况。

  1. 如果使用服务不得不有不兼容的修改,则升级版本号,如1.0.1。

线上服务对应的升级流程是:

  1. 先一半机器Provider升级到1.0.1。
  2. 升级Consumer使用1.0.1。
  3. 升级另一半Provider到1.0.1

这种情况下,可以说并没有版本并存,一次发布后老版本服务就下线了。

在服务的升级过程中要求所有消费者都完成升级,这要求服务消费者很少,或是都在同一个大的应用中。

对于有被广泛调用的服务这样的升级方式是不实现的,所以目前广泛使用的服务(如会员信息服务)都第1种情况(保持兼容)。

二、多版本并存(接口不兼容)问题

如前面说到的,多版本并存可以为广泛使用服务的不兼容升级作保证。

由于服务广泛使用,老版本的下线会要一个过程,即并存时间可能会比较长,新老版本都会有修改,两个版本服务的工程(大部分重复)的同步修改比较麻烦,需要一个合适的方法(这里不作讨论)。
# 或者说,服务provider方面接口的版本控制本身就是一个难题,多版本支持是之后的问题。

  1. 多版本并存方案

讨论服务容器时说到ClassLoader的隔离可以同时运行服务的多个版本问题。

服务不同版本的实现可以放置在:

  1. 不同的JVM
  2. 不同的ClassLoader
  3. 不同的Class(interface)中在不同JVM放置不同的服务版本,会增加资源的Overhead。

目前一JVM一机器的情况下,并存服务版本则需要更多的机器。但调用量不会服务多版本增加,不应该消费更多的机器。

在不同的ClassLoader、Class(同一JVM中)可以避免上面的问题。

对于前两者JVM、ClassLoader,不兼容的接口可以放在相同的类(全类名)中;

如果放不同Class中,则要借助Dubbo把服务映射到不同的接口类上。

  1. 多版本并存的开发

  2. Provider实现者 需要提供多个二方库放置不同版本的接口。
  3. Provider实现者 实现多个版本的服务。通过上面的方案来运行的并暴露。
  4. Consumer实现者 引用不同的二方库来引用不同版本的接口。

上面的过程和使用的方案无关。Consumer实现者没有特别。看一下Provider:

使用相同的类名(不同JVM、ClassLoader)

  1. 要求Provider为不同版本服务新建工程(避免同名类编译问题),开发不便。
  2. 使用不同JVM增加Overhead
  3. 使用不同ClassLoader增加了复杂性,影响可靠性等等。

三、总结

多版本共存成本很高,无论是开发,还是上线维护。

推荐添加新的方法,把老方法Deprecated掉,推动使用方修改。

等完全没有人使用后(可以通过监控来观察)可以考虑把老方法删除。