Статьи

MicroServices. Часть 6. Распределенная трассировка с помощью Spring Cloud Sleuth и Zipkin

Одной из проблем в архитектуре микросервисов является возможность устранения проблем. Простое действие пользователя может вызвать цепочку нисходящих вызовов микросервиса. Было бы утомительно отслеживать журналы, относящиеся к определенному действию пользователя через микросервисы. В дополнение к этому, мы могли бы хотеть отследить, почему определенный вызов микросервиса занимает так много времени. Мы можем использовать Spring Cloud Sleuth для решения подобных проблем. Spring Cloud Sleuth предоставляет возможности распределенной трассировки, и мы также можем экспортировать эту информацию трассировки в Zipkin для визуализации трассировок вызовов.

Микроуслуги с использованием Spring Boot и Spring Cloud

В этом посте мы собираемся узнать:

  • Отслеживание распределенных сервисных звонков
  • Использование Spring Cloud Sleuth для распределенной трассировки
  • Распределенная трассировка с Zipkin Server

Отслеживание распределенных сервисных звонков

В мире микросервисов пользовательское действие в пользовательском интерфейсе может вызывать одну конечную точку API микросервиса, которая, в свою очередь, вызывает другую конечную точку микросервиса.

Например, когда пользователь видит каталог, shoppingcart-ui вызывает API REST службы каталогов http: // localhost: 8181 / api / products, который, в свою очередь, вызывает API REST службы инвентаризации http: // localhost: 8282 / api / инвентарь, чтобы проверить наличие инвентаря.

Предположим, произошла исключительная ситуация или возвращенные данные неверны, и вы хотите выяснить, что не так, просмотрев журналы. Но на данный момент нет способа сопоставить журналы этого конкретного пользователя по нескольким сервисам.

Распределенная трассировка бедного человека

Одним из решений этого является то, что в начале цепочки вызовов мы можем создать CORRELATION_ID и добавить его во все операторы журнала. Наряду с этим отправьте CORRELATION_ID в качестве заголовка для всех нисходящих служб, чтобы эти нисходящие службы также использовали CORRELATION_ID в журналах. Таким образом, мы можем идентифицировать все операторы журнала, связанные с определенным действием в службах.

Мы можем реализовать это решение, используя функцию MDC каркасов Logging. Обычно у нас есть перехватчик WebRequest, где вы можете проверить, есть ли заголовок CORRELATION_ID. Если в заголовке нет CORRELATION_ID, то создайте новый и установите его в MDC. Каркасы журналов включают в себя информацию, установленную в MDC, со всеми операторами журналов.

Но вместо того, чтобы делать всю эту работу, мы можем использовать Spring Cloud Sleuth, который сделает все это и многое другое для нас.

Использование Spring Cloud Sleuth для распределенной трассировки

Во-первых, ознакомьтесь с некоторой терминологией Span, Trace, Annotations здесь http://cloud.spring.io/spring-cloud-static/Finchley.M7/single/spring-cloud.html#_terminology .

Давайте добавим стартер Sleuth к сервису инвентаризации и сервису каталогов .

1
2
3
4
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

Как только вы добавите Sleuth Starter и запустите службы, вы можете наблюдать в журналах что-то вроде этого.

1
2
2018-03-20 10:19:15.512  INFO [inventory-service,,,] 53685 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver ...
2018-03-20 10:24:15.507  INFO [inventory-service,,,] 53685 --- [trap-executor-0] c.n.d.s.r.aws.ConfigClusterResolver ...

Теперь нажмите любую конечную точку REST службы инвентаризации, скажем, http: // localhost: 8282 / api / inventory. Тогда вы можете наблюдать TraceID , SpanID в журналах.

1
2018-03-20 10:15:38.466  INFO [inventory-service,683f8e4370413032,d8abe400c68a9a6b,false] 53685 --- [oryController-3] ...

Sleuth включает шаблон [appname, traceId, spanId, exportable] в журналы MDC.

Теперь вызовите конечную точку службы каталога http: // localhost: 8181 / api / products, которая внутренне вызывает конечную точку службы инвентаризации http: // localhost: 8282 / api / inventory.

В журналах службы каталогов вы можете найти записи журнала, например:

1
2018-03-20 10:54:29.625  INFO [catalog-service,0335da07260d3d6f,0335da07260d3d6f,false] 53617 --- [io-8181-exec-10] ...

И, проверьте журналы в инвентаризации службы, вы можете найти записи журнала что-то вроде:

1
2018-03-20 10:54:29.662  INFO [inventory-service,0335da07260d3d6f,1af68249ac3a6902,false] 53685 --- [oryController-6] ...

Обратите внимание, что TraceID 0335da07260d3d6f одинаков как для службы каталогов, так и для службы инвентаризации для одного и того же вызова API REST. Таким образом, мы можем легко сопоставить журналы между службами.

Значение false в [инвентарь-сервис, 0335da07260d3d6f, 1af68249ac3a6902, false] указывает, что эта трассировка не экспортируется ни на один сервер трассировки, например Zipkin. Давайте посмотрим, как мы можем экспортировать информацию трассировки в Zipkin.

Распределенная трассировка с Zipkin Server

Мы узнали, как использовать Sleuth для добавления информации о трассировке в журналы. В дополнение к этому, мы также можем экспортировать эту информацию в Zipkin, чтобы мы могли визуализировать это через пользовательский интерфейс.

Создать Zipkin Server как приложение SpringBoot

Мы можем запустить Zipkin-сервер как приложение с весенней загрузкой или запустить в Docker-контейнере.

На данный момент Zipkin не поддерживает Spring Boot 2. Таким образом, мы можем создать zipkin-сервер приложения SpringBoot, используя версию 1.5.10.RELEASE, и добавить зависимости zipkin-server, zipkin-autoconfigure-ui.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>com.sivalabs</groupId>
    <artifactId>zipkin-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
 
    <name>zipkin-server</name>
 
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
    </parent>
 
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.RELEASE</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</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>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
</project>

Добавьте аннотацию @EnableZipkinServer к основному классу точки входа.

01
02
03
04
05
06
07
08
09
10
11
12
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.EnableZipkinServer;
 
@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(ZipkinServerApplication.class, args);
    }
}

Установите порт и имя приложения в application.properties.

1
2
spring.application.name=zipkin-server
server.port=9411

Теперь вы можете запустить Zipkin Server, запустив ZipkinServerApplication .

Zipkin Server как Docker-контейнер

Вместо создания сервера Zipkin в качестве приложения SpringBoot, вы можете использовать образ Docker для OpenZipkin .

Мы можем создать сервер Zipkin, поддерживаемый хранилищем данных в памяти, используя следующий файл docker-compose-mem.yml .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
version: '2'
 
services:
  # The zipkin process services the UI, and also exposes a POST endpoint that
  # instrumentation can send trace data to. Scribe is enabled by default.
  zipkin:
    image: openzipkin/zipkin
    container_name: zipkin
    environment:
      - STORAGE_TYPE=mem
      # Uncomment to disable scribe
      # - SCRIBE_ENABLED=false
      # Uncomment to enable self-tracing
      # - SELF_TRACING_ENABLED=true
      # Uncomment to enable debug logging
      # - JAVA_OPTS=-Dlogging.level.zipkin=DEBUG
    ports:
      # Port used for the Zipkin UI and HTTP Api
      - 9411:9411

Вы также можете использовать образ докера, поддерживаемый хранилищем данных MySQL, используя https://github.com/openzipkin/docker-zipkin/blob/master/docker-compose.yml .

После запуска сервера Zipkin вы можете перейти по адресу http: // localhost: 9411 /, чтобы просмотреть панель мониторинга пользовательского интерфейса Zipkin Server.

Экспорт информации трассировки на Zipkin Server

Мы заметили, что информация трассировки печатается в журналах, но не экспортируется. Мы можем экспортировать их на сервер Zipkin, чтобы можно было визуализировать следы на панели инструментов пользовательского интерфейса Zipkin Server.

Добавьте стартер Zipkin Client как к сервису инвентаризации, так и сервису каталогов.

1
2
3
4
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>

Сконфигурируйте URL сервера Zipkin в bootstrap.properties службы инвентаризации и службы каталогов.

1
2
spring.zipkin.base-url=http://localhost:9411/
spring.sleuth.sampler.probability=1

ПРИМЕЧАНИЕ . По умолчанию spring.sleuth.sampler.probability = 0.1, что означает, что только 10% информации о трассировке будет экспортировано в Zipkin. Сделайте это до желаемого процента.

Теперь перезапустите и службу инвентаризации, и службу каталогов и вызовите конечную точку http: // localhost: 8181 / api / products. Вы можете заметить, что в журналах напечатано значение true, означающее, что оно экспортируется.

1
2018-03-20 11:41:02.241  INFO [catalog-service,7d0d44fe314d7758,7d0d44fe314d7758,true] 53617 --- [nio-8181-exec-5] c.s.c.services.ProductService

Теперь перейдите к Zipkin UI Dashboard, вы можете увидеть имена сервисов, заполненные в первом выпадающем списке. Выберите сервис, который хотите проверить, или выберите все, а затем нажмите кнопку «Найти следы».

Нажмите на любой след, который вы можете увидеть цепочку вызовов и данные о задержке для каждого диапазона.

Вы также можете нажать на ссылку Зависимости в верхней панели навигации, чтобы увидеть зависимости сервиса.

Вы можете найти исходный код этой статьи по адресу https://github.com/sivaprasadreddy/spring-boot-microservices-series

Опубликовано на Java Code Geeks с разрешения Сивы Редди, партнера нашей программы JCG . См. Оригинальную статью здесь: MicroServices. Часть 6. Распределенная трассировка с помощью Spring Cloud Sleuth и Zipkin.

Мнения, высказанные участниками Java Code Geeks, являются их собственными.