Статьи

Шаблоны микросервисов с посредником-посредником, часть II: таймауты и повторные попытки

Этот блог является частью серии статей, в которых подробно рассматриваются Envoy Proxy и Istio.io, а также рассказывается о том, как он обеспечивает более элегантный способ подключения и управления микросервисами. Следуйте за мной @christianposta, чтобы не отставать от этих выпусков поста в блоге.

  • Что такое Envoy Proxy , как он работает?
  • Как реализовать некоторые из базовых шаблонов с Envoy Proxy ?
  • Как Istio Mesh вписывается в эту картину
  • Как работает Istio Mesh и как он обеспечивает функциональность высшего порядка в кластерах с Envoy
  • Как работает Istio Mesh auth

Вот идея для следующих нескольких частей (обновим ссылки по мере их публикации):

Часть II. Таймауты и повторные попытки с прокси-посланником

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

Эта демонстрация состоит из клиента и сервиса. Клиент — это Java-приложение http, которое имитирует выполнение http-вызовов к «восходящему» сервису (обратите внимание, мы используем терминологию Envoys здесь и выполняем это репо ). Клиент упакован в образ Docker с именем docker.io/ceposta/http-envoy-client:latest . Наряду с http-клиентом Java-приложение является экземпляром Envoy Proxy . В этой модели развертывания Envoy разворачивается как сопутствующая служба вместе со службой (в данном случае клиентом http). Когда http-клиент совершает исходящие звонки (в «восходящий» сервис), все звонки проходят через коляску Envoy Proxy.

Сервис «upstream» для этих примеров — httpbin.org . httpbin.org позволяет нам легко моделировать поведение службы HTTP. Это круто, так что проверь, если ты не видел.

И демоверсии retries и timeouts имеют собственный envoy.json конфигурации envoy.json . Я определенно рекомендую взглянуть на справочную документацию для каждого раздела файла конфигурации, чтобы помочь понять полную конфигурацию. Хорошие люди из datawire.io также собрали хорошее введение в Envoy и его конфигурацию, которую вы также должны проверить.

Запуск демонстрации повторов

Для демонстрации повторных попыток мы настроим нашу маршрутизацию в Envoy следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
"routes": [
    {
      "timeout_ms": 0,
      "prefix": "/",
      "auto_host_rewrite": true,
      "cluster": "httpbin_service",
      "retry_policy": {
        "retry_on": "5xx",
        "num_retries": 3
      }
 
    }

Здесь мы говорим, чтобы повторить до 3 раз на HTTP-статус 5xx.

Если вы запустили предыдущие демоверсии, пожалуйста, убедитесь, что вы правильно начали эту (или любую) демоверсию. У нас есть разные конфигурации посланников для каждой демонстрации, и мы хотим, чтобы каждый раз мы начинали с чистого листа.

Сначала остановите все существующие демонстрации:

1
./docker-stop.sh

Теперь давайте retries нашу демонстрацию retries :

1
./docker-run.sh -d retries

Теперь давайте поработаем с клиентом одним вызовом, который достигнет конечной точки HTTP, которая должна вернуть ошибку HTTP 500 . Мы будем использовать скрипт curl.sh который настроен для вызова curl внутри нашего демонстрационного контейнера.

1
./curl.sh -vvvv localhost:15001/status/500

Мы должны увидеть что-то вроде этого:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
* Hostname was NOT found in DNS cache
*   Trying ::1...
* connect to ::1 port 15001 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 15001 (#0)
> GET /status/500 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:15001
> Accept: */*
>
< HTTP/1.1 500 Internal Server Error
* Server envoy is not blacklisted
< server: envoy
< date: Thu, 25 May 2017 05:55:37 GMT
< content-type: text/html; charset=utf-8
< access-control-allow-origin: *
< access-control-allow-credentials: true
< x-powered-by: Flask
< x-processed-time: 0.000718116760254
< content-length: 0
< via: 1.1 vegur
< x-envoy-upstream-service-time: 684
<
* Connection #0 to host localhost left intact

Большой! Теперь давайте проверим, что Envoy сделал для нас:

1
./get-envoy-stats.sh | grep retry
1
2
3
4
5
cluster.httpbin_service.retry.upstream_rq_500: 3
cluster.httpbin_service.retry.upstream_rq_5xx: 3
cluster.httpbin_service.upstream_rq_retry: 3
cluster.httpbin_service.upstream_rq_retry_overflow: 0
cluster.httpbin_service.upstream_rq_retry_success: 0

Ура! Мы видим здесь, что посланник повторил 3 раза из-за ошибок HTTP 500 .

Повторные попытки могут иметь пагубное влияние на ваши сервисные архитектуры, если рассматривать их наивно. Они могут помочь распространять сбои или вызывать атаки типа DDoS на внутренние службы, которые могут испытывать трудности.

Некоторые вещи, которые следует иметь в виду при повторных попытках:

  • Посланник выполнит автоматическую экспоненциальную повторную попытку с дрожанием. Смотрите документы для более
  • Вы можете установить тайм-ауты повторов (время ожидания для каждой повторной попытки), но общее время ожидания маршрута (настроенное для таблицы маршрутизации; см. Демонстрацию timeouts для точной конфигурации) все еще будет удерживаться / применяться; это для короткого замыкания любого повторного запуска / отсрочки
  • Вы должны всегда устанавливать конфигурацию повторных попыток автоматического выключателя, чтобы ограничить количество квот для повторных попыток, когда у вас может быть большое количество соединений. См. Активные повторные попытки в разделе автоматического выключателя в документации посланника.

Запуск демонстрации тайм-аутов

Для демонстрации тайм-аутов мы настроим нашу маршрутизацию в Envoy следующим образом:

1
2
3
4
5
6
7
8
"routes": [
    {
      "timeout_ms": 0,
      "prefix": "/",
      "auto_host_rewrite": true,
      "cluster": "httpbin_service",
      "timeout_ms": 3000
    }

Эта конфигурация устанавливает глобальное (то есть включает все повторы) время ожидания 3 с для любых вызовов, сделанных по этому маршруту в кластер httpbin_service .

Всякий раз, когда мы имеем дело с тайм-аутами, мы должны знать общее глобальное время ожидания для запросов, исходящих на границе. Мы можем оказаться в очень трудных для отладки ситуациях, когда таймауты не сужаются, когда мы углубляемся в график сетевых вызовов. Другими словами, при прохождении графа вызовов тайм-ауты сервисных вызовов для сервисов, которые находятся глубже в графе вызовов, должны быть меньше, чем вызовы предыдущих сервисов:

Посланник может помочь распространять информацию о тайм-ауте, а протоколы, такие как gRPC, могут распространять информацию о deadline . Продолжая эту серию, мы увидим, как мы можем управлять прокси-посланниками с помощью Istio Mesh, а плоскость управления может помочь нам выполнить инъекцию ошибок, чтобы обнаружить аномалии времени ожидания.

Если вы запустили предыдущие демоверсии, пожалуйста, убедитесь, что вы правильно начали эту (или любую) демоверсию. У нас есть разные конфигурации посланников для каждой демонстрации, и мы хотим, чтобы каждый раз мы начинали с чистого листа.

Сначала остановите все существующие демонстрации:

1
./docker-stop.sh

Теперь давайте timeouts демоверсию нашего timeouts :

1
./docker-run.sh -d timeouts

Теперь давайте попробуем клиента одним вызовом, который достигнет конечной точки HTTP, что должно задержать ответ примерно на 5 секунд. Эта задержка должна быть достаточной для запуска тайм-аута посланника. Мы будем использовать скрипт curl.sh который настроен для вызова curl внутри нашего демонстрационного контейнера.

1
./curl.sh -vvvv localhost:15001/delay/5

Мы должны увидеть вывод, похожий на этот:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
* Hostname was NOT found in DNS cache
*   Trying ::1...
* connect to ::1 port 15001 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 15001 (#0)
> GET /delay/5 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:15001
> Accept: */*
>
< HTTP/1.1 504 Gateway Timeout
< content-length: 24
< content-type: text/plain
< date: Thu, 25 May 2017 06:13:53 GMT
* Server envoy is not blacklisted
< server: envoy
<
* Connection #0 to host localhost left intact
upstream request timeout

Мы видим, что наш запрос истек!

Давайте проверим статистику посланника:

1
./get-envoy-stats.sh | grep timeout

Здесь мы видим, что 1 запрос (тот, который мы отправили!) Был тайм-аут посланником.

1
2
3
4
5
cluster.httpbin_service.upstream_cx_connect_timeout: 0
cluster.httpbin_service.upstream_rq_per_try_timeout: 0
cluster.httpbin_service.upstream_rq_timeout: 1
http.admin.downstream_cx_idle_timeout: 0
http.egress_http.downstream_cx_idle_timeout: 0

Если мы отправим запрос, на этот раз с меньшей задержкой, мы увидим, что вызов прошел:

1
./curl.sh -vvvv localhost:15001/delay/2
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
* Hostname was NOT found in DNS cache
*   Trying ::1...
* connect to ::1 port 15001 failed: Connection refused
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 15001 (#0)
> GET /delay/2 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:15001
> Accept: */*
>
< HTTP/1.1 200 OK
* Server envoy is not blacklisted
< server: envoy
< date: Thu, 25 May 2017 06:15:41 GMT
< content-type: application/json
< access-control-allow-origin: *
< access-control-allow-credentials: true
< x-powered-by: Flask
< x-processed-time: 2.00246119499
< content-length: 309
< via: 1.1 vegur
< x-envoy-upstream-service-time: 2145
<
{
  "args": {},
  "data": "",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.35.0",
    "X-Envoy-Expected-Rq-Timeout-Ms": "3000"
  },
  "origin": "68.3.84.124",
}
* Connection #0 to host localhost left intact

Также обратите внимание, что Envoy распространяет заголовки тайм-аута, чтобы вышестоящие сервисы имели представление о том, чего ожидать.

Серии

Пожалуйста, следите за обновлениями ! Трассировка третьей части должна скоро приземлиться!