Spring Cloud Zipkin

Spring Cloud Zipkin

Operacje w świecie mikroserwisów to operacje które przechodzą przez różne usługi. Jak dowiedzieć się o błędzie zaistniałym podczas przetwarzania żądania do pewnego zasobu? W aplikacjach monolitycznych wystarczy sprawdzić logi serwera i wszystko jest jasne. W architekturze rozproszonej problem monitorowania aplikacji jest bardziej złożony. Sprawdzanie logów jest żmudne i czasochłonne. Zipkin to rozwiązanie tego problemu. Utwórzmy 4 mikroserwisy gdzie żądanie przechodzić będzie przez wszystkie usługi po kolei.

Na początek serwer Zipkina – niezbędne zależności:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>io.zipkin.java</groupId>
		<artifactId>zipkin-server</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-eureka</artifactId>
	</dependency>
	<dependency>
		<groupId>io.zipkin.java</groupId>
		<artifactId>zipkin-autoconfigure-ui</artifactId>
		<scope>runtime</scope>
	</dependency>
</dependencies>
 
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Camden.SR6</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

Klasa startowa:

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

Po uruchomieniu aplikacji pod adresem http://localhost:9411/ dostępny jest serwer Zpikina.

Plik application.properties:

spring.application.name                 = zipkin-server
server.port                             = 9411
spring.zipkin.locator.discovery.enabled = true
spring.sleuth.sampler.percentage        = 1.0

Mikroserwis – 1 – niezbędne zależnośći:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-sleuth</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-zipkin</artifactId>
	</dependency>
</dependencies>
 
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Camden.SR6</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

RestControler:

@RestController
class ZipkinController{
 
    @Autowired
    RestTemplate restTemplate;
 
    /*
        You have to register RestTemplate as a bean so that the interceptors will get injected.
        If you create a RestTemplate instance with a new keyword then the instrumentation WILL NOT work.
     */
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
 
    private static final Logger LOG = Logger.getLogger(ZipkinController.class.getName());
 
    @GetMapping(value="/zipkin1")
    public String zipkinService1()
    {
        LOG.info("Inside zipkinService 1...");
 
        String response = (String) restTemplate.exchange("http://localhost:8082/zipkin2", HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
        return "Inside zipkinService 1.." + response;
    }
}

Plik application.properties:

server.port             = 8081
spring.application.name = zipkin-service-1

Zależności dla kolejnych mikroserwisów są takie same ja dla pierwszego mikroserwisu.

Mikroserwis – 2:

@RestController
class ZipkinController{
 
    @Autowired
    RestTemplate restTemplate;
 
    /*
        You have to register RestTemplate as a bean so that the interceptors will get injected.
        If you create a RestTemplate instance with a new keyword then the instrumentation WILL NOT work.
     */
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
 
    private static final Logger LOG = Logger.getLogger(ZipkinController.class.getName());
 
    @GetMapping(value="/zipkin2")
    public String zipkinService2()
    {
        LOG.info("Inside zipkinService 2...");
 
        String response = (String) restTemplate.exchange("http://localhost:8083/zipkin3",
                HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
 
 
        return "Inside zipkinService 2.." + response;
    }
}

Plik application.properties:

server.port             = 8082
spring.application.name = zipkin-service-2

Mikroserwis – 3:

@RestController
class ZipkinController{
 
    @Autowired
    RestTemplate restTemplate;
 
    /*
        You have to register RestTemplate as a bean so that the interceptors will get injected.
        If you create a RestTemplate instance with a new keyword then the instrumentation WILL NOT work.
     */
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
 
    private static final Logger LOG = Logger.getLogger(ZipkinController.class.getName());
 
    @GetMapping(value="/zipkin3")
    public String zipkinService3()
    {
        LOG.info("Inside zipkinService 3...");
 
        String response = (String) restTemplate.exchange("http://localhost:8084/zipkin4",
                HttpMethod.GET, null, new ParameterizedTypeReference<String>() {}).getBody();
        return "Inside zipkinService 3..." + response;
    }
}

Plik application.properties:

server.port             = 8083
spring.application.name = zipkin-service-3

Mikroserwis – 4:

@RestController
class ZipkinController{
 
    @Autowired
    RestTemplate restTemplate;
 
    /*
        You have to register RestTemplate as a bean so that the interceptors will get injected.
        If you create a RestTemplate instance with a new keyword then the instrumentation WILL NOT work.
     */
    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
 
    private static final Logger LOG = Logger.getLogger(ZipkinController.class.getName());
 
    @GetMapping(value = "/zipkin4")
    public String zipkinService4() {
        LOG.info("Inside zipkinService 4..");
        return "Inside zipkinService 4..";
    }
}

Plik application.properties:

server.port             = 8084
spring.application.name = zipkin-service-4

Wszystkie mikroserwisy należy uruchomić a następnie wysłać żądanie GET pod adres http://localhost:8081/zipkin1

Wynik:

Inside zipkinService 1..Inside zipkinService 2..Inside zipkinService 3...Inside zipkinService 4..

Pod adresem serwera Zipkin zauważyć można, że wszystkie mikroserwisy zostały zarejestrowane:

Czas przejścia żądania od mikroserwisu 1 do 4:

Szczegółowe informacje odnośnie mikroserwisu 4:

Zobacz kod na GitHubie i zapisz się na bezpłatny newsletter!

.

Leave a comment

Your email address will not be published.


*