Telemetria w PHP

Flow PHP - Telemetry

Obserwowalność - czyli sposób na monitorowanie zachowania na podstawie emitowanych przez system sygnałów.

Od kilku lat na rynku dominuje jeden standard, który zyskuje coraz szerszą adaptację w usługach typu APM, jest nim Open Telemetry.

OpenTelemetry dostarcza nie tylko specyfikację, protokóły czy konwencje nazewnictwa. To także zbiór bibliotek i SDK pozwalający na "łatwą" adaptację w niemalże każdym systemie.

Dlaczego więc postanowiłem napisać własną bibliotekę, zamiast skorzystać z gotowych rozwiązań?

Wszystko zaczęło się od tego, że chciałem zintegrować DataFrame z Flow PHP (oraz kilka bibliotek jak np postgresql czy filesystem) z OpenTelemetry.

Pierwszym problemem, na który trafiłem to zależności, SDK OpenTelemetry

Biorąc pod uwagę, że obecnie Flow PHP (w bazowej wersji) wymaga tylko:

Ilość zależności praktycznie by się podwoiła, co w przypadku frameworka, który użytkownicy muszą dodawać do listy zależności swoich systemów staje się odrobinę problematyczne ze względu na potencjalne konflikty wersji.

Teoretycznie mógłbym uzależnić Flow jedynie od open-telemetry/api a sdk dorzucić jako zależność opcjonalną. Jednak kiedy zacząłem głębiej przyglądać się jak zbudowane jest API stwierdziłem, że nie jest ono kompatybilne z architekturą, którą przyjąłem w Flow.

Głównym problemem były dla mnie wszelkiego rodzaju globalne stany, singletony i inne mechanizmy mające w teorii ułatwić auto instrumentacje. Przykład OpenTelemetry Globals.

Mógłbym pewnie próbować obejść Globals, jednak patrząc na implementacje instrumentacji oparte o OpenTelemetry bardzo szybko trafiłbym na problemy związane z tym, że SDK jest bardzo ściśle powiązane z API, a API jest bardzo ściśle powiązane z globalnym stanem.

Tutaj musiałem stanąć przed wyborem. Separować kod Flow za pomocą dodatkowej abstrakcji, lub zbudować własne API będące jednocześnie abstrakcją dla telemetrii.

Biorąc pod uwagę, że samo API nie jest aż tak rozbudowane, podjąłem decyzję o zbudowaniu niezależnego API oraz warstwy transportu, które są zgodne z protokołem OTLP. Tak oto powstała malutka biblioteczka o nazwie flow-php/telemetry

Samo API flow-php/telemetry jest bardzo nieinwazyjne, nie opiera się o stany globalne, polega głównie na kontraktach, oraz dostarcza bardzo lekkie implementacje InMemory or Void użyteczne w testach.

API nie jest jednak wystarczające, aby wysłać gdziekolwiek sygnały. Potrzebujemy do tego serializera oraz transportu (do tego służy SDK OpenTelemetry).

Flow dostarcza coś bardzo podobnego, flow-php/telemetry-otlp-bridge.
Zadaniem tej biblioteki jest:

flow-php/telemetry-otlp-bridge pozwala serializować sygnały do:

Sygnały natomiast mogą być przesyłane poprzez:

Sygnały

Czym są sygnały?

Metryki - liczbowe dane o stanie systemu, np. liczba żądań na sekundę, średni czas odpowiedzi, itp.

Ślady (Traces / Spans) - reprezentują pojedyncze operacje w systemie, wraz z ich atrybutami, czasem trwania, itp.
Pojedynczy Trace to tak naprawdę kolekcja Span'ów, które są ze sobą powiązane, tworząc drzewo operacji.
Ponad to, Trace może być powiązany z metrykami, logami, czy innymi Trace'ami, co pozwala na pełniejszy obraz tego, co dzieje się w systemie.

Logi - tekstowe dane o zdarzeniach w systemie, często zawierające dodatkowe atrybuty, takie jak poziom logowania, czy kontekst zdarzenia.

Auto Instrumentacja

Jedną z głównych zalet korzystania z OpenTelemetry jest auto instrumentacja.

Zgodnie z założeniami, autorzy bibliotek (tacy jak ja) powinni integrować swoje narzędzia z API/SDK OpenTelemetry. Dzięki temu, jeżeli w systemie, który używa takich bibliotek skonfigurujemy serializacje oraz warstwę transportu, automatycznie, bez żadnego wysiłku dostaniemy podstawową telemetrię.

Gdyby społeczność PHP podzielała wizję twórców API/SDK - w niemalże każdym projekcie wystarczyłoby skonfigurować SDK aby uzyskać wgląd w to jak działa system produkcyjnie.

Na ten moment, nie ma jednak ani jednej biblioteki, która byłaby natywnie zintegrowana z OpenTelemetry.

Nie wiem, dlaczego tak jest, środowiska takie jak Java czy .NET mają o wiele lepszą adaptację OpenTelemetry niż PHP.

Być może gdyby SDK OpenTelemetry było bardziej popularne, nie zdecydowałbym się na pisanie własnej biblioteki.

Niemniej jednak, powoli ale skutecznie zacząłem integrować wszystkie biblioteki, które rozwijam z flow-php/telemetry.
Stworzyłem też kilka rozszerzeń do istniejących frameworków/bibliotek - co pozwala na równie skuteczną auto instrumentację.

Biblioteki z natywną integracją:

Rozszerzenia do istniejących bibliotek

Uwaga: Jeżeli rozwijasz swój projekt open source - odezwij się.
Wspólnie znajdziemy możliwie najprostszy sposób na integrację twojego narzędzia z telemetrią. Możemy to zrobić poprzez natywną integrację lub rozszerzenie.

OTEL Collector

OTEL Collector

OTEL Collector to rewelacyjne narzędzie, służące jako centralny hub do otrzymywania / przetwarzania / przesyłania dalej sygnałów.
Stawiając collector pomiędzy systemem a APM'em (Application Performance Monitoring System) unikamy vendor lockingu.

Unikamy również zbędnych, blokujących operacji I/O. Nasze sygnały są buforowane w pamięci, a w momencie przepełnienia ustawionego bufora lub zakończenia skryptu są przesyłane do collectora.

Poniżej przykłady konfiguracji collectora z monorepozytorium Flow

APM

Na rynku istnieje bardzo dużo popularnych rozwiązań pozwalających na monitorowanie systemów kompatybilnych z protokołem OTLP.
Są to narzędzia zarówno płatne, jak i w pełni darmowe, dostępne jako usługi lub open source. Zanim jednak wybierzemy właściwy APM warto zaprzyjaźnić się z samym protokołem OTLP.

Oczywiście większość APM'ów dostarcza swoje biblioteki, pozwalające na monitorowanie systemów, jednak korzystając z nich, wiążemy się bardzo mocno z konkretnym dostawcą.

Moim (przynajmniej na razie) preferowanym rozwiązaniem do lokalnego developmentu jest Aspire

Aspire jest też skonfigurowany jako APM w monorepozytorium Flow, przykład konfiguracji znajduje się tutaj.

Demo

Przykłady kodu flow-php/telemetry znajdziecie na https://flow-php.com.
Każdy z nich można uruchomić w przeglądarce za pomocą Playgroundu Flow.

Nie ma jednak lepszej formy poznania narzędzia niż dotknięcie go, dlatego każdego zainteresowanego zachęcam do postawienia lokalnie Aspire, OTEL Collectora, dodanie flow-php/telemetry oraz flow-php/telemetry-otlp-bridge.

Potem pozostaje już tylko zacząć emitować sygnały!

Poniżej zrzut ekranu z lokalnego Aspire pokazujący telemetrię zebraną podczas wykonywania testów całego monorepozytorium Flow.

About Author

Norbert Orzechowicz

Norbert Orzechowicz

Software architect with over 16 years of experience in building highly scalable transactional and analytical systems. I specialize in building bridges between business, development teams, systems architecture, and data infrastructure.

Creator of Flow, the most advanced data processing framework for PHP. In my spare time, I maintain several open-source projects and enjoy automating and optimizing everything around me.