成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java依賴沖突高效解決之道

開發 開發工具
由于阿里媽媽聯盟團隊負責業務的特殊性,系統有龐大的對外依賴,依賴集團六七十個團隊服務及N多工具組件,通過此文和大家分享一下我們積累的一些復雜依賴有效治理的經驗,除了簡單技術技巧的總結外,也會探討一些關于這方面架構的思考,希望此文能系統徹底的解決java依賴沖突對大家的困擾。

一、概述

由于阿里媽媽聯盟團隊負責業務的特殊性,系統有龐大的對外依賴,依賴集團六七十個團隊服務及N多工具組件,通過此文和大家分享一下我們積累的一些復雜依賴有效治理的經驗,除了簡單技術技巧的總結外,也會探討一些關于這方面架構的思考,希望此文能系統徹底的解決java依賴沖突對大家的困擾。

二、依賴沖突產生的本質原因

要解決依賴沖突,首先要理解一下java依賴沖突產生的本質原因。

圖1

以上圖為例,目前阿里大部分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包不滿足運行時需要,要么是容器類加載過程中加載的類不滿足運行時需要導致的。

關于容器類加載隔離策略,網上ATA上有很多資料介紹,本文重點向大家講解遇到沖突的各種解決之道,解決沖突大家只需要知道以上重點原理就夠了。

理解了依賴沖突產生的本質原因,那么發生依賴沖突如何高效定位具體是哪些jar包引起的沖突呢?請繼續看下一章節。

三、依賴沖突問題高效定位技巧

發生依賴沖突主要表現為系統啟動或運行中會發生異常,99%表現為三種NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError。下面逐一講解一下定位技巧。

1.NoClassDefFoundError、ClassNotFoundException排查定位步驟

STEP1、發生NoClassDefFoundError首先要看完整異常棧,確認是否是靜態代碼塊發生異常,靜態代碼塊發生異常堆棧與jar包沖突有很明顯的區別,出現"Could not initialize"、"Caused by: ..."關鍵字一般是靜態代碼塊發生異常導致類加載失敗:

  1. java.lang.NoClassDefFoundError: Could not initialize class testing.User  
  2.     at testing.Test.main(Test.java:23) 
  3. Caused by: java.lang.RuntimeException: UserId Not found 
  4.     at testing.User.getUserId(Test.java:41) 
  5.     at testing.User.<clinit>(Test.java:35) 
  6.     ... 1 more 

因為靜態代碼塊發生異常導致NoClassDefFoundError,修改靜態代碼塊避免拋出異常即可。如果不是靜態代碼塊發生異常導致的問題,繼續下一步。

STEP2、如果不是靜態代碼塊發生異常導致加載失敗,異常message關鍵字中會明確顯示缺失的類名稱,例如:

  1. java.lang.NoClassDefFoundError: org/apache/commons/lang/CharUtils 
  2.     at testing.Test.main(Test.java:19) 

STEP3、在IDEA中(快捷鍵Ctrl+N)查找異常棧中提示缺失的類在哪些版本的jar包中有,如上例中的org.apache.commons.lang.CharUtils

STEP4、查看應用部署機器上應用lib包目錄下(一般是/home/admin/union-uc/target/${projectName}/lib或union-pub/target/${projectName}.war/WEB-INF/lib)是否存在上一步驟中查出對應版本的jar包,以上情況一般是因為此時應用依賴的是低版本jar包,而jar包中又沒有沖突的類,絕大部分情況下NoClassDefFoundError、ClassNotFoundException定位確認都是因為maven依賴仲裁最終采納的jar包版本與運行時需要的不一致導致。

2.NoSuchMethodError排查到位步驟

STEP1、發生NoSuchMethodError,異常堆棧日志核心片段(異常棧中處于棧底的片段,見過很多同學發生異常亂翻一通,那樣毫無意義,要有目的的翻關鍵地方,不要亂翻)會明確顯示具體是哪個類,缺失了哪個方法,異常堆棧核心片段示例如下:

  1. Caused by: java.lang.NoSuchMethodError: org.springframework.beans.factory.support.DefaultListableBeanFactory.getDependencyComparator()Ljava/util/Comparator; 
  2.     at org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(AnnotationConfigUtils.java:190) 
  3.     at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.registerComponents(ComponentScanBeanDefinitionParser.java:150) 
  4.     at org.springframework.context.annotation.ComponentScanBeanDefinitionParser.parse(ComponentScanBeanDefinitionParser.java:86) 
  5.     at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:73) 

首先需確認JVM中當前加載的缺失方法類,如上"org.springframework.beans.factory.support.DefaultListableBeanFactory"類到底來自哪個jar包,目前最高效的辦法:

外部環境容器下,或者某些容器版本過低不支持Arthas在線診斷的情況下,可以通過在JVM啟動參數中增加" -XX:+TraceClassLoading",然后重新啟動系統,在系統工程日志中即可看到JVM加載類的信息。從中即可找到JVM是從哪個jar包中加載的。

STEP2、在IDEA中(快捷鍵Ctrl+N)查找異常棧中提示缺失的類在哪些版本的jar包中有,如下圖所示:

然后依次查看各版本jar包中沖突類的源碼,工程中部分jar打包時附帶了源碼包可直接看到源碼,不帶源碼的需要用IDEA插件(推薦jad)反編譯一下。然后依次搜尋各個jar包中的沖突類,搜尋第一步是點擊上圖中某個版本類,在IDEA中查找類級次關系(快捷鍵Ctrl+H),如下圖所示:

然后在沖突類及所有沖突類的父類源碼中找到NoSuchMethodError異常信息中描述缺失的方法,以上例子中就是"getDependencyComparator()Ljava/util/Comparator"。

上例中通過搜尋可以發現spring-beans-3.2.1.RELEASE.jar,spring-2.5.6.SEC03.jar兩個版本DefaultListableBeanFactory類及父類中沒有"getDependencyComparator()Ljava/util/Comparator"方法,spring-beans-4.2.4.RELEASE.jar,spring-beans-4.3.5.RELEASE.jar兩個版本DefaultListableBeanFactory類中有缺失的"getDependencyComparator()Ljava/util/Comparator"方法。

STEP3、查看應用部署機器上應用lib包目錄下(一般是/home/admin/union-uc/target/${projectName}/lib或union-pub/target/${projectName}.war/WEB-INF/lib)下,找到相關jar包的版本,如上例中:

致此定位問題根本原因是應用啟動時加載"org.springframework.beans.factory.support.DefaultListableBeanFactory"類未加載到運行時預期所需的spring-beans-4.3.5.RELEASE.jar版本,而是加載了spring-2.5.6.SEC03.jar導致。

按照以上流程步驟,基本99%的依賴沖突都可以定位到根本原因。定位到原因后如何解決沖突呢?事實上有些時候解決沖突遠沒有內網上很多帖子描述的"mvn dependency:tree"一下,排排jar那么簡單。具體細節請繼續看下一章節。

四、通過maven調整依賴jar解決依賴沖突

1.升降級jar包解決依賴沖突

上一章節中的第一個例子中,最簡單的情況,如果發生沖突的jar包高版本是完全兼容低版本功能的情況下,只需在pom中簡單升級jar包版本即可。

但如果沖突 jar包高版本不兼容低版本,且應用依賴不是很復雜的情況下,可以分析升級沖突jar包后會對哪些業務有影響,具體做法推薦通過IDEA Maven Helper 插件查找沖突jar包有哪些業務依賴(此處不推薦"mvn dependency:tree",目前本人見過的大部分Maven工程都有多個Module,比如*-dal,*-Service,*-Controller,這類工程結構如果module未單獨打包上傳Maven倉庫,"mvn dependency:tree"是不能完整分析依賴關系的),記錄下來。如下圖所示:

然后升級沖突包,通過回歸測試受到影響的二方庫對應的業務點。

如果應用依賴非常復雜(例如沖突包有幾十個二方庫依賴,或者依賴沖突包的二方庫是個基礎包,業務系統中無法清晰枚舉出使用受影響二方庫的業務點),這種情況下,如果要通過升級jar包解決依賴沖突,必須完整回歸整個應用功能。筆者有幾次因為回歸不全面引發故障的慘痛經歷,希望大家不要重蹈覆轍。通過這幾次事例,筆者深刻理解到我們這個時代最偉大的計算機科學家Dijkstra大神“簡單是可靠的先決條件”這句至理名言,深深的體會到如果一個系統復雜到你完全無法理清楚他錯綜復雜的依賴關系的時候,那說明你該重構你的系統了,否則系統維護將會逐步變成噩夢。

當然不是所有情況都可以通過升降級jar解決沖突,舉個例子:

如上圖假設應用系統同時依賴A.jar,B.jar,而A.jar,B.jar都依賴protobuf-java,系統運行時都會分別用到A.jar,B.jar中protobuf部分的功能,而且A.jar,B.jar依賴的protobuf版本無法通過升高降低版本調整到一致。由于protobuf-java3.0版本序列化協議,類內容各方面都不兼容protobuf-java2.0版本。這種情況無論如何調整依賴都無法解決沖突的問題,要解決這種沖突,請繼續往下看,第五第六章內容。

2.排除jar包解決依賴沖突

上一章節中第二個例子,主要原因是容器啟動時加載到的類不是預期spring-beans-4.3.5.RELEASE.jar中的類,而是spring-2.5.6.SEC03.jar包中的類,如果spring-2.5.6.SEC03.jar排除對業務無影響,可以通過排除spring-2.5.6.SEC03.jar來解決沖突。與上一節例子類似,可以通過IDEA Maven Helper 插件確定spring-2.5.6.SEC03.jar是由哪個jar間接依賴進來的,判斷業務的影響范圍,此處不在贅述。與上一節一樣,類似的情況不一定都可以用排除jar解決。

五、通過pandora自定義插件解決依賴沖突

第四章中有講到,如果一個應用中要同時運行兩個不兼容版本的jar包,是無法通過Maven調整依賴關系解決的。第二章講解依賴沖突原理時有提到,Pandora通過類隔離機制實現了集團各個中間件之間的隔離,Pandroa同時也支持業務方按規范創建一個可以運行在Pandora容器中的插件,容器幫業務方實現加載隔離。

聯盟一淘團隊就將類似IC、卡券這種核武器級存在的二方包根據自己業務的需要進行裁剪包裝后,制作成Pandora插件來避免依賴沖突,取得了很好的效果。

用Pandora插件確實能在不對應用做很大調整,不影響性能的情況下完美解決依賴沖突問題。

但也有一些問題就不太適合用局部方法解決了,比如:

當維護的應用依賴過于復雜,每個應用依賴外部三四十個二方庫時。這種重量級應用就會嚴重影響生產效率。

如上圖所示,早期本人負責聯盟用戶平臺時,就遇到兩個巨無霸應用,adv(6w+代碼)、pub(12w+代碼)。

一方面因為依賴多,基本每周都會遇到集團各種升級,安全問題,各種小修小補,不斷的上線。一方面業務發布需求也較多。

導致需要頻繁發布,比如有一年個人就發布了566次。此時龐大的依賴導致部署效率,影響評估回歸都會很難,此時就不應該從局部解決沖突這種視角去看,應該考慮優化應用架構,進行依賴治理,盡量避免沖突。

六、通過依賴架構治理解決依賴沖突

1.復雜依賴標準化、簡化治理

首先,依賴本身就是一種復雜的業務。大部分依賴背后都有較深的業務領域知識 或者 技術領域知識。

比如我們查詢搜索。

業務領域知識方面,光銷量就有交易成交筆數,成交件數,搜索銷量【有些訂單不計入搜索銷量】等。

技術領域知識方面,主搜索,聯盟廣告搜索引擎有時是配合使用的,比如商家未入駐廣告前給商家展示貨品信息就需要查主搜索,而入駐后投放下行時則需要用廣告引擎。不同引擎的調用方法,結果都不一樣。

如下圖所示,如果我們每個業務應用都各自實現,那么各應用開發同學就要消化大量搜索客戶端相關的業務、技術領域知識。成本是很高的。

面對這種情況,如果我們將這類復雜的依賴,由專人owner進行統一包裝標準化【專人干專事】,會大大提升組織協同效率。如下圖所示。

我們通過對主搜索,聯盟引擎的統一封裝。對檢索條件,返回結果的標準化封裝。大大降低了同學們的接入成本,以往要熟悉一個引擎的接入大概要2天,用標準化封裝后的wrapper,在專人,規范文檔的指導下僅0.5天就可以,大大提升效率。

2.重量級依賴代理服務化

第五節中有講到,應用依賴的jar包過多會導致應用啟動很慢,因此如果一個依賴引入jar包超過30個以上時,務必要警惕,這種依賴引入幾個,就會逐步導致你工作效率大大下降。比如IC,TP,優惠中心的二方包就是典型的例子。

目前我們針對這類依賴,是直接封裝一個標準代理服務,避免應用被這種巨無霸二方包拖慢。

經過以上綜合治理手段,取得了很好的效果。目前聯盟很少再需要大家去解決沖突問題。

參考鏈接 

INode講解:http://www.cnblogs.com/itech/archive/2012/05/15/2502284.html

責任編輯:武曉燕 來源: 51CTO專欄
相關推薦

2009-10-10 15:26:11

資產管理

2021-03-28 21:33:07

Redis熱點key

2016-12-22 09:02:35

Linux誤刪文件

2016-11-10 18:57:19

雙十一高并發

2011-09-10 20:48:34

2022-04-21 09:26:41

FastDFS開源分布式文件系統

2011-01-19 13:12:27

2011-09-28 14:00:12

10086短信手機安全

2015-07-20 10:06:12

2009-05-05 14:30:19

虛擬化安全解決方案

2011-08-18 14:23:52

Big Data

2012-02-13 10:30:18

2012-06-05 19:18:43

BYODAvayaAvaya IDE

2014-09-29 16:44:12

2011-11-08 10:11:34

2012-02-26 16:26:42

IBM大數據Hadoop

2019-11-27 10:28:11

公共安全大數據數據聯系

2017-04-06 12:29:40

2017-10-26 09:50:55

2015-11-24 18:01:43

數字化醫療醫院PACS系統華為
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 中文二区 | 国产日韩精品一区 | 国产一区二区三区 | 久久综合九九 | 久久久久久91香蕉国产 | www.久久| 国产精品特级毛片一区二区三区 | 成人影院网站ww555久久精品 | av大片| 久久天堂网 | 久久久精品一区 | 在线中文字幕第一页 | 国产成人99久久亚洲综合精品 | 久久久久久久久99 | 成人在线视频观看 | www.亚洲精品 | 综合色导航 | 亚洲一区二区中文字幕 | 亚洲视频1区 | 久久久久久久久久久久久9999 | 视频三区 | 亚洲免费网 | 精品国产一区二区三区性色 | av色站 | 欧美日韩久久 | 亚洲一区二区久久 | 91久久电影 | 久久精品高清视频 | 青青草综合网 | 国产一区二区视频在线 | 国产亚洲黄色片 | 国产精品久久久久久久久久免费看 | 欧美精品一区二区三区在线 | 日韩亚洲一区二区 | 97免费在线观看视频 | 青春草国产 | 亚洲美女在线一区 | 中文字幕高清免费日韩视频在线 | 国产精品三级 | 午夜噜噜噜 | 国产电影精品久久 |