System działał bez zarzutu przez 364 dni w roku. Jeden dzień w październiku obnażał prawdę o architekturze, która nie była gotowa na rzeczywiste obciążenie.

Audyt warty miliony. When Replication Works… Until It Doesn't
Kluczowe punkty
  • Niskie wykorzystanie zasobów nie oznacza braku problemów wydajnościowych
  • Merge Replication ze złożonymi filtrami join to bomba zegarowa przy dużych wolumenach
  • Blokady potrafią sprowadzić przepustowość do 1 rekordu na sekundę
  • Przeprojektowanie modelu danych dało wzrost wydajności 346x

Kontekst techniczny: rozproszona infrastruktura i Merge Replication

SQL Server Merge Replication to potężne narzędzie do synchronizacji danych w środowiskach rozproszonych geograficznie. W opisywanym przypadku mieliśmy do czynienia z architekturą hub-and-spoke: centralny Publisher oraz 9 Subscriberów rozmieszczonych w zakładach produkcyjnych na terenie całego kraju.

Publikacje obejmowały dane operacyjne, kartoteki kontrahentów, dokumenty oraz logi systemowe. Codzienne operacje generowały umiarkowany ruch replikacyjny, który system obsługiwał bez problemu. Monitoring nie pokazywał żadnych anomalii przez cały rok.

Problem ujawniał się wyłącznie podczas corocznej synchronizacji pełnego zbioru danych na potrzeby raportów dla instytucji unijnych. To klasyczny przykład sytuacji, gdy system przechodzi testy jednostkowe i integracyjne, ale zawodzi przy stress testach na produkcyjnych wolumenach.

Diagnostyka: eliminacja oczywistych podejrzanych

Pierwsza reakcja każdego DBA to sprawdzenie klasycznej triady: CPU, pamięć, dysk. W tym przypadku wszystkie metryki wyglądały zaskakująco dobrze:

  • CPU oscylowało wokół 12% wykorzystania
  • Brak queue depth na dyskach wskazujących na bottleneck I/O
  • Pamięć dostępna, brak pressure na buffer pool
  • Sieć zweryfikowana przez inżyniera Cisco; brak saturacji ani packet loss

To był pierwszy sygnał ostrzegawczy. Kiedy system jest wolny, a zasoby świecą pustkami, problem leży głębiej. System nie pracował. System czekał.

Analiza blokad: prawdziwe źródło problemu

Dopiero szczegółowa analiza wait stats i aktywnych sesji ujawniła skalę problemu. Merge Agent spędzał większość czasu na stanach oczekiwania związanych z blokadami: LCK_M_S, LCK_M_X, LCK_M_U.

Replikacja dokumentów osiągała przepustowość około 1 rekordu na sekundę. Przy 180 000 operacji dawało to blisko 47 godzin samego przetwarzania tej jednej tabeli. Jednocześnie inne publikacje działały prawidłowo, co wskazywało na problem specyficzny dla konkretnej struktury danych.

W Merge Replication każda operacja synchronizacji wymaga dostępu do tabel systemowych MSmerge_contents i MSmerge_tombstone. Przy złożonych filtrach join silnik musi wielokrotnie odpytywać tabele źródłowe, generując kaskadę blokad. To nie jest bug; to konsekwencja architektury.

Anatomia problemu: filtry join w publikacji

Merge Replication oferuje dwa typy filtrów: statyczne (WHERE na pojedynczej tabeli) oraz join filters łączące wiele tabel. Te drugie są wygodne koncepcyjnie, ale katastrofalne wydajnościowo przy dużych wolumenach.

W analizowanym środowisku tabela dokumentów była powiązana przez łańcuch join filters z tabelami kartotek i słowników. Każda operacja synchronizacji wymagała weryfikacji całego łańcucha zależności. Przy małym wolumenie zmian było to niezauważalne. Przy masowej synchronizacji generowało to eksplozję blokad.

Rozwiązanie: przeprojektowanie modelu replikacji

Kluczowe zmiany obejmowały:

  • Denormalizację kluczowych kolumn filtrujących bezpośrednio do tabel źródłowych
  • Zastąpienie join filters prostymi filtrami statycznymi
  • Eliminację zbędnych tabel pośrednich z publikacji
  • Podział dużych publikacji na mniejsze, niezależne jednostki

Zmiany wymagały modyfikacji procedur ETL zasilających tabele oraz aktualizacji aplikacji klienckiej. To nie była szybka poprawka indeksu; to była restrukturyzacja warstwy danych.

Wyzwanie testowe: brak możliwości weryfikacji

Audyt przeprowadziłem w połowie roku. Udało się odtworzyć problem w środowisku testowym z syntetycznymi danymi, ale rzeczywista weryfikacja mogła nastąpić dopiero podczas październikowej synchronizacji produkcyjnej. To częsty problem przy optymalizacji systemów przetwarzania wsadowego: pełny cykl testowy wymaga czekania na realne zdarzenie biznesowe.

Wyniki: wzrost wydajności 346x

Październikowa synchronizacja po wdrożeniu zmian osiągnęła przepustowość około 346 rekordów na sekundę. Proces, który wcześniej trwał dni, zamknął się w minutach. Merge Agent przestał czekać na blokady i zaczął faktycznie przetwarzać dane.

Co istotne, zmiany nie wymagały upgrade'u sprzętu ani zwiększenia zasobów. Ten sam serwer, ta sama sieć; inny model danych.

Najbardziej zdradliwe są systemy, które działają wystarczająco dobrze przez większość czasu. Prawdziwy test następuje w momencie szczytowego obciążenia; wtedy okazuje się, czy architektura była zaprojektowana czy tylko złożona.

Wnioski dla praktyków

Merge Replication pozostaje użytecznym narzędziem, ale wymaga świadomego projektowania. Kilka zasad, które warto zapamiętać:

  • Unikaj join filters przy tabelach przekraczających kilkadziesiąt tysięcy wierszy
  • Testuj wydajność replikacji na produkcyjnych wolumenach danych
  • Monitoruj wait stats Merge Agenta, nie tylko metryki zasobów
  • Rozważ denormalizację kosztem elegancji modelu
Wydajność systemu rozproszonego to nie tylko kwestia zasobów sprzętowych. To przede wszystkim jakość modelu danych i świadomość ograniczeń wybranej technologii replikacji. Systemy, które działają bez zarzutu przez 99% czasu, potrafią zawieść spektakularnie w tym jednym krytycznym momencie.