2009-08-28 11 views
11

Musimy odczytywać i liczyć różne typy wiadomości/uruchomić niektóre statystyki na pliku tekstowym 10 GB, np. FIX silnik log. Używamy Linuksa, 32-bit, 4 procesory, Intel, kodowanie w Perlu, ale język nie ma znaczenia.Jaki jest najszybszy sposób na odczytanie pliku 10 GB z dysku?

Znalazłem kilka ciekawych wskazówek w Tim Bray: WideFinder project. Odkryliśmy jednak, że używanie mapowania pamięci jest z natury ograniczone przez 32-bitową architekturę.

Próbowaliśmy użyć wielu procesów, które wydają się działać szybciej, jeśli przetwarzamy plik równolegle przy użyciu 4 procesów na 4 procesorach. Dodanie wielowątkowości spowalnia ją, być może ze względu na koszt przełączania kontekstów. Próbowaliśmy zmienić rozmiar puli wątków, ale jest to nadal wolniejsza niż prosta wersja wieloprocesorowa.

Część odwzorowania pamięci nie jest bardzo stabilna, czasami jest to trwa 80 sekund, a czasem 7 sekund na pliku 2 GB, może z błędów stron lub czegoś związanego z wykorzystaniem pamięci wirtualnej. W każdym razie, Mmap nie może przeskalować poza 4 GB w 32-bitowej architekturze .

Próbowaliśmy Perla IPC::Mmap i Sys::Mmap. Wygląda na to, że również na Map-Reduce, ale problem jest naprawdę I/O związany, samo przetwarzanie jest wystarczająco szybkie.

Więc zdecydowaliśmy się spróbować zoptymalizować podstawowe I/O przez strojenie rozmiar buforowania, typ itp

Czy ktoś, kto zdaje sobie sprawę z istniejącego projektu, gdzie ten problem został skutecznie rozwiązać w dowolnym języku/platformy wskaż przydatne łącze lub zaproponuj kierunek?

+2

Co to jest surowa wydajność pojedynczego procesora dla 2G? Prawdopodobnie musisz określić, czy I/O to problem, czy obliczenia procesora. – Cervo

+2

Jeśli jesteś naprawdę związany z dyskiem (IO), najlepszym rozwiązaniem jest prawdopodobnie kupowanie szybszych dysków, więcej dysków (w RAID0, RAID5, RAID10 itd.) Lub 64-bitowej maszyny z wystarczającą pamięcią do przechowywania pliku dysk RAM. Każdy rozsądny pojedynczy dysk powinien być w stanie pobrać 50 MB/s; wiele szybkich dysków powinno być w stanie popchnąć użytkownika do co najmniej 300 MB/s. – derobert

+1

Zalecam, aby nie używać Sys :: Mmap, ale Mapa plików (z powodów podanych w dokumentacji tego ostatniego). W każdym razie prawdopodobnie nie chcesz używać IPC :: Mmap. –

Odpowiedz

9

Większość czasu będziesz I/O CPU bound nie związany, więc po prostu odczytać ten plik poprzez normalne Perl I/O i przetwarza je w pojedynczym wątku. Jeśli nie udowodnisz, że możesz wykonać więcej operacji wejścia-wyjścia niż pojedynczego procesora, nie trać czasu na nic więcej. W każdym razie powinieneś zapytać: Dlaczego na Ziemi jest to w jednym wielkim pliku? Dlaczego, na Boga, nie rozdzielają go w rozsądny sposób, kiedy go generują? Byłaby to wartość więcej warta pracy. Następnie możesz umieścić go w oddzielnych kanałach I/O i użyć więcej procesorów (jeśli nie używasz RAID 0 lub NAS lub ...).

Zmierz, nie zakładaj. Nie zapomnij spłukać pamięci podręcznej przed każdym testem. Pamiętaj, że seryjne operacje we-wy są wielkości większe niż losowe.

0

Przypominam sobie projekt, w którym czytaliśmy duże pliki, Nasza implementacja wykorzystywała wielowątkowość - w zasadzie n * worker_threads zaczynało od zwiększania przesunięć pliku (0, chunk_size, 2xchunk_size, 3x chunk_size ... n-1x chunk_size) i czytał mniejsze porcje informacji. Nie potrafię sobie dokładnie przypomnieć naszego rozumowania, ponieważ ktoś inny zaprojektował całą sprawę - robotnicy nie byli jedyną rzeczą, ale w przybliżeniu, jak to zrobiliśmy.

Nadzieja pomaga

2

Czy myślałeś o strumieniowe plik i odfiltrowanie do pliku wtórnym jakieś ciekawe rezultaty? (Powtarzaj, aż znajdziesz plik o rozmiarach do opanowania).

3

Być może masz już przeczytać ten wątek, ale jeśli nie:

http://www.perlmonks.org/?node_id=512221

to opisano przy użyciu Perl zrobić to linia po linii, a użytkownicy zdają się myśleć Perl jest całkiem zdolny tego.

Och, czy można przetworzyć plik z macierzy RAID? Jeśli masz kilka dysków lustrzanych, można poprawić szybkość odczytu. Konkurencja o zasoby dyskowe może być tym, co sprawia, że ​​twoja próba wielu wątków nie działa.

Powodzenia.

3

Chciałbym wiedzieć więcej o zawartości pliku, ale nie wiedząc, inne niż to jest tekst, brzmi to jak doskonały rodzaju MapReduce problemu.

PS, najszybszy odczyt dowolnego pliku to odczyt liniowy. cat file > /dev/null powinna być prędkością, z jaką można odczytać plik.

+3

Rzeczywiście; mój kolega pracujący nad podobnym problemem wykorzystywał czas od kota do śledzenia innych problemów z szybkością odczytu plików. NFS było strasznie nie do zniesienia. :( –

1

Zasadniczo trzeba "podzielić i zdobyć", jeśli masz sieć komputerów, a następnie skopiuj plik 10G do jak największej liczby komputerów klienckich, poproś każdy komputer kliencki, aby odczytał przesunięcie pliku. Aby uzyskać dodatkowy bonus, uzyskaj KAŻDEGO komputera, aby zaimplementował wiele wątków oprócz rozproszonego czytania.

+3

"Problem jest naprawdę związany z IO" <--- powodzenia kopiowanie pliku na komputer szybciej niż dyski mogą go odczytać – derobert

1

Parsować plik jeden raz, odczytywanie linii po linii. Umieść wyniki w tabeli w porządnej bazie danych. Przeprowadź dowolną liczbę zapytań. Nakarm bestię regularnie nowymi danymi przychodzącymi.

Sobie sprawę, że manipulowanie pliku 10 GB, przenosząc ją w poprzek (nawet jeśli lokalna sieć), odkrywania skomplikowanych rozwiązań etc wszystko wymaga czasu.

+2

Baza danych kanałów i uruchamianie zapytań może zajmować więcej czasu niż całe przetwarzanie w perlu. (To z mojego doświadczenia wynika, że ​​używasz obciążenia zbiorczego i MySQL, który jest jednym z najszybszych podejść, z których możesz korzystać.) –

+1

Po uzyskaniu danych w * przyzwoitej * bazie danych możesz uruchomić dowolną liczbę zapytań (nawet tych, których nie wiedziałeś, że chciałeś uruchomić) z niewielkimi dodatkowymi kosztami. –

1

Mam współpracownika, który przyspieszył czytanie w systemie FIX, przechodząc na 64-bitowy system Linux. Jeśli jest coś wartego zachodu, upuść trochę gotówki, aby zdobyć jakiś lepszy sprzęt.

4

Wszystko zależy od tego, jakiego rodzaju preprocessing możesz wykonać i kiedy. W niektórych systemach mamy gzip tak dużych plików tekstowych, redukując je do 1/5 do 1/7 ich oryginalnego rozmiaru. Częścią tego, co jest możliwe, jest to, że nie musimy przetwarzać tych plików przez wiele godzin po ich utworzeniu, a podczas tworzenia nie mamy żadnego innego obciążenia na tych maszynach.

Przetwarzanie ich odbywa się mniej więcej w taki sposób, aby pliki te były zcat | nasze przetwarzanie. (dobrze zrobione przez gniazda unixa z niestandardowym zcat). Wymienia czas procesora na dysk i/o czas, a dla naszego systemu, który był dobrze warto. Istnieje wiele zmiennych, które mogą sprawić, że będzie to bardzo kiepski projekt dla konkretnego systemu.

1

hmmm, ale co jest nie tak z poleceniem read() w C? Zwykle ma limit 2 GB, , więc po prostu wywołaj go 5 razy w kolejności. To powinno być dość szybkie.

1

Jeśli jesteś związany I/O i twój plik znajduje się na jednym dysku, to nie ma wiele do zrobienia. Prosty jedno-wątkowy skan liniowy w całym pliku jest najszybszym sposobem na uzyskanie danych z dysku. Używanie dużych rozmiarów buforów może trochę pomóc.

Jeśli możesz przekonać autora pliku do rozpakowania go na wielu dyskach/komputerach, możesz pomyśleć o wielowątkowości czytnika (jeden wątek na głowicę czytającą, każdy wątek odczytuje dane z jednego paska).

0

Nie stwierdzono w problemie, że kolejność ma znaczenie, czy nie.Tak więc, podzielisz plik na równe części, powiedzmy po 1 GB, a ponieważ używasz wielu procesorów, wiele wątków nie będzie problemem, więc czytaj każdy plik używając osobnego wątku i korzystaj z pamięci RAM o pojemności> 10 GB, a następnie całą zawartość byłby przechowywany w pamięci RAM czytanej przez wiele wątków.

1

Ponieważ wspomnianej platformy i język nie ma znaczenia ...

Jeśli chcesz stabilną wydajność, która jest tak szybki jak nośnik źródłowy pozwala, jedyny sposób mam świadomość, że można to zrobić na W systemie Windows nakładają się wyrównane odczytywane sekwencyjne sekwencje, które nie są buforowane przez system operacyjny. Prawdopodobnie możesz dostać się do GB/s z dwoma lub trzema buforami, poza tym, w pewnym momencie potrzebujesz bufora pierścieniowego (jeden pisarz, 1+ czytników), aby uniknąć jakiegokolwiek kopiowania. Dokładna implementacja zależy od sterownika/API. Jeśli istnieje jakiekolwiek kopiowanie pamięci w wątku (zarówno w jądrze, jak i trybie użytkownika) zajmującym się IO, oczywiście większy bufor jest do kopiowania, tym więcej czasu marnuje się na to zamiast na wykonanie IO. Optymalny rozmiar bufora zależy od oprogramowania i sterownika. W systemie Windows warto wartości do wypróbowania to wielokrotności 32 KB dla dysku IO. Buforowanie plików systemu Windows, mapowanie pamięci i wszystko to zwiększa obciążenie. Tylko dobry, jeśli robi (lub oba) wielokrotne odczyty tych samych danych w sposób losowy. Tak więc, w celu odczytywania dużego pliku sekwencyjnie za jednym razem, nie chcesz, aby system operacyjny buforował wszystko lub wykonywał jakiekolwiek memcpy. Jeśli używasz C#, są również kary za wywoływanie w systemie operacyjnym z powodu marszałkowania, więc kod interopu może wymagać trochę optymalizacji, chyba że używasz C++/CLI.

Niektóre osoby wolą rozwiązywać problemy sprzętowe, ale jeśli masz więcej czasu niż pieniędzy, w niektórych scenariuszach można zoptymalizować rzeczy, aby uzyskać 100-1000 razy lepszą wydajność na jednym komputerze klasy konsumenckiej niż 1000 komputerów z wyceną dla przedsiębiorstw. Powodem jest to, że jeśli przetwarzanie jest również wrażliwe na opóźnienia, wyjście poza użycie dwóch rdzeni prawdopodobnie zwiększy opóźnienie. Właśnie dlatego sterowniki mogą przesyłać gigabajty/s, podczas gdy oprogramowanie w firmie kończy się w megabajtach/s, zanim wszystko się skończy. Niezależnie od tego, jakie są raporty, logika biznesowa i takie oprogramowanie dla przedsiębiorstw, prawdopodobnie można również wykonać w gigabajtach/na dwurdzeniowym procesorze konsumenckim, jeśli napisano coś takiego, jak pisałeś grę z lat 80-tych. Najbardziej znanym przykładem, o którym słyszałem, że w ten sposób podchodzę do całej logiki biznesowej, jest wymiana forex LMAX, która opublikowała część ich kodu opartego na buforze pierścieniowym, który został zainspirowany przez sterowniki karty sieciowej.

Zapominając o całej teorii, jeśli jesteś zadowolony z < 1 GB/s, jednym z możliwych punktów wyjścia w systemie Windows, który znalazłem, jest szukanie źródła readfile z winimage, chyba że chcesz przekopać się na próbki sdk/driver. Może potrzebować pewnych poprawek kodu źródłowego, aby poprawnie obliczyć perf przy prędkościach SSD. Eksperymentuj również z rozmiarami bufora. Przełączniki/h wielowątkowe i/lub nakładające się (port zakończenia) IO z optymalnym rozmiarem bufora (spróbuj 32,64,128 KB itd.) Bez użycia buforowania plików Windows z mojego doświadczenia dają najlepszy efekt podczas odczytu z SSD (zimne dane), a jednocześnie przetwarzanie (użyj/a do przetwarzania Adler, ponieważ w przeciwnym razie jest zbyt związany z CPU).

Powiązane problemy