全部產品
Search
文件中心

Managed Service for OpenTelemetry:通過Zipkin上報Java應用資料

更新時間:Aug 07, 2024

通過Zipkin為應用埋點並上報鏈路資料至Managed Service for OpenTelemetry後,Managed Service for OpenTelemetry即可開始監控應用,您可以查看應用拓撲、調用鏈路、異常事務、慢事務和SQL分析等一系列監控資料。本文介紹如何進行手動埋點,以及使用外掛程式進行自動埋點。

重要

為獲得更豐富的功能、更先進的鏈路追蹤能力,以及最佳使用體驗,建議您使用OpenTelemetry協議將應用接入Managed Service for OpenTelemetry

我們為您提供了詳細的OpenTelemetry接入指南和最佳實務,協助您快速上手Managed Service for OpenTelemetry。更多資訊,請參見接入應用

前提條件

擷取存取點資訊

新版控制台

  1. 登入可觀測鏈路 OpenTelemetry 版控制台,在左側導覽列單擊接入中心

  2. 開源架構地區單擊Zipkin卡片。

  3. 在彈出的Zipkin面板中選擇資料需要上報的地區。

    說明

    初次接入的地區將會自動進行資源初始化。

  4. 選擇串連方式,然後複製存取點資訊。

    若您的服務部署在阿里雲上,且所屬地區與選擇的接入地區一致,推薦使用阿里雲內網方式,否則選擇公網方式。

    image.png

舊版控制台

  1. 登入可觀測鏈路 OpenTelemetry 版控制台

  2. 在左側導覽列單擊叢集配置,然後在右側頁面單擊存取點資訊頁簽。

  3. 在頁面頂部選擇需要接入的地區,然後在叢集資訊地區開啟顯示Token開關。

  4. 用戶端採集工具地區單擊Zipkin

    相關資訊列中,擷取存取點資訊。zipkin舊中國.jpg

    說明

    如果應用部署於阿里雲生產環境,則選擇阿里雲VPC網路存取點,否則選擇公網存取點。

背景資訊

Zipkin是一款開源的分布式即時資料追蹤系統(Distributed Tracking System),由Twitter公司開發和貢獻。其主要功能是彙總來自各個異構系統的即時監控資料。

Zipkin已經開發多年,對各種架構的支援比較齊全,例如以下架構,完整資訊請參考Zipkin官方文檔

  • Apache HttpClient

  • Dubbo

  • gRPC

  • JAX-RS 2.X

  • Jersey Server

  • JMS (Java Message Service)

  • Kafka

  • MySQL

  • Netty

  • OkHttp

  • Servlet

  • Spark

  • Spring Boot

  • Spring MVC

要通過Zipkin將Java應用資料上報至Managed Service for OpenTelemetry控制台,首先需要完成埋點工作。您可以手動埋點,也可以利用各種現有外掛程式實現埋點的目的。

通過Zipkin上報資料的原理

手動埋點

如果選擇手動埋點,您就需要自行編寫代碼。

說明

如需擷取Demo,請單擊下載源碼,進入manualDemo目錄,並根據Readme運行程式。

  1. 添加依賴Jar包。

    <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave</artifactId>
                <version>5.4.2</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-sender-okhttp3</artifactId>
                <version>2.7.9</version>
            </dependency>
  2. 建立Tracer。

    private static final String zipkinEndPoint = "<endpoint>";
      ...
      // 構建資料發送對象。
      OkHttpSender sender = OkHttpSender.newBuilder().endpoint(zipkinEndPoint).build();
    
      // 構建資料上報對象。
      Reporter<Span> reporter = AsyncReporter.builder(sender).build();
    
      tracing = Tracing.newBuilder().localServiceName(localServiceName).spanReporter(reporter).build();
  3. 構建Span和Child Span。

    private void firstBiz() {
            // 建立rootspan。
            tracing.tracer().startScopedSpan("parentSpan");
            Span span =  tracing.tracer().currentSpan();
            span.tag("key", "firstBiz");
            secondBiz();
            span.finish();
        }
    
        private void secondBiz() {
            tracing.tracer().startScopedSpanWithParent("childSpan", tracing.tracer().currentSpan().context());
            Span childSpan =  tracing.tracer().currentSpan();
            childSpan.tag("key", "secondBiz");
            childSpan.finish();
            System.out.println("end tracing,id:" + childSpan.context().traceIdString());
        }
  4. (可選)為了快速排查問題,您可以為某個記錄添加一些自訂標籤,例如記錄是否發生錯誤、請求的傳回值等。

    tracer.activeSpan().setTag("http.status_code", "500");
  5. 在分布式系統中發送RPC請求時會帶上Tracing資料,包括TraceId、ParentSpanId、SpanId、Sampled等。您可以在HTTP請求中使用Extract/Inject方法在HTTP Request Headers上透傳資料。總體流程如下:

    流程圖

    1. 在用戶端調用Inject方法傳入Context資訊。

      // start a new span representing a client request
          oneWaySend = tracer.nextSpan().name(service + "/" + method).kind(CLIENT);
          --snip--
      
          // Add the trace context to the request, so it can be propagated in-band
          tracing.propagation().injector(Request::addHeader)
                           .inject(oneWaySend.context(), request);
      
         // fire off the request asynchronously, totally dropping any response
         request.execute();
      
         // start the client side and flush instead of finish
         oneWaySend.start().flush();
    2. 在服務端調用Extract方法解析Context資訊。

      // pull the context out of the incoming request
      extractor = tracing.propagation().extractor(Request::getHeader);
      
      // convert that context to a span which you can name and add tags to
      oneWayReceive = nextSpan(tracer, extractor.extract(request))
          .name("process-request")
          .kind(SERVER)
          ... add tags etc.
      
      // start the server side and flush instead of finish
      oneWayReceive.start().flush();
      
      // you should not modify this span anymore as it is complete. However,
      // you can create children to represent follow-up work.
      next = tracer.newSpan(oneWayReceive.context()).name("step2").start();

通過Spring 2.5 MVC或Spring 3.0 MVC外掛程式埋點

您可以選擇通過Spring 2.5 MVC或Spring 3.0 MVC外掛程式進行埋點。

說明

如需擷取Demo,請單擊下載源碼,進入springMvcDemo\webmvc3|webmvc25目錄,並根據Readme運行程式。

  1. applicationContext.xml中配置Tracing對象。

    <bean class="zipkin2.reporter.beans.OkHttpSenderFactoryBean">
      <property name="endpoint" value="<endpoint>"/>
    </bean>
    
    <!-- allows us to read the service name from spring config -->
    <context:property-placeholder/>
    
    <bean class="brave.spring.beans.TracingFactoryBean">
      <property name="localServiceName" value="brave-webmvc3-example"/>
      <property name="spanReporter">
        <bean class="zipkin2.reporter.beans.AsyncReporterFactoryBean">
          <property name="encoder" value="JSON_V2"/>
          <property name="sender" ref="sender"/>
          <!-- wait up to half a second for any in-flight spans on close -->
          <property name="closeTimeout" value="500"/>
        </bean>
      </property>
      <property name="propagationFactory">
        <bean class="brave.propagation.ExtraFieldPropagation" factory-method="newFactory">
          <constructor-arg index="0">
            <util:constant static-field="brave.propagation.B3Propagation.FACTORY"/>
          </constructor-arg>
          <constructor-arg index="1">
            <list>
              <value>user-name</value>
            </list>
          </constructor-arg>
        </bean>
      </property>
      <property name="currentTraceContext">
        <bean class="brave.spring.beans.CurrentTraceContextFactoryBean">
          <property name="scopeDecorators">
            <bean class="brave.context.log4j12.MDCScopeDecorator" factory-method="create"/>
          </property>
        </bean>
      </property>
    </bean>
    
    <bean class="brave.spring.beans.HttpTracingFactoryBean">
      <property name="tracing" ref="tracing"/>
    </bean>
  2. 添加Interceptors對象。

    <bean class="brave.httpclient.TracingHttpClientBuilder"
          factory-method="create">
        <constructor-arg type="brave.http.HttpTracing" ref="httpTracing"/>
      </bean>
    
      <bean factory-bean="httpClientBuilder" factory-method="build"/>
    
      <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
        <property name="interceptors">
          <list>
            <bean class="brave.spring.webmvc.SpanCustomizingHandlerInterceptor"/>
          </list>
        </property>
      </bean>
    
      <!-- Loads the controller -->
      <context:component-scan base-package="brave.webmvc"/>
  3. 添加Filter對象。

    <!-- Add the delegate to the standard tracing filter and map it to all paths -->
    <filter>
      <filter-name>tracingFilter</filter-name>
      <filter-class>brave.spring.webmvc.DelegatingTracingFilter</filter-class>
    </filter>
    <filter-mapping>
      <filter-name>tracingFilter</filter-name>
      <url-pattern>/*</url-pattern>
    </filter-mapping>

通過Spring 4.0 MVC或Spring Boot外掛程式埋點

您可以選擇通過Spring 4.0 MVC或Spring Boot外掛程式進行埋點。

說明

如需擷取Demo,請單擊下載源碼,進入springMvcDemo\webmvc4-boot|webmv4目錄,並根據Readme運行程式。

  1. 配置Tracing和Filter。

    /** Configuration for how to send spans to Zipkin */
      @Bean Sender sender() {
        return OkHttpSender.create("<endpoint>");
      }
    
      /** Configuration for how to buffer spans into messages for Zipkin */
      @Bean AsyncReporter<Span> spanReporter() {
        return AsyncReporter.create(sender());
      }
    
      /** Controls aspects of tracing such as the name that shows up in the UI */
      @Bean Tracing tracing(@Value("${spring.application.name}") String serviceName) {
        return Tracing.newBuilder()
            .localServiceName(serviceName)
            .propagationFactory(ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, "user-name"))
            .currentTraceContext(ThreadLocalCurrentTraceContext.newBuilder()
                .addScopeDecorator(MDCScopeDecorator.create()) // puts trace IDs into logs
                .build()
            )
            .spanReporter(spanReporter()).build();
      }
    
      /** decides how to name and tag spans. By default they are named the same as the http method. */
      @Bean HttpTracing httpTracing(Tracing tracing) {
        return HttpTracing.create(tracing);
      }
    
      /** Creates client spans for http requests */
      // We are using a BPP as the Frontend supplies a RestTemplate bean prior to this configuration
      @Bean BeanPostProcessor connectionFactoryDecorator(final BeanFactory beanFactory) {
        return new BeanPostProcessor() {
          @Override public Object postProcessBeforeInitialization(Object bean, String beanName) {
            return bean;
          }
    
          @Override public Object postProcessAfterInitialization(Object bean, String beanName) {
            if (!(bean instanceof RestTemplate)) return bean;
    
            RestTemplate restTemplate = (RestTemplate) bean;
            List<ClientHttpRequestInterceptor> interceptors =
                new ArrayList<>(restTemplate.getInterceptors());
            interceptors.add(0, getTracingInterceptor());
            restTemplate.setInterceptors(interceptors);
            return bean;
          }
    
          // Lazy lookup so that the BPP doesn't end up needing to proxy anything.
          ClientHttpRequestInterceptor getTracingInterceptor() {
            return TracingClientHttpRequestInterceptor.create(beanFactory.getBean(HttpTracing.class));
          }
        };
      }
    
      /** Creates server spans for http requests */
      @Bean Filter tracingFilter(HttpTracing httpTracing) {
        return TracingFilter.create(httpTracing);
      }
    
      @Autowired SpanCustomizingAsyncHandlerInterceptor webMvcTracingCustomizer;
    
      /** Decorates server spans with application-defined web tags */
      @Override public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(webMvcTracingCustomizer);
      }
  2. 配置autoconfigure(spring.factories)。

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    brave.webmvc.TracingConfiguration

通過Dubbo外掛程式埋點

您可以選擇通過Dubbo外掛程式進行埋點。

說明

如需擷取Demo,請單擊下載源碼,進入dubboDemo目錄,並根據Readme運行程式。

  1. 添加依賴Jar包。

    <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-instrumentation-dubbo-rpc</artifactId>
                <version>5.4.2</version>
            </dependency>
    
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-spring-beans</artifactId>
                <version>5.4.2</version>
            </dependency>
    
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave-context-slf4j</artifactId>
                <version>5.4.2</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-sender-okhttp3</artifactId>
                <version>2.7.9</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave</artifactId>
                <version>5.4.2</version>
            </dependency>
    
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-sender-okhttp3</artifactId>
                <version>2.7.9</version>
            </dependency>
  2. 配置Tracing對象。

    <bean class="zipkin2.reporter.beans.OkHttpSenderFactoryBean">
            <property name="endpoint" value="<endpoint>"/>
        </bean>
    
        <bean class="brave.spring.beans.TracingFactoryBean">
            <property name="localServiceName" value="double-provider"/>
            <property name="spanReporter">
                <bean class="zipkin2.reporter.beans.AsyncReporterFactoryBean">
                    <property name="sender" ref="sender"/>
                    <!-- wait up to half a second for any in-flight spans on close -->
                    <property name="closeTimeout" value="500"/>
                </bean>
            </property>
            <property name="currentTraceContext">
                <bean class="brave.spring.beans.CurrentTraceContextFactoryBean">
                    <property name="scopeDecorators">
                        <bean class="brave.context.slf4j.MDCScopeDecorator" factory-method="create"/>
                    </property>
                </bean>
            </property>
        </bean>
  3. 添加Filter配置。

    // 服務端配置。
    <dubbo:provider filter="tracing" />
    // 用戶端配置。
    <dubbo:consumer filter="tracing" />

通過Spring Sleuth外掛程式埋點

您可以選擇通過Spring Sleuth外掛程式進行埋點。

說明

如需擷取Demo,請單擊下載源碼,進入sleuthDemo目錄,並根據Readme運行程式。

  1. 添加依賴Jar包。

    <dependency>
                <groupId>io.zipkin.brave</groupId>
                <artifactId>brave</artifactId>
                <version>5.4.2</version>
            </dependency>
    
            <dependency>
                <groupId>io.zipkin.reporter2</groupId>
                <artifactId>zipkin-sender-okhttp3</artifactId>
                <version>2.7.9</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.0.1.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-sleuth-core</artifactId>
                <version>2.0.1.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-sleuth-zipkin</artifactId>
                <version>2.0.1.RELEASE</version>
            </dependency>
  2. 配置application.yml。

    說明

    請將<endpoint_short>替換成前提條件中擷取的存取點資訊(“公網存取點:”後面到“api/v2/spans”之前的內容)。

    spring:
       application:
         # This ends up as the service name in zipkin
         name: sleuthDemo
       zipkin:
         # Uncomment to send to zipkin, replacing 192.168.99.100 with your zipkin IP address
         baseUrl: <endpoint_short>
    
       sleuth:
         sampler:
           probability: 1.0
    
       sample:
       zipkin:
         # When enabled=false, traces log to the console. Comment to send to zipkin
         enabled: true
  3. 發起HTTP請求,例如http://localhost:3380/traced

    說明

    更多請求路徑,請參見Demo中com.alibaba.apm.SampleController下的方法。

常見問題

問:Demo程式執行成功,但是為什麼有的網站上無資料?

答:請斷點調試zipkin2.reporter.okhttp3.HttpCall中的parseResponse方法,查看上報資料時傳回值。如果報403錯誤,表示使用者名稱配置不正確,需要檢查Endpoint配置。