企业落地与项目实战4544 字

阿里项目依赖冲突治理之道

·全库 554 / 611

《阿里项目依赖冲突治理之道》共 0.5 万字,通篇围绕 架构、部署、日志、成本 展开,归在「企业落地与项目实战」这一层。

覆盖架构部署日志成本检索评估

适合要把 AI 项目交付出去、对结果负责的人

目录骨架(6 节)
  1. 一 概述
  2. 二 依赖冲突产生的本质原因
  3. 三 依赖冲突问题高效定位技巧
  4. 四 通过 maven 调整依赖 jar 解决依赖冲突
  5. 五 通过 pandora 自定义插件解决依赖冲突
  6. 六 通过依赖架构治理解决依赖冲突

示例代码

注:将ppt后缀名改为zip后解压

jdk版本:1.8.0_181

​

本次分享内容

  1. 依赖冲突场景描述
  2. 依赖冲突产生的本质原因
  3. 通过 maven 调整依赖 jar 解决依赖冲突
  4. 通过 pandora 自定义插件解决依赖冲突
  5. 通过依赖架构治理解决依赖冲突

一 概述

由于阿里妈妈联盟团队负责业务的特殊性,系统有庞大的对外依赖,依赖集团六七十个团队服务及 N 多工具组件,本次给大家分享一些复杂依赖有效治理的经验,除了简单技术技巧的总结外,也会探讨一些关于这方面架构的思考,希望能系统彻底的解决 java 依赖冲突对大家的困扰。

二 依赖冲突产生的本质原因

要解决依赖冲突,首先要理解一下 java 依赖冲突产生的本质原因。

以上图为例,目前阿里大部分 java 工程都是 maven 工程,此类工程从开发到上线要经历以下两个重要步骤:

1 编译打包

平时我们编写的应用代码,用 maven 编译应用代码时,maven 只依赖第一级 jar 包 (A.jar,B.jar,*.jar) 既完成应用代码的编译,至于传递依赖的 jar 包(Y.jar,Z.jar)maven 首先会对同名不同 version 的 jar 包进行依赖仲裁,然后依据仲裁结果下载对应的 jar 放到指定目录下(例如上图中 Y.jar 最终只会仲裁 1.0 或 2.0 一个版本,此处假定仲裁到 2.0 版本,Z.jar 即便内容与 Y.jar 一致,但名称不一样所以不属于 maven 仲裁范畴)。

有一点需注意不同 maven 版本可能会有差异,这会导致有时本地环境和日常、预发打包不一致造成应用逻辑表现不一致的情况(说明一下这种情况还有其他一些原因会导致,不是说一定是 maven 版本不一致仲裁结果不一致导致的)。

2 发布上线

先明确一个概念,在 JVM 中,一个类型实例是通过它的全类名和加载它的类加载器(ClassLoader)实例来唯一确定的。所以所谓的 “类隔离”,实际就是通过不同的类加载器实例去加载需要隔离的类来实现的,这样即便两个全类名完全相同但内容不同的类,只要他们的类加载器实例不同,就能在一个容器进程中共存,并且各自运行互不干扰。

发布启动容器时,不管是 tomcat、taobao-tomcat 还是 PandoraBoot,还是其他容器, 首先都是用特定的类加载器实例先加载容器本身依赖的 jar 包,容器一般都会有多个类加载器实例,容器自身所依赖的 jar 包一般由专门的类加载器实例加载实现与应用包的绝对隔离,像 Pandroa 还有专门的类加载器实例加载淘系中间件避免中间件与应用类冲突,如下图所示:

容器内部依赖 jar 加载完成后,才轮到必然的一步:由某个应用 ClassLoader 实例 (一般与容器类加载器实例不是一个) 来加载编译打包阶段打出来的应用 jar 包及应用. class 程序,这样容器才能运行业务,同时确保应用不会干扰容器的运行。

例如图 1 中,最终打出的应用包中 Y.jar-2.0,Z.jar 都有 com.taobao.Cc.class 类,但一个应用 ClassLoader 实例仅能加载 V3 或 V2 中一个版本的 com.taobao.Cc.class 类。

那到底会加载哪个版本的 com.taobao.Cc.class 类呢?答案是不一定,这个取决于容器应用类加载实现策略, 从以往遇到的情况看,tomcat,taobao-tomcat、Pandora 的做法都是直接装载应用 lib 包下所有. jar 包文件列表 (上例是 A.jar,B.jar,*.jar,Y.jar,Z.jar。除 tomcat 外都没看源码核实过)。但 Java 在装载一个目录下所有 jar 包时, 它加载的顺序完全取决于操作系统!而 Linux 的顺序完全取决于 INode 的顺序,INode 的顺序不完全能一致,所以之前就遇到类似的问题,上线 20 台机器,用同一个镜像,有 2 台就是起不来的情况。遇到这种情况目前就只能乖乖按以下章节中的手段去解决了。理论上最正确的做法应该是容器装载应用 jar 包时,按指定顺序加载。

基于以上分析,我们可以得出结论,基本所有的类冲突产生的本质原因:要么是因为 maven 依赖仲裁 jar 包不满足运行时需要,要么是容器类加载过程中加载的类不满足运行时需要导致的。

关于容器类加载隔离策略,网上有很多资料介绍,本次重点向大家讲解遇到冲突的各种解决之道,解决冲突大家只需要知道以上重点原理就够了。

理解了依赖冲突产生的本质原因,那么发生依赖冲突如何高效定位具体是哪些 jar 包引起的冲突呢?

三 依赖冲突问题高效定位技巧

发生依赖冲突主要表现为系统启动或运行中会发生异常,99% 表现为三种 NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError。下面逐一讲解一下定位技巧。

资料里没有你的场景?

把你手上的数据和想解决的那个环节发上来,我们按具体情况回,不复述方法论。

发布需求