LINUX.ORG.RU

Наиболее эффективный способ передачи файлов по сети.

 , , , ,


1

4

Пишем сетевую файловую систему над FUSE, задача предполагает передачу кучи маленьких файлов (до 10кб) с сервера на клиент и обратно + агрессивное кэширование (без синхронизации с сервером, клиент блокирует любые операции на запись используемых файлов на время работы).
Пытаюсь принять решение касательно протокола передачи, возникла пара вопросов:
1. Как эффективнее передавать данные: по TCP с потерями на контроль доставки или по UDP без попакетного контроля (контролировать чексуммами блоков большого размера, например)?
2. Утилизует ли TCP-поток всю ширину канала? Будет ли выигрыш от приема/передачи через N соединений по количеству ядер процессора?

И касательно FUSE: 3. Можно ли его научить работать асинхронно тогда, когда это возможно?
Последовательное чтение метаданных в директориях с кучей файлов — это боль.

Как эффективнее передавать данные: по TCP с потерями на контроль доставки или по UDP без попакетного контроля (контролировать чексуммами блоков большого размера, например)?

Ну, по скорости и трафику udp эффективнее. Однако ненадёжно. Если файлы маленькие, то чексумм недостаточно, т. к. маленький файл, попадающий в 1 пакет, может просто не дойти, и никто об этом не узнает — ни отправитель, ни получатель. А большие файлы, занимающие несколько пакетов, надо упорядочить, т. е. по сути создать свой доморощенный TCP поверх UDP. А оно надо? И будет ли оно эффективнее? Сомневаюсь.

aureliano15 ★★ ()

fuse
эффективный

anonymous ()
Ответ на: комментарий от aureliano15

А большие файлы, занимающие несколько пакетов, надо упорядочить, т. е. по сути создать свой доморощенный TCP поверх UDP.

Единственно, если большинство файлов помещаются в один пакет, то для больших можно создавать tcp соединение, а маленькие (умещающиеся в пакет) отправлять по udp с контрольной суммой в том же пакете, но обязательно с подтверждением. Возможно, такой вариант будет эффективнее за счёт того, что не будет устанавливаться соединение, и в случае, если процент таких маленьких файлов действительно велик. Но это надо тестировать.

aureliano15 ★★ ()

Как эффективнее передавать данные: по TCP с потерями на контроль доставки или по UDP без попакетного контроля (контролировать чексуммами блоков большого размера, например)?

Учитывая, что задача - передача файлов - подразумевает основным критерием надёжность доставки, я бы выбрал TCP, который это обеспечивает «по определению». При хорошем канале и больших пакетах данных влияние служебки будет относительно невелико, а затраты на разработку и тестирование снизятся значительно. Потому что иначе, как уже сказал aureliano15, всё равно придётся городить «свой доморощенный TCP поверх UDP».

Утилизует ли TCP-поток всю ширину канала? Будет ли выигрыш от приема/передачи через N соединений по количеству ядер процессора?

На вашем месте, я бы просто протестировал. Один и два потока, например, на большом объёме данных.

Как вариант, учитывая, что система всё равно новая, посмотрите на протоколы SCTP и DCCP. Возможно, какой-то из них подойдёт вам больше.

Rakshas ()

ну конечно лучше вопрошать на ЛОРе чем взять скажем NFS и почитать доки/рассылки/код. т.е. то, где все эти вопросы в каком-либо виде скорее всего поднимались уже 100 раз за пару десятков лет. уж TCP vs UDP точно.

mos ★★☆☆☆ ()

по TCP с потерями на контроль доставки

почему с потерями контроля доставки ?
получил файл, отправь подтверждение и\или контрольную сумму и\или ошибку

x905 ★★★★★ ()

С фусе проще будет контролировать/кешировать. Это имхо.

а вот из TCP/UDP я б выбрал TCP, просто чтоб не писать контроль последовательности/доставки и много еще чего. Не думаю, что на UDP ты сильно больше в скорость выиграешь со всеми этими самописными контролями.

Можно ли его научить работать асинхронно тогда, когда это возможно?

Хм. А у него разве на каждый клиент не свой поток открывается?

или ты про то, что пока он не обшакалит директорию, не возвращает вызов? Ну есть такое. Но у тебя же кеширование.

Постинг заблокирован: 4.3 Провокация flame

заепало.

anonymous ()
Ответ на: комментарий от x905

А если файл больше MTU, скажем, стомегабайтный, и контрольная сумма не сошлась, то переотправлять весь файл заново? Нет, это глупо. Надо, наверное, отправлять файл по кусочкам и подтверждать каждый из них отдельно. Ой, мы получили TCP.

ilammy ★★★ ()
Ответ на: комментарий от ilammy

Ой, мы получили TCP.

только при tcp программа вообще не знает об успехе приема файла на той стороне
поэтому и нужен ответ пользовательского уровня на весь файл (если они мелкие как по задаче) или на каждый кусочек как торренты uTP

x905 ★★★★★ ()
Ответ на: комментарий от Rakshas

При хорошем канале

Это проблема. Работать оно будет в 2/3G сетях с херовым каналом.

SCTP и DCCP

Спасибо, будем посмотреть

mersinvald ★★★★★ ()

для начальной передачи tar.xz

anonymous ()
Ответ на: комментарий от x905

только при tcp программа вообще не знает об успехе приема файла на той стороне

поэтому и нужен ответ пользовательского уровня на весь файл (если они мелкие как по задаче) или на каждый кусочек как торренты uTP

А зачем программе об этом знать, если полный контроль реализован на уровне протокола: и ответы о доставке с повторной отправкой в случае чего, и контрольные суммы, и отброс дублирующихся пакетов, и упорядочивание пакетов и т. д.

Единственные неувязки, которые могут возникнуть на уровне пользовательского софта, это

1. Досрочный разрыв или сброс соединения, но софт об этом узнает и сможет повторно установить соединение и отправить файл (правда файл снова придётся отправлять целиком, поэтому если такие разрывы часты, то лучше предусмотреть докачку, для чего действительно нужна доп. информация на уровне пользовательского софта).

2. В QNX 4 я однажды сталкивался с ситуацией, когда tcp-соединения не завершались, а просто подвисали. Было это давно, но нельзя исключать, что подобное возможно и теперь. Бороться с такой проблемой тоже несложно. Надо просто запускать каждое соединение в отдельном процессе и мониторить, как долго оно висит (с учётом объёма передаваемых данных), в случае чего прибивая и перезапуская. Думаю, что-то подобное можно организовать и на уровне потоков (если из соображений эффективности не хочется плодить тяжёлые процессы). Поток, конечно, просто так не прибьёшь, но если он заблокировался, его можно вывести из этого состояния определённым сигналом, по получении которого поток будет корректно завершаться.

aureliano15 ★★ ()
Ответ на: комментарий от mersinvald

Это проблема. Работать оно будет в 2/3G сетях с херовым каналом.

Тогда тем более TCP в несколько потоков (или даже всё-таки SCTP). Оно хотя бы будет в таких условиях работать. Но, как сказал всё тот же aureliano15, надо подумать о возможности докачки - на совсем фиговом канале соединение рваться может.

В общем, лучше прикрутить докачку на уровне приложений (благо задача уже отработана на многих download manager), чем навёртывать слои проверок над UDP.

Rakshas ()
Ответ на: комментарий от aureliano15

А зачем программе об этом знать, если полный контроль реализован на уровне протокола

программой пользуется человек, ему необходимо знать о доставке сообщения (файла и т.п.) на другой конец, а tcp об этом ничего не скажет вообще и никогда

Надо просто запускать каждое соединение в отдельном процессе и мониторить

вреднее совета придумать сложно

x905 ★★★★★ ()
Ответ на: комментарий от x905

А зачем программе об этом знать, если полный контроль реализован на уровне протокола

программой пользуется человек, ему необходимо знать о доставке сообщения

Так если всё успешно завершилось, то я уже знаю об этом. Это как с бумажными письмами. UDP по такой аналогии можно сравнить с обычным письмом: я смогу точно узнать, что получатель его получил, только получив ответ от него. А есть заказное письмо — это TCP — уведомление о доставке я получаю от почты (на уровне протокола), и никакие дополнительные подтверждения мне не нужны. А работает это так:

Случай 1 Местный клиент инициирует закрытие

В этом случае создается сегмент с сигналом FIN и помещается в очередь сегментов, ждущих отправления. После этого программа TCP уже не будет принимать от этого клиента каких-либо команд на отправление данных по закрытому соединению, а сама переходит в со стояние FIN-WAIT-1. Тем не менее, в этом состоянии еще возможно получение клиентом данных с этого соединения. Все сегменты, стоящие в очереди, и сам сегмент с сигналом FIN будут в случае необходимости посылаться напарнику вновь и вновь, пока не получат своего подтверждения. .

Когда программа TCP партнера подтвердит получение сигнала FIN, и сама отправит сюда свой сигнал FIN, местная программа может подтвердить получение последнего. Заметим, что программа TCP, получающая сигнал FIN, будет подтверждать его, но не будет посылать своего собственного сигнала FIN до тех пор, пока ее клиент тоже не закроет соединения.

( подробнее см. http://cdo.bseu.by/library/ibs1/net_l/tcp_ip/transp/close.htm ).

Т. е. на стороне отправителя я отправил файл и закрыл соединение, но протокол продолжит посылать пакеты, пока получатель не получит всё, и только потом передаст ему сигнал FIN. Если же связь в этот момент неожиданно разорвётся, получатель просто не получит FIN, подождёт в течение заданного тайм-аута, и запросит файл снова. Никаких неоднозначностей нет, и никакие дополнительные данные поверх протокола не нужны, если мы не рассматриваем вариант докачки.

Надо просто запускать каждое соединение в отдельном процессе и мониторить

вреднее совета придумать сложно

Какого совета? О запуске отдельных процессов или мониторинга?

Если речь о процессах, то я и о потоках упомянул, и это общепринятая практика. И у каждого подхода есть свои достоинства и недостатки. Если важна высокая надёжность в ущерб производительности, то лучше использовать процессы. Если же нужна производительность в ущерб надёжности, то лучше потоки.

Если же речь о мониторинге, то я согласен с тем, что это костыль. Но в данном случае речь идёт о нейтрализации багов в самой реализации tcp, когда соединение в случае ошибки не разрывается по тайм-ауту, а намертво засыпает. Скорее всего этого не будет, но если вдруг, то есть такой способ. Да, костыль, но что в такой ситуации можно предложить ещё? Я упомянул об этом только потому, что сам когда-то с подобным сталкивался.

aureliano15 ★★ ()
Ответ на: комментарий от aureliano15

А есть заказное письмо — это TCP — уведомление о доставке я получаю от почты (на уровне протокола)

не получит _отправляющая_ прикладная программа никакого уведомления от протокола tcp

получатель просто не получит FIN, подождёт в течение заданного тайм-аута, и запросит файл снова

тут уже получается хоть какой то протокол есть - «запрос ответ»

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

Какого совета? О запуске отдельных процессов или мониторинга?

о запуске потока на каждое соединение
1000 конектов и 1000 потоков - вся система станет колом
но просто 1000 конектов - вполне ок
как пример теже торренты

а вот мониторинг как раз и нужен, удобнее свои таймауты иметь и не полагаться на tcp

x905 ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.