Состояние разных языков программирования на примере одной задачи
От: vsb Казахстан  
Дата: 27.10.22 20:53
Оценка: 5 (3) +1
У меня тут была задача, решая которую я невольно познакомился с некоторыми нюансами некоторых языков программирования (а точней их экосистемы) и подумал, что этим интересно поделиться.

Итак задача. Имеется S3-совместимое хранилище. В нём лежат объекты (файлы). Нужно эти объекты заархивировать в tar-архив и залить в другое S3 хранилище. При повтором вызове заархивировать новые файлы и так далее.

Какие нюансы тут нужно учесть:

1. Для работы с S3 используется Amazon AWS SDK.

2. Весь алгоритм на 100% поточный. Т.е. нет нужды, например, собирать этот tar-архив на локальном диске для последующей загрузки. Нужно делать запрос в первое хранилище, по мере вычитывания объекта (файла) записывать его в поток tar (это поточный формат) и отправлять в конечное хранилище.

3. У нас неизвестен размер получившегося файла. В S3 есть два способа загрузки файлов: обычный (PUT) и Multipart Upload. При обычном способе необходимо указать размер файла заранее. Также его нельзя перезапустить в середине, только сначала. Multipart Upload это загрузка файла кусками по 5+ MB. Размер каждого куска надо указывать, но число самих кусков указывать не надо.

4. Для хорошей производительности нужно использовать многопоточную загрузку и перезапускать загрузку отдельных кусков в случае ошибок.

5. Т.к. объектов в хранилище может быть очень много, строить в памяти список загруженных объектов может быть дорого по памяти. К примеру длина имени 20 символов, 10 миллионов объектов, выходит уже 200 мегабайтов и это если всё хранится с нулевым оверхедом, а где он нулевой? Тут хорошо подходит bloom filter — вероятностная структура данных, которая занимает в разы меньше памяти, но даёт ответ с некоторой вероятностью. Иными словами в наших новых архивах какой-то процент файлов будет повторяться. Это приемлемо. Это всё к тому, что нужна реализация этого bloom filter.

Я рассматривал языки JavaScript (node.js), Java и Golang.

AWS SDK есть для всех.

Поддержка формата tar у JS плохая. Какая-то малоизвестная библиотека, у которой к тому же ограничения на максимальный размер файла. А уж какое сложное у этой библиотеки API. Разобраться в нём мне было непросто.

В дефолтном AWS SDK поддержка multipart upload сделана на уровне примитивов. То бишь предполагается, что ты сам будешь загружать каждый кусок. Для JS есть библиотека от AWS под названием lib-storage. Она реализует это всё как положено, т.е. даёт тебе stream, ты туда пишешь данные, она их буферизует кусками нужного размера и загружает эти куски нужным числом потоков, повторяя при ошибках и тд. Сразу скажу, что библиотека глючноватая и пришлось обходить один баг.

Реализация bloom filter есть, но мне не понравилась, я свою написал, но в принципе это просто. Хотя их там штук 20 вылезло в поиске, я только самую популярную посмотрел.

Итого из проблем: глючноватая библиотека lib-storage, плохая поддержка tar, не понравилась библиотека с bloom-filter (это субъективно).

Java: возможности заливать поток тупо нет. Я реализовал это сам, но только в один поток без повторов. Реализовывать полноценно — это сложная задача. Я бы справился, но не захотел. Самое противное, что из сигнатур функций кажется, будто поток заливать можно и только копаясь в реализации можно увидеть, что они тупо сохраняют поток на диск во временный файл и заливают его в конце. Свинство какое-то. Поддержка tar вроде неплохая (apache commons). Поддержка bloom filter тоже нормальная в какой-то библиотеке, кажется тоже commons.

Интереса ради немного посмотрел на Go и был очень приятно удивлён.

Поддержка поточной загрузки в SDK без всяких доп библиотек и сделана на отлично.

Поддержка tar в стандартной библиотеке. Шикарная документация, поддерживаются три разновидности (tar это не один формат, а несколько под одним именем).

Реализация bloom filter в сторонней библиотеке, мне понравилась, написана приемлемо.

Итого: используя Go все нужные шестеренки есть, просто решаешь задачу не отвлекаясь. Ни одной претензии у меня в итоге не возникло. Используя другие языки приходится изобретать велосипеды, копаться в багтерекерах, неприятно.

Вообще у меня сложилось впечатление, что мой опыт отражает некое общее состояние экосистемы этих языков. JS — 20 библиотек на любой запрос, но все — плохие. Java — на старьё библиотеки есть и хорошие, на современные требования библиотеки уже по остаточному принципу, типа кому надо — допишут. Go — прямо таки "сделано с любовью".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.