[jaeger] 二、客戶端使用 (Java版本)

小姐姐味道發表於2019-05-06

友情提示,jaeger的standalone部署方式,可以快速開啟試用。

本文通過兩個簡單的示例,說明如何使用java的api構建一個簡單的呼叫鏈。更多連載請關注《小姐姐味道》。相關程式碼見github。

https://github.com/sayhiai/example-jaeger-opentracing-tutorial-001-002
複製程式碼

由於jaeger是基於OpenTracing的,所以只要你的應用支援OpenTracing協議,就可以和Jaeger整合起來。

OpenTracing的地址是:

https://opentracing.io/
複製程式碼

接下來我們開動雙手吧。

編寫一個HelloWorld

一、maven依賴

首先,建立一個普通maven工程。然後加入依賴:

opentracing-util 0.32.0
jaeger-client 0.35.0
logback-classic 1.2.3
複製程式碼

主要用到了opentracing相關的jar包,而且用到了jaeger的java客戶端實現。

二、一段簡單的程式碼

首先建立一個簡單的loveyou類,裡面有一個簡單的方法hello。本部分之與OpenTracing有關,與Jaeger關係並不是很大。

hello方法體的前後,加入幾行簡單的程式碼,主要是根據OpenTracing規範定義的api進行一些呼叫資訊等內容的新增。

public class LoveYou {
    Tracer tracer;
    public LoveYou() {
        tracer = JaegerTracerHelper.initTracer("loveYouService");
    }

    public void hello(String name) {
        Span span = tracer.buildSpan("hello").start();
        span.setTag("name", name);

        System.out.println("Hello " + name);

        span.log("Love service say hello to " + name);
        span.finish();
    }

    public static void main(String[] args) {
        new LoveYou().hello("小姐姐味道");
    }
}
複製程式碼

程式碼主要加入了以下幾個重要的資訊。 1、構建了一個新的span,每個span有三個id:rootid、parentid、id。它們構成了樹狀呼叫鏈的每個具體節點。

2、給新加的span新增了一個tag資訊,用來進行一些自定義標識。tag有一些標準的清單,但也可以自定義。

3、給新加的span新增了log。log資訊會附著在資訊span上,一塊被收集起來,僅定義一些比較重要的資訊,包括異常棧等。一些不重要的資訊不建議使用log,它會佔用大量儲存空間。


執行程式碼後,可以在jaeger的ui端看到這次的呼叫資訊。如下:

[jaeger] 二、客戶端使用 (Java版本)

三、構建jaeger實現

我們的OpenTracing資料是如何構建,併傳送到Jaeger的server端呢?就是通過下面的程式碼完成的。

public class JaegerTracerHelper {
    public static JaegerTracer initTracer(String service) {

        final String endPoint = "http://10.30.94.8:14268/api/traces";

        final CompositeReporter compositeReporter = new CompositeReporter(
                new RemoteReporter.Builder()
                        .withSender(new HttpSender.Builder(endPoint).build())
                        .build(),
                new LoggingReporter()
        );

        final Metrics metrics = new Metrics(new NoopMetricsFactory());

        JaegerTracer.Builder builder = new JaegerTracer.Builder(service)
                .withReporter(compositeReporter)
                .withMetrics(metrics)
                .withExpandExceptionLogs()
                .withSampler(new ConstSampler(true));

        return builder.build();
    }
}
複製程式碼

JaegerTracer的引數很多,本篇不做詳細介紹。要完成示例構建需要以下簡單步驟:

1、構建Reporter,指傳送到server的方式,程式碼中構建了一個http endpoint,越過jaeger-agent直接傳送到jaeger-collector

2、構建一個Sampler,指定要收集的資訊,由於本次要收集所有的資訊。所以使用預設的ConstSampler


哦對了,為了便於除錯和發現,程式碼還加入了一個LoggingReporter,用於將span輸出到控制檯。效果如下:

[jaeger] 二、客戶端使用 (Java版本)
到此為止,一個簡單的示例java示例九完成了。以上程式碼,見github: github.com/sayhiai/exa…

實現一個2層深度的鏈

以上程式碼,僅產生了一個span,也就是一個方法呼叫。接下來,我們看一下如何完成一個多層的呼叫鏈條。

接下來還是要修改LoveYou類。我們把呼叫方法hello拆解一下,拆成dispatchhello兩個方法,並在hello方法裡sleep一秒鐘。

期望生成兩條trace資訊。

dispatch

public void dispatch(String cmd, String content) {
    Span span = tracer.buildSpan("dispatch").start();
    tracer.activateSpan(span);


    if (cmd.equals("hello")) {
        this.hello(content);
    }


    if (null != span) {
        span.setTag("cmd", cmd);
        span.finish();
    }
}
複製程式碼

hello

public void hello(String name) {
    Span span = tracer.buildSpan("hello").start();
    tracer.activateSpan(span);


    System.out.println("Hello " + name);
    try {
        Thread.sleep(TimeUnit.SECONDS.toMillis(1));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    span.setTag("name", name);
    span.log("Love service say hello to " + name);
    span.finish();
}
複製程式碼

與示例一不同的是,每次生成span之後,我們還要將其啟用一下

tracer.activateSpan(span);
複製程式碼

它的目的主要是讓span例項在當前的ctx裡面保持活躍(比如一個執行緒)。這樣,如果新的span判斷當前有活躍的span,則將它們放在同一個scope中。這樣,鏈條就串起來了。

以下是程式執行後的效果。

[jaeger] 二、客戶端使用 (Java版本)

取樣

有時候,我們的服務QPS非常高,瞬間能夠生成大量的trace資訊。這些資訊是非常相近的,且會給儲存產生很大的壓力。

如果不需要統計一些QPS之類的資訊,就可以使用sampler,僅收集部分trace。

還記得我們使用javaapi構建的jaeger例項麼?其中,有這麼一行程式碼:

.withSampler(new ConstSampler(true))
複製程式碼

這就是最簡單的取樣,意思是收集所有的資訊。jaeger支援四種不同的取樣型別。

Constant

這是一個布林開關,如果sampler.param=1,則代表收集所有的trace,如果為0,則代表什麼都不收集。

Probabilistic

基於概率進行取樣,比如sampler.param=0.1,則代表有1/10的trace將被收集。

Rate Limiting

限流方式,使用令牌桶限流。 sampler.param=2.0 則代表每秒有2個trace被收集,超出的將被拋棄。

Remote

通過遠端配置方式配置,這也是預設的方式。比如在Collector中配置strategies.json

{
  "service_strategies": [
    {
      "service": "foo",
      "type": "probabilistic",
      "param": 0.8,
      "operation_strategies": [
        {
          "operation": "op1",
          "type": "probabilistic",
          "param": 0.2
        },
        {
          "operation": "op2",
          "type": "probabilistic",
          "param": 0.4
        }
      ]
    },
    {
      "service": "bar",
      "type": "ratelimiting",
      "param": 5
    }
  ],
  "default_strategy": {
    "type": "probabilistic",
    "param": 0.5
  }
}
複製程式碼

End

通過OpenTracing的Api,可以很容易的實現呼叫鏈功能。但可以看到,由於存在各種各樣的客戶端,主要工作量就集中在對這些客戶端的相容上。比如執行緒池、SpringCloud、MQ、資料庫連線池等等等等。

使用Aop可以省去一些編碼和侵入,但可控制性會弱一些。

接下來,我們給一個簡單的OkHttp+SpringBoot呼叫,也就是分散式應用,新增trace功能。

[jaeger] 二、客戶端使用 (Java版本)

相關文章