Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення

Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення

Шановна спільнота, ця стаття буде присвячена ефективному збереженню та видачу сотень мільйонів маленьких файлів. На даному етапі пропонується кінцеве рішення для POSIX сумісних файлових систем з повноцінною підтримкою блокувань, у тому числі кластерних, і начебто навіть без милиць.

Тому для цієї мети я написав свій спеціалізований сервер.
Під час реалізації цього завдання вдалося вирішити основну проблему, принагідно домогтися економії дискового простору та оперативної пам'яті, яку нещадно споживала наша кластерна файлова система. Власне така кількість файлів шкідлива для будь-якої кластерної файлової системи.

Ідея така:

Простими словами, через сервер заливають дрібні файли, вони зберігаються безпосередньо в архів, і зчитуються з нього, а великі файли кладуться поруч. Схема: 1 папка = 1 архів, разом маємо кілька мільйонів архівів з дрібними файлами, а чи не кілька сотень мільйонів файлів. І все це реалізовано повноцінно, без будь-яких скриптів та розкладання файлів по tar/zip архівам.

Постараюся викласти коротше, заздалегідь вибачаюсь, якщо піст буде ємним.

Почалося все з того, що я не зміг знайти відповідного сервера у світі, який міг би зберігати дані, отримані через протокол HTTP безпосередньо в архіви, так щоб не було недоліків властивих звичайним архівам та об'єктним сховищам. А причиною пошуків став розрісся до великих масштабів Origin кластер з 10 серверів, в якому зібралося вже 250,000,000 дрібних файлів, а тенденція зростання і не збиралася припинятися.

Тим, хто читати статті не любить і невелика документація простіше:

сюди и сюди.

І docker заразом, зараз є варіант тільки разом з nginx всередині про всяк випадок:

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

Далі:

Якщо файлів дуже багато, необхідні значні ресурси, причому найприкріше, частина їх зникає марно. Наприклад, під час використання кластерної файлової системи (в даному випадку — MooseFS) файл, незалежно від фактичного розміру, займає щонайменше 64 KB. Тобто для файлів розміром 3, 10 або 30 КБ на диску потрібно по 64 КБ. Якщо файли чверть мільярда, ми втрачаємо від 2 до 10 терабайт. До нескінченності створювати нові файли не вдасться, тому що в тій же MooseFS є обмеження: не більше 1 мільярда за однієї репліки кожного файлу.

У міру збільшення кількості файлів потрібно багато оперативної пам'яті для метаданих. Також часті великі дампи метаданих сприяють зносу SSD-накопичувачів.

Сервер WZD. Наводимо лад на дисках.

Сервер написано мовою Go. Насамперед мені потрібно було зменшити кількість файлів. Як це зробити? За рахунок архівування, але в даному випадку без компресії, так як у мене файли це суцільні стислі картинки. На допомогу прийшла BoltDB, яку довелося позбавляти недоліків, це відображено в документації.

Разом замість чверті мільярда файлів у моєму випадку залишилося лише 10 мільйонів архівів Bolt. Якби я мала можливість змінити поточну структуру наповнення файлами директорій, то можна було б скоротити приблизно і до 1 мільйона файлів.

Всі дрібні файли упаковуються в Bolt архіви, що автоматично отримують імена директорій, в яких вони лежать, а всі великі файли залишаються поряд з архівами, їх немає сенсу упаковувати, це настроюється. Маленькі – архівуємо, великі – залишаємо без змін. Сервер працює прозоро і з тими, і з іншими.

Архітектура та особливості сервера wZD.

Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення

Сервер функціонує під керуванням операційних систем Linux, BSD, Solaris та OSX. Я тестував лише для архітектури AMD64 під Linux, але він повинен підійти і для ARM64, PPC64, MIPS64.

Основні фішки:

  • Багатопотоковість;
  • Мультисерверність, що забезпечує відмовостійкість та збалансованість навантаження;
  • Максимальна прозорість для користувача чи розробника;
  • Підтримувані HTTP-методи: GET, HEAD, PUT та DELETE;
  • Управління поведінкою під час читання та запису через клієнтські заголовки;
  • Підтримка гнучко настроюваних віртуальних хостів;
  • Підтримка CRC цілісності даних під час запису/читання;
  • Напівдинамічні буфери для мінімального споживання пам'яті та оптимального налаштування мережної продуктивності;
  • Відкладена компакція даних;
  • На додаток пропонується багатопотоковий архіватор wZA для міграції файлів без зупинки сервісу.

Реальний досвід:

Я розробляв і тестував сервер і архіватор на живих даних досить довгий час, зараз він успішно функціонує на кластері, що включає 250,000,000 дрібних файлів (картинок), розміщених у 15,000,000 директорій на окремих SATA-дисках. Кластер з 10 серверів є Origin-сервер, встановлений за CDN-мережею. Для його обслуговування використовується 2 сервери Nginx + 2 сервери wZD.

Тим, хто вирішить використовувати цей сервер, має сенс перед використанням спланувати структуру директорій, якщо це можна застосувати. Відразу зазначу, що сервер не призначений для того, щоб все запхати в 1 Bolt архів.

Тестування продуктивності:

Чим менший розмір заархівованого файлу, тим швидше виконуються з ним операції GET та PUT. Порівняємо повний час запису HTTP клієнтом у звичайні файли та в Bolt архіви, і так само читання. Порівняється робота з файлами розміром 32 KB, 256 KB, 1024 KB, 4096 KB та 32768 KB.

Працюючи з Bolt архівами перевіряється цілісність даних кожного файлу (використовується CRC), до запису і як і після запису відбувається зчитування на льоту і перерахунок, це природно вносить затримки, але головне — безпеку даних.

Тести продуктивності я проводив на SSD-накопичувачах, тому що на SATA-дисках тести не показують чіткої різниці.

Графіки за результатами тестування:

Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення
Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення

Як видно, для невеликих файлів різниця в часі читання та запису між архівованими та не заархівованими файлами невелика.

Зовсім іншу картину вже отримаємо при тестуванні читання та запису файлів розміром 32 MB:

Ефективне зберігання сотень мільйонів дрібних файлів. Self-Hosted рішення

Різниця у часі між читанням файлів – у межах 5-25 мс. Із записом справи гірші, різниця становить близько 150 мс. Але в даному випадку і не потрібно заливати великі файли, в цьому немає сенсу, вони можуть жити окремо від архівів.

*Технічно можна використовувати даний сервер і для завдань, які потребують NoSQL.

Основні методи роботи з сервером wZD:

Завантаження звичайного файлу:

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

Завантаження файлу в Bolt архів (якщо не перевищено серверний параметр fmaxsize, що визначає максимальний розмір файлу, який може бути включений до архіву, якщо ж перевищений, то файл завантажиться як зазвичай поряд з архівом):

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

Завантаження файлу (якщо на диску і в архіві є файли з однаковими іменами, то при завантаженні пріоритет за замовчуванням надається не заархівованого файлу):

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

Завантаження файлу з архіву Bolt (примусово):

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

Опис інших методів є у документації.

Документація wZD
Документація wZA

Сервер поки що підтримує лише протокол HTTP, з HTTPS поки що не працює. Також не підтримується метод POST (ще не вирішено чи потрібен він чи ні).

Хто покопається у вихідному коді, виявить там іриску, її не всі люблять, але я не прив'язував основний код до функцій веб фреймворку, крім обробника переривань, так що надалі можу швидко переписати майже на будь-який двигун.

ToDo:

  • Розробка власного реплікатора та дистриб'ютора + гео для можливості використання у великих системах без кластерних ФС (Все по дорослому)
  • Можливість повного реверсивного відновлення метаданих за їх повної втрати (у разі використання дистриб'ютора)
  • Нативний протокол для можливості використання постійних мережних з'єднань та драйвери до різних мов програмування
  • Розширені можливості використання NoSQL складової
  • Компресії різних типів (gzip, zstd, snappy) для файлів або значень всередині архівів Bolt і для звичайних файлів
  • Шифрування різних типів для файлів або значень всередині архівів Bolt і для звичайних файлів
  • Відкладена серверна відео конвертація, у тому числі і на GPU

У мене все, сподіваюся цей сервер комусь знадобиться, ліцензія BSD-3, копірайт подвійний, так як не було б компанії, де я працюю, не написав би і сервер. Розробник я в однині. Буду вдячний за знайдені баги та фіч реквести.

Джерело: habr.com

Додати коментар або відгук