文章首发于公众号:BiggerBoy。欢迎关注。

往期文章推荐

大坑!隐式转换导致索引失效...
高性能分布式限流:Redis+Lua真香!
MySQL索引知识点&常见问题汇总联合索引在B+树上的存储结构及数据查找方式
Redis分布式锁实战Mybatis第三方PageHelper插件分页原理MySQL索引底层原理

一、问题交代

当我们使用dubbo作为服务间通信的组件时,在后期的系统维护中可能会因为业务需要,服务提供者某些接口需要升级,对应的服务消费者配合作相应的修改,测试通过后一起发版上线即可。但是在这个过程中,有很多需要注意的点,不妨来梳理一下以作记录,希望对此不清楚的开发者有所帮助。
再次申明一下我们的需求吧。假设服务A提供了一个服务IHelloService,其中有一个方法sayHello,服务B、C、D...都对此有依赖,假设服务A提供的该接口已上线且被服务B、C、D正常消费,线上运行稳定。

先将服务提供者和服务消费者分别启动,此时消费方正常消费服务。

api:

public interface IHelloService {
Result sayHello(ModelParent param);
}

服务提供者:

@Component
public class HelloServiceImpl implements IHelloService {
@Override
public Result sayHello(ModelParent param) {
MyDto dto = new MyDto();
dto.setMsg("hello," + param.getName());
return Result.success(dto);
}
}

服务消费者:

@Service
public class MyService {
@DubboReference(group = "test",version = "1.0",registry = "registry2")
private IHelloService helloService; public Result test(ModelParent param) {
return helloService.sayHello(param);
}
}

二、接口迭代升级方案

过了几个月,服务B接到产品需求,为了满足需求,对服务A的IHelloService.sayHello提出新的要求,因为本次需求不涉及服务C、D的改动,所以服务A对该服务还需要满足服务C、D调用时保持老逻辑不变,因此服务A需要格外注意服务的兼容性。

注意:这里说的服务A、B、C...是一个个应用或系统。应用或系统对外提供多种服务,例如用户服务对外提供用户信息查询服务、用户注册服务等。

假设服务A和服务B的开发人员确认完需求后,服务A的开发人员想到的接口升级方案如下:

  1. 服务A新提供一个sayHelloV2方法或新服务IHelloServiceV2,提供新的业务逻辑,服务B调这个新方法或新服务,原来的sayHello保留,服务C、D继续调用且本次不用修改上线。
  2. 服务A修改IHelloService.sayHello,在原来的入参中新增字段,用于区分走新逻辑还是老逻辑。在这种方式下就需要特别注意了,因为入参增加了参数,要考虑是否会影响本次需求不涉及的服务C和服务D。

    2.1 在原入参对象中新增字段。服务C、D对于新增的字段肯定传的是null,所以可以用null标识走老逻辑,用其他值比如1标识走新逻辑。

    2.2 创建新的入参对象 ModelChildren 增加新字段,且该入参对象继承原入参对象。此时又分不同的情况。

      a.接口方法入参对象保持原入参对象不变,即,方法签名不变,仍然是Result sayHello(ModelParent param)。仅需改动有新需求的服务B的代码,将入参对象改为新入参对象,由于该对象继承了原入参对象,所以不会有问题,但服务A需要判断传的是父类 ModelParent 还是子类 ModelChildren,并从子类 ModelChildren 中获取新字段。

      b.接口方法入参对象改为新入参对象,即,方法签名修改,入参改为新对象Result sayHello(ModelChildren param)。此时,所有消费该服务的消费方均需要修改,如果消费方不改,消费方调用该方法时会抛异常org.apache.dubbo.remoting.RemotingException: Fail to decode request due to:java.lang.IllegalArgumentException:Service not found:com.biggerboy.api.IHelloService, sayHello

三、 总结

方案 参数列表 优点 缺点
新增方法sayHelloV2 - 1.新老逻辑分开,兼容老版本2.对本次不涉及的服务消费者友好,因为可以不用改动代码继续使用老方法 1.额外创建新的服务方法,对内存消耗略微增加(可忽略)
新增服务IHelloServiceV2 - 1.新老逻辑分开,兼容老版本2.对本次不涉及的服务消费者友好,因为可以不用改动代码继续使用老服务 1.额外创建新的服务,对内存消耗略微增加(可忽略)
修改入参ModelParent增加字段 不变 1.兼容老版本,对不涉及的服务无影响2.不用新增服务,不会额外消费内存 1.程序中需使用新增的字段区分新老逻辑
新增入参子类ModelChildren增加字段并继承原入参ModelParent 不变 1.兼容老版本,对不涉及的服务无影响2.不用新增服务,不会额外消费内存3.新增加了入参不会影响其他同样使用ModelParent作为参数的服务 1.程序中需使用新增的字段区分新老逻辑2.额外创建新的类,对内存消耗略微增加(可忽略)
新增入参子类ModelChildren增加字段并继承原入参ModelParent 改为子类 1.不用新增服务,不会额外消费内存2.新增加了入参不会影响其他同样使用ModelParent作为参数的服务 1.程序中需使用新增的字段区分新老逻辑2.额外创建新的类,对内存消耗略微增加(可忽略)3.需修改参数列表,当方法调用链较长且使用入参对象作为参数列表时,需修改的方法较多4.不兼容老版本,本次不涉及的服务消费者也需修改,负责报错

你们公司是如何做的呢?欢迎评论区一起讨论~

End

Dubbo服务提供者如何优雅升级?的更多相关文章

  1. Dubbo服务如何优雅的校验参数

    一.背景 服务端在向外提供接口服务时,不管是对前端提供HTTP接口,还是面向内部其他服务端提供的RPC接口,常常会面对这样一个问题,就是如何优雅的解决各种接口参数校验问题? 早期大家在做面向前端提供的 ...

  2. 技能get,React的优雅升级!

    今日,我们不啖鸡汤,不饮鸡血 只有干货——关于React的优雅升级 双手奉上,来,干了! -2019年第4期- 夫 子 说 本次升级基础包情况:react 15.6 -> 16.6 升级流程: ...

  3. Dubbo 2.6.0升级到2.7.3

    dubbo依赖,修改groupId和升级version版本号 <dependency> <groupId>com.alibaba</groupId> <art ...

  4. 【Dubbo&&Zookeeper】4、 Java实现Dubbo服务提供者及消费者注册

    转自:http://blog.csdn.net/u010317829/article/details/52128852 创建Mavn工程.HelloDubbo. pom.xml添加dubbo及spri ...

  5. 在kubernetes集群里集成Apollo配置中心(4)之dubbo服务提供者连接apollo实战

    1.登录portal.od.com(Apollo-portal),新建一个dubbo-demo-service项目 2.在Apollo项目中的dubbo-demo-service添加配置 (1)添加d ...

  6. Dubbo 优雅停机演进之路

    一.前言 在 『ShutdownHook- Java 优雅停机解决方案』 一文中我们聊到了 Java 实现优雅停机原理.接下来我们就跟根据上面知识点,深入 Dubbo 内部,去了解一下 Dubbo 如 ...

  7. dubbo多网卡时,服务提供者的错误IP注册到注册中心导致消费端连接不上

    使用了虚拟机之后,启动了dubbo服务提供者应用,又连了正式环境的注册中心: 一旦dubbo获取的ip错误后, 这种情况即使提供者服务停掉,目前dubbo没有能力清除这类错误的提供者: (需要修改源码 ...

  8. Dubbo的优雅下线原理分析

    文/朱季谦 Dubbo如何实现优雅下线? 这个问题困扰了我一阵,既然有优雅下线这种说法,那么,是否有非优雅下线的说法呢? 这,还真有. 可以从linux进程关闭说起,其实,我们经常使用到杀进程的指令背 ...

  9. Dubbo详细介绍与安装使用过程

    今天看到一篇不错的dubbo介绍教程,原文链接:http://blog.csdn.net/xlgen157387/article/details/51865289 1 Dubbo介绍 1.1 dubb ...

  10. Dubbo特性

    dubbo.properties Dubbo 将自动加载 classpath 根目录下的dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx ...

随机推荐

  1. Java 基础(二)

    类的初始 类中包括:属性,方法. 快速使用 我们都是人,而人的共同特点有很多. 比如:名字,年龄,性别,吃饭,睡觉... // 定义类 public class Person { // 定义属性 St ...

  2. redis 配置哨兵模式时出现的问题(redis 版本 6.2.5)

    今天准备搭建一个 redis 集群(redis 版本 6.2.5),在这之前要先配置好哨兵模式. 但是在配置哨兵模式时出现了问题.之前没有搭建集群时(一主两从,三台虚拟机)可以顺利配置好,而搭建集群时 ...

  3. 安装win10:我们无法创建新的分区,也无法定位现有分区

    操作环境:win10企业版ISO,U盘安装,UEFI启动 解决思路:win10 UEFI 安装需要硬盘在GPT模式,如果直接创建分区默认的是MBR,所以将磁盘转换成GPT,再分配一个EFI空白分区,就 ...

  4. jooq简单使用

    DSLContext首先简单的配置文件 <?xml version="1.0" encoding="UTF-8" standalone="yes ...

  5. 004Java的一些基本概念

    004Java的一些基本概念 1.Java特性和优势 Java至少具有以下特性: 简单性(没有头文件.没有指针运算.也没有分配内存等操作) 面向对象(万物皆对象) 可移植性(一次编写,到处运行 Wri ...

  6. Windows下fmt库的链接与使用

    下载源码. 使用mingw编译源码.注意设置cmake文件的产生路径.pkgconfig文件的产生路径(windows下用不到产生的pc文件).库的安装路径. make -j8 install. 新建 ...

  7. PYinstall打包程序出现编码错误的解决 'utf-8' codec can't decode byte 0xce in position 171: invalid continuation b

    网上说,先执行,再打包 chcp 65001 试过没有用. 解决方案: 把import的包批量注释,然后寻找是import那个文件导致. 虽然注释会导致程序运行出错,但是打包才不管你能不能运行. 最后 ...

  8. [Unity移动端]gradle打包

    建议先看一下这篇文章: https://linxinfa.blog.csdn.net/article/details/118553713?spm=1001.2101.3001.6650.10& ...

  9. Go_day04

    Go基础语法 指针 指针式存储另一个变量内存地址的变量 &a 取出a的内存地址 *b 若指针b存放的式a的地址 那么 *b就直接指向a的内存 可以直接操作其中的值 指针的使用 func mai ...

  10. vue项目 - 自定义数字输入指令 | 限制自定义小数位输入

    1.在main.js中直接加入代码: import Vue from 'vue' Vue.directive("input-limit", { bind(el, binding) ...