欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中的OpenTracing使用實(shí)例

 更新時(shí)間:2024年01月26日 09:20:10   作者:ZhaoJuFei  
這篇文章主要介紹了Java中的OpenTracing使用實(shí)例,主要的OpenTracing API將所有主要組件聲明為接口以及輔助類,例如Tracer,Span,SpanContext,Scope,ScopeManager,Format(用映射定義通用的SpanContext注入和提取格式),需要的朋友可以參考下

構(gòu)件組織

OpenTracing API的Java構(gòu)件如下:

  • opentracing-api:主要的API,無其他依賴。
  • opentracing-noop:為主要API提供無意義實(shí)現(xiàn)(NoopTracer),依賴于opentracing-api。
  • opentracing-util:工具類,例如GlobalTracer和默認(rèn)的基于ThreadLocal存儲(chǔ)的ScopeManager實(shí)現(xiàn),依賴于上面所有的構(gòu)件。
  • opentracing-mock:用于測(cè)試的mock層。包含MockTracer,簡(jiǎn)單的將Span存儲(chǔ)在內(nèi)存中,依賴于opentracing-api和opentracing-noop。

安裝(Maven)

<dependency>
    <groupId>io.opentracing</groupId>
    <artifactId>opentracing-api</artifactId>
    <version>VERSION</version>
</dependency>

也可以使用opentracing-noop,opentracing-mock,opentracing-util來安裝其他的構(gòu)件,如果安裝多個(gè)構(gòu)件,需要提供一致的VERSION。

主要API

主要的OpenTracing API將所有主要組件聲明為接口以及輔助類,例如Tracer,Span,SpanContext,Scope,ScopeManager,F(xiàn)ormat(用映射定義通用的SpanContext注入和提取格式)。

OpenTracing 社區(qū)貢獻(xiàn)

除了官方的API,也有一些苦在opentracing-contribe,保管通用的輔助類像TracerResolver和框架工具庫

例如 Java Web Servlet Filter and Spring Cloud,可以用于在使用這些框架工具的項(xiàng)目中方便的集成OpenTracing。

Quick Start

下面使用opentracing-mock中的MockTracer來進(jìn)行示例:

import java.util.Map;
import io.opentracing.mock.MockTracer;
import io.opentracing.mock.MockSpan;
import io.opentracing.tags.Tags;
// Initialize MockTracer with the default values.
MockTracer tracer = new MockTracer();
// Create a new Span, representing an operation.
MockSpan span = tracer.buildSpan("foo").start();
// Add a tag to the Span.
span.setTag(Tags.COMPONENT, "my-own-application");
// do something for business logic
// Finish the Span.
span.finish();
// Analyze the saved Span.
System.out.println("Operation name = " + span.operationName());
System.out.println("Start = " + span.startMicros());
System.out.println("Finish = " + span.finishMicros());
// Inspect the Span's tags.
Map<String, Object> tags = span.tags();

使用Span

在任何時(shí)間點(diǎn),OpenTracing Java API僅允許同一個(gè)線程中只存在一個(gè)活躍的Span。但是在同一個(gè)線程中允許同時(shí)存在符合下述條件的Span:

  • Started,新建的Span,但是沒有在任何作用域(Scope)中激活
  • Not Finished,調(diào)用finish方法之前均處于該狀態(tài)
  • Not Active,未被激活

同一個(gè)線程上可能有多個(gè)Span,如果它們:

  • 正在等待I/O操作完成
  • 被子Span阻塞
  • 或被溢出關(guān)鍵路徑

人工地將活躍的Span從一個(gè)函數(shù)傳遞到另一個(gè)函數(shù)是極為不便的,所以O(shè)penTracing要求每個(gè)Tracer包含一個(gè)作用域管理器(ScopeManager)。ScopeManager可以通過Scope來方法激活的Span,Scope來管理Span的激活與失活。ScopeManager API運(yùn)行將Span傳到到另一個(gè)線程或回調(diào),而不是傳遞Scope。

開發(fā)這在創(chuàng)建新的Span時(shí),如果當(dāng)前線程的Scope中已經(jīng)存在活躍的Span,則該活躍Span則會(huì)成為新創(chuàng)建Span的父親,除非開發(fā)者在buildSpan()時(shí)調(diào)用ignoreActiveSpan()或者明確指定父上下文(parent context)。

訪問活躍的Span

開發(fā)者可以通Scope對(duì)象訪問活躍的Span

io.opentracing.Tracer tracer = ...;
...
Scope scope = tracer.scopeManager().active();
if (scope != null) {
    scope.span().log("...");
}

在線程間移動(dòng)Span

使用OpenTracing API,開發(fā)者可以在多個(gè)不同的線程間傳輸Span。

一個(gè)Span的生命周期可以在一個(gè)線程中開始在另一個(gè)線程中結(jié)束。

不支持傳遞Scope到另一個(gè)線程或回調(diào)。Span的內(nèi)部時(shí)序細(xì)節(jié)看來如下:

[ ServiceHandlerSpan                                 ]
 | FunctionA |     waiting on an RPC      | FunctionB |
 
---------------------------------------------------------> time

當(dāng)執(zhí)行FunctionA和FunctionB時(shí)ServiceHandlerSpan是活躍的,但是在等待RPC調(diào)用的過程中是失活的。RPC可能有自己的Span,但我們現(xiàn)在只關(guān)注ServerHandlerSpan如何從FunctionA傳播到FunctionB。使用ScopeManager API可以在FunctionA中獲取Span,RPC結(jié)束后在FunctionB中重新獲取Span。步驟如下:

  • 通過startManager或startActive(false)方法創(chuàng)建一個(gè)Span以阻止Scope失活時(shí)令Span終止。
  • 在回調(diào)代碼(閉包/Runnable/Future)中調(diào)用tracer.scopeManager().active(span,false)來重新激活Span獲取一個(gè)新的Scope,當(dāng)Span不再活躍時(shí)關(guān)閉Scope(或者使用try-with-resources以簡(jiǎn)化代碼)
  • 在回調(diào)代碼末尾,調(diào)用tracer.scopeManager().active(span,true)來重新激活Span并得到一個(gè)自動(dòng)關(guān)閉的Scope。

代碼如下:

io.opentracing.Tracer tracer = ...;//通過具體的實(shí)現(xiàn)來創(chuàng)建tracer對(duì)象
...
// STEP 1 ABOVE: 開啟新的Span和Scope
try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) {
    // Span在Scope中被激活
    final Span span = scope.span();
    doAsyncWork(new Runnable() {
        @Override
        public void run() {
            // STEP 2 ABOVE: 重新激活Span
            // 如果需要自動(dòng)終止激活的Span,傳遞true給active方法
            try (Scope scope = tracer.scopeManager().activate(span, true)) {
                ...
            }
        }
    });
}

通過框架的攔截器能力實(shí)現(xiàn)HTTP請(qǐng)求追蹤

通過上文中的代碼,我們知道了如何使用Tracer對(duì)象構(gòu)建Span,如何在線程中激活Span,以及如何在異步環(huán)境的不同線程間傳遞Span。

在實(shí)際的業(yè)務(wù)開發(fā)中,我們很難使用這種侵入的方式來實(shí)現(xiàn)追蹤,更多的是利用各種框架提供的攔截器機(jī)制,來對(duì)各種業(yè)務(wù)調(diào)用進(jìn)行自動(dòng)追蹤,比如Spring AOP,Servlet Filter,等等。下面一段代碼展示了如何通過Servlet Filter來進(jìn)行服務(wù)端的HTTP請(qǐng)求追蹤。

@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
    HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        // 從Http Headers中提取上下文
    SpanContext extractedContext = tracer.extract(Format.Builtin.HTTP_HEADERS,
            new HttpServletRequestExtractAdapter(httpRequest));
      // 創(chuàng)建并激活一個(gè)新的Span,如果前面提取到的上下文不為null,則作為父SpanContext
    final Scope scope = tracer.buildSpan(httpRequest.getMethod())
            .asChildOf(extractedContext)
            .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_SERVER)
            .startActive(false);
        final Span span = scope.span();
    // 追蹤請(qǐng)求的地址
    span.setTag(Tags.HTTP_URL, httpRequest.getRequestURI());
    try {
        // 實(shí)際執(zhí)行過濾器鏈處理請(qǐng)求
        chain.doFilter(servletRequest, servletResponse);
    } finally {
         if (httpRequest.isAsyncStarted()) {
             // 如果請(qǐng)求是異步的,那么需要將Span對(duì)象傳遞到異步回調(diào)中
             httpRequest.getAsyncContext()
                     .addListener(new AsyncListener() {
                 @Override
                 public void onComplete(AsyncEvent event) throws IOException {
                     // 回調(diào)是在異步線程中執(zhí)行的
                     // 需要使用Scope在異步先線程中激活Span
                     try(Scope sc = tracer.scopeManager().activite(span, true)){
                         HttpServletResponse httpResponse = (HttpServletResponse) event.getSuppliedResponse();
                         // 追蹤響應(yīng)狀態(tài) 
                         sc.span().setTag(Tags.HTTP_STATUS, httpResponse.getStatus());
                     }
                 }
                 @Override
                 public void onTimeout(AsyncEvent event) throws IOException {
                     try(Scope sc = tracer.scopeManager().activite(span, true)){
                         // 記錄錯(cuò)誤
                         sc.span().setTag(Tags.ERROR, true)
                         sc.span().log(Maps.of(Fields.EVENT, event,
                                      Fields.ERROR_KIND, "TIMEOUT"))
                     }
                 }
                 @Override
                 public void onError(AsyncEvent event) throws IOException {
                     try(Scope sc = tracer.scopeManager().activite(span, true)){
                         // 記錄錯(cuò)誤
                         sc.span().setTag(Tags.ERROR, true)
                         sc.span().log(
                             Maps.of(Fields.EVENT, event,
                                     Fields.ERROR_KIND, event.getThrowable().getClass()))
                     }
                 }
                 @Override
                 public void onStartAsync(AsyncEvent event) throws IOException {
                 }
             });
         } else {
             // 如果是同步請(qǐng)求,直接終止Span
             scope.span().finish();
         }
         // 釋放當(dāng)前線程中的Span
         scope.close();
    }
}

利用這個(gè)過濾器,在Servlet應(yīng)用中,用于追蹤請(qǐng)求代碼與業(yè)務(wù)代碼解耦,并且僅需要一次編寫,下面來看客戶端如何追蹤請(qǐng)求并向處理請(qǐng)求的服務(wù)端傳遞上下文,以Spring RestTemplate為例:

可以通過RestTemplate.setInterceptors注冊(cè)攔截器。

@Override
public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body,
                                    ClientHttpRequestExecution execution) throws IOException {
    // 創(chuàng)建新的Span,以當(dāng)前線程中的SpanContext為父,如沒有則自己成為根Span
    try (Scope scope = tracer.buildSpan(httpRequest.getMethod().toString())
            .withTag(Tags.SPAN_KIND.getKey(), Tags.SPAN_KIND_CLIENT).startActive(true)) {
        // 追蹤請(qǐng)求地址
        scope.span().setTag(Tags.HTTP_URL, httpRequest.getURI().toString())
        // 將SpanContext注入到請(qǐng)求頭中
        // 看前文中的代碼可以知道,服務(wù)端通過Tracer.extract可以從請(qǐng)求頭中提取出SpanContext
        tracer.inject(scope.span().context(), Format.Builtin.HTTP_HEADERS,
                new HttpHeadersCarrier(httpRequest.getHeaders()));
        // 實(shí)際執(zhí)行請(qǐng)求
        return execution.execute(httpRequest, body);
    }
}

使用opentracing-spring-cloud

上文中通過代碼示例了,如何通過框架工具提供的攔截器能力來實(shí)現(xiàn)請(qǐng)求追蹤,由于Spring MVC,RestTemplate,Servlet……這些開源工具是的用戶相當(dāng)廣泛,所以在opentracing-contrib項(xiàng)目中提供了非常多針對(duì)這些被廣泛使用的開源工具的集成支持包。

其中java-spring-cloud子項(xiàng)目,為spring-cloud項(xiàng)目提供了opentracing-spring-cloud-starter,這個(gè)starter通過依賴了很多其他的opentrcing集成支持庫,來為基于spring-cloud架構(gòu)的應(yīng)用提供一站式opentracing集成方案,其中包括如下組件:

利用SpringBoot的AutoConfiguration機(jī)制為用戶提供了幾乎無須手動(dòng)配置的集成方案。

  • Spring Web (RestControllers, RestTemplates, WebAsyncTask, WebClient, WebFlux)
  • @Async, @Scheduled, Executors
  • WebSocket STOMP
  • Feign, HystrixFeign
  • Hystrix
  • JMS
  • JDBC
  • Mongo
  • Zuul
  • Reactor
  • RxJava
  • Redis
  • Standard logging - logs are added to active span
  • Spring Messaging - trace messages being sent through Messaging Channels
  • RabbitMQ

使用SpringCloud的開發(fā)者,可以簡(jiǎn)單的將opentracing-spring-cloud-starter添加到自己項(xiàng)目的依賴中,來體驗(yàn)它帶來的opentracing集成。

如果不使用SpringCloud也可以其為起點(diǎn),按自己的需求從其依賴中挑選自己需要的部分,或者瀏覽opentracing-contrib項(xiàng)目來尋找自己需要的支持庫。

使用Jaeger

前文中描述的API以及中間件集成方案,都是對(duì)OpenTracing API的集成,仔細(xì)看代碼中缺少一個(gè)必要的構(gòu)建Tracer對(duì)象的步驟。在實(shí)際場(chǎng)景中,我們需要一種具體的OpenTracing實(shí)現(xiàn),來創(chuàng)建Tracer對(duì)象。

Jaeger是由Uber開源的OpenTracing實(shí)現(xiàn)項(xiàng)目,它提供了追蹤數(shù)據(jù)上報(bào)服務(wù)以及數(shù)據(jù)的視圖,來幫助開發(fā)者解決分布式系統(tǒng)中的如下問題:

  • 分布式事務(wù)監(jiān)控
  • 性能和延遲優(yōu)化
  • 分析故障源頭
  • 服務(wù)以來分析
  • 分布式上下文傳播

以來jaeger-client-java可以利用如下代碼創(chuàng)建一個(gè)Tracer對(duì)象:

Configuration config = new io.jaegertracing.Configuration("服務(wù)名稱");
// 設(shè)置數(shù)據(jù)發(fā)送方式
Configuration.SenderConfiguration sender = new Configuration.SenderConfiguration();
sender.withEndpoint("<endpoint>"); // endpoint可以是在阿里云上購買的鏈路追蹤服務(wù)或者自己使用Jaeger搭建的服務(wù)
// 設(shè)置采樣方式
config.withSampler(new Configuration.SamplerConfiguration().withType("const").withParam(1));
// 設(shè)置數(shù)據(jù)上報(bào)方式
config.withReporter(new Configuration.ReporterConfiguration().withSender(sender).withMaxQueueSize(10000));
Tracer tracer = config.getTracer();

Configuration類提供了非常多的配置功能,有興趣的開發(fā)者可以閱讀其API文檔來了解更多的自定義選項(xiàng),甚至擴(kuò)展Jaeger的功能。

到此這篇關(guān)于Java中的OpenTracing使用實(shí)例的文章就介紹到這了,更多相關(guān)OpenTracing使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中如何判斷是否為閏年詳細(xì)實(shí)例

    Java中如何判斷是否為閏年詳細(xì)實(shí)例

    所謂閏年就是指2月有29天的那一年,下面這篇文章主要給大家介紹了關(guān)于Java中如何判斷是否為閏年的相關(guān)資料,文中通過圖文以及實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-06-06
  • Java 數(shù)據(jù)結(jié)構(gòu)七大排序使用分析

    Java 數(shù)據(jù)結(jié)構(gòu)七大排序使用分析

    這篇文章主要介紹了Java常用的排序算法及代碼實(shí)現(xiàn),在Java開發(fā)中,對(duì)排序的應(yīng)用需要熟練的掌握,這樣才能夠確保Java學(xué)習(xí)時(shí)候能夠有扎實(shí)的基礎(chǔ)能力。那Java有哪些排序算法呢?本文小編就來詳細(xì)說說Java常見的排序算法,需要的朋友可以參考一下
    2022-04-04
  • java算法之二分查找法的實(shí)例詳解

    java算法之二分查找法的實(shí)例詳解

    這篇文章主要介紹了java算法之二分查找法的實(shí)例詳解的相關(guān)資料,這里提供簡(jiǎn)單實(shí)例幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • Java中使用MyBatis-Plus操作數(shù)據(jù)庫的實(shí)例

    Java中使用MyBatis-Plus操作數(shù)據(jù)庫的實(shí)例

    本文主要介紹了Java中使用MyBatis-Plus操作數(shù)據(jù)庫的實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-02-02
  • Java中的MultipartFile接口和File類解讀

    Java中的MultipartFile接口和File類解讀

    本文主要介紹了Java中的File類和Spring框架中的MultipartFile接口,File類提供了對(duì)文件和目錄操作的方法,如創(chuàng)建、刪除、重命名、判斷文件是否存在等,MultipartFile接口用于處理文件上傳,提供了獲取上傳文件信息和保存上傳文件的方法
    2025-02-02
  • SpringBoot中@PathVariable注解使用

    SpringBoot中@PathVariable注解使用

    本文詳細(xì)介紹了SpringBoot中@PathVariable注解的使用方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • Jenkins環(huán)境搭建實(shí)現(xiàn)過程圖解

    Jenkins環(huán)境搭建實(shí)現(xiàn)過程圖解

    這篇文章主要介紹了Jenkins環(huán)境搭建實(shí)現(xiàn)過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Springboot如何實(shí)現(xiàn)Web系統(tǒng)License授權(quán)認(rèn)證

    Springboot如何實(shí)現(xiàn)Web系統(tǒng)License授權(quán)認(rèn)證

    這篇文章主要介紹了Springboot如何實(shí)現(xiàn)Web系統(tǒng)License授權(quán)認(rèn)證,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • 如何在springMVC的controller中獲取request

    如何在springMVC的controller中獲取request

    這篇文章主要介紹了如何在springMVC的controller中獲取request,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • SpringBoot嵌入式Web容器原理與使用介紹

    SpringBoot嵌入式Web容器原理與使用介紹

    Web開發(fā)的核心內(nèi)容主要包括內(nèi)嵌的Servlet容器和SpringMVCSpringBoot使用起來非常簡(jiǎn)潔,大部分配置都有SpringBoot自動(dòng)裝配,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-10-10

最新評(píng)論