Microservice mesh и тестирование под высокой нагрузкой

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

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

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

Прежде всего, дадим определение Service Mesh — это подход к организации взаимодействия группы микросервисов, когда между ними создается посредник, который решает вопросы наблюдения за трафиком, аутентификации и аудита, отслеживания доступности, балансировки нагрузки и мониторинга системы. Одним из решений для Kubernetes, которое реализует Service Mash является Istio. Кроме непосредственно регистрации сервисов и присоединения их к точкам публикации для внешних клиентов и взаимодействия микросервисов (здесь используется Ingress-контроллер Envoy), Istio обеспечивает отслеживание запросов (Tracing) и замеры времени обработки запроса (и отслеживания всей цепочки вызовов, которые связаны с запросом клиента), контроль доступа между микросервисами и управление трафиком (с использованием расширяемой системы для определения политик доступа).

Первым делом установим инструмент управления Istio (istioctl) и настроим тестовое приложение:

curl -L https://istio.io/downloadIstio | sh -
mv istio*/ /usr/local/lib/istio/
export PATH=/usr/local/lib/istio:$PATH
istioctl install --set profile=demo -y
kubectl label namespace default istio-injection=enabled
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.15/samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.15/samples/bookinfo/networking/bookinfo-gateway.yaml
kubectl get svc istio-ingressgateway -n istio-system
https://raw.githubusercontent.com/istio/istio/release-1.15/samples/addons/prometheus.yaml
https://raw.githubusercontent.com/istio/istio/release-1.15/samples/addons/grafana.yaml
https://raw.githubusercontent.com/istio/istio/release-1.15/samples/addons/jaeger.yaml
https://raw.githubusercontent.com/istio/istio/release-1.15/samples/addons/kiali.yaml
istioctl dashboard kiali

После установки будут развернуты несколько микросервисов (в пространство имен default) и зарегистрированы соответствующие сервисы и правила доступа из внешней сети (через Ingress), адрес которого нам будет необходим для выполнения нагрузочного тестирования. В завершение будут установлены дополнения для мониторинга трафика и системы и запущена веб-панель с возможностью наблюдения за взаимосвязью микросервисов и прохождением трафика. Для нас будут наиболее важны метрики нагрузки на микросервисы (Workloads - Traces, Workloads - Inbound metrics), а также информация о количестве запросов к отдельным микросервисам (Graph - Inbound).

Для проверки нагрузки мы будем использовать внешнюю точку подключения /productpage. Рассмотрим теперь возможности инструмента нагрузочного тестирования fortio. Одной из важных особенностей fortio является возможность удаленного управления процессом, создающим нагрузку, что позволяет запускать имитацию высокой нагрузки непосредственно в облаке или использовать ферму с несколькими процессами для создания распределенной нагрузки. Fortio может также работать внутри других приложений на Go, поскольку может быть собран как библиотека и выполняться в составе кода интеграционного тестирования. Также вариант сборки сервера (docker-контейнер fortio/fortio) предоставляет минималистичный веб-интерфейс для запуска тестов и исследования их результатов, а также для управления очередью тестов через REST API.

Процесс Fortio может быть запущен в одном из следующих режимов:

  • server - предоставляет веб-интерфейс (на порт 8080) и API (порт 8079) для удаленного запуска тестов

  • report - сервер с отчетами о тестировании (без возможности запуска новых тестов)

  • load - запустить нагрузочное тестирование на указанный адрес

При запуске теста можно дополнительно передать заголовки (-H), изменить количество параллельных потоков выполнения (-c) и количество запросов в секунду (-qps), общее количество запросов (-n) или время выполнения теста (-t). Результатом тестирования будет построение гистограмм и определение статистических замеров (min, max, 50, 75, 90, 99 и 99.9 перцентиль), также результаты могут быть сохранены в json (-a), при этом важно примонтировать к контейнеру внешний каталог на путь, указанный в -data-dir. Дополнительно можно указать идентификатор запуска (например может совпадать с номером сборки при автоматическом запуске в сборочном конвейере) через -runid, она будет добавлен к названию файла json. Также можно тестировать не только http, но и tcp, udp и socket-подключения, а также gRPC-сервисы (-grpc). Кроме оценки количества успешных запросов (которые можно скоррелировать с информацией от kiali) также можно собирать профили использовать процессора и памяти (наиболее актуально при локальном тестировании или встраивании теста непосредственно в тестовые сценарии).

Особое внимание уделяется возможности проксирования запросов на несколько точек, например это может быть важно при распределенной системе и необходимости проверки разных внешних адресов в одном тесте (-M определяет http-прокси-сервер, -P используется для tcp/udp-прокси, они могут использоваться как цель тестирования и будет пересылать запросы на указанные endpoint) и смещению запросов между параллельно запущенными подключениями (-jitter делает случайное отклонение, -uniform - применяет нормальное распределение для группы клиентов). Также можно добавлять дополнительный данные для запроса (--payload или --payload-file).

Для автоматического запуска теста можно использовать REST API (на сервере /fortio/rest/run с передачей json, при этом могут одновременно выполняться несколько сценариев нагрузочного тестирования). Остановить выполнение теста можно через /fortio/rest/stop, посмотреть текущее состояние выполнения через /fortio/rest/status. Например, для тестирования развернутого сервиса (в предположении, что в GATEWAY_URL будет записан адрес и порт публикации Ingress) можно использовать следующий запрос:

curl -v -d '{"metadata": {"url":"$GATEWAY_URL/", "c":"4", "qps":"10000", "t": 10, "async":"on", "save":"on"}}' \
     "localhost:8080/fortio/rest/run?jsonPath=.metadata"

Посмотреть статус выполнения можно с помощью запроса:

curl -v "localhost:8080/fortio/rest/status"

В отчете по результатам нагрузочного тестирование будет информация о времени выполнения запроса (минимальное, максимальное, среднее), запрошенном и реальном количестве обработанных запросов ("RequestedQPS", "ActualQPS").

Также библиотека может использоваться в коде проектов на Go через импорт fortio.org/fortio. Так, для тестирования http-сервисов, можно импортировать fortio.org/fortio/fhttp и запустить тест с передачей необходимых опций для runner:

        ro := periodic.RunnerOptions{
        		QPS:         qps,
        		Duration:    *durationFlag,
        		NumThreads:  *numThreadsFlag,
        		Percentiles: percList,
        		Resolution:  *resolutionFlag,
        		Out:         out,
        		Labels:      labels,
        		Exactly:     *exactlyFlag,
        		Jitter:      *jitterFlag,
        		Uniform:     *uniformFlag,
        		RunID:       *bincommon.RunIDFlag,
        		Offset:      *offsetFlag,
        		NoCatchUp:   *nocatchupFlag,
        	}
    	httpOpts := bincommon.SharedHTTPOptions()

        o := fhttp.HTTPRunnerOptions{
			HTTPOptions:        *httpOpts,
			RunnerOptions:      ro,
			Profiler:           *profileFlag,
			AllowInitialErrors: *allowInitialErrorsFlag,
			AbortOn:            *abortOnFlag,
		}
		res, err = fhttp.RunHTTPTest(&o)

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


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

Источник: https://habr.com/ru/company/otus/blog/686924/


Интересные статьи

Интересные статьи

На Хабре ни для кого не секрет, что в текущей повестке практически все сферы частного бизнеса вынуждены реагировать на происходящие изменения. Большое количество привычных всем нам зарубежных сервисов...
Много лет назад я отправился на поиски. Покрытие казалось для меня важным словом в тестировании, но в какой-то момент я поймал себя на мысли, что не обладаю достаточно четким представлением об этом. Я...
Добрался тут изучить ряд статей на тему Data Fabric, последнее время довольно много публикуется материала на эту тему: как про Data Fabric в целом, так и сравнения этого подхода с такими модными понят...
Привет, меня зовут Фахридин Джамолидинов, я специалист департамента тестирования в «Ростелеком ИТ». Занимаюсь автоматизацией тестирования основного сайта компании rt.ru. ...
Данной заметкой продолжается цикл о резервном копировании Резервное копирование, часть 1: Зачем нужно резервное копирование, обзор методов, технологий Резервное копирование, часть 2: Обзор ...