微服务接口兼容常见问题

在进行微服务持续迭代开发的过程中,由于新特性在不停的加入,一些过时的特性在不停的修改,接口兼容问题面临巨大的挑战,特别是在运行环境多版本共存(灰度发布)的情况下。本章节主要描述接口兼容管理的一些实践建议,以及在使用CSE过程中碰到了兼容性问题的解决办法。由于微服务一般都通过REST接口对外提供服务,没有特殊说明的情况下,这里的接口都指REST接口。

保证接口兼容的实践

为了防止接口兼容问题,开发者在进行接口变更(新增、修改、删除等)的时候,建议遵循下面的一些原则。

  1. 只增加接口,不修改、不删除接口。

  2. 作为Provider,增加接口的时候,相应的将微服务版本号递增。比如将2.1.2修改为2.1.3。版本号按照规范使用x.y.z的格式,只包含数字便于管理,建议每位数字不大于125。

  3. 作为Consumer,使用Provider的新接口时候,指定Provider的最小版本号。比如:cse.references.[serviceName].version-rule=2.1.3+,其中serviceName为Provider的微服务名称。

  4. 在服务中心,定期清理不再使用的老版本的微服务信息。

ServiceComb还有如下一些注意事项:

  1. 修改微服务信息,必须升级版本号,因为服务注册的时候,不会覆盖已经注册的微服务信息。

接口兼容常见问题及其解决办法

  • 开发阶段,由于存在频繁的接口修改,又不想频繁修改版本号,容易本地和服务中心契约不一致,且契约未被允许更新到服务中心,导致调试的时候接口调用失败的情况。

推荐使用CSE提供了微服务按environment区分、隔离的能力(当前支持development和production),允许处于development环境的微服务在不升级版本的情况下,仅需重启服务即可重新注册契约到服务中心。

所有微服务在microservice.yaml中增如下配置,且需要在Provider启动后,再重启Consumer(若请求走edge,需要重启edge服务):

service_description:
name: xxx-service
version: 0.0.1
environment: development
  • 开发阶段,由于存在频繁的接口修改,也不会清理服务中心的数据,容易出现调试的时候接口调用失败的情况。

推荐使用华为公有云在线的服务中心,可以直接登录使用微服务引擎提供的微服务管理功能删除微服务或微服务实例。

微服务引擎也提供了本地轻量化服务中心,将服务停止后即可清理服务中心数据。服务中心及其frontend代码已开源,项目地址

  • 发布阶段,需要审视下接口兼容的实践的步骤,确保不在线上引入接口兼容问题。如果不小心漏了其中的某个步骤,则可能导致如下一些接口兼容问题:

  • [ ] 如果修改、删除接口:导致一些老的Consumer将请求路由到新的Provider,调用失败。

解决办法:指定Provider的版本号、或修改Consumer适配新的Provider。

  • [ ] 如果忘记修改微服务版本号:导致一些新的Consumer将请求路由到老的Provider,调用失败。

解决办法:升级Provider版本号、删除老的Provider实例、重启Consumer。

  • [ ] 如果忘记配置Consumer的最小依赖版本:当部署顺序为先停止Consumer,再启动Consumer,再停止Provider,再启动Provider的情况,Consumer无法获取到新接口信息,就采用了老接口,当Provider启动以后,Consumer发起对新接口的调用会失败;或者在Provider没启动前,调用新接口失败等。

解决办法:建议先启动Provider,再启动Consumer。

通用规避措施:出现的接口兼容问题不同,处理方式会有差异。极端情况,只需要清理Provider、Consumer的微服务信息,然后重启微服务即可。当服务调用关系复杂的情况下,接口兼容问题影响范围会更加广泛,同时清理Provider、Consumer数据会变得复杂,因此建议遵循上面的规范,避免不兼容的情况发生。

常见的接口不兼容情况的日志

  • consumer method [com.huawei.paas.cse.demo.CodeFirstPojoIntf:testUserMap] not exist in swagger

可能是Provider增加了接口,但是没有更新版本号。需要删除微服务数据或者更新版本号后重新启动Provider,并重启Consumer。

  • 契约或接口变更(含增删查改、参数变化等),但environment未设定为development,契约不允许更新。schemaId为download、upload的两个契约已存在,但新增的schemaId为TaskTemplateController的无法注册,相应接口自然会调用失败。需要升级版本号,或指定environment为development。

2018-06-14 22:51:55,239 [ERROR] SchemaIds is different between local and service center. Please change microservice version. id=1f4c94c66fe011e8945700ff37174dd4 appId=uploadapp, name=upload-service, version=0.0.1, local schemaIds=[download, upload, TaskTemplateController], service center schemaIds=[download, upload] org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.checkSchemaIdSet(MicroserviceRegisterTask.java:116)
2018-06-14 22:51:55,243 [INFO] schemaId download exists true org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
2018-06-14 22:51:55,246 [INFO] schemaId upload exists true org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
2018-06-14 22:51:55,249 [WARN] get response for org.apache.servicecomb.serviceregistry.api.response.GetExistenceResponse failed, 400:Bad Request, {"errorCode":"400016","errorMessage":"Schema does not exist","detail":"schema does not exist."}
org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.lambda$null$0(ServiceRegistryClientImpl.java:118)
2018-06-14 22:51:55,250 [INFO] schemaId TaskTemplateController exists false org.apache.servicecomb.serviceregistry.task.MicroserviceRegisterTask.registerSchemas(MicroserviceRegisterTask.java:144)
2018-06-14 22:51:55,258 [ERROR] Register schema 1f4c94c66fe011e8945700ff37174dd4/TaskTemplateController failed, statusCode: 400, statusMessage: Bad Request, description: {"errorCode":"400014","errorMessage":"Undefined schema id","detail":"schemaId non-exist, can't be added, environment is production"}
. org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.registerSchema(ServiceRegistryClientImpl.java:306)
  • Provider无可用版本,请查Provider和Consumer是否属于同一environment(默认为空字符串),且成功注册到服务中心。
2018-06-15 11:03:56,045 [ERROR] invoke failed, invocation=PRODUCER rest customer-service.reactiveClient.hello org.apache.servicecomb.swagger.invocation.exception.DefaultExceptionToResponseConverter.convert(DefaultExceptionToResponseConverter.java:35)
java.lang.IllegalStateException: Probably invoke a service before it is registered, appId=uploadapp, name=upload-service
at org.apache.servicecomb.core.definition.schema.ConsumerSchemaFactory.getOrCreateMicroserviceMeta(ConsumerSchemaFactory.java:90)
at org.apache.servicecomb.core.provider.consumer.ReferenceConfig.<init>(ReferenceConfig.java:36)
at org.apache.servicecomb.core.provider.consumer.ConsumerProviderManager.getReferenceConfig(ConsumerProviderManager.java:82)
  • 本地开发调试时无法使用部分云上仪表盘功能,会出现下述异常,不影响功能,可以忽略。可以通过设置cse.monitor.client.enable为false禁用仪表盘功能。
2018-06-14 22:23:59,407 [WARN] {"errorCode":"400012","errorMessage":"Micro-service does not exist","detail":"provider not exist, consumer 8e24bc416fde11e8945700ff37174dd4 find provider default/CseMonitoring/latest"}
org.apache.servicecomb.serviceregistry.client.http.ServiceRegistryClientImpl.lambda$null$4(ServiceRegistryClientImpl.java:199)
2018-06-14 22:23:59,408 [ERROR] Can not find any instances from service center due to previous errors. service=default/CseMonitoring/latest org.apache.servicecomb.serviceregistry.registry.AbstractServiceRegistry.findServiceInstances(AbstractServiceRegistry.java:256)
  • 下面两种错误(前者直接消费upload-service,后者通过edge-service消费upload-service)均表示接口未注册到服务中心或消费者未拿到最新契约,调用报locate path failed. 请排除:1、Provider对应接口契约已注册到服务中心,内容与本地应用启动时输出一致;2、确保Consumer和edge-service在Provider启动后,手动重启以重新获取Provider契约信息;3、Debug启动Consumer,找到ConsumerSchemaFactory类中的loadSwagger(位于servicecomb的java-chassis-core包中),查看schemaContent内容是否拿到Consumer对应契约内容。
2018-06-15 14:52:45,312 [ERROR] locate path failed, status:Not Found, http method:GET, path:/favicon.ico/, microserviceName:upload-service org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:72)
2018-06-15 14:56:35,342 [ERROR] locate path failed, status:Not Found, http method:POST, path:/taskTemplate/uploadTaskTemplate/, microserviceName:upload-service org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:72)
2018-06-15 14:56:35,344 [ERROR] edge server failed. org.apache.servicecomb.edge.core.AbstractEdgeDispatcher.onFailure(AbstractEdgeDispatcher.java:33)
InvocationException: code=404;msg=CommonExceptionData [message=Not Found]
at org.apache.servicecomb.common.rest.locator.OperationLocator.locate(OperationLocator.java:77)
at org.apache.servicecomb.common.rest.locator.ServicePathManager.consumerLocateOperation(ServicePathManager.java:107)
at org.apache.servicecomb.edge.core.EdgeInvocation.locateOperation(EdgeInvocation.java:114)
at org.apache.servicecomb.common.rest.AbstractRestInvocation.findRestOperation(AbstractRestInvocation.java:77)
at org.apache.servicecomb.edge.core.EdgeInvocation.edgeInvoke(EdgeInvocation.java:66)
at com.huawei.cse.houseapp.edge.ApiDispatcher.onRequest(ApiDispatcher.java:84)
at io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:223)
  • 消费接口时Content-Type不一致将报参数非法,如前端使用form-data,Provider需要application/json
2018-06-27 14:51:13,939 [ERROR] invoke failed, invocation=PRODUCER rest loadbalance-isolation-server.hello.sayHello org.apache.servicecomb.swagger.invocation.exception.DefaultExceptionToResponseConverter.convert(DefaultExceptionToResponseConverter.java:35)
java.lang.IllegalArgumentException: argument type mismatch
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)

作者:无微不至

基于华为云CSE微服务接口兼容常见问题的更多相关文章

  1. 微服务架构 | 4.2 基于 Feign 与 OpenFeign 的服务接口调用

    目录 前言 1. OpenFeign 基本知识 1.1 Feign 是什么 1.2 Feign 的出现解决了什么问题 1.3 Feign 与 OpenFeign 的区别与对比 2. 在服务消费者端开启 ...

  2. 智能家居巨头 Aqara 基于 KubeSphere 打造物联网微服务平台

    背景 从传统运维到容器化的 Docker Swarm 编排,从 Docker Swarm 转向 Kubernetes,然后在 Kubernetes 运行 SpringCloud 微服务全家桶,到最终拥 ...

  3. 基于Spring Cloud的微服务入门教程

    (本教程的原地址发布在本人的简书上:http://www.jianshu.com/p/947d57d042e7,若各位看官有什么问题或不同看法请在这里或简书留言,谢谢!) 本人也是前段时间才开始接触S ...

  4. 干货|基于 Spring Cloud 的微服务落地

    转自 微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的 ...

  5. 基于Spring Cloud的微服务落地

    微服务架构模式的核心在于如何识别服务的边界,设计出合理的微服务.但如果要将微服务架构运用到生产项目上,并且能够发挥该架构模式的重要作用,则需要微服务框架的支持. 在Java生态圈,目前使用较多的微服务 ...

  6. Spring Cloud微服务接口这么多怎么调试

    导读 我们知道在微服务架构下,软件系统会被拆分成很多个独立运行的服务,而这些服务间需要交互通信,就需要定义各种各样的服务接口.具体来说,在基于Spring Cloud的微服务模式中,各个微服务会基于S ...

  7. Docker从入门到掉坑(二):基于Docker构建SpringBoot微服务

    本篇为Docker从入门到掉坑第二篇:基于Docker构建SpringBoot微服务,没有看过上一篇的最好读过 Docker 从入门到掉坑 之后,阅读本篇. 在之前的文章里面介绍了如何基于docker ...

  8. 基于Openshift的SpringBoot微服务

    基于Openshift的SpringBoot微服务 OpenShift是红帽的云开发平台即服务(PaaS).自由和开放源码的云计算平台使开发人员能够创建.测试和运行他们的应用程序,并且可以把它们部署到 ...

  9. 基于 Spring Cloud 的微服务架构实践指南(下)

    show me the code and talk to me,做的出来更要说的明白 本文源码,请点击learnSpringCloud 我是布尔bl,你的支持是我分享的动力! 一.引入 上回 基于 S ...

随机推荐

  1. Java基础系列4:抽象类与接口的前世今生

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 1.抽象类: 当编写 ...

  2. [LINQ2Dapper]最完整Dapper To Linq框架(一)---基础查询

    此例子是使用LINQ2Dapper封装,效率优于EntityFramwork,并且支持.NetFramework和.NetCore框架,只依赖于Dapper 支持.net framework4.5.1 ...

  3. 大宇java面试系列(三):Redis常见面试题

    1. Redis 是什么?都有哪些使用场景? 我们先来理解经典的CAP理论: 一致性:是指从数据层面来看的一致性. 可用性:是指从系统层面的可用性. 容错性:是指从网络层面的的容错性. 数据库逐渐从关 ...

  4. nyoj 1112-求次数 (string, substr(begin, length), map, pair)

    1112-求次数 内存限制:64MB 时间限制:1000ms 特判: No 通过数:3 提交数:8 难度:2 题目描述: 题意很简单,给一个数n 以及一个字符串str,区间[i,i+n-1] 为一个新 ...

  5. 力扣(LeetCode)翻转字符串里的单词 个人题解

    给定一个字符串,逐个翻转字符串中的每个单词. 示例 1: 输入: "the sky is blue" 输出: "blue is sky the" 示例 2: 输 ...

  6. fiddler工具使用大全

    Fiddler基础知识 Fiddler是强大的抓包工具,它的原理是以web代理服务器的形式进行工作的,使用的代理地址是:127.0.0.1,端口默认为8888,我们也可以通过设置进行修改. 代理就是在 ...

  7. 0xe7f001f0!?NDK调试过程,无故抛出SIGSEGV。

    arm调试过程,如果抛一个SIGSEGV,地址在 0xe7f001f0 附近,原因居然是因为我在调试.当我使用n指令跳到下一行代码时,往往变成了continue指令一样地执行.还不确定地抛出SIGSE ...

  8. CSS如何设置列表样式属性,看这篇文章就够用了

    列表样式属性 在HTML中有2种列表.无序列表和有序列表,在工作中无序列表比较常用,无序列表就是ul标签和li标签组合成的称之为无序列表,那什么是有序列表呢?就是ol标签和li标签组合成的称之为有序列 ...

  9. bert+seq2seq 周公解梦,看AI如何解析你的梦境?【转】

    介绍 在参与的项目和产品中,涉及到模型和算法的需求,主要以自然语言处理(NLP)和知识图谱(KG)为主.NLP涉及面太广,而聚焦在具体场景下,想要生产落地的还需要花很多功夫. 作为NLP的主要方向,情 ...

  10. TreeMap的源码学习

    TreeMap的源码学习 一).TreeMap的特点 根据key值进行排序. 二).按key值排序的两种排序算法实现 1).在构造方法中传入比较器 public TreeMap(Comparator& ...