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

一波三折,APM監控系統對于OSGI架構的探索實踐

原創
開發 架構
當我們的監控系統遇到了OSGI架構系統也是碰撞出了激烈的火花,足足用了兩天的時間,才搞定了各種水土不服。我把期間的各種酸甜苦辣記錄下來,希望為奮斗在APM一線的同行們提供一點點幫助。

2017年我們一直在做分布式服務跟蹤系統的升級改造,為了更好的服務于廣大的開發和運維人員,能夠在數以千萬計的微服務系統中快速的發現問題、定位問題。一年下來,接入了上千個系統,快的幾分鐘,慢的不到10分鐘,最多就是處理一下jar包依賴沖突問題,所以能這么迅速的推廣。不過前幾天遇到一個客戶,他們的系統采用的是OSGI的框架。OSGI這個詞相信大部分人是聽過沒用過的。

當我們的監控系統遇到了OSGI架構系統也是碰撞出了激烈的火花,足足用了兩天的時間,才搞定了各種水土不服。我把期間的各種酸甜苦辣記錄下來,希望為奮斗在APM一線的同行們提供一點點幫助。

在整個過程中,我們遇到了四個技術關鍵點:

  • 把一個普通的jar包Bundle化。
  • OSGI的類加載機制。
  • 引入第三方非Bundle化的jar包。
  • 通過Activator在Bundle的啟動和停止實現回調。

項目背景

首先我簡單介紹下兩個項目的背景:

監控系統:這是一個利用動態字節碼技術,自動的無侵入的對目標系統實行秒級實時監控,監控內容包括但不限于容量、性能、成功率、調用鏈、應用拓撲等,詳細內容請參考:http://os.51cto.com/art/201709/552641.htm。

目標系統:分為兩部分,第一部分以war包形式發布,部署到Web容器內,接收http請求;第二部分采用OSGI架構,每一個Bundle是一個業務服務(可以理解為Bundle就是微服務)。這兩部分通過servlet的橋接方式連接,其中一些公用Bundle(如slf4j)會放在war包的指定目錄中,每個業務Bundle不需要再單獨引入。這個架構是我在解決了所有問題之后才總結出來的,在這里提前拋出是為了方便理解后邊的內容。

剛開始的時候,我們就把它當做一個普通的系統來接入,把我們的jar包放到了目標系統war包的WEB-INF/lib下,加入啟動腳本,再啟動系統,可以看到我們的jar打印出的啟動日志,然后就沒有然后了,除了那一行日志,沒有任何效果。這個時候,我就意識到了OSGI系統不是這么玩的,于是開始OSGI的漫漫探索之路......

當看到OSGI的每一個Bundle包都是用單獨ClassLoader負責加載時,我仿佛找到了解決方案。

我們把監控jar包打到了每一個業務的Bundle里邊,然后重啟,結果監控成功了,問題解決了。

從純技術角度來看貌似是沒什么問題,然而噩夢才剛剛開始。由于監控jar包打入了業務Bundle內,帶來了兩個比較棘手的問題:第一,技術上每個業務Bundle都需要這么去引入,加大了開發工作量,這個和我們極致的設計理念是不符的;第二,業務上每一個業務Bundle就成為了一個單獨應用,客戶方表示我們這個是一個應用,而不是多個應用。

所以還是要解決之前的問題,把整個目標系統所有的Bundle當做一個應用去接入監控。

我不熟悉目標系統和OSGI架構,客戶開發方又不了解監控系統的原理和實現過程,經過了長時間的各種嘗試和交流,仍沒有絲毫進展。于是我們決定采用一個最原始,最簡單,最笨,也是最有效的方法,從“hello world”開始。

當一個系統出現問題,你又不知道問題出在哪部分的時候,要么把這些“部分”一個一個去掉,直到發現沒有“問題”為止;要么從“零”開始,然后一個一個的加入,直到出現“問題”為止,我們采取了后者。

首先,針對我們的監控jar包去掉基于動態字節碼的自動監控,采用編程式的直接API調用,并且將API接口做了Mock,去掉了所有的第三方依賴。修改目標系統的代碼,在希望被監控的方法中直接調用監控API。打包,部署,啟動,被監控Bundle不能啟動,報錯......

  1. Missing Constraint: Import-Package: com..................sgm...... 

經過和對方開發人員的溝通和網上查閱OSGI相關資料,了解到這是一個OSGI打包的規范問題。

之前我們的監控jar包是沒有按照OSGI的規范去打包的,打的只是一個普通的jar包,所以在OSGI框架下,其他的Bundle是無法訪問到我們的jar包中的類,造成啟動報錯的問題。這里遇到了我們第一個要解決的主要問題:

1. 普通jar包Bundle化

先看下邊的兩張圖:

 

上邊的兩張圖是jar包中META-INF/MANIFEST.MF文件,第一張圖是普通jar包,第二圖是具有OSGI規范的jar包。既然知道了,那這樣的OSGI的包怎么打?我們用maven來編譯,順理成章的就找到了maven-Bundle-plugin的這個插件,使用很簡單,代碼如下:

  1. <plugin> 
  2. <groupId>org.apache.felix</groupId> 
  3. <artifactId>maven-Bundle-plugin</artifactId> 
  4. <version>3.3.0</version> 
  5. <extensions>true</extensions> 
  6. <executions> 
  7. <execution> 
  8. <id>Bundle-manifest</id> 
  9. <phase>process-classes</phase> 
  10. <goals> 
  11. <goal>manifest</goal> 
  12. </goals> 
  13. </execution> 
  14. </executions> 
  15. <configuration> 
  16. <instructions> 
  17. <Import-Package>org.slf4j</Import-Package> 
  18. <Export-Package>com.wangyin.sgm.client</Export-Package> 
  19. <Bundle-RequiredExecutionEnvironment>JavaSE-1.6</Bundle-RequiredExecutionEnvironment> 
  20. </instructions> 
  21. </configuration> 
  22. </plugin>

在這么多屬性中, Import-Package和Export-Package尤其重要,一個jar包就是一個Bundle,Bundle和Bundle之間的訪問全靠這兩個屬性來控制。

Import-Package:說明了這個Bundle jar需要調用外部其他Bundle的哪些包(package)。

Export-Package: 說明了這個Bundle jar可以提供哪些包(package)供其他Bundle去調用。

當一個Bundle啟動的時候,會分為Resolved(解析),Installed(安裝),Started(激活)等幾個步驟,解析就是檢查jar是不是正常,安裝的時候會把Export-Package中的指定的包進行注冊,這就知道哪些包由哪些Bundle來提供,激活的時候會檢查當前這個Bundle的Import-Package依賴的包是不是都有對應的Bundle來提供,否則激活失敗。

修改監控客戶端,把父項目,子項目,子子項目全部按照OSGI規范打包,又是一遍部署重啟,這次被監控的業務Bundle沒有報錯,而是監控客戶端啟動報錯:

  1. Missing Constraint: Import-Package: org.slf4j 

有了剛才的經驗,一看就知道是沒有slf4j,可是對方開發人員反饋slf4j是有的,他們自己也在用,這就奇怪了。

這時我發現還有在監控客戶端里MANIFEST.MF的一句話org.slf4j;version="[1.7,2)",version這個詞引起了我的注意。

原來在目標系統里的slf4j是1.5版本,而監控客戶端要求1.7版本,slf4j降級再試,這次目標系統成功調用到了監控客戶端的API,打印出了日志,萬里長征終于邁出了第一步。但這只是一個Mock的版本,真正的監控程序還沒有加入。

先小結一下:首先在OSGI的框架下,所有jar必須按照OSGI的規范去打包,否則不能使用;其次要對Import-Package和Export-Package配置好,需要依賴外部哪些包,自己又可以提供哪些包供外部使用,同時注意版本,依賴時一般都是要高于哪個版本。

接下來,就要加入真正的代碼跑一跑,根據前面的經驗還是要慢慢來,我們分兩步加入代碼,第一次先加入監控代碼,待成功后加入網絡傳輸部分的代碼,后邊遇到的坑讓我們發現這個決定是正確的。

打包部署啟動調用這個流程已經很熟練了,報錯還是如期出現了,這次報錯的是com.lmax的disruptor這個第三方開源jar包:

  1. Missing Constraint: Import-Package: sun.misc 

納尼?sun.misc沒有?這不是jdk里的嗎,為什么會沒有呢?于是,又是一番資料查找,終于明白了其中的道理。

這里就要講到OSGI的類加載機制了,它并不是我們常說的雙親委托機制。關于這個問題,網上已經有很多文章介紹了,但這里我還是結合這個例子簡單的說一下。

2. OSGI的類加載機制

首先每一個Bundle(jar)都會被一個單獨的ClassLoader去加載,當一個Bundle的ClassLoader嘗試去加載一個類的時候:

  1. 如果這個類的包名是java.*開頭的,那么直接交給bootstrap ClassLoader去加載。
  2. 查看這個類是否在OSGI的配置文件中有org.osgi.framework.bootdelegation屬性定義,如果定義了,交給bootstrap ClassLoader去加載這個類。
  3. 查看這個類是否在OSGI的配置文件中有org.osgi.framework.system.packages屬性定義,如果定義了,交給父類加載器去加載,一般就是AppClassLoader。
  4. 查看這個類是否在本Bundle的MANIFEST.MF文件的Import-Package中定義,如果定義了,交給Export-Package這個類的Bundle去加載。
  5. 在上邊條件都不滿足的時候,那這個類就是自己的Bundle的內部類,由自己的ClassLoader去加載。

現在我們來看一下,下邊這張圖是disruptor的MANIFEST.MF文件:

在disruptor里使用了sun.misc.Unsafe類,在啟動disruptor的時候,需要加載sun.misc.Safe,那么1,2,3點都不滿足,命中了第4點,就開始尋找帶有Export-Package的Bundle,那肯定找不到。

遵循上邊的原則,在配置文件中加入了org.osgi.framework.bootdelegation=javax.*,sun.*,同時又把disruptor中的Import-Package刪掉了,問題成功解決了,又向勝利邁進了一步。

接下來,就要把網絡傳輸這部分加入進來了,系統就可以監控了,數據需要發送出來才可以真正的使用。有了之前的經驗,感覺應該問題不大,然而現實情況并不是這樣……

當把這部分代碼和依賴加入后,各種的Missing Constraint: Import-Package: xxx。我發現所有的依賴的第三方jar都在里邊,為什么還會報錯,我開始懷疑是這些第三方jar本身的問題。

打開這些jar文件的MANIFEST.MF文件查看,果然如此,我們依賴的這些jar有多一半都不是Bundle化的jar包,這里就涉及到了本文第三個要解決的核心問題。

3. OSGI如何加載第三方非Bundle化的jar包

OSGI如何加載第三方非Bundle化的jar包,有如下幾種方式:

  • 通過父類加載器加載,也就是配置org.osgi.framework.system.packages。
  • 將jar轉換成Bundle,然后Export-Package。
  • 把jar打包進引用方的Bundle。

第一種方式需要目標系統配置,同樣不符合我們的設計理念,顯然不合適,于是我們首先嘗試了第二種方式,重新打包那些非Bundle的第三方jar。

在這個過程中,我們發現這絕對是個苦逼的活,需要找到源碼,下載源碼,修改pom,有的找源碼很費勁,有的還是ant編譯的,有的雖然是maven管理,但又依賴了父項目……

總之想順利的重新打包是個很費勁的事。看來只剩下第三條路了,這又要退回到之前第一個問題,如何打一個Bundle jar。

之前我們是把maven工程的每一個子項目分別Bundle化,如果要把第三方jar打入Bundle,那就有可能一個第三方jar被多次打入不同的子項目Bundle,造成浪費。

所以決定放棄對原有項目的每個子項目單獨Bundle化的方案,而是新建一個子項目,由這個子項目引入所有的其他子項目和第三方依賴jar,把他們所有打成一個大的Bundle jar。

  1. <Import-Package>org.osgi.framework,org.slf4j</Import-Package> 
  2. <Export-Package>com.wangyin.sgm.client</Export-Package> 
  3. <Private-Package>com.wangyin.*,com.lmax.disruptor.*,…… 
  4. </Private-Package>

看一下上邊的配置,比之前多了一個Private-Package,就是說哪些Package是這個Bundle的內部包,也就是要打入最后Bundle jar的東西。

現在通過編程式API直接調用的方式已經可以監控到目標系統了,最后要做的就是引入運行時字節碼增強技術。

還是按照常規的方式,把我們的Agent通過javaagent方式啟動,有了之前的經驗,我知道這個是被bootstrap ClassLoader加載的,于是就直接在org.osgi.framework.bootdelegation中加入了監控Agent的包名。

結果啟動正常,但是無法自動監控,看了日志后發現是監控客戶端沒有啟動。監控客戶端的啟動是通過在每個類加載的時候,嘗試性的使用它的類加載去加載監控客戶端的啟動類。

如果可以加載上,那么就啟動成功了,因為啟動程序是放在了啟動類的static塊中,且啟動類是一個單例模式,記錄著被監控應用的信息。

從這個啟動日志來分析,被監控系統有200多個Bundle,每個Bundle啟動都去加載監控客戶端,然后我們希望監控客戶端被它自己的類加載器去加載。這里就是本文第四個核心問題。

4. 如何在Bundle啟動的時候去做一些初始化操作

在OSGI的規范里提供了一個叫BundleActivator的接口,里邊有start和stop兩個方法,顧名思義,在Bundle啟動和停止的時候會回調這兩個方法,這就好辦了,我們可以在start方法中實現啟動監控客戶端的代碼。

  1. <instructions> 
  2. <Bundle-Activator>com.wangyin.sgm.client.Activator</Bundle-Activator> 
  3. <Import-Package>org.osgi.framework,org.slf4j</Import-Package> 
  4. <Export-Package>com.wangyin.sgm.client</Export-Package> 
  5. <Private-Package>com.wangyin.*,com.lmax.disruptor.*,org.apache.flume.* 
  6.         ,org.apache.avro.*,com.thoughtworks.*, 
  7.         ,org.apache.commons.compress.*,org.apache.commons.lang.* 
  8.         ,org.codehaus.jackson.*,org.jboss.netty.*,org.apache.velocity.* 
  9.         ,org.xerial.snappy,org.tukaani.xz.* 
  10. </Private-Package> 
  11. <Bundle-RequiredExecutionEnvironment>JavaSE-1.6</Bundle-RequiredExecutionEnvironment> 
  12. </instructions>

上邊的Bundle-Activator這個標簽,指定這個Bundle的Activator是哪個類。

至此所有的問題都得到了解決,這次OSGI應用接入APM監控足足花掉了兩天的時間。

由于負責監控系統的人員并沒有使用過OSGI,被監控目標系統的開發人員也不知道監控的原理是什么,一開始我們都以兩個產品整體去接入,做了許多的無用功,耽誤了很多時間。

從這個案例可以看出,當你所做的東西需要應用到一個你不熟悉的技術領域的時候,又不可能有足夠的時間去學習這個領域的知識,有一個最好的辦法就是改造你所做的系統,從零開始,逐漸加碼,去適應那個不熟悉的領域。

千萬不要想著能整體一下解決所有問題,因為可能要解決所有問題有100個技術點需要去修改,這100個問題同時暴露,你只有把它們同時都修改了,才能看到你的成果,這是根本不可能的事情。

而這100個問題一個個暴露出來,把一個不可能完成的大任務拆分成若干個可完成的小任務,修改一個,看到一步成功的效果,問題就得到了解決。

作者簡介:

[[215901]]

張晨, 資深研發工程師,目前任職京東金融,曾任職于搜狐等互聯網公司,擅長Java底層技術的研發及疑難問題的定位。從2015年開始從事智能運維監控平臺的研發與實踐,參與并主導了APM等產品的研發與應用,經歷了多次618和雙11的千萬級TPS的運維保障,支撐了京東金融的大量業務應用。

[[215902]]

沈建林,曾在多家知名第三方支付公司任職系統架構師,致力于基礎中間件與支付核心平臺的研發,主導過 RPC 服務框架、數據庫分庫分表、統一日志平臺,分布式服務跟蹤、流程編排等一系列中間件的設計與研發,參與過多家支付公司支付核心系統的建設?,F任京東金融集團資深架構師,負責基礎開發部基礎中間件的設計和研發工作。擅長基礎中間件設計與開發,關注大型分布式系統、JVM 原理及調優、服務治理與監控等領域。

責任編輯:王雪燕 來源: 51CTO
相關推薦

2009-07-29 09:07:51

Linux驅動開源操作系統微軟

2020-02-12 16:50:32

MySQL備份數據庫

2020-08-06 17:16:47

抖音Tiktok美國

2010-07-05 09:41:30

美國云計算

2018-05-26 23:03:07

中興芯片特朗普

2021-10-29 05:39:46

歐盟英偉達收購

2020-07-14 13:17:23

GitHub宕機服務中斷

2021-01-01 09:03:44

故障HAProxy服務器

2021-11-04 18:27:02

緩存架構Eureka

2014-09-02 10:19:22

IT程序員

2014-09-29 14:35:57

WIFI物聯網RFID

2021-09-01 13:46:07

GitHub Copi漏洞代碼訓練

2014-08-19 09:34:01

2021-12-26 00:13:24

Log4jLogback漏洞

2010-10-21 14:38:07

網絡融合

2010-01-21 17:05:21

互聯網

2018-05-26 15:50:15

2015-11-17 12:56:33

浪潮SC15

2010-06-03 15:30:01

Windows2008

2021-12-08 10:35:04

開源監控Zabbix
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 草b视频 | 国产成人精品综合 | 国产综合久久 | 最新高清无码专区 | 九一在线| 欧美在线观看一区 | 99福利在线观看 | 韩日免费视频 | 成人欧美一区二区三区视频xxx | 综合视频在线 | 日本高清视频在线播放 | 亚洲 欧美 另类 日韩 | 亚洲精品女人久久久 | 91精品国产一区二区三区 | 国产精品美女久久久久久不卡 | 久久久久久久久久久久91 | 免费h在线 | 亚洲永久| 国产区在线看 | 四虎影院在线播放 | 欧美亚洲视频在线观看 | 日韩精品网站 | 中文字幕黄色大片 | 国产a爽一区二区久久久 | 日日骑| 亚洲国产成人精品女人久久久 | 国产高清一区二区 | 久久久久国产精品人 | 亚洲综合字幕 | 国产日韩久久 | 久久视频免费看 | 精品久久久久久久人人人人传媒 | 91视频在线| 日韩成人国产 | 亚洲综合大片69999 | 福利二区| 理论片免费在线观看 | 黄色网毛片 | 久久网站免费视频 | 久久国产精品免费视频 | 久久国产综合 |