Planowanie pojemności w systemach IoT: jak przewidywać obciążenie i nie blokować rozwoju

0
31
2.5/5 - (2 votes)

Nawigacja:

Gdzie IoT się dławi: scenka z życia i sens planowania pojemności

Po kilku miesiącach udanego pilotażu klient decyduje się „odpalić produkcję”: zamiast 500 czujników w hali, uruchamia od razu 5000 w kilku zakładach. Pierwszego dnia wszystko wygląda dobrze, drugiego zaczynają ginąć dane, trzeciego broker MQTT nie wyrabia, a dashboard potrafi ładować się kilkadziesiąt sekund. Zespół ma wrażenie, że system, który w labie był „rakietą”, nagle zamienił się w betonowy blok.

Różnica między środowiskiem testowym a realnym światem w IoT bywa brutalna. Działa przy 200–500 urządzeniach? To prawie nic nie mówi o tym, czy ta sama platforma poradzi sobie przy 50 000, kiedy każde z nich raportuje częściej, wysyła większe payloady, a biznes dorzucił kilka nowych funkcji po drodze.

Planowanie pojemności w systemach IoT to świadome projektowanie i zarządzanie zasobami tak, aby platforma:

  • nie dławiła się przy rosnącej liczbie urządzeń i użytkowników,
  • nie blokowała rozwoju produktu (bo „infrastruktura nie wyrabia”),
  • nie generowała zbędnych kosztów na przewymiarowaną chmurę lub sprzęt.

Traktowanie planowania pojemności jako „gaszenia pożaru”, czyli reagowania dopiero wtedy, gdy system padnie po wdrożeniu większego klienta, ma konkretną cenę: opóźnione wdrożenia, weekendy spędzone na ratowaniu klastra, doraźne doklejanie kolejnych maszyn bez zrozumienia, gdzie faktycznie leży problem. Tak powstaje chaotyczne skalowanie, w którym koszt rośnie szybciej niż przychód.

Znacznie bezpieczniejsze podejście to zbudowanie przybliżonego modelu obciążenia już na etapie projektowania. Nie musi być idealny matematycznie – wystarczy, że wskaże rząd wielkości: czy mówimy o dziesiątkach, setkach, czy tysiącach żądań na sekundę, o megabitach czy gigabitach na łączu, o gigabajtach czy terabajtach danych miesięcznie.

Mini-wniosek: bez choćby zgrubnego modelu obciążenia, każda decyzja infrastrukturalna – od wyboru bazy danych po wielkość klastra – jest zgadywanką. A zgadywanie zazwyczaj wychodzi drożej niż spokojne zaplanowanie pojemności systemu IoT.

Osoba rysuje schemat blokowy i plan budżetu na białej tablicy
Źródło: Pexels | Autor: Christina Morillo

Jak wygląda typowy system IoT od strony obciążenia

Warstwa urządzeń i jej ukryte koszty

Źródłem obciążenia w systemach IoT są urządzenia: czujniki, bramki, sterowniki PLC, kamery. Obciążenie nie wynika tylko z liczby urządzeń, ale z kilku konkretnych parametrów:

  • częstotliwość wysyłania danych (np. co 10 s, minutę, godzinę),
  • rozmiar pojedynczego komunikatu (payloadu),
  • rodzaj łączności (GSM/LTE, Wi‑Fi, LoRaWAN, Ethernet),
  • zachowanie przy błędach (ile razy i jak szybko retransmituje dane).

W pilotażu często zakłada się tryb „laboratoryjny”: stabilna sieć, niewielka liczba urządzeń, brak zakłóceń. W produkcji dochodzą realne problemy: zasięg jest słabszy, urządzenia tracą połączenie, kolejkują dane lokalnie i wysyłają „zaległości” hurtem, gdy tylko wróci zasięg. To oznacza nagłe piki ruchu, których wcześniej nie było.

Dobierając parametry raportowania na warstwie urządzeń, decyduje się w praktyce o tym, jak duże obciążenie trafi dalej do brokera, backendu, bazy danych i interfejsów. Zmiana częstotliwości raportowania z 60 sekund na 10 sekund to sześciokrotnie większy ruch. Przy 100 urządzeniach nie robi wrażenia. Przy 100 000 – zamienia się w lawinę.

Warstwa komunikacyjna: broker, protokół, sesje

Kolejny element to warstwa komunikacyjna: broker MQTT/AMQP, HTTP API, WebSockety, czasem SMS lub protokoły branżowe (np. Modbus przez bramkę). Najczęściej „wąskim gardłem” stają się:

  • liczba równoczesnych połączeń (np. dziesiątki tysięcy sesji MQTT),
  • przepustowość brokera – ile wiadomości na sekundę jest w stanie obsłużyć,
  • opóźnienia – jak szybko wiadomość trafia z urządzenia do konsumenta (np. serwisu przetwarzającego).

HTTP bywa prostsze na start, ale przy bardzo dużej liczbie urządzeń staje się mniej efektywne niż lekkie protokoły typu MQTT czy CoAP. Utrzymywanie długotrwałych sesji, keepalive, heartbeaty – wszystko to zużywa pamięć, wątki, gniazda sieciowe na serwerach.

W praktyce wielu operatorów platform IoT odkrywa, że pierwszy element, który „pęka”, to właśnie broker lub frontowe API: liczba połączeń rośnie szybciej, niż przewidywano, a jeden nieprzewidziany pik (np. masowa aktualizacja firmware) potrafi zabić całą warstwę komunikacyjną.

Warstwa przetwarzania: mikroserwisy, kolejki, strumienie

Za komunikacją stoi warstwa przetwarzania: mikroserwisy (lub monolit), kolejki, systemy streamowe (Kafka, Pulsar, Kinesis), funkcje serverless. To tutaj dane są:

  • walidowane,
  • wzbogacane metadanymi (np. lokalizacja, klient, typ urządzenia),
  • agregowane (np. średnie 5‑minutowe),
  • zapisywane do baz danych,
  • wykorzystywane do alertów, reguł automatyki, machine learningu.

Wąskimi gardłami w tej warstwie bywają:

  • komponenty stanowe (cache współdzielony, sesje, blokady),
  • zbyt „ciężkie” operacje synchroniczne (np. liczenie skomplikowanych agregacji przy każdym komunikacie zamiast w oknach czasowych),
  • niewydolne kolejki, które nie są w stanie „przepchnąć” nagłych pików.

Tutaj szczególnie istotne jest, czy serwisy są stateless i można je łatwo skalować horyzontalnie, czy każdy z nich ma lokalny stan, który blokuje skalowanie i utrudnia równomierne rozkładanie obciążenia.

Warstwa danych i prezentacji: bazy, API, dashboardy

System IoT często utrzymuje co najmniej kilka baz danych:

  • time‑series (TSDB) do przechowywania szeregów czasowych z urządzeń,
  • NoSQL do metadanych urządzeń, konfiguracji, zdarzeń,
  • relacyjna (SQL) do danych biznesowych, uprawnień, billingów.

Do tego dochodzi warstwa prezentacji: dashboardy, raporty, API dla integratorów. Tu obciążenie jest inne niż na wejściu: zamiast wielu małych zapisów dominuje mieszanka:

  • wielu odczytów (widoki, wykresy, raporty),
  • cięższych zapytań (agregacje, filtrowanie po wielu wymiarach, eksport danych).

Typowe wąskie gardła w tej części to:

  • brak indeksów lub złe indeksy w bazie,
  • łączenie danych z wielu tabel przy dużych wolumenach,
  • brak cache’owania wyników raportów, które są odświeżane co kilka sekund przez wielu użytkowników naraz.

Identyfikacja punktów krytycznych w architekturze IoT

Patrząc na cały łańcuch – od urządzenia po dashboard – da się wskazać kilka typowych miejsc, które „pękają” w pierwszej kolejności:

  • broker wiadomości (MQTT/AMQP) – liczba równoległych połączeń, throughput,
  • baza szeregów czasowych – IOPS i rozmiar danych,
  • sieć – przepustowość i opóźnienia między regionami/klastrami,
  • pamięć i CPU w serwisach agregujących i analitycznych,
  • API „raportowe” – ciężkie zapytania bez ograniczeń (np. eksport rok‑do‑roku dla 10 tys. urządzeń).

Bez takiej mapy łatwo „przewymiarować” nie ten komponent, który trzeba. Dokłada się wirtualki do backendu, podczas gdy realny problem leży w niewydolnej bazie danych albo pojedynczym brokerze działającym w trybie „single node”.

Mini-wniosek: planowanie pojemności systemów IoT zaczyna się od zrozumienia, gdzie w ogóle może dojść do przeciążenia. Zanim zacznie się liczyć rps‑y i gigabajty, potrzebna jest mapa elementów, które mogą stać się wąskim gardłem.

Model obciążenia w IoT: jak policzyć, ile „tego wszystkiego” będzie

Szacowanie liczby urządzeń i scenariuszy rozwoju

Żeby cokolwiek policzyć, trzeba mieć poczucie, ilu urządzeń realnie można się spodziewać. Zamiast jednego „magicznego” numeru, warto oprzeć się na trzech scenariuszach:

  • konserwatywnym – jeśli sprzedaż rozwija się wolniej niż plan,
  • realistycznym – zgodnym z aktualnymi kontraktami, pipeline’em, pilotażami,
  • agresywnym – jeśli 1–2 duże wdrożenia „siądą” jednocześnie.

Przykładowa siatka myślenia:

  • aktualnie: 1000 aktywnych urządzeń,
  • za 12 miesięcy:
    • scenariusz konserwatywny: 3000,
    • realistyczny: 8000,
    • agresywny: 15 000.

Te scenariusze warto potem wpleść w dalsze obliczenia – planowanie pojemności systemu IoT staje się wtedy rozmową o „co się stanie, jeśli wejdzie agresywny scenariusz”, a nie o abstrakcyjnych liczbach oderwanych od biznesu.

Wzór myślowy: od urządzeń do wiadomości na sekundę

Kluczowy krok: zamienić liczbę urządzeń i sposób ich pracy na parametry, które rozumie infrastruktura – głównie liczbę komunikatów na jednostkę czasu. Przydatny jest bardzo prosty wzór myślowy:

Liczba wiadomości na sekundęliczba urządzeń × (wiadomości na minutę na urządzenie) ÷ 60 × współczynnik retransmisji

Jeżeli każde urządzenie wysyła jedną wiadomość co 30 sekund, to zapewnia 2 wiadomości na minutę. Przy 10 000 urządzeń daje to 20 000 wiadomości na minutę, czyli ok. 333 wiadomości na sekundę. Jeśli urządzenia w trudnym środowisku retransmitują dane (np. średnio 20% komunikatów jest wysyłanych ponownie), realna liczba komunikatów wzrośnie do ok. 400 na sekundę.

Drugi parametr to rozmiar wiadomości. Jeśli pojedynczy payload ma ok. 1 kB, a system przyjmuje 400 wiadomości na sekundę, to ruch „do środka” wynosi orientacyjnie 400 kB/s, czyli ok. 0,4 MB/s. To nadal niewiele. Ale gdy payload rośnie (np. urządzenie wysyła 50 pomiarów naraz, do tego metadane, sygnatury, logi), z 1 kB potrafi się zrobić 10 kB – i nagle jest to 4 MB/s, a przy kolejnych klientach łatwo dochodzi się do dziesiątek MB/s.

Przekład na RPS, TPS, IOPS i przepustowość sieci

Kiedy wiadomo już, ile przychodzi wiadomości na sekundę i jaki jest ich rozmiar, można model obciążenia przełożyć na pojęcia używane przez dostawców chmury i adminów:

  • RPS (requests per second) – ile żądań HTTP / komunikatów przez broker trafia do systemu,
  • TPS (transactions per second) – ile operacji biznesowych i zapisów/odczytów w bazie to generuje,
  • IOPS – ile operacji dyskowych na sekundę będzie potrzebne do zapisania i odczytania danych,
  • przepustowość sieci – ile MB/s lub Mb/s przejdzie przez interfejsy sieciowe.

Przykład uproszczonego przełożenia:

  • każdy komunikat z urządzenia powoduje:
    • 1 zapis do bazy szeregów czasowych,
    • 1 zapis do bazy zdarzeń (NoSQL),
    • czasem 1 odczyt konfiguracji z cache/bazy.

Przy 400 wiadomościach na sekundę to ok. 800–1200 operacji bazodanowych na sekundę. Jeśli baza działa na dyskach SSD i ma odpowiednią ilość RAM i indeksów, taki poziom obciążenia jest spokojnie obsługiwalny. Ale jeśli ten sam wzorzec skalować liniowo do 100 000 urządzeń (czyli kilka tysięcy wiadomości na sekundę), nagle zaczynają się liczyć IOPS dysku, architektura replikacji i partycjonowanie.

Sezonowość, piki i „tryb awaryjny”

Obciążenie IoT rzadko jest równomierne. Występują:

  • piki dobowo – np. rano, gdy uruchamiane są linie produkcyjne lub pojazdy,
  • Wzorce ruchu w ciągu dnia, tygodnia i roku

    Operator widzi w monitoringu, że codziennie o 7:05 ruch z urządzeń „strzela” trzykrotnie w górę, a o 7:20 wszystko wraca do normy. Przez długi czas nikt się tym nie przejmuje, dopóki jednego zimowego poranka nie dochodzi do opóźnień w alarmach, bo kilka komponentów nie wytrzymuje nagłego skoku. Dopiero wtedy pada pytanie: czy system był projektowany pod średnie, czy pod te krótkie, powtarzalne szczyty?

    W systemach IoT obciążenie bardzo często układa się w powtarzalne wzorce:

  • dobowe – urządzenia „śpią” w nocy, budzą się w dzień (liczniki energii, czujniki w biurach, floty pojazdów),
  • tygodniowe – poniedziałek–piątek ruch produkcyjny, weekendy niemal cisza,
  • sezonowe – systemy grzewcze zimą, nawadnianie latem, monitoring turystyczny w sezonie.

Model obciążenia, który uwzględnia tylko średnią z miesiąca, jest zbyt gładki i grzeczny. W praktyce bardziej liczy się:

  • 95. i 99. percentyl ruchu – jak wygląda „typowo wysoki” i „prawie najgorszy” moment dnia,
  • długość trwania piku – 2 minuty, 30 minut, 3 godziny,
  • korelacja pików – czy wszystkie urządzenia „strzelają” w tym samym czasie, czy fale są przesunięte.

Jeśli np. wszystkie czujniki w budynkach raportują na pełną godzinę, a agregacje liczone są też „na pełną”, to szczyt może być kilkukrotnie wyższy niż równomiernie rozsmarowana średnia. Zmiana harmonogramu raportowania (np. losowe przesunięcie o kilkanaście sekund) bywa tańsza niż dokładanie kolejnych węzłów do klastra.

Mini-wniosek: model obciążenia musi zawierać nie tylko liczbę wiadomości, ale też ich rozkład w czasie. Projektuje się nie pod „średnią dobę”, tylko pod konkretne, powtarzalne szczyty.

Zdarzenia rzadkie, ale bolesne: aktualizacje, awarie, kampanie

Najspokojniejszy system IoT potrafi „wybuchnąć” informacyjnie w jednym, konkretnym dniu. Klasyczny przykład: masowe wdrożenie nowej wersji firmware’u, o którym ktoś zapomniał wspomnieć zespołowi odpowiedzialnemu za platformę. Zamiast standardowego ruchu pojawia się ściana requestów, po której zostają time‑outy i restart klastra.

W planowaniu pojemności trzeba jawnie ująć scenariusze typu:

  • masowa aktualizacja firmware – ile urządzeń aktualizuje się w ciągu godziny, ile prób ponawiania występuje przy słabym zasięgu,
  • awaria łączności – urządzenia kumulują dane i wysyłają „hurtowo” po powrocie sieci,
  • kampania marketingowa lub pilotaż – nagły wzrost nowych aktywacji, rejestracji, pierwszych synchronizacji danych,
  • zmiana konfiguracji – wysłanie nowej polityki raportowania lub reguł automatyki do całej floty.

Tego typu scenariusze można opisać prostymi pytaniami:

  • „Jeśli 20% floty będzie aktualizowane jednego dnia, ile to jest requestów na minutę?”
  • „Jeżeli 10% urządzeń straci sieć na godzinę i potem nada wszystko naraz, jaki będzie pik?”

Odpowiedzi pozwalają policzyć maksymalne chwilowe obciążenie, które system powinien przetrwać bez „rozsypania się”. Czasem okazuje się, że taniej jest technicznie ograniczyć te scenariusze (throttling, okienkowanie, rozkładanie w czasie) niż dobijać infrastrukturę do poziomu „wytrzymamy wszystko zawsze”.

Tryb degradacji: co system może sobie odpuścić pod obciążeniem

Gdy platforma zaczyna się dławić, zwykle jest już za późno na skalowanie „na gorąco”. Pomaga za to świadomie zaprojektowany tryb degradacji – czyli decyzja, co może przestać działać w pierwszej kolejności, żeby krytyczne funkcje przetrwały.

W systemach IoT typowe mechanizmy to:

  • odkładanie zadań niekrytycznych – raporty, eksporty, ciężkie analizy wsadowe idą później lub wolniej,
  • obniżenie częstotliwości odczytów – urządzenia przełączają się w „tryb oszczędny”, wysyłając mniej danych,
  • priorytetyzacja typów komunikatów – alarmy i sterowanie mają pierwszeństwo przed telemetrią diagnostyczną,
  • proste odpowiedzi fallback – np. API raportowe zwraca krótszy zakres danych lub wynik częściowy.

Taki tryb trzeba zaprojektować przed planowaniem pojemności. Inaczej każdy pik trzeba obsłużyć „na 100%”, co w praktyce zwykle oznacza marnotrawstwo zasobów przez większość czasu.

Zbliżenie na wykres cyklu planowania biznesowego z niebieskim ołówkiem
Źródło: Pexels | Autor: RDNE Stock project

Metryki, bez których nie da się rozmawiać o pojemności

Dlaczego „CPU 70%” to za mało

Zespół operacyjny patrzy na dashboard: CPU „na zielono”, RAM „na zielono”, a klienci zgłaszają opóźnienia. Okazuje się, że broker kolejkuje komunikaty, baza ma rosnące opóźnienie zapisu, a front API zaczyna limitować requesty. Surowe metryki infrastruktury nie mówią wprost, czy system robi to, do czego został zbudowany.

Żeby sensownie rozmawiać o pojemności, trzeba zestawić metryki techniczne z metrykami domenowymi (biznesowymi):

  • „czy komunikaty dochodzą w czasie X sekund?”,
  • „czy alarm jest podjęty w czasie Y?”,
  • „czy wszystkie dane są zapisane bez utraty i duplikacji?”.

Same wykresy CPU i RAM służą raczej do diagnozy niż do planowania pojemności. W planowaniu liczy się to, ile sensownej pracy system wykonuje przy określonym obciążeniu i kiedy zaczyna się „łamać”.

Metryki przepływu: od wiadomości do opóźnień end‑to‑end

Dobrze zaprojektowana platforma IoT potrafi odpowiedzieć na kilka prostych pytań typu „od–do”. Na przykład: ile czasu mija od nadania wiadomości przez urządzenie do jej pojawienia się na dashboardzie? Ile z tych wiadomości ginie po drodze?

Przydatne metryki przepływu to m.in.:

  • liczba komunikatów na sekundę na każdym głównym etapie (broker, kolejka, serwis przetwarzający, baza),
  • średnie i percentylowe opóźnienie (p50, p95, p99) przetwarzania komunikatu,
  • wielkość backlogu – ile komunikatów czeka w kolejkach, jak szybko backlog rośnie lub maleje,
  • współczynnik błędów – ile komunikatów kończy się retransem, błędem walidacji, odrzuceniem.

Jeśli w normalnym trybie backlog jest bliski zera, a w godzinach szczytu rośnie i spada w rozsądnym czasie (np. kilkanaście minut), system ma bufor na piki. Gdy backlog rośnie i nie wraca do normy, to jasny sygnał, że pojemność którejś warstwy jest przekroczona.

Metryki zasobów: CPU, pamięć, I/O i sieć w kontekście IoT

Standardowe metryki infrastruktury nadal są potrzebne – tylko trzeba je interpretować w kontekście wzorców ruchu IoT.

Kluczowe obserwacje:

  • CPU – w serwisach przetwarzających i agregujących często jest głównym ograniczeniem (np. przetwarzanie JSON, kompresja, szyfrowanie),
  • RAM – zbyt mało pamięci w TSDB lub brokerze kończy się intensywnym swapem i gwałtownym spadkiem wydajności,
  • IOPS i throughput dysku – długie serie zapisów drobnych rekordów potrafią „zabić” wolniejszy storage, nawet przy niskim użyciu CPU,
  • przepustowość i opóźnienia sieci – szczególnie między regionami/klastrami lub między brokerem a bazą danych.

Użyteczna jest prosta „pigułka” metryk dla każdego komponentu:

  • ile komunikatów/operacji na sekundę obsługuje,
  • jaki ma poziom CPU/RAM/IO w tych warunkach,
  • jakie ma opóźnienia i współczynnik błędów.

Taki profil można potem wykorzystać w symulacjach: „jeśli dodamy 50% ruchu, co się stanie z CPU brokerów, ile IOPS będzie potrzebne w TSDB?”.

Metryki biznesowe: SLA, SLO i „co jest naprawdę ważne”

Technologie technologiami, ale system IoT na końcu ma zrobić konkretną robotę: włączyć alarm, pokazać raport, wyłączyć maszynę. Dlatego planowanie pojemności powinno startować od pytań o SLA/SLO, np.:

  • „w ilu procentach przypadków alarm ma zostać przetworzony w czasie krótszym niż X sekund?”,
  • „w jakim czasie dane z ostatnich 24 godzin muszą być dostępne w raportach?”,
  • „jaki odsetek komunikatów może się spóźnić, a ile musi być real‑time?”.

Dopiero mając te parametry, można ustalać, jaki poziom opóźnień i strat jest akceptowalny przy różnych poziomach obciążenia. Bez nich łatwo przewymiarować wszystko „na wszelki wypadek” albo odwrotnie – zbudować system tani, ale bezużyteczny w kluczowych momentach.

Mini-wniosek: metryki techniczne bez kontekstu biznesu są jak prędkościomierz bez informacji, dokąd jedziemy. Pojemność trzeba mierzyć tym, czy system dowozi swoje obietnice przy rosnącym ruchu.

Smart żarówki i smartfon symbolizujące obciążenie systemu IoT
Źródło: Pexels | Autor: Jakub Zerdzicki

Architektura pod wzrost: jak projektować, żeby można było skalować

Stateless tam, gdzie się da, stan tam, gdzie się opłaca

Podczas pierwszego pilotażu zespół często „ścina zakręty”: dorzuca trochę stanu do serwisu HTTP, przechowuje sesje w pamięci procesu, robi lokalne cache. Działa to świetnie przy kilkuset urządzeniach, dopóki nie pojawia się potrzeba postawienia drugiej instancji. Wtedy zaczyna się walka o spójność i sesje „przyklejone” do jednego węzła.

Bezpieczniejszym podejściem jest założenie, że każdy serwis przetwarzający komunikaty jest z natury stateless:

  • stan użytkownika i urządzenia trzymany jest w bazie lub cache współdzielonym,
  • sesje są tokenami przekazywanymi w każdym żądaniu, nie pamięcią w procesie,
  • wszystkie dane potrzebne do przetworzenia komunikatu są jawnie dostępne z zewnątrz.

Oczywiście nie każdy komponent może być stateless (bazy, TSDB, brokery). Ale im więcej elementów przetwarzających jest bezstanowych, tym łatwiej jest skalować je horyzontalnie i przenosić między węzłami bez skomplikowanych migracji.

Oddzielenie ścieżki krytycznej od reszty

Wyobraźmy sobie system, w którym ten sam serwis obsługuje alarmy i generuje raporty miesięczne. W dzień zmasowanej kampanii raportowej to raporty „zjadają” CPU i pamięć, a alarmy zaczynają się spóźniać. Z punktu widzenia architektury doszło do zmieszania ścieżki krytycznej (alarmy) z niekrytyczną (raporty).

Prostszy i bezpieczniejszy model:

  • ścieżka krytyczna – minimalny zestaw komponentów, które muszą działać zawsze: komunikacja, walidacja, zapis, reguły sterujące, alarmy,
  • ścieżka „miękka” – raporty, analityka, batchowe przetwarzanie, eksporty, uczenie modeli.

Ścieżkę krytyczną projektuje się z dużym naciskiem na odporność, prostotę i możliwość szybkiego dołożenia kolejnych instancji. Ścieżkę „miękką” można agresywnie przerywać, throttlować i opóźniać podczas pików.

Kolejki, bufory i back‑pressure jako bezpiecznik

W pewnym projekcie liczba komunikatów z czujników nagle skoczyła kilkukrotnie, bo klient zmienił konfigurację raportowania. Gdyby serwisy przyjmowały komunikaty synchronicznie, cały system padłby od razu. Uratowały go kolejki, które „sprężynowały” obciążenie, pozwalając backendowi przetrawić je z opóźnieniem, ale bez utraty danych.

Elementy, które pomagają w takich sytuacjach, to przede wszystkim:

  • kolejki wiadomości (RabbitMQ, Kafka, SQS) między brokerem/ingestem a przetwarzaniem,
  • bufory po stronie urządzeń – lokalne przechowywanie danych na chwilę, gdy chmura nie przyjmuje,
  • mechanizmy back‑pressure – świadome spowalnianie producentów, gdy konsumenci nie nadążają,
  • limitowanie i throttling – twarde ograniczenia na API, aby nie dało się „zabić” systemu jednym klientem.

Dobrze ustawione progi kolejki (alerty, automatyczne skalowanie) potrafią zamienić niekontrolowany pik w zarządzalny backlog, który schodzi w ciągu godzin, a nie sekund.

Modułowość i granice serwisów jako dźwignia skalowania

W jednym z projektów zespół próbował skalować „monolit IoT”: pojedynczy backend obsługiwał rejestrację urządzeń, ingest danych, alarmy, raporty i integracje. Dodawanie kolejnych instancji pomagało na chwilę, po czym całość znowu się dławiła w najmniejszym, ale wspólnym fragmencie kodu. Problem nie leżał w braku mocy, tylko w braku sensownych granic.

Przy planowaniu pojemności opłaca się rozciąć system na moduły zgodnie z naturalnymi osiami wzrostu i ryzyka:

  • ingest/komunikacja – przyjmowanie komunikatów z urządzeń (protokoły, autoryzacja, podstawowa walidacja),
  • przetwarzanie strumieniowe – normalizacja, reguły, agregaty, alertowanie,
  • magazyn danych operacyjnych – to, co potrzebne „tu i teraz” do sterowania i wizualizacji,
  • magazyn danych historycznych/analityka – hurtownia, jeziorko danych, batchowe ETL‑e,
  • obsługa urządzeń i konfiguracji – provisioning, firmware OTA, parametry pracy.

Każdy z tych modułów ma inny wzorzec obciążenia, a więc inną „krzywą bólu”. W ingestcie ograniczeniem będzie często sieć i liczba połączeń, w przetwarzaniu – CPU, w magazynie historycznym – IOPS i koszt storage’u. Oddzielenie tego na poziomie architektury pozwala planować pojemność dla każdego modułu osobno, zamiast „podkręcać” całość na ślepo.

Mini‑wniosek: modułowość to nie tylko wygodniejszy kod, ale też możliwość osobnego skalowania tego, co rośnie najszybciej i boli najmocniej.

Skalowanie pionowe vs poziome w realnym IoT

Przy pierwszym większym piku ruchu typowy odruch to „dorzucić większą maszynę”. Działa to do pewnego momentu, aż przy kolejnym skoku okazuje się, że największy dostępny typ instancji w chmurze już jest użyty – i ruch nie ma się gdzie podziać.

Skalowanie pionowe (większy serwer) ma sens na starcie i przy komponentach trudnych do zrównoleglenia (np. pojedynczy węzeł bazy master). Jednak w IoT większość przetwarzania jest naturalnie równoległa – każdy komunikat, urządzenie czy tenant może być obsługiwany osobno. Tu wygrywa skalowanie poziome:

  • więcej instancji serwisu ingestującego za load balancerem,
  • wiele konsumentów z tej samej kolejki/brokera,
  • sharding danych po urządzeniu, kliencie lub regionie.

Dobrą praktyką jest świadomie zdefiniować górny limit pionowego skalowania dla każdego komponentu („do jakiej wielkości maszyny jesteśmy skłonni dojść”) i już przy zbliżaniu się do niego mieć gotowy plan na poziome rozdzielenie ruchu lub danych. Inaczej łatwo utknąć w miejscu, w którym jedyną „optymalizacją” zostaje modlitwa, by klient nie podwoił liczby urządzeń z dnia na dzień.

Mini‑wniosek: pionowe skalowanie kupuje czas, ale nie rozwiązuje problemu wzrostu; projekt pod prawdziwe IoT powinien od początku zakładać możliwość „rozlewania się” ruchu na wiele węzłów.

Separacja tenantów i regionów jako wentyl bezpieczeństwa

Firma wdraża platformę IoT dla kilku dużych klientów. Jeden z nich robi agresywny rollout nowych urządzeń i nagle generuje kilkukrotnie więcej ruchu niż pozostali. System zaczyna się dławić, choć pozostali klienci nie zmienili nic w swoim użyciu. Powód: wszyscy siedzą na tych samych zasobach.

Przy większej skali dobrze działa model, w którym:

  • klienci (tenanci) są podzieleni na grupy o podobnym profilu ruchu,
  • najwięksi dostają osobne „pule pojemności” – wydzielone klastry brokerów, osobne kolejki, dedykowane bazy lub przynajmniej schematy,
  • regiony geograficzne mają własne klastry ingestu i przetwarzania, łączone na wyższej warstwie (np. w hurtowni danych).

Taki podział daje dwie korzyści. Po pierwsze, awaria lub „eksplozja” ruchu jednego klienta nie wycina całej platformy. Po drugie, planowanie pojemności można robić osobno dla każdej grupy tenantów: „klaster A obsługuje klientów przemysłowych, rośnie liniowo; klaster B – konsumenckie IoT, ma ostre piki wieczorem”.

Mini‑wniosek: separacja tenantów i regionów to nie fanaberia architekta, tylko praktyczne narzędzie, które ogranicza zasięg kłopotów i upraszcza estymację potrzebnej pojemności.

Gotowość na awarie i „bieda‑tryb” pracy

W pewnym systemie awaria klastra analitycznego blokowała przyjmowanie nowych danych z urządzeń, bo pipeline był zaprojektowany jako jedna, długa zależność. Kilka godzin problemów z hurtownią doprowadziło do utraty danych w ingestcie, choć technicznie nie musiało tak być.

Architektura pod wzrost w IoT powinna zakładać, że:

  • komponenty niekrytyczne mogą się psuć bez zatrzymywania ścieżki krytycznej,
  • system ma degradacyjny tryb pracy – np. przyjmuje dane, ale je tylko buforuje i nie generuje raportów,
  • backlog z okresu awarii można potem odtworzyć i „przemielić” bez ręcznej interwencji.

Do tego dochodzi świadome projektowanie limitów ochronnych: maksymalny rozmiar backlogu na tenant, limity wiadomości na urządzenie, osobne kolejki dla ścieżki krytycznej i analitycznej. Zamiast liczyć na to, że „jakoś to będzie”, lepiej z góry zdefiniować, co system poświęci, gdy zabraknie pojemności – raporty godzinne, eksporty CSV czy może część mniej ważnych metryk.

Mini‑wniosek: planowanie pojemności to także planowanie kontrolowanej degradacji, a nie tylko dodawania serwerów, gdy robi się gorąco.

Planowanie pojemności w praktyce: prosta metoda krok po kroku

Krok 1: Zdefiniuj scenariusze użycia i poziomy skali

Zespół produktowy mówi: „docelowo milion urządzeń”, ale w logach dziś widać ledwie kilka tysięcy. Jeśli na tym etapie przyjmiesz „milion” jako jedyny punkt odniesienia, skończysz z abstrakcyjną rozmową i przypadkowymi liczbami.

Praktyczniej jest rozrysować kilka konkretnych poziomów skali i scenariuszy:

  • stan obecny – „tu i teraz”,
  • planowany wzrost w ciągu 6–12 miesięcy (np. rollout u dwóch nowych klientów),
  • scenariusz „kampanijny” – ostre piki (np. aktualizacja firmware’u, event marketingowy, odczyty raz na minutę zamiast raz na 15 minut),
  • ambitny, ale realny cel (np. 10× obecnego ruchu w 2–3 lata).

Do każdego poziomu dołącz opis biznesowy: ilu klientów, ile aktywnych urządzeń, jak często raportują, które funkcje są używane (alarmy, raporty, OTA). Te scenariusze później bezpośrednio włożysz do modelu obciążenia.

Mini‑wniosek: zamiast jednego „magicznego” miliona urządzeń lepiej pracuje się z kilkoma namacalnymi poziomami skali, pod które da się policzyć ruch.

Krok 2: Zbuduj prosty model obciążenia

Gdy już wiadomo, jak ma wyglądać świat przy różnych poziomach rozwoju, można przejść do liczb. Nie chodzi o skomplikowane symulacje, tylko o policzenie rzędu wielkości.

Dla każdego scenariusza zapisz kilka podstawowych założeń:

  • urządzenia: liczba, średnia częstotliwość raportowania, typowe i maksymalne rozmiary komunikatu,
  • użytkownicy: ilu ich jest, jak często korzystają z dashboardu/API, jakie operacje wykonują,
  • operacje tła: raporty okresowe, agregacje, exporty, OTA – jak często są uruchamiane, z jakim rozkładem w czasie.

Z tego można już policzyć pierwsze wielkości:

  • wiadomości na sekundę (średnio i w piku) na wejściu do systemu,
  • szacunkowy ruch sieciowy (MB/s) między głównymi komponentami,
  • liczbę zapisów/odczytów na sekundę do głównych baz (TSDB, relacyjna, cache).

Nie trzeba trafiać w punkt – wystarczy uczciwy model „z dokładnością do 2–3×”. Największy błąd to brak modelu: wtedy każda decyzja o pojemności jest zgadywanką.

Mini‑wniosek: prosty arkusz z liczbą urządzeń, częstotliwością i kilkoma współczynnikami konwersji robi większą różnicę niż najbardziej wyrafinowany dashboard bez kontekstu.

Krok 3: Zmierz aktualną przepustowość komponentów

W wielu zespołach nikt nie wie, ile realnie „ciągnie” pojedyncza instancja brokera, serwisu ingestującego czy bazy przy sensownych opóźnieniach. Dopiero awaria lub pik odkrywa te liczby – zwykle w najmniej wygodnym momencie.

Żeby zaplanować pojemność, trzeba zbudować profil wydajnościowy kluczowych komponentów. Można to zrobić tak:

  • wybrać kilka realistycznych scenariuszy ruchu (np. 2×, 5×, 10× obecnego),
  • uruchomić testy obciążeniowe dla wejścia (MQTT/HTTP), przetwarzania (serwisy) i zapisów (bazy),
  • dla każdego poziomu ruchu zanotować: throughput, opóźnienia (p95/p99), użycie CPU/RAM/IO, backlog.

Na tej podstawie powstaje prosta tabela typu:

  • „jeden broker obsługuje stabilnie do N wiadomości/s przy p95 < X ms, potem zaczyna rosnąć backlog”,
  • „jeden worker przetwarzający radzi sobie z M komunikatami/s przy CPU ~70%”,
  • „TSDB przy K zapisach/s ma opóźnienia < Y ms, powyżej tego IOPS staje się wąskim gardłem”.

Te liczby nie są dane raz na zawsze (zmieniają się wraz z wersjami oprogramowania i konfiguracją), ale dają punkt wyjścia: wiadomo już, ile „roboty” wykonuje jeden węzeł w zdrowych warunkach.

Mini‑wniosek: bez zmierzonej przepustowości komponentów nie ma sensownego planowania – jest tylko życzeniowe myślenie, że „jakoś to wytrzyma”.

Krok 4: Zderz model ruchu z profilem wydajności

Na tym etapie masz dwa zbiory liczb: model obciążenia (ile ruchu generują urządzenia i użytkownicy) oraz profil wydajności komponentów (ile każdy potrafi obsłużyć). Teraz pora je na siebie nałożyć.

Przykładowe pytania, na które trzeba odpowiedzieć dla każdego scenariusza skali:

  • ile instancji brokera potrzeba, aby obsłużyć ruch z marginesem bezpieczeństwa (np. 30–40%)?,
  • ile workerów przetwarzających komunikaty jest potrzebnych, by backlog nie rósł w godzinach szczytu?,
  • czy obecna konfiguracja TSDB/klastra bazy wystarczy, czy trzeba dodać shard/replicę albo przyspieszyć storage?,
  • czy przepustowość między komponentami (np. ingest → Kafka → procesor → TSDB) nie jest ograniczana przez sieć lub NAT.

Efektem jest prosta macierz: scenariusz skali × liczba instancji/rozmiar klastra dla każdego komponentu. Z niej wynika też wprost, który element stanie się wąskim gardłem jako pierwszy – zwykle to on powinien być priorytetem w roadmapie technicznej.

Mini‑wniosek: samo policzenie ruchu nie wystarczy; trzeba z góry wiedzieć, przy jakim poziomie ruchu który komponent „siądzie” i co wtedy zrobimy.

Krok 5: Ustal progi, alerty i automatyczne reakcje

W jednym z zespołów alerty były ustawione wyłącznie na progi CPU i RAM. Gdy backlog zaczynał rosnąć, nic się nie działo, bo CPU nadal było „zielone”. Informacja o problemie przychodziła dopiero od klienta. W kontekście planowania pojemności taki system monitoringu jest praktycznie ślepy.

Na bazie modelu i pomiarów można zdefiniować sensowne progi działania:

  • progi backlogu w kolejkach (np. „jeśli liczba wiadomości > N przez >5 min – dołóż workerów / skaluj konsumentów”),
  • progi opóźnień end‑to‑end (np. p95 > X sekund dla alarmów przez >Y min),
  • progi użycia infrastruktury (CPU > 70%, IOPS blisko limitu storage’u) – ale w połączeniu z metrykami przepływu,
  • progi kosztowe (np. „jeśli autoskalowanie przekracza Z instancji przez tydzień – czas na trwałą zmianę architektury lub planu taryfowego”).

Do tego dochodzą akcje automatyczne – od prostego autoskalowania po zmianę polityk kolejki (np. przenoszenie części ruchu na mniej priorytetowe kolejki) i włączenie trybu degradowanego. Chodzi o to, żeby system reagował na zbliżanie się do limitów pojemności szybciej niż ludzie.

Mini‑wniosek: plan pojemności bez dobrze dobranych progów i automatycznych reakcji kończy się ręcznym gaszeniem pożarów przy każdym większym piku.

Krok 6: Zaplanuj ewolucję – kiedy zmienić architekturę