Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Zabbix to system monitorowania. Jak każdy inny system, napotyka trzy główne problemy wszystkich systemów monitorowania: gromadzenie i przetwarzanie danych, przechowywanie historii i jej czyszczenie.

Etapy odbierania, przetwarzania i rejestrowania danych wymagają czasu. Niewiele, ale w przypadku dużego systemu może to skutkować dużymi opóźnieniami. Problem z pamięcią masową to problem z dostępem do danych. Służą do raportów, kontroli i wyzwalaczy. Opóźnienia w dostępie do danych również wpływają na wydajność. Kiedy bazy danych się rozrastają, nieistotne dane muszą zostać usunięte. Usunięcie jest trudną operacją, która również pochłania część zasobów.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Problemy opóźnień podczas gromadzenia i przechowywania w Zabbix rozwiązywane są poprzez buforowanie: kilka rodzajów pamięci podręcznych, buforowanie w bazie danych. Aby rozwiązać trzeci problem, buforowanie nie jest odpowiednie, więc Zabbix użył TimescaleDB. Powie ci o tym Andriej Guszczyn - Inżynier wsparcia technicznego Zabbix SIA. Andrey wspiera Zabbix od ponad 6 lat i ma bezpośrednie doświadczenie w zakresie wydajności.

Jak działa TimescaleDB, jaką wydajność może zapewnić w porównaniu ze zwykłym PostgreSQL? Jaką rolę odgrywa Zabbix dla bazy danych TimescaleDB? Jak zacząć od zera i jak przeprowadzić migrację z PostgreSQL oraz która konfiguracja ma lepszą wydajność? O tym wszystkim pod cięciem.

Wyzwania związane z produktywnością

Każdy system monitorowania stoi przed specyficznymi wyzwaniami związanymi z wydajnością. Opowiem o trzech z nich: gromadzeniu i przetwarzaniu danych, przechowywaniu i czyszczeniu historii.

Szybkie gromadzenie i przetwarzanie danych. Dobry system monitorowania powinien szybko odbierać wszystkie dane i przetwarzać je według wyrażeń wyzwalających – według swoich kryteriów. Po przetworzeniu system musi także szybko zapisać te dane w bazie danych do późniejszego wykorzystania.

Przechowywanie historii. Dobry system monitorowania powinien przechowywać historię w bazie danych i zapewniać łatwy dostęp do wskaźników. Historia jest potrzebna do wykorzystania w raportach, wykresach, wyzwalaczach, progach i elementach danych obliczonych alertów.

Czyszczenie historii. Czasami przychodzi dzień, kiedy nie musisz przechowywać metryk. Po co Ci dane zebrane 5 lat temu, miesiąc czy dwa: niektóre węzły zostały usunięte, niektóre hosty lub metryki nie są już potrzebne, ponieważ są nieaktualne i nie są już gromadzone. Dobry system monitorowania powinien przechowywać dane historyczne i co jakiś czas je usuwać, aby baza danych nie rosła.

Usuwanie nieaktualnych danych to kluczowy problem, który znacząco wpływa na wydajność bazy danych.

Buforowanie w Zabbixie

W Zabbix pierwsze i drugie wywołanie są rozwiązywane przy użyciu buforowania. Pamięć RAM służy do gromadzenia i przetwarzania danych. Do przechowywania - historia w wyzwalaczach, wykresach i obliczonych elementach danych. Po stronie bazy danych istnieje buforowanie podstawowych wyborów, na przykład wykresów.

Buforowanie po stronie samego serwera Zabbix to:

  • Pamięć podręczna konfiguracji;
  • pamięć podręczna wartości;
  • Pamięć podręczna historii;
  • Pamięć podręczna trendów.

Rozważ je bardziej szczegółowo.

Pamięć podręczna konfiguracji

Jest to główna pamięć podręczna, w której przechowujemy metryki, hosty, elementy danych, wyzwalacze – wszystko, czego potrzebujemy do przetwarzania wstępnego i gromadzenia danych.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Wszystko to przechowywane jest w ConfigurationCache, aby nie tworzyć niepotrzebnych zapytań w bazie danych. Po uruchomieniu serwera aktualizujemy tę pamięć podręczną, tworzymy i okresowo aktualizujemy konfiguracje.

Zbieranie danych

Schemat jest dość duży, ale najważniejsze w nim jest zbieracze. Są to różne „pollery” - procesy montażowe. Odpowiadają za różne rodzaje montażu: zbierają dane poprzez SNMP, IPMI i przekazują je wszystkie do PreProcessing.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDBKolektory są zaznaczone na pomarańczowo.

Zabbix obliczył elementy agregacji potrzebne do agregacji kontroli. Jeśli je posiadamy, pobieramy dla nich dane bezpośrednio z ValueCache.

Przetwarzanie wstępne HistoryCache

Wszystkie moduły zbierające używają ConfigurationCache do odbierania zadań. Następnie przekazują je do PreProcessingu.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Funkcja PreProcessing używa pamięci ConfigurationCache do odbierania kroków przetwarzania wstępnego. Przetwarza te dane na różne sposoby.

Po przetworzeniu danych za pomocą PreProcessing zapisujemy je w HistoryCache do przetwarzania. To kończy zbieranie danych i przechodzimy do głównego procesu w Zabbix - synchronizator historii, ponieważ jest to architektura monolityczna.

Uwaga: Przetwarzanie wstępne jest dość trudną operacją. W wersji 4.2 został przeniesiony do serwera proxy. Jeśli masz bardzo dużego Zabbixa z dużą liczbą elementów danych i częstotliwością gromadzenia danych, to znacznie ułatwia to pracę.

Pamięć podręczna wartości, historia i trendy

Synchronizator historii to główny proces, który atomowo przetwarza każdy element danych, czyli każdą wartość.

Synchronizator historii pobiera wartości z HistoryCache i sprawdza konfigurację pod kątem obecności wyzwalaczy obliczeń. Jeśli istnieją, to się kalkuluje.

Synchronizator historii tworzy zdarzenie, eskalację w celu utworzenia alertów, jeśli wymaga tego konfiguracja, i rejestruje. Jeśli istnieją wyzwalacze do dalszego przetwarzania, przechowuje tę wartość w ValueCache, aby nie mieć dostępu do tabeli historii. W ten sposób ValueCache zostaje wypełniony danymi niezbędnymi do wyliczenia wyzwalaczy i wyliczanych elementów.

Synchronizator historii zapisuje wszystkie dane do bazy danych i zapisuje je na dysk. Proces przetwarzania kończy się tutaj.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Buforowanie w bazie danych

Po stronie bazy danych znajdują się różne pamięci podręczne, w których chcesz przeglądać wykresy lub raporty dotyczące zdarzeń:

  • Innodb_buffer_pool po stronie MySQL;
  • shared_buffers po stronie PostgreSQL;
  • effective_cache_size po stronie Wyroczni;
  • shared_pool po stronie DB2.

Istnieje wiele innych pamięci podręcznych, ale są to główne pamięci podręczne dla wszystkich baz danych. Umożliwiają przechowywanie danych w pamięci RAM, które często są potrzebne do zapytań. Mają do tego własne technologie.

Wydajność bazy danych jest krytyczna

Serwer Zabbix stale gromadzi dane i zapisuje je. Po ponownym uruchomieniu odczytuje również historię, aby wypełnić pamięć podręczną ValueCache. Korzysta ze skryptów i raportów API Zabbixa, który jest zbudowany na interfejsie internetowym. Zabbix API uzyskuje dostęp do bazy danych i pobiera niezbędne dane do wykresów, raportów, list zdarzeń i najnowszych wydań.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Do wizualizacji - grafana. Jest to rozwiązanie popularne wśród naszych użytkowników. Może bezpośrednio wysyłać żądania poprzez API Zabbix i do bazy danych oraz tworzy pewną konkurencję w otrzymywaniu danych. Dlatego potrzebne jest dokładniejsze i lepsze dostrojenie bazy danych, aby zapewnić szybkie dostarczanie wyników i przeprowadzanie testów.

Gospodyni domowa

Trzecim wyzwaniem wydajnościowym w Zabbixie jest czyszczenie historii za pomocą Housekeepera. Podąża za wszystkimi ustawieniami - elementy danych wskazują, jak długo przechowywać dynamikę zmian (trendy) w dniach.

Obliczamy TrendsCache na bieżąco. Kiedy dane napływają, agregujemy je przez godzinę i zapisujemy w tabelach dynamiki zmian trendów.

Gospodyni uruchamia i usuwa informacje z bazy danych za pomocą zwykłych „wyborów”. Nie zawsze jest to skuteczne, co widać na wykresach wydajności procesów wewnętrznych.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Czerwony wykres pokazuje, że synchronizator historii jest stale zajęty. Pomarańczowy wykres u góry przedstawia Gospodynię, która stale działa. Czeka, aż baza danych usunie wszystkie określone przez niego wiersze.

Kiedy należy wyłączyć Housekeepera? Na przykład istnieje „ID pozycji” i musisz w określonym czasie usunąć ostatnie 5 tysięcy wierszy. Dzieje się to oczywiście według indeksu. Ale zazwyczaj zbiór danych jest bardzo duży, a baza danych nadal odczytuje dane z dysku i umieszcza je w pamięci podręcznej. Jest to zawsze bardzo kosztowna operacja dla bazy danych i, w zależności od rozmiaru bazy danych, może prowadzić do problemów z wydajnością.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Gospodynię można łatwo wyłączyć. W interfejsie internetowym w „Administracja ogólna” znajduje się ustawienie dla Housekeeper. Wyłączamy wewnętrzne zarządzanie historią trendów wewnętrznych i nie zarządza już nią.

Gospodyni została wyłączona, wykresy się wyrównały – jakie problemy mogą się w tym przypadku pojawić i co mogłoby pomóc w rozwiązaniu trzeciego wyzwania wydajnościowego?

Partycjonowanie - partycjonowanie lub partycjonowanie

Zazwyczaj partycjonowanie jest konfigurowane w inny sposób w każdej relacyjnej bazie danych, którą wymieniłem. Każdy ma swoją własną technologię, ale ogólnie są podobne. Utworzenie nowej partycji często prowadzi do pewnych problemów.

Zazwyczaj partycje są konfigurowane w zależności od „konfiguracji” – ilości danych tworzonych w ciągu jednego dnia. Z reguły partycjonowanie wydawane jest w ciągu jednego dnia, jest to minimum. Dla trendów nowej partii - 1 miesiąc.

Wartości mogą się zmienić, jeśli „konfiguracja” jest bardzo duża. Jeśli mały „setup” wynosi do 5 nvps (nowe wartości na sekundę), średni od 000 do 5 000, to duży powyżej 25 000 nvps. Są to duże i bardzo duże instalacje wymagające starannej konfiguracji bazy danych.

W przypadku bardzo dużych instalacji okres jednego dnia może nie być optymalny. Widziałem partycje MySQL o wielkości 40 GB lub więcej dziennie. Jest to bardzo duża ilość danych, która może powodować problemy i wymaga ograniczenia.

Co daje partycjonowanie?

Tabele partycjonowania. Często są to osobne pliki na dysku. Plan zapytań wybiera jedną partycję bardziej optymalnie. Zwykle partycjonowanie odbywa się według zakresu - dotyczy to również Zabbix. Używamy tam „znacznika czasu” – czasu od początku ery. Dla nas to zwykłe liczby. Ustawiasz początek i koniec dnia - to jest przegroda.

Szybkie usuwanie - DELETE. Wybrano jeden plik/podtabelę, a nie kilka wierszy do usunięcia.

Znacząco przyspiesza odzyskiwanie danych SELECT - używa jednej lub więcej partycji, a nie całej tabeli. Jeśli uzyskujesz dostęp do danych sprzed dwóch dni, są one pobierane z bazy danych szybciej, ponieważ wystarczy załadować tylko jeden plik do pamięci podręcznej i zwrócić go, a nie dużą tabelę.

Często wiele baz danych jest również przyspieszanych INSERT — wstawienia do tabeli podrzędnej.

Baza danych skali czasu

W wersji 4.2 zwróciliśmy uwagę na TimescaleDB. Jest to rozszerzenie dla PostgreSQL z natywnym interfejsem. Rozszerzenie efektywnie współpracuje z danymi szeregów czasowych, nie tracąc przy tym korzyści płynących z relacyjnych baz danych. TimescaleDB również automatycznie partycjonuje.

TimescaleDB ma koncepcję hipertable (hipertabela), którą tworzysz. Zawiera kawałki - przegrody. Kawałki to automatycznie zarządzane fragmenty hipertabli, które nie wpływają na inne fragmenty. Każdy fragment ma swój własny zakres czasu.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

TimescaleDB kontra PostgreSQL

TimescaleDB działa naprawdę wydajnie. Producenci rozszerzenia twierdzą, że stosują bardziej poprawny algorytm przetwarzania zapytań, w szczególności inserts . W miarę wzrostu rozmiaru wstawki zbioru danych algorytm utrzymuje stałą wydajność.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Po 200 milionach wierszy PostgreSQL zwykle zaczyna znacząco opadać i spada wydajność do 0. TimescaleDB pozwala efektywnie wstawiać „wstawki” dla dowolnej ilości danych.

Instalacja

Instalacja TimescaleDB jest dość łatwa dla każdego pakietu. W dokumentacja wszystko jest szczegółowo opisane - zależy to od oficjalnych pakietów PostgreSQL. TimescaleDB można również zbudować i skompilować ręcznie.

W przypadku bazy danych Zabbix po prostu aktywujemy rozszerzenie:

echo "CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;" | sudo -u postgres psql zabbix

Aktywujesz extension i utwórz go dla bazy danych Zabbix. Ostatnim krokiem jest utworzenie hipertabeli.

Migracja tabel historii do TimescaleDB

Jest do tego specjalna funkcja create_hypertable:

SELECT create_hypertable(‘history’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘history_unit’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘history_log’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘history_text’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘history_str’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘trends’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
SELECT create_hypertable(‘trends_unit’, ‘clock’, chunk_time_interval => 86400, migrate_data => true);
UPDATE config SET db_extension=’timescaledb’, hk_history_global=1, hk_trends_global=1

Funkcja ma trzy parametry. Pierwszy - tabela w bazie danych, dla którego musisz utworzyć hipertabelę. Drugi - pole, zgodnie z którym musisz utworzyć chunk_time_interval — odstęp fragmentów podziału do wykorzystania. W moim przypadku odstęp wynosi jeden dzień – 86 400.

Trzeci parametr - migrate_data. Jeśli ustawisz true, następnie wszystkie bieżące dane są przesyłane do wcześniej utworzonych fragmentów. Sam tego używałem migrate_data. Miałem około 1 TB, co zajęło ponad godzinę. Nawet w niektórych przypadkach podczas testów usuwałem dane historyczne typów postaci, które nie były wymagane do przechowywania, aby ich nie przenosić.

Ostatni krok - UPDATE: w db_extension położyć timescaledbaby baza danych wiedziała, że ​​to rozszerzenie istnieje. Zabbix aktywuje go i poprawnie używa składni i zapytań do bazy danych - czyli tych funkcji, które są niezbędne dla TimescaleDB.

Konfiguracja sprzętu

Korzystałem z dwóch serwerów. Pierwszy - Maszyna VMware. Jest dość mały: 20 procesorów Intel® Xeon® CPU E5-2630 v 4 @ 2.20 GHz, 16 GB RAM i 200 GB SSD.

Zainstalowałem na nim PostgreSQL 10.8 z systemem operacyjnym Debian 10.8-1.pgdg90+1 i systemem plików xfs. Skonfigurowałem wszystko minimalnie, aby używać tej konkretnej bazy danych, pomijając to, czego będzie używał sam Zabbix.

Na tej samej maszynie znajdował się serwer Zabbix, PostgreSQL i agentów obciążenia. Miałem 50 aktywnych agentów, którzy używali LoadableModuledo bardzo szybkiego generowania różnych wyników: liczb, ciągów znaków. Wypełniłem bazę danych dużą ilością danych.

Początkowo konfiguracja zawierała 5 elementów danych na hosta. Prawie każdy element zawierał wyzwalacz upodobniający go do rzeczywistych instalacji. W niektórych przypadkach był więcej niż jeden czynnik wyzwalający. Dla jednego węzła sieci były 3 000–7 000 wyzwalaczy.

Interwał aktualizacji elementu danych − 4-7 sekund. Regulowałem samo obciążenie, używając nie tylko 50 agentów, ale dodając ich więcej. Ponadto, korzystając z elementów danych, dynamicznie dostosowywałem obciążenie i zmniejszałem interwał aktualizacji do 4 s.

PostgreSQL. 35 000 NVPS

Moje pierwsze uruchomienie na tym sprzęcie odbyło się na czystym PostgreSQL - 35 tysięcy wartości na sekundę. Jak widać wstawianie danych zajmuje ułamki sekund - wszystko przebiega dobrze i szybko. Jedyną rzeczą jest to, że dysk SSD o pojemności 200 GB szybko się zapełnia.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

To jest standardowy pulpit nawigacyjny wydajności serwera Zabbix.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Pierwszy niebieski wykres to liczba wartości na sekundę. Drugi wykres po prawej stronie przedstawia ładowanie procesów kompilacji. Trzeci to ładowanie wewnętrznych procesów kompilacji: synchronizatorów historii i Housekeepera, który działa tutaj już od dłuższego czasu.

Czwarty wykres pokazuje wykorzystanie HistoryCache. Jest to swego rodzaju bufor przed wstawieniem do bazy danych. Zielony piąty wykres pokazuje wykorzystanie ValueCache, czyli ile trafień ValueCache dla wyzwalaczy – jest to kilka tysięcy wartości na sekundę.

PostgreSQL. 50 000 NVPS

Następnie zwiększyłem obciążenie do 50 tysięcy wartości na sekundę na tym samym sprzęcie.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Przy ładowaniu z Housekeepera wstawienie 10 tysięcy wartości trwało 2-3 sekundy.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB
Gospodyni już zaczyna przeszkadzać w pracy.

Trzeci wykres pokazuje, że ogólnie rzecz biorąc, obciążenie traperów i synchronizatorów historii nadal wynosi 60%. Na czwartym wykresie HistoryCache zaczyna już dość aktywnie się zapełniać podczas działania Housekeepera. Jest zapełniony w 20%, czyli około 0,5 GB.

PostgreSQL. 80 000 NVPS

Następnie zwiększyłem obciążenie do 80 tysięcy wartości na sekundę. To około 400 tysięcy elementów danych i 280 tysięcy wyzwalaczy.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB
Koszt ładowania trzydziestu synchronizatorów historii jest już dość wysoki.

Zwiększyłem także różne parametry: synchronizatory historii, pamięci podręczne.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Na moim sprzęcie ładowanie synchronizatorów historii wzrosło do maksimum. HistoryCache szybko zapełnił się danymi - w buforze zgromadziły się dane do przetwarzania.

Przez cały ten czas obserwowałem wykorzystanie procesora, pamięci RAM i innych parametrów systemu i stwierdziłem, że wykorzystanie dysku było maksymalne.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Osiągnąłem użytek maksymalne możliwości dysku na tym sprzęcie i na tej maszynie wirtualnej. Przy takiej intensywności PostgreSQL zaczął dość aktywnie opróżniać dane, a dysk nie miał już czasu na zapis i odczyt.

Drugi serwer

Wziąłem inny serwer, który miał już 48 procesorów i 128 GB RAM-u. Dostroiłem go - ustawiłem synchronizator historii na 60 i osiągnąłem akceptowalną wydajność.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Tak naprawdę jest to już granica produktywności, przy której trzeba coś zrobić.

Skala czasuDB. 80 000 NVPS

Moim głównym zadaniem jest przetestowanie możliwości TimescaleDB pod kątem obciążenia Zabbix. 80 tysięcy wartości na sekundę to dużo, częstotliwość zbierania metryk (oczywiście poza Yandexem) i dość duży „setup”.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Na każdym wykresie widać spadek – to jest właśnie migracja danych. Po awariach na serwerze Zabbix profil ładowania synchronizatora historii bardzo się zmienił - spadł trzykrotnie.

TimescaleDB pozwala na wstawianie danych prawie 3 razy szybciej i zużywa mniej HistoryCache.

Dzięki temu otrzymasz dane terminowo.

Skala czasuDB. 120 000 NVPS

Następnie zwiększyłem liczbę elementów danych do 500 tys.Głównym zadaniem było przetestowanie możliwości TimescaleDB - otrzymywałem obliczoną wartość 125 tysięcy wartości na sekundę.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Jest to działająca „konfiguracja”, która może działać przez długi czas. Ale ponieważ mój dysk miał tylko 1,5 TB, zapełniłem go w ciągu kilku dni.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

Najważniejsze jest to, że w tym samym czasie zostały utworzone nowe partycje TimescaleDB.

Jest to całkowicie niezauważalne dla wydajności. Kiedy na przykład tworzone są partycje w MySQL, wszystko jest inne. Zwykle dzieje się to w nocy, ponieważ blokuje ogólne wstawianie, pracę z tabelami i może powodować pogorszenie jakości usług. Nie dotyczy to TimescaleDB.

Jako przykład pokażę jeden wykres spośród wielu w społeczności. Na zdjęciu włączona jest TimescaleDB, dzięki czemu spadło obciążenie procesora przy użyciu io.weight. Zmniejszyło się także wykorzystanie elementów procesów wewnętrznych. Co więcej, jest to zwykła maszyna wirtualna na zwykłych dyskach naleśnikowych, a nie dysk SSD.

Wysoka wydajność i natywne partycjonowanie: Zabbix z obsługą TimescaleDB

odkrycia

TimescaleDB to dobre rozwiązanie dla małych „konfiguracji”, które wpływają na wydajność dysku. Umożliwi to kontynuację dobrej pracy do czasu jak najszybszej migracji bazy danych na sprzęt.

TimescaleDB jest łatwy w konfiguracji, zapewnia wzrost wydajności, dobrze współpracuje z Zabbixem i ma przewagę nad PostgreSQL.

Jeśli używasz PostgreSQL i nie planujesz go zmieniać, polecam używaj PostgreSQL z rozszerzeniem TimescaleDB w połączeniu z Zabbix. To rozwiązanie działa skutecznie aż do średniego „ustawienia”.

Kiedy mówimy „wysoka wydajność”, mamy na myśli Wysokie obciążenie++. Nie będziesz musiał długo czekać, aby poznać technologie i praktyki, dzięki którym usługi mogą służyć milionom użytkowników. Lista raporty na 7 i 8 listopada już skompilowaliśmy, ale tutaj spotkania można zaproponować więcej.

Zapisz się do naszego biuletyn и telegram, w którym ujawniamy cechy nadchodzącej konferencji i dowiemy się, jak najlepiej z niej skorzystać.

Źródło: www.habr.com

Dodaj komentarz