Состояние разных языков программирования на примере одной задачи
От: 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 — прямо таки "сделано с любовью".
Re: Состояние разных языков программирования на примере одно
От: Baiker  
Дата: 27.10.22 21:19
Оценка: 3 (1) +3 :)))
Здравствуйте, vsb, Вы писали:

vsb>У меня тут была задача...


Одна весьма специфичная задача, безалаберный JS, аутсайдерский Go, протухшая Жаба... какой-то Rosetta Code на минималках.

Вот задача QuickSort. На её (и других) примерах можно увидеть, сколько чудовищно дебильных, неэффективных и вычурных языков было придумано! Все языки, у которых реализация заняла больше 10 строк, можно сразу нахер на помойку! (и Go туда же) Немерле и Ди закономерно порадовали. Джабба даже в функциональном стиле выглядит как многословное дерьмо. Создателю "К" хочется просто переломать руки. Котлин — молодец, намного лучше Жаббы. За Меркури надо сразу сжигать на костре.
Отредактировано 27.10.2022 21:49 Baiker . Предыдущая версия .
Re[2]: Состояние разных языков программирования на примере одно
От: SkyDance Земля  
Дата: 27.10.22 23:14
Оценка:
B>Вот задача QuickSort.

Ничуть не менее специфичная. В подавляющем большинстве случаев ее вообще решать не надо.

Сравнивать языки — дело бессмысленное и бесполезное.

Сравнивать можно фреймворки, и только в применении с конкретным задачам. Например, для стартапов, по-быстрому сделать легко масштабируемый прототип с веб-мордой — Phoenix (на Elixir).
Re[3]: Состояние разных языков программирования на примере одно
От: Baiker  
Дата: 28.10.22 10:56
Оценка:
Здравствуйте, SkyDance, Вы писали:

B>>Вот задача QuickSort.


SD>Ничуть не менее специфичная. В подавляющем большинстве случаев ее вообще решать не надо.


Тут есть одна тонкость — выразительные средства языка. Непосредственно сортировка — да, никто её не пишет. Но пишут другие алгоритмы, основанные на списках! А списки — вот в моих программах сплошь и рядом. Если в языке типа протухшего Фортрана надо писать 2 страницы перетасовок, то нахрен такого мамонта.

SD>Сравнивать языки — дело бессмысленное и бесполезное.


Ну почему же? Крайне интересное занятие! Ты же ВЫБИРАЛ язык, прежде чем стал на нём писать? Каждый проф.программист хотя бы десяток языков точно перебрал (у меня их более 20).

SD>Сравнивать можно фреймворки


Как дополнение к выразительным средствам — да. Например, Жабовский "фрэймворк" — это фэйспалм в квадрате. После него на .NET пишешь как песню!
Re: Состояние разных языков программирования на примере одной задачи
От: Michael7 Россия  
Дата: 28.10.22 12:22
Оценка:
Здравствуйте, vsb, Вы писали:

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


Было бы интересно еще узнать впечатление о C++ для этой задачи.
Re[4]: Состояние разных языков программирования на примере одно
От: Tai Казахстан  
Дата: 28.10.22 12:55
Оценка:
Здравствуйте, Baiker, Вы писали:

B>Ну почему же? Крайне интересное занятие! Ты же ВЫБИРАЛ язык, прежде чем стал на нём писать? Каждый проф.программист хотя бы десяток языков точно перебрал (у меня их более 20).


А зачем ты столько перебирал?
Re: Состояние разных языков программирования на примере одной задачи
От: Gt_  
Дата: 28.10.22 19:01
Оценка:
По жава
Each AWS SDK implements automatic retry logic. The AWS SDK for Java automatically retries requests, and you can configure the retry settings using the ClientConfiguration class. For example, you might want to turn off the retry logic for a web page that makes a request with minimal latency and no retries. Use the ClientConfiguration class and provide a maxErrorRetry value of 0 to turn off the retries.


Хочешь сказать вот такие примеры куда то в темп пишут?
https://gist.github.com/blagerweij/ad1dbb7ee2fff8bcffd372815ad310eb#file-s3outputstream-java
Re[2]: Состояние разных языков программирования на примере о
От: vsb Казахстан  
Дата: 28.10.22 19:15
Оценка:
Здравствуйте, Gt_, Вы писали:

Gt_>Хочешь сказать вот такие примеры куда то в темп пишут?

Gt_>https://gist.github.com/blagerweij/ad1dbb7ee2fff8bcffd372815ad310eb#file-s3outputstream-java

Это как раз то, о чём я говорил — реализация multipart upload руками. Этот код имеет следующие проблемы:

1. Он загружает данные в 1 поток. Если загружать данные параллельно хотя бы в 2 потока, на хорошей сети будет ощутимое повышение скорости.

2. Он загружает данные синхронно. Иными словами мы читаем данные, пишем в буфер и в какой-то момент на секунду программа останавливается, когда приходит время загрузить очередной кусок, хотя она могла бы в это время скачивать данные. Правильная реализация должна запускать загрузку очередного куска в фоне и сразу возвращать управление, давая писать дальше, по крайней мере если предыдущий кусок уже загрузился.

Правильная реализация должна по мере записи и накопления буферов запускать потоки или переиспользовать существующие с учетом настроенных ограничений и загружать куски в этих потоках, а потом всё остановить. И если произошла неисправимая ошибка — удалить все загруженные куски и сам объект multipart upload.

Такой класс, с учётом вышеперечисленных нюансов, должен быть в SDK из коробки.

Написать его, как положено, с тестами и код-ревью, можно, но это дело не одного дня, по крайней мере для меня.
Отредактировано 28.10.2022 19:20 vsb . Предыдущая версия . Еще …
Отредактировано 28.10.2022 19:20 vsb . Предыдущая версия .
Отредактировано 28.10.2022 19:18 vsb . Предыдущая версия .
Re[3]: Состояние разных языков программирования на примере о
От: Pyromancer  
Дата: 28.10.22 19:28
Оценка: +1
Здравствуйте, vsb, Вы писали:

vsb>Такой класс, с учётом вышеперечисленных нюансов, должен быть в SDK из коробки.


Наивняк, AWS SDK в любом языке своей реализации простая и тупая обёртка поверх их же API.
Можешь не использовать SDK, а слать POST https://{{service}}.{{region}}.amazonaws.com с именем API в хедере X-Amz-Target. Вычисление подписи, а также формирование этого запроса, это всё что делает их SDK.
Re[3]: Состояние разных языков программирования на примере о
От: Gt_  
Дата: 28.10.22 19:53
Оценка:
vsb>Это как раз то, о чём я говорил — реализация multipart upload руками.

не, ты какую-то чушь написал про ретраи и "что из сигнатур функций кажется, будто поток заливать можно и только копаясь в реализации можно увидеть, что они тупо сохраняют поток на диск во временный файл"

я aws не видел, потому не вьезжаю чего ты прицепился к low level api и что не так с
public class TransferManager
extends Object

High level utility for managing transfers to Amazon S3.

TransferManager provides a simple API for uploading content to Amazon S3, and makes extensive use of Amazon S3 multipart uploads to achieve enhanced throughput, performance and reliability.

When possible, TransferManager attempts to use multiple threads to upload multiple parts of a single upload at once. When dealing with large content sizes and high bandwidth, this can have a significant increase on throughput.

Update: и по моему у тебя на уровне идеи что-то не того, как ты стрим параллелить собрался ? на ходу это же один поток будет, который этот тар при твоей жизни и не закачает. тебе нудно локльно паковать, и грузить куски этого тара в параллель.
Отредактировано 28.10.2022 20:24 Gt_ . Предыдущая версия .
Re[4]: Состояние разных языков программирования на примере о
От: Gt_  
Дата: 28.10.22 19:57
Оценка:
vsb>>Такой класс, с учётом вышеперечисленных нюансов, должен быть в SDK из коробки.

P>Наивняк, AWS SDK в любом языке своей реализации простая и тупая обёртка поверх их же API.

P>Можешь не использовать SDK, а слать POST https://{{service}}.{{region}}.amazonaws.com с именем API в хедере X-Amz-Target. Вычисление подписи, а также формирование этого запроса, это всё что делает их SDK.

и что, этот http post разложит файл на блоки и начнет асинхронную загрузку ? что-то я сомневаюсь.
Re: Состояние разных языков программирования на примере одной задачи
От: Pzz Россия https://github.com/alexpevzner
Дата: 28.10.22 22:02
Оценка: 2 (1)
Здравствуйте, vsb, Вы писали:

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


Так, чисто для информации. .tar-овские файлы рожать легко. Особенно если нет нужды заморачиваться длинными именами.

Мой опенсорсный драйвер сканера, он в отладочном режиме картинки в .tar-файл складывает, на случай, если они мне понадобятся для каких-то разборок с картинками. Это было совсем не сложно сделать.

А Go, да, в нем экосистема шикарная. Каково же было мое удивление, когда в ней не оказалось библиотеки, реализующей IPP протокол (тот, который для принтера). Пришлось свою за два дня написать.
Re[4]: Состояние разных языков программирования на примере о
От: vsb Казахстан  
Дата: 28.10.22 22:33
Оценка:
Здравствуйте, Gt_, Вы писали:


vsb>>Это как раз то, о чём я говорил — реализация multipart upload руками.


Gt_>не, ты какую-то чушь написал про ретраи и "что из сигнатур функций кажется, будто поток заливать можно и только копаясь в реализации можно увидеть, что они тупо сохраняют поток на диск во временный файл"


И что конкретно тебе не понятно?

Gt_>я aws не видел, потому не вьезжаю чего ты прицепился к low level api и что не так с

Gt_>public class TransferManager
Gt_>extends Object

Gt_>High level utility for managing transfers to Amazon S3.


Gt_>TransferManager provides a simple API for uploading content to Amazon S3, and makes extensive use of Amazon S3 multipart uploads to achieve enhanced throughput, performance and reliability.


Gt_>When possible, TransferManager attempts to use multiple threads to upload multiple parts of a single upload at once. When dealing with large content sizes and high bandwidth, this can have a significant increase on throughput.


https://github.com/aws/aws-sdk-java/issues/1139
https://github.com/aws/aws-sdk-java-v2/issues/3128

Вот, даже не поленился и нашел место: https://github.com/aws/aws-sdk-java/blob/ab0f1bc28a6dc7dda434dc495ceb8dda007fa364/aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/AmazonS3Client.java#L1944

Насчёт sdkv2 полной уверенности нет, там какая-то мутная реактивщина, в которой без поллитра не разберешься, может там и заработает. Хотя issue висит, так что не факт.

Gt_>Update: и по моему у тебя на уровне идеи что-то не того, как ты стрим параллелить собрался ? на ходу это же один поток будет, который этот тар при твоей жизни и не закачает. тебе нудно локльно паковать, и грузить куски этого тара в параллель.


В чём проблема-то? Берёшь и параллелишь. Выдал тебе outputstream 5 мегабайт в буфер в оперативной памяти, ты начал закачку в отдельном потоке и дальше считываешь в следующий буфер. Следующий считался — начал ещё одну закачку. Следующий считался, приостановили выполнение, пока какой-нибудь поток не закончит загрузку (если предположить, что у нас степень параллельности = 2). Никакой необходимости локально сохранять всё нет. Только те куски, которые загружаются в настоящий момент.
Отредактировано 28.10.2022 22:55 vsb . Предыдущая версия .
Re[5]: Состояние разных языков программирования на примере о
От: Gt_  
Дата: 29.10.22 13:04
Оценка:
vsb>>>Это как раз то, о чём я говорил — реализация multipart upload руками.

Gt_>>не, ты какую-то чушь написал про ретраи и "что из сигнатур функций кажется, будто поток заливать можно и только копаясь в реализации можно увидеть, что они тупо сохраняют поток на диск во временный файл"


vsb>И что конкретно тебе не понятно?


не понятно зачем ты полез в low level api, если тебе сложно код читать. есть же TransferManager, либа высокого уровня.

vsb>Вот, даже не поленился и нашел место: https://github.com/aws/aws-sdk-java/blob/ab0f1bc28a6dc7dda434dc495ceb8dda007fa364/aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/AmazonS3Client.java#L1944


там нету записи на диск, все в памяти.
можешь внятно объяснить откуда темп файлы тебе чудятся ?
Re[4]: Состояние разных языков программирования на примере одно
От: SkyDance Земля  
Дата: 29.10.22 15:01
Оценка:
B>Тут есть одна тонкость — выразительные средства языка. Непосредственно сортировка — да, никто её не пишет. Но пишут другие алгоритмы, основанные на списках! А списки — вот в моих программах сплошь и рядом.

О, месье любитель LISP'а? Самый выразительный язык на эту тему (хотя другие функциональные тоже хороши).

B>Как дополнение к выразительным средствам — да. Например, Жабовский "фрэймворк" — это фэйспалм в квадрате. После него на .NET пишешь как песню!


Не дополнение, а самое главное. Именно фреймворки (их удобство, полнота и качество) определяют популярность языка.
Re: Состояние разных языков программирования на примере одной задачи
От: Буравчик Россия  
Дата: 30.10.22 10:41
Оценка: 2 (1)
Здравствуйте, vsb, Вы писали:

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


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


А самый полезный язык забыл...

Python:
— Есть библиотека для AWS
— Есть библиотека для tar
— Поддерживается Multipart Upload
— Легко делать обработку ошибок
— Легко параллелить (asyncio, threads, processes)
— Есть реализация bloom filter, в том числе быстрые (судя по заявлениям создателей)
Best regards, Буравчик
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.