Спасибо большое! На счет полнодуплексности еще нужно поработать, не смотря на то что отправка сегментов идёт с двух сторон, на данном этапе протокол не позволяет клиенту отправлять полезную нагрузку, но это поправимо и я обязательно сделаю это
Спасибо за такой прекрасный комментарий! За «кадром» я проводил сравнение с TCP, но почему-то забыл об этом упомянуть в статье. Результаты оказались плачевными. Если мои измерения не ошибочны, то мой протокол медленнее TCP Cubic примерно в 100 раз. Предполагаю что дело как раз в отсутствии congestion control и юзерспейсе (постоянные системные вызовы, в то время как TCP работает напрямую в ядре линукс). Сам контроль перегрузки я планирую реализовывать дальше, и рассказать об этом в следующей части которую напишу как только реализую новые механизмы + подготовлю бенчмарки для сравнения с TCP
Еще меня очень зацепила ваша мысль про то насколько сильно мы привязаны к TCP/UDP. Я тоже об этом задумывался и по факту в нынешних реалиях многие нововведения которые семантически относятся к транспортному уровню, но по какой-то причине не могут быть добавлены в TCP - вынуждены выносить на прикладной уровень. На мой взгляд это сильно размывает сами уровни TCP/IP и усложняет всё. Честно говоря, я даже не представляю как эту проблему в теории можно было бы решить :(
В процессе работы над этим проектом меня не раз просили сделать что-то наподобие VPN-протокола. Тема конечно интересная, но я не вижу особого смысла в этом, и как мне кажется фундамент этого протокола не очень хорошо подходит для VPN
Спасибо большое! Я думал над тем чтобы сделать на голом сокете, но решил всё таки не усложнять себе жизнь. Хотелось чтобы работало без рута, ну и плюсом получилось избежать возни с айпи и портами, как я писал в статье: айпи и порт отправителя я беру из заголовка UDP
К сожалению, вы немного упустили суть и контекст статьи :)
Кхм, позвольте изъяснить:
Это не прикладная задача для продакшена, это исследовательский/учебный проект. Цель не «передать файл любой ценой», а с нуля руками реализовать фундаментальную надежную доставку и изучить архитектуру транспортного уровня (ровно по тому же пути идут в курсе CS144 Стэнфорда или при разработке протоколов вроде QUIC и KCP)
Никакой TCP-сокет никуда не оборачивается: Протокол использует только сырые UPD-датаграммы и сам реализует логику отслеживания состояния
Насчет «увеличить размер чанка, чтобы потери были реже»: К сожалению, это заблуждение. В реальной сети размер полезной нагрузки жестко ограничен размером MTU (обычно 1500 байт на Ethernet). Если сделать чанк больше, то айпи уровень порежет сегмент на несколько фрагментов. Потеря любого этого фрагмента приводит к потере всего сегмента целиком. То есть увеличение размера чанка не снижает потери, а гарантированно их увеличивает
Насчет избыточности: Прямое исправление ошибок работает только при относительно небольших потерях и требует отправки огрлмного объема избыточных данных (что раздувает трафик). Добиться 100% гарантии доставки файла байт-в-байт без обратной связи и подтверждений в стохастической сети - невозможно
Рекомендую все же ознакомиться со статьей целиком - там подробно и на пальцах описано, зачем и как это работает
Про сквозную целостность в связке с L2 CRC32, есть нюанс:
Кажется что если на канальном уровне всё уже закрыто мощной проверкой, то городить проверки на верхних уровнях не имеет смысла. Но тут момент в том что канальная проверка защищает только конкретный «провод» между двумя узлами. На промежуточном роутере пакет распаковывается, а при отправке дальше генерируется новый CRC. То есть может произойти такая ситуация, когда внутри какого то транзитного узла сбойнет память и пакет исказится, следующий узел же подпишет этот мусор валидным CRC. Так что проверка на транспортном уровне все же важна. Конечно не в таком виде как у меня сейчас)
Насчет сложности QUIC - согласен. Утрамбовали огромный комбайн, который повторить в одиночку точно невозможно, та и не нужно. Хочется создать что-то легкое и простое, при этом полезное для каких-либо сценариев
P.S. Жаль что проект на го заглох. Если когда нибудь он будет в опенсорсе или какой нибудь материал по нему, я бы с удовольствием почитал, очень интересно как другие люди решают похожи архитектурные проблемы
Спасибо за потрясающий, глубокий комментарий и пищу для размышлений! С огромным удовольствием прочитал
По пунктам: 1. Про слабости One's Complement: всё по факту, алгоритм уязвим. Пока что я решил сделать его как временный костыль и как дань канону TCP/UDP) Но в серьезном продакшене тут конечно направшивается что-то серьёзнее 2. Про суммирование: красивый трюк, я же собирал слова через сдвиги скорее из-за паранойи и того что не додумался до другого решения 3. Про разделение контроля перегрузки, потока, и дедлайны потерь: крутая фича, обязательно попробую реализовать это, чтобы немного приблизиться к семантике того же QUIC 4. Про AEAD и seq num: тоже шикарная идея, избавляет сразу от нескольких проблем. Еще тоже попробую сделать)
Заберу эти мысли в заметки архитектуры для второй части проекта. Еще раз жму руку за конструктив и экспертизу!
Спасибо огромное за теплый отзыв и плюсик! Букав и правда получилось прилично, но очень хотелось показать весь путь и эволюцию проекта. Надеюсь, лонгрид не разочарует :)
Спасибо большое! На счет полнодуплексности еще нужно поработать, не смотря на то что отправка сегментов идёт с двух сторон, на данном этапе протокол не позволяет клиенту отправлять полезную нагрузку, но это поправимо и я обязательно сделаю это
Хороший вопрос. Да, обязательно буду добавлять подобное. Во-первых это интересно реализовать, а во-вторых в реальной сети без этого никуда :)
Спасибо за такой прекрасный комментарий! За «кадром» я проводил сравнение с TCP, но почему-то забыл об этом упомянуть в статье. Результаты оказались плачевными. Если мои измерения не ошибочны, то мой протокол медленнее TCP Cubic примерно в 100 раз. Предполагаю что дело как раз в отсутствии congestion control и юзерспейсе (постоянные системные вызовы, в то время как TCP работает напрямую в ядре линукс). Сам контроль перегрузки я планирую реализовывать дальше, и рассказать об этом в следующей части которую напишу как только реализую новые механизмы + подготовлю бенчмарки для сравнения с TCP
Еще меня очень зацепила ваша мысль про то насколько сильно мы привязаны к TCP/UDP. Я тоже об этом задумывался и по факту в нынешних реалиях многие нововведения которые семантически относятся к транспортному уровню, но по какой-то причине не могут быть добавлены в TCP - вынуждены выносить на прикладной уровень. На мой взгляд это сильно размывает сами уровни TCP/IP и усложняет всё. Честно говоря, я даже не представляю как эту проблему в теории можно было бы решить :(
В процессе работы над этим проектом меня не раз просили сделать что-то наподобие VPN-протокола. Тема конечно интересная, но я не вижу особого смысла в этом, и как мне кажется фундамент этого протокола не очень хорошо подходит для VPN
Спасибо за информацию, не видел эту статью, действительно похожая тема!
По поводу существующих протоколов: Я захотел создать что-то подобное своими руками, для того чтобы на практике понять как оно работает под капотом ;)
Спасибо большое! Я думал над тем чтобы сделать на голом сокете, но решил всё таки не усложнять себе жизнь. Хотелось чтобы работало без рута, ну и плюсом получилось избежать возни с айпи и портами, как я писал в статье: айпи и порт отправителя я беру из заголовка UDP
Конечно без UDP было бы еще интереснее, тут да :)
К сожалению, вы немного упустили суть и контекст статьи :)
Кхм, позвольте изъяснить:
Это не прикладная задача для продакшена, это исследовательский/учебный проект. Цель не «передать файл любой ценой», а с нуля руками реализовать фундаментальную надежную доставку и изучить архитектуру транспортного уровня (ровно по тому же пути идут в курсе CS144 Стэнфорда или при разработке протоколов вроде QUIC и KCP)
Никакой TCP-сокет никуда не оборачивается: Протокол использует только сырые UPD-датаграммы и сам реализует логику отслеживания состояния
Насчет «увеличить размер чанка, чтобы потери были реже»: К сожалению, это заблуждение. В реальной сети размер полезной нагрузки жестко ограничен размером MTU (обычно 1500 байт на Ethernet). Если сделать чанк больше, то айпи уровень порежет сегмент на несколько фрагментов. Потеря любого этого фрагмента приводит к потере всего сегмента целиком. То есть увеличение размера чанка не снижает потери, а гарантированно их увеличивает
Насчет избыточности: Прямое исправление ошибок работает только при относительно небольших потерях и требует отправки огрлмного объема избыточных данных (что раздувает трафик). Добиться 100% гарантии доставки файла байт-в-байт без обратной связи и подтверждений в стохастической сети - невозможно
Рекомендую все же ознакомиться со статьей целиком - там подробно и на пальцах описано, зачем и как это работает
Про сквозную целостность в связке с L2 CRC32, есть нюанс:
Кажется что если на канальном уровне всё уже закрыто мощной проверкой, то городить проверки на верхних уровнях не имеет смысла. Но тут момент в том что канальная проверка защищает только конкретный «провод» между двумя узлами. На промежуточном роутере пакет распаковывается, а при отправке дальше генерируется новый CRC. То есть может произойти такая ситуация, когда внутри какого то транзитного узла сбойнет память и пакет исказится, следующий узел же подпишет этот мусор валидным CRC. Так что проверка на транспортном уровне все же важна. Конечно не в таком виде как у меня сейчас)
Насчет сложности QUIC - согласен. Утрамбовали огромный комбайн, который повторить в одиночку точно невозможно, та и не нужно. Хочется создать что-то легкое и простое, при этом полезное для каких-либо сценариев
P.S. Жаль что проект на го заглох. Если когда нибудь он будет в опенсорсе или какой нибудь материал по нему, я бы с удовольствием почитал, очень интересно как другие люди решают похожи архитектурные проблемы
Спасибо за потрясающий, глубокий комментарий и пищу для размышлений! С огромным удовольствием прочитал
По пунктам:
1. Про слабости One's Complement: всё по факту, алгоритм уязвим. Пока что я решил сделать его как временный костыль и как дань канону TCP/UDP) Но в серьезном продакшене тут конечно направшивается что-то серьёзнее
2. Про суммирование: красивый трюк, я же собирал слова через сдвиги скорее из-за паранойи и того что не додумался до другого решения
3. Про разделение контроля перегрузки, потока, и дедлайны потерь: крутая фича, обязательно попробую реализовать это, чтобы немного приблизиться к семантике того же QUIC
4. Про AEAD и seq num: тоже шикарная идея, избавляет сразу от нескольких проблем. Еще тоже попробую сделать)
Заберу эти мысли в заметки архитектуры для второй части проекта. Еще раз жму руку за конструктив и экспертизу!
Хаха, спасибо! Задел на продолжение есть, и возможно не одно)
Спасибо огромное за теплый отзыв и плюсик! Букав и правда получилось прилично, но очень хотелось показать весь путь и эволюцию проекта. Надеюсь, лонгрид не разочарует :)