2012-04-25 13 views
20

Mam problem, w którym muszę bardzo szybko załadować wiele danych (5+ miliardów wierszy) do bazy danych (najlepiej mniej niż 30 minut, ale szybciej jest lepiej), a ostatnio zasugerowano mi zaglądanie do postgresql (nie udało mi się z mysql i patrzyłem na hbase/cassandra). Moja konfiguracja polega na tym, że mam klaster (obecnie 8 serwerów), który generuje wiele danych, i myślałem o uruchomieniu baz danych lokalnie na każdym komputerze w klastrze, który szybko zapisuje lokalnie, a następnie na końcu (lub w całym procesie generowania danych) dane są połączone razem. Dane nie są w żadnej kolejności, więc nie obchodzi mnie, który konkretny serwer jest na nim (o ile w końcu tam jest).Auto sharding postgresql?

Moje pytania brzmią, czy istnieją dobre tutoriale lub miejsca, w których można się dowiedzieć o automatycznym odkładaniu PostgreSQL (znalazłem wyniki firm takich jak sykpe, które wykonują automatyczne sharding, ale bez samouczków, chcę się z tym bawić)? Czy to, co próbuję zrobić, to możliwe? Ponieważ dane nie są w jakiejkolwiek kolejności, zamierzałem użyć automatycznie zwiększającego się numeru identyfikacyjnego, czy spowoduje to konflikt, jeśli dane zostaną scalone (to już nie jest duży problem)?

Aktualizacja: Pomysł Franka poniżej niwelował problem z automatycznym inkrementowaniem, o który pytałem. Nasuwa się teraz pytanie, w jaki sposób mogę się dowiedzieć o automatycznym shardowaniu i czy obsługuje ono rozproszone przesyłanie danych do wielu serwerów?

+1

Załadowałem ~ 10 milionów wierszy do bazy danych postgres w <5 min, więc z przekonaniem mogę powiedzieć, że jest to bardzo ważny zasób, na którym można polegać podczas ładowania danych do jednego fragmentu: http: // www .postgresql.org/docs/8.1/statical/populate.html To również wygląda obiecująco: http://support.projects.postgresql.org/ –

+9

'Chciałem użyć auto-inkrementującego numeru ID, spowoduje to konflikt jeśli dane są scalane? Po prostu zwiększaj o 10 i zacznij od różnych przesunięć. Serwer 1 używa identyfikatorów 1.11,21,31; serwer 2 używa identyfikatorów 2,12,22,32 –

+0

@FrankFarmer Dzięki za link i świetny pomysł na ponowne zwiększenie. Wydaje mi się, że to trochę skomplikowane, wtedy myślę, że pytanie dotyczy tylko automatycznego dzielenia i rozproszonego przesyłania. – Lostsoul

Odpowiedz

2

Oto kilka rzeczy, które mogą pomóc:

  • DB na każdym serwerze powinien mieć mały stolik meta danych z unikalnych cech, które serwera. Takich jak serwer; serwery mogą być ponumerowane kolejno. Oprócz zawartości tej tabeli, prawdopodobnie staramy się zachować schemat na każdym serwerze w możliwie największym stopniu.

  • Z miliardami rzędów będziesz potrzebować biginta (lub UUID lub podobnego). Przy większych rozmiarach możesz przydzielić duży zakres dla każdego serwera i ustawić jego kolejność, aby go użyć. Na przykład. serwer 1 otrzyma 1..1000000000000000, serwer 2 otrzyma 1000000000000001 do 2000000000000000 itd.

  • Jeśli dane są prostymi punktami danych (jak odczyt temperatury z dokładnie 10 instrumentów na sekundę), można uzyskać wzrost wydajności poprzez przechowywanie go w tabela z kolumnami (time timestamp, values double precision[]) zamiast bardziej poprawnych (time timestamp, instrument_id int, value double precision). Jest to wyraźna denormalizacja na rzecz wydajności. (. I blogged o moje własne doświadczenia z tym systemem)

1

Niestety nie mam tutorial pod ręką, ale oto zarys ewentualnego rozwiązania:

  • Załaduj jeden osiem swoje dane do instancji PG na każdym z serwerów
  • Aby uzyskać optymalną prędkość ładowania, nie należy używać wkładek, ale należy użyć metody COPY
  • Po załadowaniu danych nie należy łączyć ośmiu baz danych w jedną. Zamiast tego użyj plProxy, aby uruchomić pojedynczą instrukcję, aby wysłać zapytanie do wszystkich baz danych jednocześnie (lub prawą, aby spełnić zapytanie).

Jak już wspomniano, klucze mogą być problemem. Użyj nienakładających się sekwencji lub uuidów lub numerów sekwencji z prefiksem struny, nie powinno być zbyt trudne do rozwiązania.

Należy rozpocząć od testu COPY na jednym z serwerów i sprawdzić, jak blisko 30-minutowej bramki można uzyskać. Jeśli twoje dane nie są ważne i masz najnowszą wersję Postgresql, możesz spróbować użyć narzędzia unlogged tables, które powinno być dużo szybsze (ale nie może być bezpieczne w razie awarii).Brzmi jak zabawny projekt, powodzenia.

+0

Dzięki, popatrzę na plProxy..to naprawdę ciekawe.Wypróbuję to i niezalogowane stoły .. – Lostsoul

14

Po pierwsze: czy rzeczywiście trzeba wstawiać wygenerowane dane z klastra bezpośrednio do relacyjnej bazy danych? Nie masz nic przeciwko łączeniu go na końcu, więc po co zawracać sobie głowy wstawianiem do bazy danych? Na twoim stanowisku chciałbym, żeby twoje węzły klastra zapisywały płaskie pliki, prawdopodobnie gzipowe dane CSV. Następnie zbiorczo importowałem i scalałem te dane za pomocą narzędzia takiego jak pg_bulkload.

Jeśli musisz wstawić bezpośrednio do relacyjnej bazy danych: To jest (część), do której są przeznaczone PgPool-II i (w skrócie) PgBouncer. Skonfiguruj PgBouncer do równoważenia obciążenia między różnymi węzłami i powinieneś być dość posortowany.

Należy zauważyć, że PostgreSQL to transakcyjna baza danych z gwarancją trwałości danych. Oznacza to również, że jeśli używasz go w uproszczony sposób, wykonywanie wielu małych zapisów może być powolne. Musisz zastanowić się, jakie kompromisy chcesz wprowadzić między trwałością, szybkością i kosztem sprzętu.

Na jednym krańcu każdy INSERT może być swoją własną transakcją, która jest synchronicznie zatwierdzana na dysku przed zwróceniem sukcesu. Ogranicza to liczbę transakcji na sekundę do liczby fsync(), jakie może wykonać Twój podsystem dyskowy, który często jest tylko w dziesiątkach lub setkach na sekundę (bez kontrolera RAID do tworzenia kopii zapasowych baterii). Jest to ustawienie domyślne, jeśli nie robisz nic specjalnego i jeśli nie zawijasz swoich INSERT s w INSERT s w INSERT i .

Na drugim krańcu powiesz: "Naprawdę nie obchodzi mnie, czy stracę dane wszystkie" i użyję unlogged tables dla twoich wstawek. Zasadniczo daje to bazie danych pozwolenie na wyrzucanie danych, jeśli nie może zagwarantować, że wszystko jest w porządku - powiedzmy, po awarii systemu operacyjnego, awarii bazy danych, utracie zasilania itp.

Pośrednie miejsce, w którym prawdopodobnie będziesz chciał być . Wiąże się to z pewną kombinację asynchronous commit, group commits (commit_delay i commit_siblings), wkładki dawkowania na grupy zawinięte w wyraźnej BEGIN i END, itd. Zamiast INSERT dozowania można zrobić COPY ładunki kilku tysięcy rekordów naraz. Wszystko to wymienia wytrzymałość danych na szybkość.

Dla szybkich wkładek luzem należy również rozważyć wstawienie do tabel bez indeksów z wyjątkiem klucza podstawowego. Może nawet tego. Utwórz indeksy po zakończeniu wprowadzania zbiorczego. To będzie o wiele szybciej.

+0

Wow .. dziękuję za wspaniałą odpowiedź. Twoje prawo Nie potrzebuję bazy danych, ale próbuję użyć jej do udostępnienia danych końcowych innym węzłom pracującym. Tak więc mój pierwszy proces generuje wiele danych, ale drugi proces wykorzystuje klaster do analizy danych w stosunku do poprzedniego zestawu danych (generowanego w ten sam sposób tylko w innym dniu). Nie jestem pewien, czy potrzebuję średnich lub bardziej ekstremalnych niezalogowanych tabel, ponieważ jeśli używam danych tylko wtedy, gdy db umrze, to będę wiedział, kiedy umrze i może ponownie uruchomić moje przetwarzanie, ale jeśli to nie umrze i idzie powoli, a ja przegapę mój termin. – Lostsoul

+0

Czy uważasz, że bardziej sensowne w moim przypadku jest zapisanie danych jako pliku i przesłanie go po prostu? Pomyślałem, że odkąd zamierzałem mieć to w bazie danych do analizy w końcu mogę równie dobrze tworzyć wątki w moim programie, które wysyłają je podczas przetwarzania, ale jeśli jest to szybsze, tylko po to, aby pisać lokalnie, a następnie przesyłać zbiorczo, może po prostu Zrób to ... Również nie mam żadnych indeksów w tabeli (moja kolumna jest słownikiem string/int, które ładuję jako ciąg, a druga to kolumna ID, która moim zdaniem będzie długa int ..). Wszystkie inne rozważania decyzyjne służą tylko szybkości. – Lostsoul

+0

Rzecz w wstawianiu danych do zaszyfrowanej bazy danych polega na tym, że jest to użyteczne tylko wtedy, gdy możesz zapytać o nią w postaci zignorowanej. Są na to narzędzia (patrz np. PL/Proxy), ale są one bardziej skomplikowane i trudniejsze w użyciu niż pojedyncza instancja DB. OTOH, mogą być znacznie szybsze. Jeśli nie będziesz przesyłać zapytań o odłamki, ale zamiast tego chcesz scalić dane przed ich analizowaniem, możesz równie dobrze napisać je jako płaskie pliki i po prostu wstawić je do ostatecznego DB. –

-1

Można użyć mySQL - który obsługuje automatyczne dzielenie w klastrze.

+2

Wydaje mi się, że myślisz o Klastrze MySQL, który jest płatnym produktem oddzielnym od samego MySQL. – Peeja

1

Użyj citus do automatycznego dzielenia PostgreSQL. Pomocne jest również this link.