PostgreSQL / EDB

Ryzen w ogniu testów: jak współdzielenie zasobów CPU degraduje PostgreSQL?

2026-05-22
Podziel się

Wydajność bazy danych nie kończy się na liczbie TPS i niskim średnim czasie odpowiedzi. W praktyce to właśnie niewidoczne na pierwszy rzut oka skoki latencji potrafią destabilizować aplikacje, powodować trudne do diagnozy problemy i obniżać realną jakość usług. W tym artykule pokazujemy, dlaczego uruchamianie PostgreSQL na tym samym hoście co backend może stać się kosztowną pułapką architektoniczną oraz jak zjawisko „Hałaśliwego Sąsiada” wpływa na stabilność systemu pod obciążeniem. Na podstawie rzeczywistych testów przeprowadzonych na procesorach AMD Ryzen analizujemy zachowanie bazy danych w warunkach konkurencji o zasoby CPU, demaskując ograniczenia popularnych metryk monitoringu i pokazując, dlaczego izolacja warstwy danych często daje większe korzyści niż sama moc sprzętu.

W dobie powszechnej wirtualizacji i konteneryzacji, dążenie do maksymalnego wykorzystania sprzętu stało się standardem. Często w ramach oszczędności zasobów lub uproszczenia architektury decydujemy się na uruchomienie silnika bazy danych (np. PostgreSQL) na tym samym hoście, na którym pracuje aplikacja backendowa.

Teoretycznie jest to rozwiązanie idealne. Eliminujemy opóźnienia sieciowe, korzystamy z błyskawicznych połączeń przez Unix Sockets i upraszczamy stos technologiczny. W praktyce jednak narażamy bazę danych na zjawisko znane jako „Noisy Neighbor” (Hałaśliwy Sąsiad).

Spis treści:

Czym jest Hałaśliwy sąsiad?

To sytuacja, w której jeden proces (w naszym przypadku aplikacja backendowa) agresywnie konsumuje zasoby współdzielone (cykle procesora, pamięć cache L3 czy przepustowość szyny pamięci) negatywnie wpływając na wydajność innych procesów działających na tym samym fizycznym hoście.

Dla bazy danych, która wymaga przewidywalnych czasów odpowiedzi do obsługi transakcji, bycie „sąsiadem” aktywnej aplikacji może oznaczać drastyczną degradację jakości usługi, niewidoczną w prostych statystykach średniego obciążenia CPU.

Cel artykułu

W niniejszym opracowaniu, na podstawie precyzyjnych testów przeprowadzonych na procesorach AMD Ryzen, wykażemy:

  1. Dlaczego lokalne połączenie bazy danych z aplikacją jest „pułapką wydajnościową” pod obciążeniem.
  2. Jak konkurencja o procesor wpływa na stabilność latencji p99.
  3. Dlaczego izolacja bazy danych (skalowanie poziome) jest kluczowa dla utrzymania wysokiego standardu SLA, nawet jeżeli wiąże się to z użyciem teoretycznie słabszego sprzętu.

Przejdziemy przez twarde dane – od idealnego stanu jałowego (0% Load), aż po skrajne wysycenie zasobów, demaskując przy tym słabości najpopularniejszych metryk monitoringu.

Środowisko testowe i metodyka

Aby wyniki były rzetelne i powtarzalne, środowisko testowe zostało ustandaryzowane pod kątem wydajności, mimo różnic w warstwie sprzętowej. Kluczowym elementem metodyki było doprowadzenie do sytuacji, w której moc obliczeniowa obu maszyn wirtualnych była porównywalna w stanach jałowych.

Infrastruktura sprzętowa (Hardware)

Testy przeprowadzono na dwóch węzłach klastra Proxmox o odmiennej charakterystyce procesorów:

  • Węzeł 1 (szybszy): AMD Ryzen 7 8745HS (architektura Zen 4, 4nm), 32 GB RAM DDR5.
  • Węzeł 2 (stabilniejszy): AMD Ryzen 7 5825U (architektura Zen 3, 7nm), 64 GB RAM DDR4.

Obie maszyny połączone były za pomocą switcha 1 Gbps, co symuluje standardowe warunki sieciowe w małych i średnich infrastrukturach.

Konfiguracja Maszyn Wirtualnych (Software)

Na obu węzłach uruchomiono identyczne maszyny wirtualne z systemem Rocky Linux 9.6. Parametry VM zostały dobrane tak, aby zminimalizować narzut wirtualizacji:

  • CPU: 4 rdzenie (typ: host), aby zapewnić bezpośredni dostęp do instrukcji procesora;
  • RAM: 8096 MB;
  • dysk: 32 GB SSD (local storage);
  • baza danych: PostgreSQL 17 (domyślna konfiguracja, bez agresywnej optymalizacji, aby uwypuklić wpływ zasobów procesora).

Normalizacja mocy obliczeniowej

Zastosowano mechanizmy Proxmox (cpulimit=1.8, cpuunits=1024) na szybszym węźle, aby wyrównać jego wydajność do poziomu słabszej jednostki. Weryfikacja za pomocą sysbench cpu potwierdziła uzyskanie niemal identycznej wydajności syntetycznej:

  • Maszyna 26: 10709 events per second;
  • Maszyna 27: 10685 events per second.

Scenariusze obciążenia (Baseline vs Stress)

Głównym celem badania było sprawdzenie, jak wzrastające obciążenie procesora przez aplikację zewnętrzną (wymagającego sąsiada) wpływa na parametry bazy danych. W tym celu zdefiniowano trzy poziomy obciążenia tła generowanego przez narzędzie stress-ng:

  • 0% Load: test wydajności bazy danych bez żadnych dodatkowych procesów obciążających hosta. Pozwala na wyznaczenie teoretycznego maksimum wydajności w idealnych warunkach.
  • 30% Load: symulacja standardowej pracy aplikacji backendowej dzielącej zasoby z bazą. Użyto komendy: stress-ng --cpu 4 --cpu-load 30 --vm 1 --vm-bytes 256M --vm-keep --vm-hang 0
  • 40% Load: scenariusz wysokiego obciążenia, testujący granice stabilności systemu. Użyto komendy: stress-ng --cpu 4 --cpu-load 40 --vm 1 --vm-bytes 256M --vm-keep --vm-hang 0

Metodyka pomiarowa i konfiguracje połączeń

Wszystkie testy były automatyzowane za pomocą autorskiego skryptu, uruchamianego poleceniami w formacie ./test.sh "SCENARIUSZ" 20 60 (gdzie „20” oznaczało liczbę wątków pgbench, a „60” czas trwania testu w sekundach). Czas 60 sekund został uznany za w pełni reprezentatywny po przeprowadzeniu wcześniejszych, 300-sekundowych testów walidacyjnych, które dały zbieżne wyniki. Dla każdego scenariusza badano przepustowość w funkcji rosnącej liczby równoległych klientów (połączeń): 2, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 oraz 100.

Niezależnie od scenariusza, generator ruchu (pgbench) oraz aplikacja obciążająca (stress-ng) były zawsze uruchamiane na maszynie .26.

  • A0 (Local Direct): baza danych uruchomiona na tej samej maszynie co klient (.26). Komunikacja odbywała się lokalnie, z wykorzystaniem niezwykle wydajnych Unix Sockets.
  • A2 (Remote Bouncer): baza danych przeniesiona na dedykowaną maszynę (.27). Klient z maszyny .26 łączył się po sieci ze stojącym przed bazą na maszynie .27 procesem pgbouncer.

Wyniki: Transactions Per Second (TPS)

Wydajność bazy danych mierzona liczbą transakcji na sekundę (TPS) jest często pierwszym wskaźnikiem, na który patrzą administratorzy. W naszych testach przy narastającym obciążeniu procesora przez aplikację zewnętrzną, wyniki TPS ujawniają nieliniową naturę spadku przepustowości.

Porównanie przepustowości (Baseline vs Load)

Analizując wyniki z testów 0% Load, 30% Load i 40% Load, widzimy drastyczne różnice w odporności obu scenariuszy na wzrastające obciążenie tła.

Scenariusz TPS (0% Load) TPS (30% Load) TPS (40% Load) Spadek (0% -> 40%)
A0 (Local Direct) 5615.76 3785.25 3726.01 -33.65%
A2 (Remote Bouncer) 4442.78 2352.46 1708.40 -61.55%
tps comparison
Wykres przedstawia wydajność TPS dla różnych poziomów obciążenia. Zauważ, jak model zdalny (A2) drastycznie traci przepustowość przy 40% obciążenia, co wynika z nasycenia procesora na hoście aplikacji.

Wnioski z analizy wyników dla TPS

  1. Model Lokalny (A0): mimo konkurencji o zasoby, utrzymuje relatywnie wysoką przepustowość (3726.01 TPS) dzięki niskim kosztom komunikacji przez Unix Socket. Jednak, jak zobaczymy w kolejnym rozdziale, odbywa się to kosztem gigantycznej niestabilności latencji.
  2. Model Zdalny (A2): spadek TPS do poziomu 1708.40 przy 40% obciążenia tła jest sygnałem ostrzegawczym. Pokazuje on, że „hałaśliwy sąsiad” (stress-ng) na hoście aplikacji potrafi zdławić generator ruchu (pgbench), uniemożliwiając mu pełne wykorzystanie potencjału odizolowanej bazy danych.
  3. Wąskie gardło po stronie klienta: w scenariuszu A2 spadek TPS jest napędzany przez dwa czynniki. Po pierwsze, brak wolnych cykli CPU na hoście .26 dławi generator obciążenia (pgbench), uniemożliwiając mu wysycenie bazy danych. Po drugie, jak zobaczymy w kolejnej sekcji, przy tym poziomie obciążenia baza danych zaczyna odnotowywać zauważalne piki latencji „ogonowej” (p99), co sygnalizuje, że środowisko powoli zbliża się do punktu nasycenia i traci swoją idealną przewidywalność.

Pułapka średniej latencji – analiza p95 i p99

Większość systemów monitoringu skupia się na średniej latencji (Average Latency). Nasze testy dowodzą, że w warunkach konkurencji o zasoby, średnia jest wskaźnikiem skrajnie mylącym, ponieważ „maskuje” rzeczywiste problemy użytkowników końcowych. To doskonały przykład na to, dlaczego współczesna inżynieria odchodzi od tradycyjnego monitoringu na rzecz podejścia observability.

avg latency
Porównanie średniej latencji. Choć model lokalny (A0) wydaje się szybszy, to tylko część prawdy o systemie.

Pełne zestawienie wyników latencji (A0 vs A2)

Scenariusz Load [%] Avg Latency [ms] p95 Latency [ms] p99 Latency [ms]
A0 (Local Direct) 0% 17.20 71.54 98.34
A0 (Local Direct) 30% 25.53 89.78 164.56
A0 (Local Direct) 40% 25.82 93.30 173.94
A2 (Remote Bouncer) 0% 22.50 70.52 97.23
A2 (Remote Bouncer) 30% 42.50 91.63 103.58
A2 (Remote Bouncer) 40% 58.48 88.73 167.53

Analiza stabilności „ogona” latencji

Najważniejszym wnioskiem z powyższego zestawienia jest dynamika wzrostu latencji p99:

  1. Odporność na skoki (0% -> 30% Load): w teście z wysoką liczbą połączeń (j=100), w modelu lokalnym (A0), dodanie 30% obciążenia aplikacji spowodowało skok p99 o 66.22 ms. W tym samym czasie w modelu zdalnym (A2) latencja p99 wzrosła zaledwie o 6.35 ms..
  2. Punkt krytyczny (40% Load): przy 40% obciążeniu hosta aplikacji, latencja p99 w modelu zdalnym zaczęła gwałtownie rosnąć, osiągając 167.53 ms.
p95 comparison
Wykres p95 pokazuje, że nawet przy 95% wszystkich zapytań, różnice między modelem lokalnym a zdalnym zaczynają się zacierać przy wysokim obciążeniu.
p99 comparison log
Kluczowy wykres latencji p99 (skala logarytmiczna). Widać na nim wyraźnie, jak model lokalny (A0) gwałtownie traci stabilność przy dużym obciążeniu (40% Load), podczas gdy model zdalny (A2) oferuje znacznie bardziej przewidywalne czasy odpowiedzi.

Analiza wykorzystania CPU a stabilność bazy

Zrozumienie przyczyn degradacji latencji p99 wymaga spojrzenia na to, co dzieje się bezpośrednio wewnątrz procesora podczas testów. Porównanie wydajności CPU dla scenariuszy A0 i A2 przy obciążeniu 30% i 40% ujawnia krytyczne różnice w dostępności zasobów.

Scenariusz A0 (Local): walka o każdy cykl

W modelu lokalnym (A0), maszyna .26 musi jednocześnie obsługiwać bazę danych, aplikację stress-ng oraz generator ruchu pgbench.

cpu v5 26 A0
Wykorzystanie CPU na maszynie .26 (A0): 30% obciążenia. Zauważ niemal całkowity brak czasu bezczynności (Idle < 3%). System pracuje na granicy wydolności.

Przy wzroście obciążenia hosta do 40% Load, margines błędu całkowicie znika:

cpu v10 26 A0
Wykorzystanie CPU na maszynie .26 (A0): 40% obciążenia. Procesor jest stale wysycony. Każde zapytanie bazy musi „walczyć” o czas procesora z agresywnym procesem stress-ng, co skutkuje latencją p99 na poziomie 173.94 ms.

Scenariusz A2 (Remote): izolacja jako gwarant spokoju

W modelu zdalnym (A2), obciążenie jest rozdzielone. Maszyna .26 obsługuje aplikację, a maszyna .27 zajmuje się wyłącznie bazą danych.

Klucz do sukcesu leży jednak w obciążeniu maszyny .27 (DB Host):

cpu v5 27 A2
Wykorzystanie CPU na dedykowanej maszynie .27 (A2). Baza danych ma dla siebie znaczną część zasobów (duży obszar Idle), co pozwala jej na błyskawiczną reakcję na zapytania i utrzymanie niskiej latencji p99 (na poziomie 3-10 ms dla niskiej liczby połączeń, co jest niemożliwe w scenariuszu A0).

Wnioski z analizy wykorzystania CPU

Korelacja między brakiem czasu bezczynności (Idle) a latencją p99 jest niemal liniowa. W momencie, gdy Idle na maszynie .26 spada poniżej 5%, każda operacja synchronizacji procesów (Locking) czy przełączanie kontekstu zaczyna generować ogromne opóźnienia „ogonowe”.

Izolacja bazy danych na maszynie .27 zapewnia jej tzw. Headroom – zapas mocy obliczeniowej niezbędny do obsługi nagłych skoków latencji, co jest niemożliwe w przesyconym modelu lokalnym A0. Nawet przy wzroście obciążenia hosta aplikacji do 40% Load, dedykowana maszyna wciąż zachowuje ten zapas mocy, co obrazuje poniższy wykres:

cpu v10 27 A2
Wykorzystanie CPU na dedykowanej maszynie .27 (A2) przy 40% obciążeniu hosta aplikacji. Baza danych, mimo zwiększonego natłoku zapytań, utrzymuje dostępny obszar Idle, gwarantując przewidywalność i mniejszą degradację czasów odpowiedzi niż w scenariuszu współdzielonym.

Analiza porównawcza zasobów dedykowanych i współdzielonych

W optymalizacji systemów bazodanowych dobór procesora opiera się często na surowych wskaźnikach wydajności (CPU Mark). Jednak dane z testów (30% Load) wskazują na istotne różnice w zachowaniu silnika PostgreSQL, w zależności od stopnia izolacji zasobów obliczeniowych, co redefiniuje pojęcie „wydajnego hosta” w środowisku produkcyjnym.

Zestawienie wyników: Ryzen 8000 (współdzielony) vs Ryzen 5000 (dedykowany)

Kluczowe wnioski płyną z porównania scenariuszy A0 (Local Direct) oraz A2 (Remote Bouncer) przy stałym obciążeniu generowanym przez aplikację zewnętrzną (stress-ng na poziomie 30%).

Metryka (j=2) A0 (Local – Ryzen 8000 + App) A2 (Remote – Ryzen 5000 Dedyk)
Latencja p99 53.83 ms 3.24 ms
Wariancja opóźnień Wysoka (niestabilność) Niska (przewidywalność)

Mimo wykorzystania nowszej architektury (Zen 4) w scenariuszu A0, latencja p99 była ponad 16-krotnie wyższa niż na starszym procesorze (Zen 3) pracującym w pełnej izolacji. Wynik ten potwierdza, że narzut sieciowy (fizyczny switch) jest pomijalny w porównaniu do narzutu wynikającego z braku stabilności czasowej procesora współdzielonego.

Dlaczego lokalny socket ustępuje izolacji sieciowej? (analiza techniczna)

Zjawisko to wynika bezpośrednio z architektury procesora i sposobu zarządzania procesami przez jądro systemu operacyjnego.

Mechanizm „Cache Thrashing” w pamięci L3

Współczesne procesory Ryzen opierają wydajność na dużych i szybkich pamięciach cache L3. W modelu 8745HS cache ten jest zasobem krytycznym.

  • Problem: aplikacja stress-ng, operując na dużych strukturach danych, dokonuje agresywnego wyrzucania stron pamięci PostgreSQL z cache L3.
  • Skutek: backend Postgresa po przejęciu cykli CPU doświadcza serii „cache misses”. Konieczność sięgania do pamięci RAM (latencja rzędu mikrosekund) zamiast L3 (nanosekundy) powoduje gwałtowne wydłużenie czasu wykonania pojedynczych operacji, co kumuluje się w wysokich percentylach latencji.

Przełączanie kontekstu (Context Switching) – dlaczego procesor traci czas na „myślenie o pracy”?

Z perspektywy developera, model procesowy PostgreSQL (one-process-per-connection) jest bardzo bezpieczny i czytelny – każdy backend bazy to osobny proces systemowy. Jednak przy dużej skali (np. w tym wypadku 100 połączeń) i ograniczonej liczbie rdzeni (4 rdzenie w VM) model ten staje się wyzwaniem dla planisty systemu operacyjnego (schedulera).

Czym właściwie jest Context Switch dla procesu Postgresa?

Wyobraź sobie, że pracujesz nad trudnym zadaniem programistycznym (to nasz proces Postgresa), ale masz tylko jedno biurko (rdzeń CPU). Nagle system decyduje, że teraz czas na aplikację (stress-ng). Aby to zrobić, procesor musi wykonać szereg operacji, które nie przynoszą żadnej wartości biznesowej:

  1. Zrzut stanu (Save Context): procesor musi zapisać aktualną zawartość wszystkich rejestrów (w tym wskaźnik stosu i licznik rozkazów) do pamięci. To zamrożenie stanu zapytania SQL w połowie jego wykonywania.
  2. Czyszczenie „biurka” (TLB Flush): to najbardziej kosztowny krok. Ponieważ procesy mają izolowaną pamięć (Virtual Memory), przełączenie z bazy na aplikację wymaga odświeżenia struktur sterujących pamięcią w procesorze (TLB – Translation Lookaside Buffer). To tak jakbyś przy każdej zmianie zadania musiał chować wszystkie dokumenty do szafy i wyciągać zupełnie inne, bo nie możesz korzystać z tych samych „adresów”.
  3. Ładowanie nowego kontekstu (Restore Context): wczytanie stanu aplikacji stress-ng i przywrócenie jej rejestrów.

Gdy stress-ng kończy swój kwant czasu, cały proces odbywa się w drugą stronę. Przy obciążeniu 30% i 100 połączeniach, takie operacje dzieją się tysiące razy na sekundę, zamieniając potężny procesor w urządzenie, które większość czasu spędza na „przekładaniu papierów”.

Problem „wywłaszczonego właściciela blokady” (Lock Holder Preemption)

To zjawisko najlepiej tłumaczy, dlaczego latencja p99 potrafi skoczyć o kilkadziesiąt milisekund przy najmniejszym obciążeniu. W Postgresie procesy często muszą na siebie czekać, używając lekkich blokad (tzw. LWLocks lub Spinlocks) na strukturach w pamięci współdzielonej (Shared Memory).

Scenariusz katastrofy:

  1. Backend A pobiera blokadę na istotną strukturę danych w pamięci współdzielonej.
  2. Dokładnie w tym milisekundowym momencie Scheduler wywłaszcza Backend A i oddaje rdzeń aplikacji stress-ng.
  3. Backend B (i 10 innych) chce pobrać tę samą blokadę, ale Backend A „śpi” w kolejce do procesora, wciąż trzymając klucz do blokady.
  4. Wszystkie inne procesy Postgresa stają w miejscu. Z punktu widzenia aplikacji, baza „zamiera” na kilka-kilkanaście milisekund, czekając aż Backend A w końcu dostanie swoje 100 mikrosekund czasu procesora, by zwolnić blokadę. To zjawisko sprawia, że w modelu A0 (30% Load) przy obciążeniu 100 połączeniami (j=100) latencja p99 wynosi aż 164.56 ms.

Zjawisko „Tail Latency”

Współdzielenie zasobów CPU bezpośrednio przekłada się na tzw. „długi ogon” latencji. O ile średni czas odpowiedzi (average) może wydawać się akceptowalny, o tyle p99 (reprezentujący 1% najwolniejszych zapytań) demaskuje brak przewidywalności systemu. W scenariuszu A2 (Remote), dzięki dedykacji rdzeni, planista systemu obsługuje niemal wyłącznie procesy bazy, co pozwala na płynne zwalnianie blokad i utrzymanie niskiej latencji nawet pod obciążeniem.

Wnioski architektoniczne

Dane empiryczne wskazują, że izolacja zasobów jest ważniejszym czynnikiem stabilizującym bazę danych niż czysta moc obliczeniowa. Przeniesienie warstwy danych na osobny host (A2):

  • wyeliminowało konkurencję o cache L3;
  • zminimalizowało ryzyko blokowania backendów przez wywłaszczone procesy (Lock Holder Preemption);
  • umożliwiło utrzymanie stabilnej latencji p99, która przy niskim obciążeniu (j=2) jest niemal 17-krotnie niższa niż w modelu lokalnym (3.24 ms vs 53.83 ms), a przy pełnym wysyceniu (j=100 i 30% obciążeniu tła) pozostaje o 60.98 ms niższa niż w scenariuszu A0.

Dla architektów systemów wniosek jest jasny: w scenariuszach zdominowanych przez walkę o zasoby CPU, skalowanie poziome (izolacja bazy) oferuje wyższą jakość usługi (QoS) i przewidywalność niż agresywne skalowanie pionowe na jednym hoście.

Podsumowanie i rekomendacje dla architektów

Przeprowadzone testy demaskują popularny mit, że dołożenie surowej mocy obliczeniowej do jednego hosta (Vertical Scaling) zawsze rozwiąże problemy wydajnościowe bazy danych. W środowiskach o mieszanym obciążeniu (aplikacja + baza), prawdziwym wyzwaniem nie jest brak cykli procesora, lecz nieprzewidywalność ich przydzielania.

Główne wnioski z testów

  1. Izolacja wygrywa z surową mocą: nawet teoretycznie słabszy procesor (AMD Ryzen 7 5825U) pracujący w izolacji na dedykowanym hoście oferuje znacznie stabilniejsze czasy odpowiedzi (p99) niż najnowsza jednostka (Ryzen 7 8745HS) dzieląca zasoby z aplikacją.
  2. Średnia latencja to pułapka: średni czas odpowiedzi (Average Latency) faworyzuje model lokalny, ale całkowicie ignoruje drastyczne „piki” opóźnień (jitter), które w modelu A0 sięgają 173.94 ms przy 40% Load.
  3. Punkt przełamania stabilności: przy umiarkowanym obciążeniu (30% Load), model zdalny (A2) niemal nie odczuwa wzrostu latencji p99 (+6.35 ms), podczas gdy model lokalny traci stabilność niemal natychmiast (+66.22 ms).

Kiedy bezwzględnie rozdzielić warstwy (App i DB)?

Na podstawie zebranych danych, rekomendujemy migrację bazy danych na osobny host w następujących przypadkach:

  • kiedy stabilność SLA jest priorytetem: jeżeli p99 na poziomie powyżej 100 ms jest nieakceptowalny dla Twojej aplikacji;
  • w środowiskach o skokowym obciążeniu CPU: jeżeli aplikacja backendowa wykonuje periodyczne, ciężkie zadania (np. generowanie raportów, przetwarzanie obrazów), które destabilizują pracę bazy;
  • przy dużej liczbie połączeń: powyżej 50-100 aktywnych połączeń (j) narzut na zarządzanie procesami (Context Switching) i walka o cache procesora stają się dominującymi czynnikami degradującymi jakość usługi.

Złota zasada architektoniczna

Mimo teoretycznych zysków z braku narzutu sieciowego, w architekturze o wysokiej dostępności i wysokiej jakości usług (QoS), separacja warstwy danych jest fundamentem przewidywalności.

Jeżeli Twój budżet pozwala na wybór między jednym „potężnym” serwerem a dwoma „średnimi”, a głównym wyzwaniem jest intensywne i zmienne obciążenie CPU po stronie aplikacji, dane z naszych testów jednoznacznie sugerują wybór dwóch mniejszych jednostek. Taka fizyczna separacja warstwy danych jest fundamentem przewidywalności systemu. Należy jednak pamiętać, że w systemach limitowanych przez I/O dyskowe lub przepustowość pamięci, ocena architektury musi być przeprowadzona indywidualnie.