Pull to refresh

Comments 46

И в чем же децентрализация, если достаточно погасить сигнальный сервер, чтобы все умерло?
Тут можно 100 сигнальных серверов поднять и гасить устанешь. Он же не несет никакой нагрузки, просто сводит отправителя и получателя.
Достаточно создать правило deny all и сделать whitelist как в Китае, чтобы все перестало работать.
Достаточно выйти в инет через GSM-свисток и все перестанет работать. UDP хорошо ходит в открытом инете, а вот «последняя миля» все портит. А так да, админ может легко все запретить.
Возможно в качестве таких серверов могут выступать клиенты, имеющие статический адрес. Но тут возникает другая проблема: как без сервера узнавать адреса таких клиентов? Вариантов вижу не много:
0) Зашитые в клиенте адреса;
1) Широкополосные запросы в локальных сетях;
2) Ссылки, получаемые по другим каналам (от знакомых например);
3) Перебор (полушутка);
Может быть ещё можно было бы выделить какое-то использование сторонних сервисов (независимо от их «согласия»).
Еще есть довольно разумный вариант с броадкастом по списку, хранящимся в публичном репозитории. Осталось только репозиторий как-нибудь хранить децентрелизовано, но это уже задача привычнее
Я бы добавил пункт номер -1: DHT сети. Чуть подробнее я о них писал в комментарии ниже.
А в дополнение к этому можно сделать открытый сервер анонсов, который может установить на свой сайт кто угодно. Этот сервер поддерживает стандартный URL вида mysite.com/announce.p2p или что-то вроде этого. Это просто json (возможно даже статический), где перечислены домены других таких же серверов, IP пиров, которые имеют белый адрес и часто онлайн (т.е. те, что с высоким рейтингом в сети). При самом первом входе в сеть нам нужен хотя бы один живой такой сервер анонсов. Дальше ссылки на сервера анонсов уже будут накапливаться клиентом, а в DHT будет таблица рейтинга серверов и нодов, чтобы сеть голосованием могла маркировать недобросовестные пиры и сервера анонсов.
Ну и, чтобы два раза не вставать, можно подумать как приспособить тут технологию blockchain.
На самом деле, для обнаружения узлов можно использовать открытые BitTorrent-трекеры и сеть Mainline DHT (которая основана на Kademlia). Тогда свой сервер анонсов писать не придётся. И клиент будет подключён к той же DHT-сети, что и торрент-клиенты (которых много), таким образом имея доступ к огромной хеш-таблице и, в свою очередь, помогая работе DHT.

Я для своего полностью распределённого приложения инкрементальной синхронизации файлов для service discovery использовал именно такой подход, работает замечательно.
Приложения написаны на Python версии 2.7, протестированы под Debian 7.7.


Какова причина такого выбора?
Модуль pystun под python 2.7. Если смущает Debian 7.7, то под 8.3 и Xubuntu 14.04 тоже работает.
Под Alt Linux 6.0, кстати, тоже работает.
Что-то мне подсказывает, что это не p2p в привычном понимании, а просто еще одна реализация режима direct, который давным давно уже был в мессенджерах. Могу ошибаться, но по-моему одна из реализаций icq-клиента подразумевала именно такой режим работы.
Тут еще неплохо бы вычислить MTU. UDP пакет может быть до 65536 байт, но как только он превышает IP пакет, то потери резко увеличиваются.
И через сотовые интернеты работать не будет, т.к. там потери UDP 80%+
Дельное замечание, спасибо!
Есть хитрый ход (вместо STUN сервера), тройной пинг, узел А шлет пакет на B, а B на A, как только узел А получил пакет от B, то можно сразу слать инфу, т.к. B готов к приему, маршруты на роутерах сформировались. Для ускорения установка связи в три шага, условно 3 пакета A-B-A с обоих сторон, тогда первый пробивший NAT максимально быстро установит двухстороннюю связь, т.е. НАТы будут готовы слать в обе стороны.
А СТУНы тут лишние, виндовый брандмауэр всего минуту ждет прежде чем входящие пакеты запретить. Т.е. если открываешь случайный порт, то у тебя минута чтобы получить на него ответ.
Это все работает при идеальных условиях, пока пакеты не теряются. Как начинают теряться тоже работает, но сложнее.
О, спасибо! Давным-давно нечто подобное было очень нужно для одной поделки, но по незнанию думал, что ничего подобного провернуть нельзя и даже гуглить в эту сторону не стал, а зря.
Советую что-нибудь почитать про маршрутизацию IP сетей. Опять же решение не идеальное, будет работать в 80-90% случаев. Если надо 100%, то без TCP не обойтись. Не любят UDP инет-провайдеры, отчасти из-за торрентов, отчасти из-за неуправляемости.
Можно и не друг-друга пинговать, а любой адрес, при этом A может не знать адреса B заранее. Скажем, A пингует 1.2.3.4 и не знает адреса B, а B, в свою очередь, знает адрес A, отправляет ему ICMP-пакет от своего адреса, что 1.2.3.4 недоступен, и все, NAT пробит.

Есть работающая реализация — pwnat.
Вы только что описали TURN реализацию

Она повсеместно используется если NAT закрыт, беда в том, что В приходится гонять кучу траффика через себя. В паблике TURN серверов почти нет.
Есть еще одна проблема: два клиента за одним роутером могут друг-друга не увидеть. Некоторые роутеры пускают пакеты изнутри-внутрь, а некоторые рубят. Поэтому тут локальные IP тоже надо использовать.
Вы ценный комментатор ), была бы карма, плюсанул бы!
Год бился об эту тему ))) не взлетело. Взял паузу. Точнее взлетело, но не на 100% как хотелось бы. GSM-свистки все испортили. Поэтому делюсь забегами по граблям, может кому поможет. Сейчас с мыслями собираюсь, время появится и пойду на второй забег, версия 2.0 )))
А так UDP — тема. В 100 Мбит сети одного провайдера выжимал 11 Мбайт/сек, в гигабитной локалке 86 Мбайт/сек.
UFO just landed and posted this here
Пакет был 1500 пакет езернета минус 20 заголовок IP, минус 8 заголовок UDP. Минус мой заголовок 16 байт. Замерял полезные данные (без заголовков). 140 гигабайт/сек это сетка 1200-1300 Гбит, завидую :)
UFO just landed and posted this here
143 гигабита в гигабитной сетке не может быть. Я так понимаю что гигабит это максимальная пропускная способность канала. Т.е. идеальная передача, когда канал нисколько не простаивает. Если данных для передачи будет больше, то они просто будут скапливаться на входе в очереди.
Если пакеты маленькие и их много, то тут возрастает нагрузка на свичи, т.к. они оперируют пакетами, т.е. им есть разница обработать 64 пакета по 1500 байт или 1500 пакетов по 64 байта, во втором случае работы больше и обычное домашнее железо может просто не успеть их обработать, отсюда будут простои канала в ожидании данных, т.е. скорость упадет ниже гигабита.
UFO just landed and posted this here
Я в локалке 100к+ ппс делал
Судя по цифрам, гоняли через loopback? :D
Раз у начал делиться, пишу все что было. Еще одни грабли от нехороших провайдеров: задержка пакетов до десятков секунд. Это тоже нездорово, т.к. считаешь пакет потерянным, а он приходит через полминуты-минуту, завис где-то в кэше. Одни провайдеры его просто убивают, а другие доставляют любой ценой.
Не хотите статью написать с подробностями о встреченных подводных камнях, думаю Хабрасообществу был-бы интересен такой опыт? На каком языке реализовывали задумки и каков конечный результат?
Как будет результат — тогда и напишу. А пока просто опыт неудачника. Не думаю что он кому-то интересен.
Очень даже интересен! Тоже хочу аналог TCP сделать, опыта набираюсь потихоньку. Интересуют любые подробности про подводные камни. Про 80% потерь на GSM я и не подозревал…
Язык С. Результат не очень. Повторить TCP не удалось. Задача была: direct-доставка сообщений любого размера. Решил проблемы на 90%, надо 100%.
Мы экспериментальным путём обнаружили немного другое. После определённого периода (секунд 10-20) неиспользования канала данных, канал разрывается оператором где-то на нижнем (канальном?) уровне; при этом высшие уровни не информируются. Т.е. если было поднято TCP соединение, оно так и останется поднятым и неразорванным. При дальнейшей попытке использования канал восстанавливается (опять же, без сигнализации), на что уходит 5-10 секунд. То есть на уровне TCP, если передавать часто — отклик очень быстрый, но стоит немного задержаться — и получаем огромный лаг. Опять же, нет никакой гарантии, что восстановить канал удастся. В общем выходит так, что ориентироваться на сигнализацию в TCP нельзя, и быть уверенным в передаче, если соединение установилось — тоже нельзя; только ACK на уровне приложения!
Я почти уверен, что большинство мобильных сетей ведут себя подобным образом; различаются детали (период ожидания до разъединения и т.п.). Просто они же так экономят критический ресурс — ёмкость соты.
Про UDP, к сожалению, не знаю, но что-то мне подсказывает, что поведение может быть похожим: пока канал поднят, UDP будет пролетать; чуть задержались — UDP или будет теряться, или, как вы пишете, буферизоваться где-то в том месте, где управляется состояние канала.
В GSM просто терялись UDP пакеты. Главная проблема кстати и были эти провалы. То связь есть, долетает относительно быстро и вдруг раз и встало все от секунд до десятков секунд, и никак под это не подстроишься, не предскажешь, не продиагностируешь быстро, нет какой-то стабильной последовательности. Есть подозрение что там просто под TCP приоритеты выставлены, т.к. потери IP пакетов от TCP соединения гарантированно вызовут повторные отправки что еще больше забьет канал. Во-вторых по UDP идут в основном торренты да скайпы всякие, что сотовым не особо и надо. TeamViewer тоже очень плохо работает, т.к. тоже UDP.

Запаздывание пакетов я наблюдал не в GSM, а на входе в ЦОД, где хостилась моя виртуалка с сервером. Тут кстати UDP тоже быстрее работает, т.к. TCP зажимается провайдером и при заявленном интерфейсе 100 Мбит реально одно TCP соединение дает 10-30, UDP немного побольше, но далеко не 100.
И еще, в одном провайдере не проходил пакет с конкретными данными. Просто не проходил сколько не посылай. Как подсказали, оказалось первые 8 байт совпали с торрентами, провайдер просто рубил установку соединения между пирами. Т.е. тупо рубилось по сигнатуре. Не любят провайдеры UDP, там где не любят надо туннелировать в TCP.
Я и с TCP наступал на похожее, только не у провайдера, а на MS TMG (мётрвая штука, но всё же вполне допустимый прецендент). Один абстрактный пакет данных не проходит вообще. Оказалось, совпал с сигнатурой какого-то вируса в его базе данных.
Мутная тема, сложная, всё хочу добраться до неё, да всё никак. Автор молодец, полезное дело.
Интересная тема, я тоже написал чат работающий примерно по такой схеме.
Правда без STUN сервера, у меня публичный сервер и его функции выполняет. Связь клиент-сервер сделана по TCP, а клиент-клиент по UDP.
Исходники, кстати, в открытом доступе: GitHub
А вы не думали использовать DHT вместо сигнальных серверов? Там можно распределенно держать как таблицу пользовательских профилей, так и сигналы (приглашения) на соединение.
В двух словах DHT можно представить как распределенное key-value хранилище, Только ключи упорядоченны, хотя и рандомны, а пирам присвоены ключи из того же пространства. Зная несколько произвольных пиров (поддерживая с ними коннекты), всегда можно понять какие из них «ближе» к искомому ключу. Делается запрос именно на эти пиры и, если они сами не знают значения, они делятся контактами с теми своими «знакомыми» пирами, которые в свою очередь ещё «ближе» к вашей цели. Таким образом по принципу «теории 6 рукопожатий» мы очень быстро выходим на пир с самым «ближайшим» адресом к искомому ключу. Если этот пир не знает значения, то никто не знает или просто все кто знают оффлайн и нужно ждать. Пиры хранят не только свои значения, но и ближайшие. Обычно у пиров есть лимит на хранение данных, скажем 100мб, и они складывают туда все ближайшие пары ключ-значение, что влезут в ограничение.
Это основа. На ней реализованы реально работающие сети и можно ими пользоваться для хранения данных о контактах.
DHT не использовалась, т.к. в формулировке задачи был указан именно сигнальный сервер.
Идея распределённых хеш-таблиц в децентрализованных распределённых системах — хорошая, с точки зрения доступности информации. Но нужно учитывать среднее время получения ключа по значению при поиске подходящего пира, с учетом времени, в течении которого нужный порт абонента, с которым хочу связаться, открыт. Исходя из комментариев коллег, полученные опытным путем данные говорят, что это время составляет всего десятки секунд.
На сигнальном сервере информация всегда актуальна, т.к. обновляется в заданные промежутки времени запросами от клиентов (при необходимости можно поднять несколько сигнальных серверов, между которыми реплицировать обновляемые данные, а если один из основных сигнальных серверов гаснет, клиент связывается с другим доступным).
Как быстро данные будут обновляться от пира к пиру, как быстро нужное значение может быть найдено?
Не буду строить из себя эксперта, ни разу ещё не экспериментировал с этой штукой. Однако мне кажется информация по DHT может ходить не так уж и медленно. Если коннекты с соседями у каждого онлайн-пира установлены и поддерживаются постоянно, то длительность передачи пакета по такой сети будет примерно равно удвоенному логарифму от объёма сети, умноженному на время передачи пакета по уже поднятому коннекту. Ну то есть не десятки секунд. Да, наврено при малом объёме сети и низкой связности вся эта схема будет работать нестабильно, но в штатном режиме при некоторой степени избыточности в построении маршрутов (посылать запросы не ближайшему к цели соседу, а нескольким ближайшим) всё должно быть нормально… по крайней мере я не вижу явных проблем.
Ктсати, следует ранжирвать «соседних» пиров не только по их «ключевому расстоянию», но и по их субъективному рейтингу, расчитываемому на основе пинга и прочих показателей стабильности канала до них.
Тоже далеко не эксперт, а Ваша идея интересная и требует своего кропотливого исследователя.
Делал подобные вещи и для C# даже написал велосипедную библиотеку для этого всего.
Если знать нюансы которые описаны в wikipedia большинство и вдобавок посмотреть практическую часть,
то ничего сложного нет. И в понимании NAT, STUN, MTU и прочих вещей.
Вот если что библиотека. Может кому интересно. Кода там мало, он как по мне читабельный и подойдет если не хочется писать велоспиеды.
github.com/RevenantX/LiteNetLib
Sign up to leave a comment.

Articles