[jaeger] 3. Реализовать распределенный вызов (OkHttp+SpringBoot)

Spring Boot распределенный
[jaeger] 3. Реализовать распределенный вызов (OkHttp+SpringBoot)

Во многих случаях,traceОн распространяется в различных приложениях, и наиболее часто используемый метод удаленного вызова —Http.

В этом случае мы обычно добавляем дополнительныеHttp HeaderПередайте информацию трассировки, а затем систематизируйте ее.

В этом разделе собраны текущие самые горячиеSpringBootсервер, а затемOkHttp3Совершайте звонки, чтобы показать, как организована распределенная цепочка звонков.

Для большей сериализации обратите внимание на вкус Miss Sister. Для соответствующего кода этой статьи см.:

https://github.com/sayhiai/example-jaeger-opentracing-tutorial-003

Требуемые знания:

创建一个简单的SpringBoot应用
使用OkHttp3发起一个Post请求
了解OpenTracing的inject和extract函数

функция вставки и извлечения

Это две функции для межпроцессной трассировки, стремящиеся найти общий метод передачи трассировки. Это две мощные функции, которые предоставляют ряд абстракций, чтобы протокол OpenTracing не был связан с конкретной реализацией.

Carrier 携带trace信息的载体,下文中将自定义一个
inject 将额外的信息`注入`到相应的载体中
extract 将额外的信息从载体中`提取`出来

На самом деле, большая часть этого носителя реализуется Map (в частности, текстовой картой) или другими бинарными методами.

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

Создайте серверную часть

maven-зависимости

Во-первых, импортируйте соответствующую конфигурацию весенней загрузки через bom.

spring-boot-dependencies 2.1.3.RELEASE

Затем введите другие зависимости

opentracing-util 0.32.0
jaeger-client 0.35.0
logback-classic 1.2.3
spring-boot-starter-web 2.1.3.RELEASE
okhttp 3.14.1

Приложение SpringBoot

Создайте приложение SpringBoot, укажите порт 8888 и инициализируйте порт по умолчанию.Tracer.

@SpringBootApplication
@EnableAutoConfiguration
@ComponentScan(basePackages = {  "com.sayhiai.example.jaeger.totorial03.controller",
})
public class App extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
    @Bean
    public JaegerTracer getJaegerTracer() {
        return JaegerTracerHelper.initTracer("LoveYou");
    }
}

Создайте простую службу в каталоге контроллера/hello, передать параметры через тело запроса.

Код ключа следующий:

@PostMapping("/hello")
@ResponseBody
public String hello(@RequestBody String name,HttpServletRequest request) {
        Map<String, String> headers = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String header = headerNames.nextElement();
            headers.put(header, request.getHeader(header));
        }

        System.out.println(headers);

        Tracer.SpanBuilder builder = null;
        SpanContext parentSpanContext = tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapAdapter(headers));
        if (null == parentSpanContext) {
            builder = tracer.buildSpan("hello");
        } else {
            builder = tracer.buildSpan("hello").asChildOf(parentSpanContext);
        }

        Span span = builder.start();

Сначала получите информацию о заголовке и продолжитеextract, если получитьSpanContextЕсли он не пуст, это означает, что текущий запрос инициирован другим приложением. В этом случае мы берем источник запроса как источник текущего запросаparent.

Используйте Curl, чтобы позвонить, чтобы убедиться, что служба запущена и работает.

curl -XPOST http://localhost:8888/hello  -H "Content-Type:text/plain;charset=utf-8"   -d "小姐姐味道"

Создать клиентский вызов OkHttp3

Создать перевозчика

OkHttp3 — это очень легкая библиотека классов, информацию о ее заголовке можно установить с помощью следующего кода.

Request.Builder builder;
builder.addHeader(key, value);

Выше мы упоминали, что собираемся создать пользовательскийCarrier, здесь по наследствуTextMap, чтобы реализовать один.

public class RequestBuilderCarrier implements io.opentracing.propagation.TextMap {
    private final Request.Builder builder;

    RequestBuilderCarrier(Request.Builder builder) {
        this.builder = builder;
    }

    @Override
    public Iterator<Map.Entry<String, String>> iterator() {
        throw new UnsupportedOperationException("carrier is write-only");
    }

    @Override
    public void put(String key, String value) {
        builder.addHeader(key, value);
    }
}

позвонить

Используйте OkHttp3, чтобы инициировать простой запрос Post.

public static void main(String[] args) {
    Tracer tracer = JaegerTracerHelper.initTracer("Main");

    String url = "http://localhost:8888/hello";
    OkHttpClient client = new OkHttpClient();
    Request.Builder request = new Request.Builder()
            .url(url)
            .post(RequestBody.create(MediaType.parse("text/plain;charset=utf-8"), "小姐姐味道"));


    Span span = tracer.buildSpan("okHttpMainCall").start();
    Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
    Tags.HTTP_METHOD.set(span, "POST");
    Tags.HTTP_URL.set(span, url);
    tracer.activateSpan(span);

    tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new RequestBuilderCarrier(request));

    client.newCall(request.build()).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            e.printStackTrace();
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            System.out.println(response.body().string());
        }
    });

    span.finish();
}

Обратите внимание, что в середине метода мы используем функцию ввода, чтобы прикрепить информацию о трассировке кRequestBuilderCarrierпередача дальше.

Эти две функции используют реализацию jaeger. Видеть:

io.jaegertracing.internal.propagation.TextMapCodec

Запустим метод Main и посмотрим на предысторию Jaeger.Вы видите, что наша распределенная трассировка сгенерирована.

End

В этой статье показан общий способ создания распределенной цепочки вызовов. По аналогии с этим методом легко написатьHttpClientКлиентский компонент компонента.

Далее мы будем использовать специальный Aop Spring для инкапсуляции службы SpringCloud, вызываемой через интерфейс Feign. Вы обнаружите, что реализация сборщика на стороне клиента, подобного Sleuth, довольно проста.