Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie

Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie

Droga społeczności, W tym artykule skupimy się na wydajnym przechowywaniu i odzyskiwaniu setek milionów małych plików. Na tym etapie proponowane jest ostateczne rozwiązanie dla systemów plików zgodnych z POSIX z pełną obsługą blokad, w tym blokad klastrowych, i pozornie nawet bez kul.

W tym celu napisałem więc własny serwer niestandardowy.
W trakcie realizacji tego zadania udało nam się rozwiązać główny problem, a jednocześnie osiągnąć oszczędność miejsca na dysku i pamięci RAM, które nasz klastrowy system plików bezlitośnie pochłaniał. Właściwie taka liczba plików jest szkodliwa dla każdego klastrowego systemu plików.

Pomysł jest taki:

Krótko mówiąc, małe pliki są przesyłane przez serwer, są zapisywane bezpośrednio w archiwum, a także z niego odczytywane, a duże pliki są umieszczane obok siebie. Schemat: 1 folder = 1 archiwum, w sumie mamy kilka milionów archiwów z małymi plikami, a nie kilkaset milionów plików. A wszystko to jest w pełni zaimplementowane, bez żadnych skryptów i umieszczania plików w archiwach tar/zip.

Postaram się pisać krótko, z góry przepraszam, jeśli post będzie długi.

Wszystko zaczęło się od tego, że nie mogłem znaleźć na świecie odpowiedniego serwera, który mógłby zapisywać dane otrzymane poprzez protokół HTTP bezpośrednio do archiwów, bez wad charakterystycznych dla konwencjonalnych archiwów i magazynowania obiektowego. A powodem poszukiwań był klaster Origin składający się z 10 serwerów, który rozrósł się do dużej skali, w którym zgromadziło się już 250,000,000 XNUMX XNUMX małych plików, a tendencja wzrostowa nie zamierzała się zatrzymać.

Dla tych, którzy nie lubią czytać artykułów, łatwiejsza będzie krótka dokumentacja:

tutaj и tutaj.

I jednocześnie doker, teraz na wszelki wypadek jest opcja tylko z nginxem w środku:

docker run -d --restart=always -e host=localhost -e root=/var/storage 
-v /var/storage:/var/storage --name wzd -p 80:80 eltaline/wzd

Dalej:

Jeśli plików jest dużo, potrzebne są znaczne zasoby, a najgorsze jest to, że część z nich jest marnowana. Na przykład w przypadku korzystania z klastrowego systemu plików (w tym przypadku MooseFS) plik, niezależnie od jego rzeczywistego rozmiaru, zawsze zajmuje co najmniej 64 KB. Oznacza to, że dla plików o rozmiarze 3, 10 lub 30 KB wymagane jest 64 KB na dysku. Jeśli plików jest ćwierć miliarda, tracimy od 2 do 10 terabajtów. Tworzenie nowych plików nie będzie możliwe w nieskończoność, ponieważ MooseFS ma ograniczenie: nie więcej niż 1 miliard na jedną replikę każdego pliku.

W miarę wzrostu liczby plików metadane wymagają dużej ilości pamięci RAM. Częste zrzuty dużych metadanych również przyczyniają się do zużycia dysków SSD.

serwer wZD. Uporządkowaliśmy wszystko na dyskach.

Serwer jest napisany w Go. Przede wszystkim musiałem zmniejszyć liczbę plików. Jak to zrobić? Ze względu na archiwizację, ale w tym przypadku bez kompresji, ponieważ moje pliki to po prostu skompresowane obrazy. Z pomocą przyszedł BoltDB, który trzeba było jeszcze wyeliminować ze swoich niedociągnięć, co znajduje odzwierciedlenie w dokumentacji.

W sumie zamiast ćwierć miliarda plików w moim przypadku pozostało już tylko 10 milionów archiwów Bolta. Gdybym miał możliwość zmiany aktualnej struktury plików katalogów, możliwe byłoby zmniejszenie ich do około 1 miliona plików.

Wszystkie małe pliki są pakowane do archiwów Bolt, które automatycznie otrzymują nazwy katalogów, w których się znajdują, a wszystkie duże pliki pozostają obok archiwów; nie ma sensu ich pakować, można to dostosować. Małe archiwizujemy, duże pozostawiamy bez zmian. Serwer działa w sposób przejrzysty z obydwoma.

Architektura i cechy serwera wZD.

Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie

Serwer działa pod systemami operacyjnymi Linux, BSD, Solaris i OSX. Testowałem tylko pod kątem architektury AMD64 pod Linuksem, ale powinno działać na ARM64, PPC64, MIPS64.

Główne cechy:

  • Wielowątkowość;
  • Multiserver zapewniający odporność na awarie i równoważenie obciążenia;
  • Maksymalna przejrzystość dla użytkownika lub programisty;
  • Obsługiwane metody HTTP: GET, HEAD, PUT i DELETE;
  • Kontrola zachowania podczas czytania i pisania za pomocą nagłówków klienta;
  • Wsparcie dla elastycznych hostów wirtualnych;
  • Obsługa integralności danych CRC podczas zapisu/odczytu;
  • Bufory półdynamiczne zapewniające minimalne zużycie pamięci i optymalne dostrajanie wydajności sieci;
  • Odroczone zagęszczanie danych;
  • Dodatkowo oferowany jest wielowątkowy archiwizator wZA umożliwiający migrację plików bez zatrzymywania usługi.

Prawdziwe doświadczenie:

Od dłuższego czasu rozwijam i testuję serwer i archiwizator na żywych danych, obecnie z powodzeniem działa on na klastrze zawierającym 250,000,000 15,000,000 10 małych plików (obrazków) zlokalizowanych w 2 2 XNUMX katalogów na oddzielnych dyskach SATA. Klaster XNUMX serwerów to serwer Origin zainstalowany za siecią CDN. Do jego obsługi wykorzystywane są XNUMX serwery Nginx + XNUMX serwery wZD.

Dla tych, którzy zdecydują się na korzystanie z tego serwera, mądrze byłoby zaplanować strukturę katalogów, jeśli ma to zastosowanie, przed użyciem. Od razu zastrzegam, że serwer nie jest przeznaczony do upychania wszystkiego w archiwum 1 Bolta.

Test wydajności:

Im mniejszy rozmiar spakowanego pliku, tym szybciej wykonywane są na nim operacje GET i PUT. Porównajmy całkowity czas zapisu i odczytu przez klienta HTTP do zwykłych plików i archiwów Bolta. Porównuje się pracę z plikami o rozmiarach 32 KB, 256 KB, 1024 KB, 4096 KB i 32768 KB.

Podczas pracy z archiwami Bolt sprawdzana jest integralność danych każdego pliku (stosuje się CRC), przed nagraniem, a także po nagraniu, następuje odczyt i przeliczenie w locie, co naturalnie wprowadza opóźnienia, ale najważniejsze jest bezpieczeństwo danych.

Przeprowadziłem testy wydajności na dyskach SSD, ponieważ testy na dyskach SATA nie wykazują wyraźnej różnicy.

Wykresy oparte na wynikach testów:

Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie
Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie

Jak widać, w przypadku małych plików różnica w czasie odczytu i zapisu pomiędzy plikami zarchiwizowanymi i niezarchiwizowanymi jest niewielka.

Zupełnie inny obraz uzyskujemy testując odczyt i zapis plików o wielkości 32 MB:

Efektywnie przechowuj setki milionów małych plików. Rozwiązanie hostowane samodzielnie

Różnica czasu pomiędzy odczytem plików mieści się w granicach 5-25 ms. Gorzej jest z nagrywaniem, różnica wynosi około 150 ms. Ale w tym przypadku nie ma potrzeby przesyłania dużych plików, po prostu nie ma to sensu, mogą one żyć oddzielnie od archiwów.

*Technicznie rzecz biorąc, możesz używać tego serwera do zadań wymagających NoSQL.

Podstawowe metody pracy z serwerem wZD:

Ładowanie zwykłego pliku:

curl -X PUT --data-binary @test.jpg http://localhost/test/test.jpg

Wgranie pliku do archiwum Bolta (o ile nie zostanie przekroczony parametr serwerowy fmaxsize, który określa maksymalny rozmiar pliku, który może zostać zawarty w archiwum; w przypadku jego przekroczenia plik zostanie wrzucony normalnie obok archiwum):

curl -X PUT -H "Archive: 1" --data-binary @test.jpg http://localhost/test/test.jpg

Pobieranie pliku (jeśli na dysku i w archiwum znajdują się pliki o tej samej nazwie, to przy pobieraniu domyślnie priorytet ma plik niezarchiwizowany):

curl -o test.jpg http://localhost/test/test.jpg

Pobieranie pliku z archiwum Bolta (wymuszone):

curl -o test.jpg -H "FromArchive: 1" http://localhost/test/test.jpg

Opisy pozostałych metod znajdują się w dokumentacji.

Dokumentacja wZD
Dokumentacja wZA

Serwer obecnie obsługuje tylko protokół HTTP, nie współpracuje jeszcze z HTTPS. Metoda POST również nie jest obsługiwana (jeszcze nie zdecydowano, czy jest potrzebna, czy nie).

Ktokolwiek zagłębi się w kod źródłowy, znajdzie tam toffi, nie każdemu się to podoba, ale nie powiązałem głównego kodu z funkcjami frameworka sieciowego, z wyjątkiem obsługi przerwań, więc w przyszłości mogę go szybko przepisać na prawie dowolne silnik.

Do zrobienia:

  • Opracowanie własnego replikatora i dystrybutora + geo dla możliwości zastosowania w dużych systemach bez klastrowych systemów plików (Wszystko dla dorosłych)
  • Możliwość całkowitego i zwrotnego odzyskania metadanych w przypadku ich całkowitej utraty (w przypadku korzystania z dystrybutora)
  • Natywny protokół umożliwiający wykorzystanie trwałych połączeń sieciowych i sterowników dla różnych języków programowania
  • Zaawansowane możliwości wykorzystania komponentu NoSQL
  • Kompresje różnych typów (gzip, zstd, snappy) dla plików lub wartości wewnątrz archiwów Bolta i dla zwykłych plików
  • Szyfrowanie różnych typów plików lub wartości wewnątrz archiwów Bolt i zwykłych plików
  • Opóźniona konwersja wideo po stronie serwera, w tym na GPU

Mam wszystko, mam nadzieję, że ten serwer się komuś przyda, licencja BSD-3, podwójne prawa autorskie, bo gdyby nie było firmy, w której pracuję, serwer nie byłby pisany. Jestem jedynym programistą. Byłbym wdzięczny za wszelkie znalezione błędy i prośby o nowe funkcje.

Źródło: www.habr.com

Dodaj komentarz