Postgres nie nadąża z zapisem danych

Tak przy okazji, jak miałem ostatnio problem dodawania dużej ilości danych to zrobiłem coś takiego:

  1. Aplikacja działająca na pumie
  2. Celluloid ustawiony tak, żeby był dostępny 1 worker na każdą tabelę, tabel było 4
  3. Do takiej aplikacji wysyła się requesty z danymi, które mają być dodane i opisem, które pola są unikalne
  4. Aplikacja przetwarza te requesty, grupuje dane i wykonuje jednego selecta dla każdej grupy w celu sprawdzenia które rekordy już istnieją w bazie, a później jedno COPY, które wkłada od razu wiele rekordów (COPY jest z reguły duuużo szybsze niż INSERT)

Dzięki temu, że jest tylko jeden worker dla każdej tabeli, nie trzeba się martwić o duplikaty (co może być problemem przy wkładaniu kilkuset rekordów na raz). U mnie selecty i COPY wykonywały się w workerach, ale nic nie stoi na przeszkodzie, żeby to trochę zmodyfikować i wykonywać selecty współbieżnie - jedyne co trzeba by zrobić, to zapisywać które rekordy zostały dodane w workerze - wtedy wiadomo co pominąć przy dodawaniu.

W sumie to i może warto w końcu nauczyć się celluloida, to co napisałem jest dopiero we wstępnej fazie i nie wykluczam, że trzeba będzie mechanizm pobierania danych przerobić i dopisać mechanizm prezentacji danych, ale to już można po najniższej linii oporu, czyli prosta aplikacja railsowa, bez logowania itd.

Tzn. w tym moim rozwiązaniu celluloid nie jest niezbędny - jedyne założenie, które tam jest ważne, to żeby wkładanie danych nie odbywało się współbieżnie dla tej samej tabeli. To samo można osiągnąć tworząc jeden wątek dla tabeli albo używając mutexów, wybrałem celluloida, głównie dlatego, że ma fajne API do komunikacji z workerami i od razu implementuje mutexa dla danego workera, metoda exclusive

Tak się tylko zastanawiam jak mocną maszynę musiałbym mieć żeby obsłużyć np. 20 takich źródeł, które by co 10 sekund wysyłało nowe dane, żeby nie dostało czkawki i nagle nie odmówiło posłuszeństwa.

Imho bottleneckiem tak czy siak będzie tutaj baza danych, więc raczej nie będzie znaczenia czy użyjesz pumy czy goliatha czy czegokolwiek innego, ale jeżeli będziesz grupować te rekordy, to nie powinno być problemu. W rozwiązaniu, które robiłem wysyłane jest od ok. 100 do kilku tysięcy rekordów na raz. Nawet w przypadku godzin szczytu dodanie takiej grupy kilkuset rekordów zajmowało z reguły kilkaset milisekund. Oczywiście zależy to też od maszyny, tamta była dość mocna.

  1. Która wersja postgresa
  2. Jakie wartości mają kluczowe parametry takie jak: shared_buffers, effective_cache_size, work_mem itp. Tuningowałeś coś postgresa?
  3. Jakie parametry ma serwer, na którym działa postgres (ram, dyski, cpu). Jaka jest utylizacja tych parametrów. Jaki jest rozkład (Twoja aplikacja generuje jakiś widoczny narzut?). Jakie jest obciążenie serwera? Co go obciąża? Na czym?
  4. Jeśli problemem rzeczywiście jest postgres to z czym postgres ma problem? Nie nadąża zapisywać (za mało I/O, pamięci za mało?), co pokazuje vmstat?
  5. Monitorujesz jakoś postgresa? Jakiś dziennik wolnych zapytań, ilość hitów per sekunda, rozkład zapytań, czy inne cuś? :slight_smile:

[quote=wafcio]Przy zapisie danych do bazy postgres w bardzo krótkim czasie następuje zakleszczenie i otzrymuje komunikat:
PG::UnableToSend: another command is already in progress[/quote]
To nie jest “nie nadąża” (nienadążanie by się objawiało coraz dłuższym czasem wykonywania kolejnych insertów aż do timeoutu) tylko wyścig.

Poprosiłem Bernarda który zjadł zęby na eventmachine i postgresie żeby rzucił okiem na ten wątek, zdiagnozował i powiedział jak to rozwiązać.