
Jednym z problemów, z którymi często borykają się dostawcy oprogramowania z wieloma produktami, jest duplikacja kompetencji inżynierów — programistów, testerów i administratorów infrastruktury — praktycznie w każdym zespole. Dotyczy to również kosztownych inżynierów — specjalistów w zakresie testowania obciążeniowego.
Zamiast zajmować się swoimi bezpośrednimi obowiązkami i wykorzystywać swoje unikalne doświadczenie do budowania procesu testowania obciążeniowego, wybierania metodologii, optymalnych wartości metryk i pisania automatycznych testów zgodnie z profilami obciążenia, inżynierowie często muszą od podstaw wdrażać infrastrukturę testową, konfigurować narzędzia obciążeniowe, samodzielnie integrować je z systemami CI, konfigurować monitoring i publikować raporty.
Rozwiązania niektórych problemów organizacyjnych w testowaniu, które stosujemy w Positive Technologies, można znaleźć w . A w tym opowiem o możliwości integracji testów obciążeniowych w ogólny konwój CI za pomocą koncepcji „testowanie obciążeniowe jako usługa” (load testing as a service). Dowiesz się, jak i jakie obrazy Dockera źródeł obciążenia można wykorzystać w konwoju CI; jak połączyć źródła obciążenia ze swoim projektem CI za pomocą szablonu budowy; jak wygląda pipeline demonstracyjny do uruchamiania testów obciążeniowych i publikowania wyników. Artykuł może być przydatny dla inżynierów testujących oprogramowanie oraz inżynierów automatyzacji w CI, którzy zastanawiają się nad architekturą swojego systemu obciążeniowego.
Istota koncepcji
Koncepcja testowania obciążeniowego jako usługi oznacza możliwość integrowania narzędzi obciążeniowych Apache JMeter, Yandex.Tank i własnych frameworków w dowolnym systemie ciągłej integracji. Przykład demonstracyjny będzie dla GitLab CI, ale zasady przedstawione są ogólne dla wszystkich systemów CI.
Testowanie obciążeniowe jako usługa to scentralizowana usługa przeprowadzania testów obciążeniowych. Testy obciążeniowe uruchamiane są w wydzielonych pulach agentów, a publikacja wyników następuje automatycznie w GitLab Pages, Influx DB i Grafana lub w systemach raportowania testów (TestRail, ReportPortal itp.). Automatyzacja i skalowanie realizowane są w maksymalnie prosty sposób — poprzez dodanie i parametryzację w projekcie GitLab CI zwykłego szablonu gitlab-ci.yml.
Zalet tego podejścia polega na tym, że cała infrastruktura CI, agenci obciążenia, obrazy kontenerów źródeł obciążenia, pipeline'y testowe oraz publikacja raportów są wspierane przez scentralizowany dział automatyzacji (inżynierów DevOps), a inżynierowie zajmujący się testowaniem obciążeniowym mogą skoncentrować swoje wysiłki na opracowywaniu testów i analizie ich wyników, nie zajmując się kwestiami infrastrukturalnymi.
Dla uproszczenia opisu przyjmijmy, że docelowa aplikacja testowa lub serwer zostały już wdrożone i skonfigurowane wcześniej (można do tego używać zautomatyzowanych skryptów w Pythonie, SaltStack, Ansible itp.). Wówczas cała koncepcja testowania obciążenia jako usługi składa się z trzech etapów: przygotowanie, testowanie, publikacja raportów. Szczegóły przedstawione na schemacie (wszystkie obrazy są klikalne):
Podstawowe pojęcia i definicje w testowaniu obciążenia
Podczas przeprowadzania testów obciążeniowych staramy się przestrzegać , używamy odpowiedniej terminologii i zalecanych metryk. Przedstawię krótki wykaz podstawowych pojęć i definicji w testowaniu obciążenia.
Agent obciążenia (load agent) — wirtualna maszyna, na której uruchomiona będzie aplikacja — źródło obciążenia (Apache JMeter, Yandex.Tank lub własny moduł obciążeniowy).
Cel testowania (target) — serwer lub aplikacja zainstalowana na serwerze, która będzie poddawana obciążeniu.
Scenariusz testowy (test case) — zbiór parametryzowanych kroków: działania użytkowników i oczekiwane reakcje na te działania, z zarejestrowanymi żądaniami sieciowymi i odpowiedziami, w zależności od zadanych parametrów.
Profil lub plan obciążenia (profile) — w (p. 4.2.4, str. 43) profile obciążenia określają krytycznie ważne dla konkretnego testu metryki oraz opcje zmiany parametrów obciążenia w trakcie testu. Przykłady profili można zobaczyć na rysunku.
Test (test) — scenariusz z z góry określonym zestawem parametrów.
Plan testów (test-plan) — zbiór testów i profil obciążenia.
Testrun (testrun) — jedna iteracja uruchomienia jednego testu z całkowicie zrealizowanym scenariuszem obciążenia i uzyskanym raportem.
Żądanie sieciowe (request) — zapytanie HTTP wysyłane od agenta do celu.
Odpowiedź sieciowa (response) — Odpowiedź HTTP wysyłana od celu do agenta.
Kod odpowiedzi HTTP (HTTP responses status) — standardowy kod odpowiedzi z serwera aplikacji.
Transakcja (transaction) — pełny cykl "żądanie — odpowiedź". Transakcja jest uważana za zakończoną od momentu wysłania żądania (request) do zakończenia odbioru odpowiedzi (response).
Status transakcji (transactions status) — czy cykl "żądanie – odpowiedź" zakończył się pomyślnie. Jeśli w tym cyklu wystąpił jakikolwiek błąd, cała transakcja uznawana jest za nieudaną.
Czas odpowiedzi (latency) — czas od zakończenia wysyłania żądania (request) do rozpoczęcia odbioru odpowiedzi (response).
Metryki obciążenia (metrics) — określone w trakcie testowania obciążeniowego cechy obciążanego serwisu oraz agenta obciążeniowego.
Podstawowe metryki do pomiaru parametrów obciążenia
Niektóre z najbardziej powszechnie używanych i zalecanych w metodologii (str. 36, 52) metryki przedstawione są w tabeli poniżej. Podobne metryki dla agenta i celu przedstawione są w jednej linii.
Metryki dla agenta obciążeniowego
Metryki systemu docelowego lub aplikacji testowanej pod obciążeniem
Liczba vCPU i pamięci RAM,
Dysk — "fizyczne" cechy agenta obciążeniowego
CPU, Pamięć, użycie dysku — dynamika obciążenia procesora, pamięci i dysku
w trakcie testowania. Zwykle mierzona w procentach od
maksymalnie dostępnych wartości
Przepustowość sieciowa (na agencie obciążeniowym) — przepustowość
interfejsu sieciowego na serwerze,
gdzie zainstalowany jest agent obciążeniowy.
Zwykle mierzona w bajtach na sekundę (bps)
Przepustowość sieciowa(na celu) — przepustowość interfejsu sieciowego
na serwerze docelowym. Zwykle mierzona w bajtach na sekundę (bps)
Wirtualni użytkownicy— liczba wirtualnych użytkowników,
realizujących scenariusze obciążenia i
imitujących rzeczywiste działania użytkowników
Status wirtualnych użytkowników, Przeszło/Niepowiodło się/Łącznie — liczba udanych i
nieudanych statusów działania wirtualnych użytkowników
dla scenariuszy obciążenia oraz ich łączna liczba.
Zwykle oczekuje się, że wszyscy użytkownicy będą w stanie zrealizować
wszystkie swoje zadania, określone w profilu obciążenia.
Każdy błąd oznacza, że również rzeczywisty użytkownik nie będzie w stanie
rozwiązać swojego zadania, korzystając z systemu.
Żądania na sekundę (minutę)— liczba żądań sieciowych na sekundę (lub minutę).
Ważna cecha agenta obciążeniowego: ile może generować żądań.
W rzeczywistości jest to symulacja interakcji z aplikacją przez wirtualnych użytkowników
Odpowiedzi na sekundę (minutę)
— liczba odpowiedzi sieciowych na sekundę (lub minutę).
Ważna cecha docelowej usługi: ile udało się
wygenerować i wysłać odpowiedzi na zapytania z
agenta obciążeniowego
Status odpowiedzi HTTP— liczba różnych kodów odpowiedzi
od serwera aplikacji, otrzymanych przez agenta obciążeniowego.
Na przykład, 200 OK oznacza udane zapytanie,
a 404 — że zasób nie został znaleziony
Opóźnienie (czas odpowiedzi) — czas od zakończenia
wysyłania zapytania (request) do rozpoczęcia odbioru odpowiedzi (response).
Zwykle mierzony w milisekundach (ms)
Czas odpowiedzi transakcji— czas jednej pełnej transakcji,
zakończenie cyklu „zapytanie — odpowiedź”.
To czas od początku wysyłania zapytania (request)
do zakończenia odbioru odpowiedzi (response).
Czas transakcji może być mierzony na kilka sposobów: uwzględnia się minimalne,
maksymalne, średnie oraz, na przykład, 90. percentyl.
Minimalne i maksymalne odczyty — to ekstremalne
stanowiska wydajności systemu.
Dziewięćdziesiąty percentyl jest najczęściej używany,
ponieważ pokazuje większość użytkowników,
którzy wygodnie pracują na granicy wydajności systemu
Transakcje na sekundę (minutę)
— liczba pełnych transakcji na sekundę (minutę),
czyli ile aplikacja mogła przyjąć i
przetworzyć zapytań i wydać odpowiedzi.
W rzeczywistości jest to przepustowość systemu
Status transakcji
, Przeszły / Nieudane / Całkowite — liczba udanych, nieudanych i całkowita liczba transakcji.
Dla rzeczywistych użytkowników nieudana
transakcja w rzeczywistości oznacza
niemożność pracy z systemem pod obciążeniem
Główna zasada testowania obciążeniowego
Główna zasada testowania obciążeniowego jest bardzo prosta i składa się z trzech podstawowych etapów, o których już wspomniałem:
Przygotowanie — Test — Raport , czyli przygotowanie celów testowania i ustalenie parametrów dla źródeł obciążenia, następnie wykonanie testów obciążeniowych i na końcu, stworzenie i opublikowanie raportu z testowania.Uwagi do schematu:
QA.Tester — ekspert w testach obciążeniowych,
- Cel — docelowa aplikacja, której zachowanie pod obciążeniem należy zbadać.
- Klasyfikator bytów, etapów i kroków na schemacie
Etapy i kroki
Co się dzieje
Co się dzieje
Co na wejściu
Co na wyjściu
Przygotowanie: etap przygotowania do testowania
ParametryŁadowania
Zadanie i inicjalizacja
przez użytkownika
parametry obciążenia,
wybór metryk i
przygotowanie planu testów
(profil obciążenia)
Parametry użytkownika do
inicjalizacji agenta obciążenia
Plan testów
Cel testowania
VM
Wdrożenie w chmurze
wirtualnej maszyny o
wymaganych charakterystykach
Parametry VM dla agenta obciążenia
Skrypty automatyzacji do
tworzenia VM
Skonfigurowana VM w
chmurze
Env
Konfiguracja systemu operacyjnego i przygotowanie
środowiska do
działania agenta obciążenia
Parametry środowiska dla
agenta obciążenia
Skrypty automatyzacji do
ustawienia środowiska
Przygotowane środowisko:
system operacyjny, usługi i aplikacje,
niezbędne do pracy
agenta obciążenia
LoadAgents
Instalacja, konfiguracja i parametryzacja
agenta obciążenia.
Lub pobranie obrazu Docker z
wstępnie skonfigurowanym źródłem obciążenia
Obraz Docker źródła obciążenia
(JMeter, JM lub własny framework)
Parametry konfiguracji
agenta obciążenia
Skonfigurowany i gotowy
do działania agent obciążenia
Test: etap wykonywania testów obciążeniowych. Źródłami są agenci obciążenia, wdrożeni w dedykowanych pulach agentów dla GitLab CI
Ładowanie
Uruchomienie agenta obciążenia
z wybranym planem testów
i parametrami obciążenia
Parametry użytkownika
do inicjalizacji
agenta obciążenia
Plan testów
Cel testowania
Logi wykonania
testów obciążeniowych
Logi systemowe
Dynamika zmiany metryk celu i agenta obciążenia
UruchomAgenty
Wykonanie przez agenta
obciążenia scenariuszy testowych
zgodnie z
profilu obciążenia
Interakcja agenta obciążenia
z celem testowania
Plan testów
Cel testowania
Logi
Zbieranie "surowych" logów
w trakcie testowania obciążenia:
zapisy o działaniach agenta obciążenia,
stanie celu testowania
i VM, na której uruchomiono agenta
Logi wykonania
testów obciążeniowych
Logi systemowe
Metryki
Zbieranie "surowych" metryk w trakcie testowania
Dynamika zmiany metryk celu
i agenta obciążenia
Raport: etap przygotowania raportu o testowaniu
Generator
Przetwarzanie zebranych
systemem obciążenia i
systemem monitoringu "surowych"
metryk i logów
Sformułowanie raportu w
czytelnej dla człowieka formie,
możliwe z elementami
analityki
Logi wykonania
testów obciążeniowych
Logi systemowe
Dynamika zmiany metryk
celo i agenta obciążenia
Przetworzone "surowe" logi
w formacie nadającym się do
eksportu do zewnętrznych magazynów
Statyczny raport obciążenia,
nadający się do analizy przez człowieka
Publikacja
Opublikowanie raportu
o testowaniu obciążenia
w zewnętrznym
serwisie
Przetworzone „surowe”
logi w formacie, nadającym się
do eksportu do zewnętrznych
magazynów
Zapisane w zewnętrznym
magazynie raporty o
obciążeniu, nadające się
do analizy przez człowieka
Podłączenie źródeł obciążenia w szablonie CI
Przejdźmy do części praktycznej. Chcę pokazać, jak w niektórych projektach w firmie wdrożyliśmy koncepcję testowania obciążeniowego jako usługi.
Na początku nasi inżynierowie DevOps stworzyli w GitLab CI dedykowany pul agentów do uruchamiania testów obciążeniowych. Aby nie pomylić ich w szablonach z innymi, na przykład z pulami budowlanymi, dodaliśmy tagi do tych agentów, : load. Można używać dowolnych innych zrozumiałych tagów. Ustala się je GitLab CI Runners.
Jak określić wymaganą moc sprzętową? Właściwości agentów obciążeniowych — odpowiednia liczba vCPU, RAM i dysku — można obliczyć na podstawie tego, że na agencie muszą być uruchomione Docker, Python (dla Yandex.Tank), agent GitLab CI oraz Java (dla Apache JMeter). Dla Javy pod JMeter również zaleca się użycie co najmniej 512 MB RAM, a jako górny limit, .
W związku z tym, na podstawie naszego doświadczenia, zalecamy użycie dla agentów obciążeniowych co najmniej: 4 vCPU, 4 GB RAM, 60 GB SSD. Przepustowość karty sieciowej określa się na podstawie wymagań profilu obciążenia.
Głównie korzystamy z dwóch źródeł obciążenia — obrazów Docker Apache JMeter i Yandex.Tank.
to narzędzie open-source firmy Yandex do przeprowadzania testów obciążeniowych. Oparte na jego modułowej architekturze — wysokowydajnym asynchronicznym generatorze HTTP-zapytań Phantom. Tank ma wbudowany monitoring zasobów testowanego serwera przez protokół SSH, może automatycznie zatrzymać test według ustalonych warunków, umie wyświetlać wyniki zarówno w konsoli, jak i w formie wykresów, a także można do niego podłączyć własne moduły w celu rozszerzenia funkcjonalności. Zresztą, używaliśmy Tanka, gdy to jeszcze nie było mainstreamem. W artykule „można przeczytać historię, jak w 2013 roku przeprowadzaliśmy za jego pomocą testowanie obciążeniowe jednego z produktów naszej firmy.
— to narzędzie open source do testowania obciążenia opracowane przez firmę Apache. Może być stosowane zarówno do testowania aplikacji internetowych statycznych, jak i dynamicznych. JMeter obsługuje ogromną ilość protokołów i metod interakcji z aplikacjami: HTTP, HTTPS (Java, NodeJS, PHP, ASP.NET itd.), SOAP / REST Webservices, FTP, TCP, LDAP, SMTP(S), POP3(S) i IMAP(S), bazy danych przez JDBC, potrafi wykonywać polecenia shell oraz pracować z obiektami Java. JMeter ma IDE do tworzenia, debugowania i uruchamiania planów testów. Posiada również CLI do pracy w wierszu poleceń w każdej zgodnej z Javą OS (Linux, Windows, Mac OS X). Narzędzie potrafi dynamicznie generować raporty HTML z testów.
Dla wygody użycia wewnątrz naszej firmy, aby testerzy mogli sami zmieniać i dodawać środowisko, stworzyliśmy zbiory obrazów dockera dla źródeł obciążenia na GitLab CI z publikacją wewnętrzną . Dzięki temu szybciej i łatwiej łączymy je w pipeline'ach do testów obciążeniowych. Jak zrobić docker push do rejestru przez GitLab CI — zobacz w .
Podstawowy plik dockera dla Yandex.Tank wzięliśmy stąd:
Dockerfile
1 | FROM direvius/yandex-tank
2 | ENTRYPOINT [""]A dla Apache JMeter stąd:
Dockerfile
1 | FROM vmarrazzo/jmeter
2 | ENTRYPOINT [""]Jak działa nasz system ciągłej integracji, możesz przeczytać w artykule „».
Szablon i pipeline
Przykład szablonu do przeprowadzania testów obciążeniowych dostępny jest w projekcie . W można przeczytać instrukcję użycia szablonu. W samym szablonie (plik ) znajdują się uwagi dotyczące każdego etapu.
Szablon jest bardzo prosty i demonstruje trzy etapy testowania obciążenia, opisane powyżej w schemacie: przygotowanie, testowanie i publikacja raportów. Odpowiadają za to : Prepare, Test i Report.
- Etap powinno być używane do wstępnego konfigurowania celów testowania lub sprawdzania ich dostępności. Środowisko dla źródeł obciążenia nie wymaga konfiguracji, są wcześniej zbudowane jako obrazy dockera i umieszczone w rejestrze dockera: wystarczy wskazać potrzebną wersję na etapie Test. Można je jednak przebudować i stworzyć własne zmodyfikowane obrazy.
- Etap jest używane do wskazania źródła obciążenia, uruchamiania testów i przechowywania artefaktów testowania. Możesz wybrać dowolne źródło obciążenia: Yandex.Tank, Apache JMeter, swoje lub wszystkie razem. Aby wyłączyć niepotrzebne źródła, wystarczy skomentować lub usunąć zadanie. Punkty wejścia dla źródeł obciążenia:
- parametry uruchamiania Yandex.Tank są określone w pliku.,
- parametry uruchamiania Apache JMeter są określone w pliku .
Uwaga: szablon konfiguracji kompilacji jest używany do skonfigurowania interakcji z systemem CI i nie zakłada umieszczania w nim logiki testów. Dla testów wskazuje się punkt wejścia, w którym znajduje się zarządzający skrypt bash. Sposób uruchamiania testów, tworzenie raportów i same scenariusze testowe muszą być realizowane przez inżynierów QA. W przykładzie demo dla obu źródeł obciążenia używany jest najprostszy test — żądanie głównej strony Yandexu. Scenariusze i parametry testów znajdują się w katalogu .
- Na etapie należy opisać sposoby publikacji wyników testów uzyskanych na etapie Test do zewnętrznych magazynów, na przykład do GitLab Pages lub specjalnych systemów raportowania. Dla GitLab Pages konieczne jest, aby po zakończeniu testów katalog ./public był niepusty i zawierał przynajmniej plik index.html. O niuansach działania usługi GitLab Pages możesz przeczytać .
Przykłady, jak eksportować dane:
- z JMeter do ,
- z Yandex.Tank do .
Instrukcje dotyczące ustawienia publikacji:
- HTML statyk w ,
- w InfluxDB, a następnie w .
W przykładzie demo pipeline z testami obciążeniowymi i dwoma źródłami obciążenia (można wyłączyć niepotrzebne) wygląda tak:
Apache JMeter potrafi samodzielnie generować raport HTML, więc korzystniej jest przechowywać go w GitLab Pages za pomocą wbudowanych mechanizmów. Oto jak wygląda raport Apache JMeter:
W przykładzie demo dla Yandex.Tank zobaczysz jedynie w sekcji dla GitLab Pages. W trakcie testowania Tank potrafi zapisywać wyniki w bazie InfluxDB, a stamtąd można je wyświetlić na przykład w Grafana (konfiguracja jest realizowana w pliku ). Oto jak raport Tank wygląda w Grafana:
Podsumowanie
W artykule opisałem koncepcję „testowania obciążenia jako usługi” (load testing as a service). Główna idea polega na wykorzystaniu infrastruktury wstępnie skonfigurowanych pul agentów obciążeniowych, obrazów Dockera źródeł obciążenia, systemów raportowania oraz wspólnego procesu w GitLab CI opartych na prostym szablonie .gitlab-ci.yml (przykład ). Wszystko to jest wspierane przez mały zespół inżynierów-automatyzatorów i powielane na żądanie zespołów produktowych. Mam nadzieję, że pomoże to w przygotowaniu oraz wdrożeniu podobnej schemy w twojej firmie. Dziękuję za uwagę!
P. S. Chciałbym serdecznie podziękować moim kolegom, Sergejowi Kurbanowowi i Nikolajowi Jusewowi, za pomoc techniczną w realizacji koncepcji testowania obciążenia jako usługi w naszej firmie.
Autor: — zastępca kierownika działu technologii i procesów rozwoju (DevOps) w firmie Positive Technologies
Źródło: habr.com
