花钱的年华

江南白衣,公众号:春天的旁边

服务化体系之-兼容性与版本号

| Filed under 技术

准备挽起袖子写个服务化的大系列,不想错过的同学,先把公众号关注了,jnby1978。

家大业大之后,服务的版本和兼容性就是个让人不得不正视的问题。

最近,路上有个说法,既然都是微服务了,那不同的版本可以认为是两个完全不一样的微服务,没必要再保留版本号了。

这篇文章按着唯品会的实战经历来探讨一下。

我们平时面对的现状是:服务每周每天都在升级,有些升级是业务逻辑升级,接口不变;有些是接口变了,但是兼容的,偶然还有一些是不兼容的。

家大业大的体系永远不可能在服务接口升级的时候,同时(比如同一个深夜,同一个小时甚至同一分钟)将所有调用者的客户端也升级的,相反所有客户端的升级可能是很长一段时间的事情,而且可能客户端还没全升完,服务端的接口又变了。

 

1. 兼容性原则

先搞些铺垫,我们一般认为下面的情况是兼容的:

  1. 增加新方法
  2. 增加可选的参数
  3. 修改参数为可选
  4. 删除参数
  5. 框架支持的话,参数的名称,顺序也可以改(如Thrift)

参数是对象的话,其属性的变更参见2-5条。

然后一般认为下面的情况是不兼容的:

  1. 修改方法的名称
  2. 删除方法
  3. 增加必填的参数
  4. 修改参数为必填
  5. 修改参数和返回值的类型

参数是对象的话,属性的变更参照3-5条。

 

2. 不兼容时服务如何升级?

服务要进行不兼容的升级时,前面说了客户端不可能同时升级的,那怎么办?

一种是不修改原来的接口,直接在同一个服务里增加新的方法来解决。这种应该是最简单的做法,少量接口变动时优先使用,就是有点dirty。

一种是同时运行新旧两个服务。这种方式干净,但麻烦,要注意:

  • 要保证旧版的客户端SDK,调用不能被路由到新服务上。
  • 随着客户端不断割接过来,控制好新旧两个的集群容量。

 

3. 版本号原则

服务的版本号,和软件的版本号一样,一般整成三位:

第一位:不兼容的大版本, 如1.0 vs 2.0
第二位:兼容的新功能版本,如1.1 vs 1.2
第三位:兼容的BugFix版本,如1.1.0 vs 1.1.1

果拿着低版本的SDK(如1.0.0) 发起请求,会被服务化框架路由到所有的兼容版本上(如1.1.1,1.2.0),但不会到不兼容的版本上的(如2.0.1)。

 

4. 最终问题,到底要不要版本号?

4.1 版本号用于标示SDK版本是有益的

即使是兼容的小版本。

版本号能让服务端与客户端两头的开发人员更好的对话。毕竟所谓兼容,有时候也有着某种代价与折衷,互相明确彼此的版本会更好。

如果服务治理中心,能让所有服务提供者一目了然各个调用者的版本会更好,起码方便催人升级呀。

同时,在中央服务文档中心,有了版本号后也能为服务接口的每一个小版本保留一份文档。

 

不兼容的版本,怎么办?

像我们这种命名渣,好不容易为服务搞了个贴切的名字,再想第二个其实很不容易,一般只能在函数名,服务名里直接带上数字,如GoodsService2,或者GoodsServiceNew,GoodsNewSerivce.....

因此,如果加新方法的简单方式撑不住了,要独立新旧两个服务时,还是继续使用版本号来区分吧。当然,引入了版本号在框架里也引入了一定的复杂度,见后。
 

4.3 基于版本的配置

我们家框架之前的设计,将配置的粒度支持到每个小版本上,比如1.0版本的超时是10ms,1.1版本是20ms。然后根据客户端的版本来就近选择,回头来看,白白增加复杂度....

 

其实兼容的小版本只有一份配置就好,明年得简化。

 

但不兼容的大版本还是要两份,比如自定义的路由。不兼容的版本本质上真的就是两个微服务了。

 

4.4 最终结论

建议还是有版本, 服务化框架里的相关逻辑,只取第一位的主版本号。第二、三位则用于SDK版本管理沟通,以及中央服务文档中心。

当然,以上只是针对唯品会这种体量的公司的一家之言,各有各的玩法,并非四海皆准。

转载请保留链接:http://calvin1978.blogcn.com/articles/version.html

有关的...

发表评论

您的电子邮箱不会被公开。

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>