1. 程式人生 > >springcloud-sleuth+zipkin入門一

springcloud-sleuth+zipkin入門一

說明

zipkin是twitter公司基於Google的drapper論文,建立一套分散式、服務計時框架,可以用於鏈路跟蹤。目前有的java版本的實現有DropWizard zipkin和Springcloud-sleuth+zipkin等。本文是搭建Springcloud的入門例項。

重要概念

trace:個人理解,是一條鏈路的抽象,表示了一次完成的鏈路資訊。traceid是該鏈路的唯一標識
span:是鏈路呼叫的節點,是鏈路上一次方法執行的過程。spanId是該過程的標識,同時span可以通過新增tag的方式附加業務資訊。
Springcloud針對鏈路節點過程抽象了四種類型:
sr:server receive服務端接收
ss:server send 服務端傳送
cr: client receive 客戶端接收
cs:Client send 客戶端傳送。
下圖說明了Springsleuth的鏈路呼叫圖:
這裡寫圖片描述


引入上下級span關係後可以形成下面鏈路圖:
這裡寫圖片描述

搭建Springcloud-sleuth+zipkin

1環境說明

  • 開發IDE:intellij IDEA2017
  • jdk:1.8
  • maven:3.3.9
  • springboot:1.5.2RELEASE
  • springcloud:Camden.SR7

2建立zipkin伺服器

建立maven工程,並在pom.xml中引入zipkin相關依賴如下:

<!--引入Springzipkinserver-->
        <dependency>
            <groupId
>
io.zipkin.java</groupId> <artifactId>zipkin-server</artifactId> <version>2.4.2</version> </dependency> <!--引入Springzipkinwebui--> <dependency> <groupId>io.zipkin.java</groupId> <artifactId
>
zipkin-autoconfigure-ui</artifactId> <version>2.4.2</version> </dependency>

zipkinui是用於頁面顯示用的。
建立Springboot啟動類,並添加註解@EnableZipkinServer,表示為zipkin伺服器。

@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplicatoin {

    public static void main(String[] args) {
        SpringApplication.run(ZipkinServerApplicatoin.class,args);
    }
}

3建立zipkin監控服務

建立maven專案並在pom.xml檔案中加入如下程式碼:

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Camden.SR7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--引入zipkin-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
    </dependencies>

注意Springcloud依賴管理的版本,不同的版本可能會報錯。這裡我們使用的是Camden.SR7版本。

在resources/application.yml中加入如下配置:

server:
  port: 8082
spring:
  application:
    name: zipkinclientserverone
  zipkin:
    base-url: http://localhost:8080
  sleuth:
    sampler:
      percentage: 1.0

這裡我們將抽樣率percentage:設定為100%,表示會抽取所有記錄。
建立rest客戶端:


@RestController
public class SleuthController {

    @ResponseBody
    @RequestMapping("/sayHello/{name}")
    public String sayHello(@PathVariable String name) {
        return "hello " + name;
    }
}

到這裡最簡單的單個服務的鏈路耗時呼叫就 完成了。

說明

  • 這種整合的zipkin資訊是預設儲存在記憶體中的
  • 客戶端的sleuth資訊,是通過socket請求傳送到zipkin伺服器的,客戶端會不停掃描sleuth佇列,一旦有資訊就推送到zipkin伺服器
  • 客戶端多級服務鏈路採集是通過新增請求頭實現的,原理是通過AOP切面,在請求頭裡新增鏈路資訊,二級服務,通過filter獲取鏈路資訊併發送到zipkin伺服器。
  • Spring支援的二級服務呼叫方式有:feign、resttemplate兩種方式,當然,這兩種方式都要求通過Spring容器來做。如果自己建立連線或者resttemplate是不可能被Spring處理的,畢竟是AOP方式實現鏈路資訊新增。
  • zipkin服務端是通過HttpProcesser來處理鏈路資訊,因此想要通過webfilter實現攔截是不可能的。

4多級服務呼叫鏈路

上面完成了單級服務呼叫,這裡我們在建立一個zipkin監視服務,並且該服務為上面服務提供服務支援。建立過程如上面一致,只是將埠改為8888。這裡不再贅述

5修改第一個工程加入RestTemplate支援和Feign支援

增加RestTemplate配置,由Spring管理restTemplate,否則不能被鏈路呼叫攔截。

@Configuration
public class RestTemplateConfiguration {

    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

建立feign呼叫api

@FeignClient(name = "sleuthService",url = "http://localhost:8888")
public interface SleuthService {
    @RequestMapping("/sayHello/{name}")
    public String sayHello(@PathVariable(name="name")String name);
}

修改controller


@RestController
public class SleuthController {
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private SleuthService sleuthService;

    @ResponseBody
    @RequestMapping("/sayHello/{name}")
    public String sayHello(@PathVariable String name) {
        return "hello " + name;
    }
    @ResponseBody
    @RequestMapping("/restHello/{name}")
    public String restHello(@PathVariable String name){
        return restTemplate.getForObject("http://localhost:8888/sayHello/" + name,String.class );
    }
    @ResponseBody
    @RequestMapping("/feignHello/{name}")
    public String feignHello(@PathVariable String name){
        return sleuthService.sayHello(name);
    }
}