瓜子二手车在 Dubbo 版本升级、多机房方案方面的思考和实践

前言

随着瓜子业务的不断发展,系统规模在逐渐扩大,目前在瓜子的私有云上已经运行着数百个 Dubbo 应用,上千个 Dubbo 实例。瓜子各部门业务迅速发展,版本没有来得及统一,各个部门都有自己的用法。随着第二机房的建设,Dubbo 版本统一的需求变得越发迫切。几个月前,公司发生了一次与 Dubbo 相关的生产事故,成为了公司 基于社区 Dubbo 2.7.3 版本升级的诱因。

接下来,我会从这次线上事故开始,讲讲我们这段时间所做的 Dubbo 版本升级的历程以及我们规划的 Dubbo 后续多机房的方案。

一、Ephermal节点未及时删除导致provider不能恢复注册的问题修复

事故背景

在生产环境,瓜子内部各业务线共用一套zookeeper集群作为dubbo的注册中心。2019年9月份,机房的一台交换机发生故障,导致zookeeper集群出现了几分钟的网络波动。在zookeeper集群恢复后,正常情况下dubbo的provider应该会很快重新注册到zookeeper上,但有一小部分的provider很长一段时间没有重新注册到zookeeper上,直到手动重启应用后才恢复注册。

排查过程

首先,我们统计了出现这种现象的dubbo服务的版本分布情况,发现在大多数的dubbo版本中都存在这种问题,且发生问题的服务比例相对较低,在github中我们也未找到相关问题的issues。因此,推断这是一个尚未修复的且在网络波动情况的场景下偶现的问题。

接着,我们便将出现问题的应用日志、zookeeper日志与dubbo代码逻辑进行相互印证。在应用日志中,应用重连zookeeper成功后provider立刻进行了重新注册,之后便没有任何日志打印。而在zookeeper日志中,注册节点被删除后,并没有重新创建注册节点。对应到dubbo的代码中,只有在FailbackRegistry.register(url)doRegister(url)执行成功或线程被挂起的情况下,才能与日志中的情况相吻合。

    public void register(URL url) {super.register(url);failedRegistered.remove(url);failedUnregistered.remove(url);try {// Sending a registration request to the server sidedoRegister(url);} catch (Exception e) {Throwable t = e;// If the startup detection is opened, the Exception is thrown directly.boolean check = getUrl().getParameter(Constants.CHECK_KEY, true)&& url.getParameter(Constants.CHECK_KEY, true)&& !Constants.CONSUMER_PROTOCOL.equals(url.getProtocol());boolean skipFailback = t instanceof SkipFailbackWrapperException;if (check || skipFailback) {if (skipFailback) {t = t.getCause();}throw new IllegalStateException("Failed to register " + url + " to registry " + getUrl().getAddress() + ", cause: " + t.getMessage(), t);} else {logger.error("Failed to register " + url + ", waiting for retry, cause: " + t.getMessage(), t);}// Record a failed registration request to a failed list, retry regularlyfailedRegistered.add(url);}}

在继续排查问题前,我们先普及下这些概念:dubbo默认使用curator作为zookeeper的客户端,curator与zookeeper是通过session维持连接的。当curator重连zookeeper时,若session未过期,则继续使用原session进行连接;若session已过期,则创建新session重新连接。而ephemeral节点与session是绑定的关系,在session过期后,会删除此session下的ephemeral节点。

继续对doRegister(url)的代码进行进一步排查,我们发现在CuratorZookeeperClient.createEphemeral(path)方法中有这么一段逻辑:在createEphemeral(path)捕获了NodeExistsException,创建ephemeral节点时,若此节点已存在,则认为ephemeral节点创建成功。这段逻辑初看起来并没有什么问题,且在以下两种常见的场景下表现正常:

  1. Session未过期,创建Ephemeral节点时原节点仍存在,不需要重新创建
  2. Session已过期,创建Ephemeral节点时原节点已被zookeeper删除,创建成功
    public void createEphemeral(String path) {try {client.create().withMode(CreateMode.EPHEMERAL).forPath(path);} catch (NodeExistsException e) {} catch (Exception e) {throw new IllegalStateException(e.getMessage(), e);}}

但是实际上还有一种极端场景,zookeeper的Session过期与删除Ephemeral节点不是原子性的,也就是说客户端在得到Session过期的消息时,Session对应的Ephemeral节点可能还未被zookeeper删除。此时dubbo去创建Ephemeral节点,发现原节点仍存在,故不重新创建。待Ephemeral节点被zookeeper删除后,便会出现dubbo认为重新注册成功,但实际未成功的情况,也就是我们在生产环境遇到的问题。

此时,问题的根源已被定位。定位问题之后,经我们与 Dubbo 社区交流,发现考拉的同学也遇到过同样的问题,更确定了这个原因。

问题的复现与修复

定位到问题之后,我们便开始尝试本地复现。由于zookeeper的Session过期但Ephemeral节点未被删除的场景直接模拟比较困难,我们通过修改zookeeper源码,在Session过期与删除Ephemeral节点的逻辑中增加了一段休眠时间,间接模拟出这种极端场景,并在本地复现了此问题。

在排查问题的过程中,我们发现kafka的旧版本在使用zookeeper时也遇到过类似的问题,并参考kafka关于此问题的修复方案,确定了dubbo的修复方案。在创建Ephemeral节点捕获到NodeExistsException时进行判断,若Ephemeral节点的SessionId与当前客户端的SessionId不同,则删除并重建Ephemeral节点。在内部修复并验证通过后,我们向社区提交了issues及pr。

kafka类似问题issues:https://issues.apache.org/jira/browse/KAFKA-1387

dubbo注册恢复问题issues:https://github.com/apache/dubbo/issues/5125

二、瓜子的dubbo升级历程

上文中的问题修复方案已经确定,但我们显然不可能在每一个dubbo版本上都进行修复。在咨询了社区dubbo的推荐版本后,我们决定在dubbo2.7.3版本的基础上,开发内部版本修复来这个问题。并借这个机会,开始推动公司dubbo版本的统一升级工作。

为什么要统一dubbo版本

  1. 统一dubbo版本后,我们可以在此版本上内部紧急修复一些dubbo问题(如上文的dubbo注册故障恢复失效问题)。
  2. 瓜子目前正在进行第二机房的建设,部分dubbo服务也在逐渐往第二机房迁移。统一dubbo版本,也是为dubbo的多机房做铺垫。
  3. 有利于我们后续对dubbo服务的统一管控。
  4. dubbo社区目前的发展方向与我们公司现阶段对dubbo的一些诉求相吻合,如支持gRPC、云原生等。

为什么选择dubbo2.7.3

  1. 我们了解到,在我们之前携程已经与dubbo社区合作进行了深度合作,携程内部已全量升级为 2.7.3 的社区版本,并在协助社区修复了 2.7.3 版本的一些兼容性问题。感谢携程的同学帮我们踩坑~
  2. dubbo2.7.3版本在当时虽然是最新的版本,但已经发布了2个月的时间,从社区issues反馈来看,dubbo2.7.3相对dubbo2.7之前的几个版本,在兼容性方面要好很多。
  3. 我们也咨询了dubbo社区的同学,推荐升级版本为2.7.3。

内部版本定位

基于社区dubbo2.7.3版本开发的dubbo内部版本属于过渡性质的版本,目的是为了修复线上provider不能恢复注册的问题,以及一些社区dubbo2.7.3的兼容性问题。瓜子的dubbo最终还是要跟随社区的版本,而不是开发自已的内部功能。因此我们在dubbo内部版本中修复的所有问题均与社区保持了同步,以保证后续可以兼容升级到社区dubbo的更高版本。

兼容性验证与升级过程

我们在向dubbo社区的同学咨询了版本升级方面的相关经验后,于9月下旬开始了dubbo版本的升级工作。

  1. 初步兼容性验证
    首先,我们梳理了一些需要验证的兼容性case,针对公司内部使用较多的dubbo版本,与dubbo2.7.3一一进行了兼容性验证。经验证,除dubboX外,dubbo2.7.3与其他dubbo版本均兼容。dubboX由于对dubbo协议进行了更改,与dubbo2.7.3不兼容。
  2. 生产环境兼容性验证
    在初步验证兼容性通过后,我们与业务线合作,挑选了一些重要程度较低的项目,在生产环境对dubbo2.7.3与其他版本的兼容性进行了进一步验证。并在内部版本修复了一些兼容性问题。
  3. 推动公司dubbo版本升级
    在10月初,完成了dubbo兼容性验证后,我们开始在各个业务线推动dubbo的升级工作。截止到12月初,已经有30%的dubbo服务的完成了版本升级。按照排期,预计于2020年3月底前完成公司dubbo版本的统一升级。

兼容性问题汇总

在推动升级dubbo2.7.3版本的过程整体上比较顺利,当然也遇到了一些兼容性问题:

  • 创建zookeeper节点时提示没有权限
    dubbo配置文件中已经配置了zookeeper的用户名密码,但在创建zookeeper节点时却抛出KeeperErrorCode = NoAuth的异常,这种情况分别对应两个兼容性问题:

    • issues:https://github.com/apache/dubbo/issues/5076
      dubbo在未配置配置中心时,默认使用注册中心作为配置中心。通过注册中心的配置信息初始化配置中心配置时,由于遗漏了用户名密码,导致此问题。
    • issues:https://github.com/apache/dubbo/issues/4991
      dubbo在建立与zookeeper的连接时会根据zookeeper的address复用之前已建立的连接。当多个注册中心使用同一个address,但权限不同时,就会出现NoAuth的问题。
    • 参考社区的pr,我们在内部版本进行了修复。
  • curator版本兼容性问题

    • dubbo2.7.3与低版本的curator不兼容,因此我们默认将curator版本升级至4.2.0
    <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.2.0</version>
    </dependency>
    <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version>
    </dependency>
    • 分布式调度框架elastic-job-lite强依赖低版本的curator,与dubbo2.7.3使用的curator版本不兼容,这给dubbo版本升级工作带来了一定阻塞。考虑到elastic-job-lite已经很久没有人进行维护,目前一些业务线计划将elastic-job-lite替换为其他的调度框架。
  • openFeign与dubbo兼容性问题
    issues: https://github.com/apache/dubbo/issues/3990

dubbo的ServiceBean监听spring的ContextRefreshedEvent,进行服务暴露。openFeign提前触发了ContextRefreshedEvent,此时ServiceBean还未完成初始化,于是就导致了应用启动异常。
参考社区的pr,我们在内部版本修复了此问题。

  • RpcException兼容性问题
    dubbo低版本consumer不能识别dubbo2.7版本provider抛出的org.apache.dubbo.rpc.RpcException。因此,在consumer全部升级到2.7之前,不建议将provider的com.alibaba.dubbo.rpc.RpcException改为org.apache.dubbo.rpc.RpcException
  • qos端口占用
    dubbo2.7.3默认开启qos功能,导致一些混部在物理机的dubbo服务升级时出现qos端口占用问题。关闭qos功能后恢复。
  • 自定义扩展兼容性问题
    业务线对于dubbo的自定义扩展比较少,因此在自定义扩展的兼容性方面暂时还没有遇到比较难处理的问题,基本上都是变更package导致的问题,由业务线自行修复。
  • skywalking agent兼容性问题
    我们项目中一般使用skywalking进行链路追踪,由于skywalking agent6.0的plugin不支持dubbo2.7,因此统一升级skywalking agent到6.1。

三、dubbo多机房方案

瓜子目前正在进行第二机房的建设工作,dubbo多机房是第二机房建设中比较重要的一个话题。在dubbo版本统一的前提下,我们就能够更顺利的开展dubbo多机房相关的调研与开发工作。

初步方案

我们咨询了dubbo社区的建议,并结合瓜子云平台的现状,初步确定了dubbo多机房的方案。

  1. 在每个机房内,部署一套独立的zookeeper集群。集群间信息不同步。这样就没有了zookeeper集群跨机房延迟与数据不同步的问题。
  2. dubbo服务注册时,仅注册到本机房的zookeeper集群;订阅时,同时订阅两个机房的zookeeper集群。
  3. 实现同机房优先调用的路由逻辑。以减少跨机房调用导致的不必要网络延迟。

同机房优先调用

dubbo同机房优先调用的实现比较简单,相关逻辑如下:

  1. 瓜子云平台默认将机房的标志信息注入容器的环境变量中。
  2. provider暴露服务时,读取环境变量中的机房标志信息,追加到待暴露服务的url中。
  3. consumer调用provider时,读取环境变量中的机房标志信息,根据路由策略优先调用具有相同标志信息的provider。

针对以上逻辑,我们简单实现了dubbo通过环境变量进行路由的功能,并向社区提交了pr。

dubbo通过环境变量路由pr: https://github.com/apache/dubbo/pull/5348


原文链接
本文为阿里云原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/517037.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

炸裂!谷歌这波操作,预警了什么?

我们都知道谷歌爸爸收购了Cask Data一家公司。长期以来&#xff0c;谷歌致力于推动围绕 GoogleCloud 的企业业务&#xff0c;但在这方面一直被亚马逊和微软吊打&#xff0c;这次的收购正是为了弥补自身的短板。被收购的 Cask Data 是一家专门提供基于Hadoop的大型数据分析服务解…

美团点评基于 Flink 的实时数仓平台实践

一、美团点评实时计算演进 美团点评实时计算演进历程 在 2016 年&#xff0c;美团点评就已经基于 Storm 实时计算引擎实现了初步的平台化。2017 年初&#xff0c;我们引入了 Spark Streaming 用于特定场景的支持&#xff0c;主要是在数据同步场景方面的尝试。在 2017 年底&am…

element-ui简单使用

1.安装 npm i element-ui -S2.使用在main.js import ElementUI from element-ui; import element-ui/lib/theme-chalk/index.css; Vue.use(ElementUI);3.sublime text安装element-ui代码片段插件 打开sublime text的安装目录&#xff0c;找到存放插件的目录&#xff0c;例如…

koa-generator 快速生成 koa2 服务的脚手架工具

文章目录1. 全局安装脚手架工具2. 执行生成3. 安装依赖4. 启动服务5. 默认的访问地址通常我们可以借助于脚手架&#xff0c;快速创建一个Koa2项目&#xff0c;当然也可以自己从头搭建&#xff1b;脚手架会帮我们提前搭好基本的架子 1. 全局安装脚手架工具 cnpm install -g koa…

轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

首先介绍下在本文出现的几个比较重要的概念&#xff1a; 函数计算&#xff08;Function Compute&#xff09;: 函数计算是一个事件驱动的服务&#xff0c;通过函数计算&#xff0c;用户无需管理服务器等运行情况&#xff0c;只需编写代码并上传。函数计算准备计算资源&#xff…

股市中的Santa Claus Rally (圣诞节行情)

圣诞节行情 Santa Claus Rally Santa Claus Rally 是指 12 月 25 日圣诞节前后股市的持续上涨这样一个现象。《股票交易员年鉴》的创始人 Yale Hirsch 于 1972 年创造了这个定义&#xff0c;他将当年最后五个交易日和次年前两个交易日的时间范围定义为反弹日期。 根据 CFRA Re…

没想到!!Unicode 字符还能这样玩?

来源 | 程序通事责编 |晋兆雨头图 | CSDN 付费下载自视觉中国上周的时候&#xff0c;朋友圈的直升飞机不知道为什么就火了&#xff0c;很多朋友开着各种花式飞机带着起飞。图片来自网络还没来得及了解咋回事来着&#xff0c;这个直升飞机就????到的微博热搜。图片来自网络后…

开发小程序问题总结

1.获取页面可视区的高度 //getSystemInfoSync是获取系统的信息的 wx.getSystemInfoSync().windowHeight;2.获取页面的dom元素&#xff0c;原生js在小程序中是无法获取到dom元素的&#xff0c;可以通过下面的方式获取 //https://developers.weixin.qq.com/miniprogram/dev/api…

为什么 APP 纷纷开发“暗黑模式”?优酷最佳实践总结

一、缘起 随着iOS 13和Android 10的正式发布&#xff0c;一个名词"暗黑模式(Dark Mode)"逐渐走入了大家的视野。各大APP都将暗黑模式的适配列入了开发日程&#xff0c;舆情上用户们对暗黑模式支持的呼声也非常的高。优酷主客也顺应时势&#xff0c;启动了相应的技术…

Mongo 安装、配置、启动 Windows

文章目录一、Mongo 安装1. Mongo 下载2. 安装3. 配置环境变量4. 验证5. 连接二、Mongo 配置2.1. 编辑mongod.cfg2.2. 修改dbPath2.3. systemLog路径2.4. 启动Mongod服务2.5. 安装MongoDB服务2.6. 验证一、Mongo 安装 1. Mongo 下载 下载Mongo数据库并安装 https://www.mongod…

混合云存储阵列与云存储网关的协同解决方案

前言 混合云存储阵列&#xff08;CSA&#xff09;于2017年云栖大会发布&#xff0c;上市2年多&#xff0c;已经被基因测序&#xff0c;医疗PACS&#xff0c;影视制作&#xff0c;非编&#xff0c;广电&#xff0c;视频监控等行业和场景的客户广泛采用。混合云存储阵列承载了用户…

炸裂!Google这波操作,预警了什么?

我们都知道谷歌爸爸收购了Cask Data一家公司。长期以来&#xff0c;谷歌致力于推动围绕 GoogleCloud 的企业业务&#xff0c;但在这方面一直被亚马逊和微软吊打&#xff0c;这次的收购正是为了弥补自身的短板。被收购的 Cask Data 是一家专门提供基于Hadoop的大型数据分析服务解…

Robo 3T 安装连接 MongoDB

文章目录1. 官网2.安装3. 连接 MongoDB1. 官网 https://robomongo.org 2.安装 3. 连接 MongoDB

何为真正的 FaaS ?阿里舜天平台做了四大创新

导读&#xff1a;数据中心和云计算的超高增速&#xff0c;AI、视频、基因测序等应用对于算力的无尽渴求和摩尔定律发展事实上已经停滞的现实&#xff0c;均给异构加速带来了巨大的应用潜力和商机。但 Faas 解决方案仍有较高的门槛&#xff0c;今天&#xff0c;我们一起了解 Faa…

oracle+mybatis查询遇到CHAR类型字段

工作中遇到的&#xff1a; 某一张表A的某个字段B的类型为CHAR(4),往表A中插入一条数据&#xff0c;B字段的值为1&#xff0c;表面上(肉眼)看到B的值为1&#xff0c;但实际上为1加3个空格&#xff0c;会出现如下问题&#xff1a;mybatis的sql中用B字段去做查询条件 B1’时查不到…

阿里云杜欢:云上Serverless开发能力将成为前端的“金手指”

云 端模式成为当前前端开发的新风向&#xff0c;由此而来的 Serverless 正帮助前端工程师提升开发能力和效率。InfoQ 记者在近日有幸在 2019ArchSummit 全球架构师峰会北京站采访到了阿里高级前端技术专家杜欢&#xff08;风驰&#xff09;&#xff0c;他为我们详细梳理了阿里…

SOA为什么不“香”了? | 大咖说中台

作者 | 耿立超责编 | 晋兆雨来源 | 《大数据平台架构与原型实现&#xff1a;数据中台建设实战》SOA 所有的理念都是基于现有应用系统展开的&#xff0c;不管是对服务的梳理还是服务之间的交互&#xff0c;都是以现有应用系统为载体的&#xff0c;中台不同于SOA 的地方在于&…

MongoDB 4.2 内核解析 - Change Stream

MongoDB 从3.6版本开始支持了 Change Stream 能力&#xff08;4.0、4.2 版本在能力上做了很多增强&#xff09;&#xff0c;用于订阅 MongoDB 内部的修改操作&#xff0c;change stream 可用于 MongoDB 之间的增量数据迁移、同步&#xff0c;也可以将 MongoDB 的增量订阅应用到…

Vue项目启动后Error: Cannot find module ‘xxx’的解决方法

文章目录1. 删除2. 安装依赖3. 启动项目解决方法 1. 删除 删除 node_modules 整个文件夹和 package-lock.json 文件(这个文件不一定有)&#xff0c;注意不是 package.json 2. 安装依赖 在项目下运行&#xff1a;npm install# or yarn3. 启动项目 npm start # or yarn star…

看到抖音上Python工程师晒得工资条,我沉默了......

我是个抖音中毒者闲来无事就喜欢刷抖音最近刷到了一个Python工程师的工资条然后我默默的打开看了然后就默默的关闭了如今Python技术由于大数据、人工智能的兴起Python也越来越火大家都纷纷学Python我不能跟你确保说学完Python你就能拿高工资但是你学完Python肯定有饭吃说不定还…