skywalking學習筆記

seef發表於2018-03-28

前言

隨著業務越來越複雜,企業應用也進入了分散式服務化的階段,傳統的日誌監控等方式無法很好達到跟蹤呼叫,排查問題等需求。在谷歌論文《 Dapper,大規模分散式系統的跟蹤系統》的指導下,許多優秀的APM應運而生。

分散式追蹤系統發展很快,種類繁多,給我們帶來很大的方便。但在資料採集過程中,有時需要侵入使用者程式碼,並且不同系統的 API 並不相容,這就導致瞭如果您希望切換追蹤系統,往往會帶來較大改動。OpenTracing為了解決不同的分散式追蹤系統 API 不相容的問題,誕生了 OpenTracing 規範。OpenTracing 是一個輕量級的標準化層,它位於應用程式/類庫和追蹤或日誌分析程式之間。詳細介紹見 opentracing文件中文版

本文要介紹的就是國人吳晟基於OpenTracking實現的開源專案skywalking(碼雲github)。

skywalking簡介

針對分散式系統的APM(應用效能監控)系統,特別針對微服務、cloud native和容器化(Docker, Kubernetes, Mesos)架構, 其核心是個分散式追蹤系統。

特點

架構

5.x Architecture

安裝

  • agent
    探針,用來收集和傳送資料到歸集器。

    1. 增加jvm引數 -javaagent:/path/to/skywalking-agent/skywalking-agent.jar
    2. 配置conf檔案 /config/agent.config
    
    # 當前的應用編碼,最終會顯示在webui上。
    # 建議一個應用的多個例項,使用有相同的application_code。請使用英文
    agent.application_code=Your_ApplicationName
    
    # 每三秒取樣的Trace數量
    # 預設為負數,代表在保證不超過記憶體Buffer區的前提下,採集所有的Trace
    # agent.sample_n_per_3_secs=-1
    
    # 設定需要忽略的請求地址
    # 預設配置如下
    # agent.ignore_suffix=.jpg,.jpeg,.js,.css,.png,.bmp,.gif,.ico,.mp3,.mp4,.html,.svg
    
    # 探針除錯開關,如果設定為true,探針會將所有操作位元組碼的類輸出到/debugging目錄下
    # skywalking團隊可能在除錯,需要此檔案
    # agent.is_open_debugging_class = true
    
    # 對應Collector的config/application.yml配置檔案中 agent_server/jetty/port 配置內容
    # 例如:
    # 單節點配置:SERVERS="127.0.0.1:8080" 
    # 叢集配置:SERVERS="10.2.45.126:8080,10.2.45.127:7600" 
    collector.servers=127.0.0.1:10800
    
    # 日誌檔名稱字首
    logging.file_name=skywalking-agent.log
    
    # 日誌檔案最大大小
    # 如果超過此大小,則會生成新檔案。
    # 預設為300M
    logging.max_file_size=314572800
    
    # 日誌級別,預設為DEBUG。
    logging.level=DEBUG
    複製程式碼
    1. 啟動被監控應用
  • collector
    鏈路資料歸集器,資料可以落地ElasticSearch,單機也可以落地H2,不推薦,H2僅作為臨時演示用。

  • web
    web視覺化平臺,用來展示落地的資料。

  • ui
    單獨的開源ui專案,更美觀易用。demo

介面

  • 拓撲
    skywalking學習筆記
  • 例項
    skywalking學習筆記
  • 系統監控
    skywalking學習筆記
  • 呼叫鏈路
    skywalking學習筆記
  • span
    skywalking學習筆記
  • 服務
    skywalking學習筆記

對比

分散式鏈路追蹤技術對比

技術

  • Java Agent
    Java agent是用一個簡單的jar檔案來表示的。跟普通的Java程式很相似,Java agent定義了一些類作為入口點。 這些作為入口點的類需要包含一個靜態方法,這些方法會在你原本的Java程式的main方法呼叫之前被呼叫:

    class MyAgent {
      public static void premain(String args, Instrumentation inst) {
        // implement agent here ...
      }
    }
    複製程式碼

    關於處理Java agent時最有趣的部分,是premain方法中的第二個引數。這個引數是以一個Instrumentation介面的實現類例項的形式存在的。這個接 口提供了一種機制,能夠通過定義一個ClassFileTransformer,來干預對Java類的載入過程。有了這種轉設施,我們就能夠在Java類 被使用之前,去實現對類邏輯的強化。
    在最基本的用例中,Java agent會用來設定應用屬性或者配置特定的環境狀態,agent能夠作為可重用和可插入的元件。如下的樣例描述了這樣的一個agent,它設定了一個系統屬性,在實際的程式中就可以使用該屬性了:

    public class Agent {
      public static void premain(String arg) {
        System.setProperty("my-property", “foo”);
      }
    }
    複製程式碼

    如果要使用這個agent,必須要將agent類和資源打包到jar中,並且在jar的manifest中要將Agent-Class屬性設定為包含premain方法的agent類。(agent必須要打包到jar檔案中,它不能通過拆解的格式進行指定。)接下來,我們需要啟動應用程式,並且在命令列中通過javaagent引數來引用jar檔案的位置:

    java -javaagent:myAgent.jar -jar myProgram.jar
    複製程式碼

    我們還可以在位置路徑上設定可選的agent引數。在下面的命令中會啟動一個Java程式並且新增給定的agent,將值myOptions作為引數提供給premain方法:

    java -javaagent:myAgent.jar=myOptions -jar myProgram.jar
    複製程式碼

    通過重複使用javaagent命令,能夠新增多個agent。
    但是,Java agent的功能並不侷限於修改應用程式環境的狀態,Java agent能夠訪問Java instrumentation API,這樣的話,agent就能修改目標應用程式的程式碼。Java虛擬機器中這個鮮為人知的特性提供了一個強大的工具,有助於實現面向切面的程式設計。
    如果要對Java程式進行這種修改,我們需要在agent的premain方法上新增型別為Instrumentation的第二個引數。Instrumentation引數可以用來執行一系列的任務,比如確定物件以位元組為單位的精確大小以及通過註冊ClassFileTransformers實際修改類的實現。ClassFileTransformers註冊之後,當類載入器(class loader)載入類的時候都會呼叫它。當它被呼叫時,在類檔案所代表的類載入之前,類檔案transformer有機會改變或完全替換這個類檔案。按照這種方式,在類使用之前,我們能夠增強或修改類的行為,如下面的樣例所示:

    public class Agent {
     public static void premain(String argument, Instrumentation inst) {
       inst.addTransformer(new ClassFileTransformer() {
         @Override
         public byte[] transform(
           ClassLoader loader,
           String className,
           Class<?> classBeingRedefined, // 如果類之前沒有載入的話,值為null
           ProtectionDomain protectionDomain,
           byte[] classFileBuffer) {
           // 返回改變後的類檔案。
         }
       });
     }
    }
    複製程式碼

    通過使用Instrumentation例項註冊上述的ClassFileTransformer之後,每個類載入的時候,都會呼叫這個transformer。為了實現這一點,transformer會接受一個二進位制和類載入器的引用,分別代表了類檔案以及試圖載入類的類載入器。
    Java agent也可以在Java應用的執行期註冊,如果是在這種場景下,instrumentation API允許重新定義已載入的類,這個特性被稱之為“HotSwap”。不過,重新定義類僅限於替換方法體。在重新定義類的時候,不能新增或移除類成員,並且型別和簽名也不能進行修改。當類第一次載入的時候,並沒有這種限制,如果是在這樣的場景下,那classBeingRedefined會被設定為null。

  • Byte Buddy
    Byte Buddy是開源的、基於Apache 2.0許可證的庫,它致力於解決位元組碼操作和instrumentation API的複雜性。Byte Buddy所聲稱的目標是將顯式的位元組碼操作隱藏在一個型別安全的領域特定語言背後。通過使用Byte Buddy,任何熟悉Java程式語言的人都有望非常容易地進行位元組碼操作。 作為Byte Buddy的簡介,如下的樣例展現瞭如何生成一個簡單的類,這個類是Object的子類,並且重寫了toString方法,用來返回“Hello World!”。與原始的ASM類似,“intercept”會告訴Byte Buddy為攔截到的指令提供方法實現:

    Class<?> dynamicType = new ByteBuddy()
      .subclass(Object.class)
      .method(ElementMatchers.named("toString"))
      .intercept(FixedValue.value("Hello World!"))
      .make()
      .load(getClass().getClassLoader(),          
            ClassLoadingStrategy.Default.WRAPPER)
      .getLoaded();
    複製程式碼

    詳見ByteBuddy作者的《Make agents, not frameworks》及譯文《構建Java Agent,而不是使用框架》

原始碼分析

更詳細的原始碼分析見芋道原始碼-skywailking

參考

Apache SkyWalking
分散式鏈路追蹤&應用監控APM軟體-skywalking