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:
Leave a comment