使用Spring Sleuth和Zipkin跟蹤微服務

  隨着微服務數量不斷增加,須要跟蹤一個請求從一個微服務到下一個微服務的傳播過程, Spring Cloud Sleuth 正是解決這個問題,它在日誌中引入惟一ID,以保證微服務調用之間的一致性,這樣你就能跟蹤某個請求是如何從一個微服務傳遞到下一個。java

  若是你有使用AOP攔截Servlet的經驗,作一個基於AOP的簡單服務統計和跟蹤很容易。但要像Zipkin那樣可以跟蹤服務調用鏈就比較困難了。所謂調用鏈,就是A服務調用B服務,B服務又調用了C、D服務。這樣一個鏈要想統計跟蹤,要寫很多代碼。而Spring Cloud Sleuth能讓你不寫一行代碼的狀況下完成這些。mysql

  本文涉及5個spring boot工程:git

 

  前三個驗證基本的Sleuth使用,後面兩個演示若是使用消息中間件做爲Zipkin的源,以及若是將Zipkin的監控數據配置到mysql數據庫。因爲前者和後者在配置方面相差較大,所以有必要將其分開展現。簡單的Sleuth應用,在這裏是指Sleuth http應用,就是Sleuth經過http請求的方式將監控日誌推送到Zipkin服務器。如圖所示,cloud-sleuth-server其實就是Zipkin Server它接收來自微服務cloud-sleuth-service1和cloud-sleuth-service2的監控日誌推送,cloud-sleuth-service1調用了cloud-sleuth-service2,造成一個簡單的調用鏈。其中cloud-sleuth-service1 pom配置:web

  <dependencies>
  <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>
  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>               
 </dependencies>spring

SleuthClientApplication應用:sql

@SpringBootApplication
public class SleuthClientApplication {

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

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

@RestController
class HomeController {

	private static final Log log = LogFactory.getLog(HomeController.class);
	@Autowired
	private RestTemplate restTemplate;
	
	private String url="http://localhost:9986";

	@RequestMapping("/service1")
	public String service1() throws Exception {
		log.info("service1");
		Thread.sleep(200L);
		String s = this.restTemplate.getForObject(url + "/service2", String.class);
		return s;
	}	
}

  application.properties:
  spring.application.name=sleuthService1
  server.port=9987
  spring.zipkin.baseUrl=http://localhost:9966
  spring.zipkin.enabled=true數據庫

  只須要在pom文件裏配置spring-cloud-sleuth-zipkin而且在配置文件裏配置spring.zipkin.baseUrl,那麼service1就能夠把監控日誌發送給目標是baseUrl指向的Zipkin服務器,就是會自動調用zipkin的某個rest接口將監控日誌傳給它。服務器

  Zipkin Server的pom配置:app

   <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>io.zipkin</groupId>
            <artifactId>zipkin-ui</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
    </dependency>spring-boot

SleuthServerApplication:

@SpringBootApplication
@EnableZipkinServer
public class SleuthServerApplication {

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

  application.properties配置:
  spring.application.name=sleuthServer
  server.port=9966
  至於service2,配置和service1同樣,就是Application裏面增長了servcie2 rest接口:

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

@RestController
class HiController {

	private static final Log log = LogFactory.getLog(HiController.class);

	@RequestMapping("/service2")
	public String hi() throws Exception {
		log.info("service2");
		Thread.sleep(100L);
		return "service2";
	}
}	

  運行後,訪問service1,再按照zipkin server配置的端口打開zipkin server的監控頁面,運行結果以下:

   點開某一個請求後,會看到詳細的調用鏈請求信息:

點開調用鏈的某個請求能夠看更詳細的請求信息:

  上圖所示,依次是:

  Sleuthservcie1 Client Send:service1發起請求service2的時間戳。

  Sleuthservcie2 Server Receive:service2收到請求的時間戳。

  Sleuthservcie2 Server Send:service2處理完髮送結果時間戳。

  Sleuthservcie1 Client Receive:service1收到結果的時間戳。

  圖中最上方就是這個請求所用的總的時間,各個環節的處理請求時間一目瞭然。

 

  若是是生產環境,通常須要用到第二套方案。就是先把日誌發送到消息隊列,而後再由zipkin接受,zipkin接收後保存日誌到數據庫。具體的配置也很簡單,要注意的地方就是spring 官方的例子找不到消息中間件的具體配置,多是在某個地方有默認,筆者仍是本身配置了一下:

  spring.sleuth.sampler.percentage=1.0

  spring.rabbitmq.host=127.0.0.1

  spring.rabbitmq.port=5672

  spring.rabbitmq.username=guest

  spring.rabbitmq.password=guest

  spring.rabbitmq.virtualHost=/

  消息隊列只須要配置上就會自動建立隊列。數據庫配置也是如此,其官方例子中也有,只需配置上就會自動建表。

  spring.datasource.schema=classpath:/mysql.sql

  spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/test

  spring.datasource.username=root

  spring.datasource.password=123

  spring.datasource.initialize=true

  spring.datasource.continueOnError=true

  spring.sleuth.enabled=false

  zipkin.storage.type=mysql

   具體參照源碼,源碼在老地方:

  https://git.oschina.net/zhou666/spring-cloud-7simple

相關文章
相關標籤/搜索