streszczenie
W jaki sposób można skonfigurować Linuksa zarówno do odczytu z lokalnego dysku / systemu plików, jak i zapisu do udziału sieciowego w tym samym czasie, w przeciwieństwie do odczytu, gdy żadne dane nie przechodzą przez sieć, a następnie wysyłania tych danych przez sieć, gdy dysk lokalny jest bezczynny?
Znacznie szybciej jest czytać i pisać jednocześnie, zamiast wykonywać tylko jedną operację, a następnie drugą na przemian.
Detale
Przenoszę dużą ilość danych z dysków lokalnych na komputerze z systemem Linux na urządzenie NAS.
Używam rsync
w zasadzie kopia /srv/data
do /mnt/nas
, który jest zamontowanie CIFS.
Zaczęło się dobrze, czytając z prędkością 100 MB / s i zapisując na serwerze NAS z prędkością 100 MB / s (limit sieci gigabitowej), przy jednoczesnym czytaniu i pisaniu.
Jednak teraz, kilka godzin później, odkrywam, że czyta z dysku lokalnego, a następnie zatrzymuję odczyt podczas zapisywania na NAS, a gdy nie ma już danych do zapisania na NAS, wznawia czytanie z dysku jeszcze raz. Sieć jest bezczynna podczas odczytywania dysku, a dysk jest bezczynny, gdy sieć jest używana.
Nie trzeba dodawać, że czytanie 200 MB, a następnie pisanie 200 MB zajmuje znacznie więcej czasu niż czytanie i pisanie 200 MB jednocześnie.
Jak mogę skonfigurować jądro tak, aby było zgodne z wcześniejszym zachowaniem czytania i pisania w tym samym czasie, zamiast przełączać się między czytaniem a pisaniem, wykonując tylko jedną operację na raz?
Kilka spostrzeżeń: gdy dysk lokalny odczytuje z prędkością 100 + MB / s, wszystko wydaje się przebiegać równolegle w porządku, ale kiedy dysk zwalnia (z jakiegoś powodu wydaje się, że z jakiegoś powodu idzie teraz z prędkością tylko 20 MB / s), to wtedy zapis wydaje się, że następuje zmiana.
Mogę również uruchomić sync
ręcznie co kilka sekund, aby uzyskać pisze dzieje się równolegle z odczytuje (choć oczywiście przy zredukowanych prędkościach) jednak umieszczenie sync
w while
pętli tak, że działa co pięć sekund nie wydaje się właściwym rozwiązaniem ...
Jądro wydaje się buforować około 1 GB danych, a następnie zapisywać je tak szybko, jak to możliwe w sieci - co jest w porządku - po prostu nie rozumiem, dlaczego powolny dysk musi przestać być odczytywany, gdy dane są wysyłane przez sieć.
Odpowiedzi:
Po dalszych badaniach wydaje się, że ten problem jest mniej związany z jądrem, a więcej na temat
rsync
interakcji i CIFS.O ile wiem, dzieje się tak, że gdy
rsync
zamyka plik docelowy, CIFS (i prawdopodobnie każdy system plików sieciowych) zapewnia, że plik zostanie całkowicie opróżniony i zapisany na dysku zdalnym, zanim nastąpiclose
powrót syscall. Ma to na celu zapewnienie dowolnej aplikacji, że po pomyślnym zakończeniu operacji zamykania plik został całkowicie zapisany i nie ma ryzyka wystąpienia dalszych błędów, które mogłyby spowodować utratę danych.Gdyby tego nie zrobiono, aplikacja mogłaby zamknąć plik, wyjść z założenia, że operacja zapisu zakończyła się powodzeniem, a później (być może z powodu problemu z siecią) dane nie mogły zostać zapisane, ale do tego czasu jest już za późno, aby aplikacja mogła cokolwiek z tym zrobić, na przykład zapytać użytkownika, czy zamiast tego chce zapisać plik w innym miejscu.
Wymaganie to oznacza, że za każdym razem, gdy
rsync
kopiowanie pliku zostanie zakończone, cały bufor dysku musi zostać opróżniony przez sieć, zanimrsync
będzie można kontynuować czytanie następnego pliku.Obejściem tego problemu jest zamontowanie udziału CIFS z opcją,
cache=none
która wyłącza tę funkcję i powoduje, że wszystkie operacje we / wy idą bezpośrednio do serwera. Eliminuje to problem i umożliwia równoległe wykonywanie odczytów i zapisów, jednak wadą tego rozwiązania jest to, że wydajność jest nieco niższa. W moim przypadku prędkość transferu sieciowego spada ze 110 MB / s do 80 MB / s.Może to oznaczać, że jeśli kopiujesz duże pliki, wydajność może być lepsza przy naprzemiennym zachowaniu odczytu / zapisu. W przypadku wielu mniejszych plików wyłączenie pamięci podręcznej spowoduje mniej opróżnień pamięci podręcznej za każdym razem, gdy plik jest zamykany, co może zwiększyć wydajność.
Wydaje się, że
rsync
potrzebuje opcji zamknięcia uchwytów plików w innym wątku, aby mógł zacząć czytać następny plik, podczas gdy ostatni jest jeszcze opróżniany.EDYCJA: Potwierdziłem, że
cache=none
zdecydowanie pomaga przy przesyłaniu dużej liczby małych plików (podnosi z 10 MB / s do 80 MB / s), ale podczas przesyłania dużych plików (1 GB +)cache=none
spada transfer z 110 MB / s do tego samego 80 MB / s. Sugeruje to, że powolny transfer z wielu małych plików nie polega na wyszukiwaniu dysku źródłowego, a więcej na tak dużej ilości opróżniania pamięci podręcznej ze wszystkich małych plików.źródło
rsync
ma odczytać plik w innym wątku (faktycznie, inny proces), ponieważ jest zaprojektowany tak, że jedna kopiarsync
działa na każdej stronie w sieci, nawet w przypadku gdy obie kopie są po tej samej stronie (i system plików jest ukrywanie fakt, że istnieje sieć). Wydaje mi się, że to nie pomaga, ponieważ proces czytnika bardzo szybko wypełnia potok, gdy proces zapisu blokujeclose()
.rsync
działałby lepiej, gdybyś korzystałrsync
z drutu, a nie CIFS.rsync
na serwerze NAS, byłoby użyciersync
przez sieć (jakrsync -a files localhost:/dest/path
) przy jednoczesnym sztucznym wprowadzeniu ogromnego bufora (co najmniej wielu megabajtów) do połączeń sieciowych. Nie jestem pewien, jak wyglądałby najlepszy hack do tego celu.rsync
samego urządzenia NAS również rozwiązałoby problem. Trochę bardziej skomplikowane (dziwne uprawnienia NAS, upuszczanie dowiązań symbolicznych itp.), Ale myślę, że gdybym miał trochę więcej danych do skopiowania, warto poświęcić na to czas.dump(8)
na NAS zamontowanym na NFS. W tym czasie zdiagnozowałem problem jako maksymalizujący obciążenie procesora na serwerze NAS, ze względu na połączony efekt serwera NFS i zapory działającej na serwerze NAS (pudełko nie było zrootowane, a zapory nie można całkowicie wyłączyć z interfejs WWW). Problem zniknął, gdy zastąpiliśmy NAS starym komputerem. FWIW.