Це переклад попереднього повідомлення в блозі одного з розробників мережі Yggdrasil, в якому він намагався дати розширене пояснення змін, які вплинуть на мережу після випуску 0.5.

 Це переклад попереднього повідомлення в блозі одного з розробників мережі Yggdrasil, в якому він намагався дати розширене пояснення змін, які вплинуть на мережу після випуску 0.5.

Як на мене, зміни досить цікаві та надихаючі. Чекати з нетерпінням. Клієнт для Android я вже почав модифікувати під ці зміни, збірки вже тестуються ентузіастами російськомовної спільноти.

Але досить вступних слів, я залишаю промову Arceliar :

вступ

Невдовзі з’явиться версія 0.5.0, тому зараз, здається, вдалий час пояснити, над чим ми працювали протягом останніх кількох років. Хоча загалом ми цілком задоволені версією 0.4.X, у цьому дизайні є кілька проблем, які можуть спричинити поведінку мережі не так, як нам хочеться. Метою цієї публікації в блозі є короткий огляд роботи версії 0.4, пояснення проблем, пов’язаних із цим підходом, і опис змін, які ми внесли у версію 0.5, щоб спробувати їх вирішити.

Поточний стан

Схема маршрутизації 0.4.X складається з трьох основних компонентів:

  1. Маршрутизація на основі DHT використовується для надсилання трафіку, коли маршрут до пункту призначення невідомий.

  2. Схема маршрутизації Greedy Tree, яка використовується для маршрутизації трафіку в DHT і "пошуку шляху" для маршрутизації джерела.

  3. Схема маршрутизації джерела, яка кодує шлях, знайдений у просторі дерева, у заголовках пакетів, щоб трафік міг слідувати більш прямим маршрутом, ніж той, який пропонує DHT (і продовжувати працювати, поки змінюється стан дерева).

Життєвий цикл з’єднання проходить ці три етапи послідовно. Під час початкового обміну ключами шлях до пункту призначення невідомий, тому трафік направляється через DHT. Коли вузли отримують трафік, що надходить через DHT, вони починають пошук шляху, щоб знайти більш ефективний маршрут через простір дерева. Коли пошук шляху завершено, вони перемикаються на маршрутизацію джерела, яка інкапсулює пакет, маршрутизований через DHT, у пакет, маршрутизований джерелом. Якщо пакет, надісланий джерелом, коли-небудь блокується, заголовок маршрутизації джерела видаляється, а маршрутизація завершується через DHT. Отримання цього направленого пакету DHT запускає пошук шляху у фоновому режимі, щоб знайти новий шлях.

Загалом ця конструкція працює добре. Однорангові користувачі можуть почати спілкуватися (у нашому випадку, надсилаючи трафік для обміну ключами) до того, як знадобиться шукати будь-які маршрути, і все відновиться елегантно. Для виявлення пошкоджених шляхів не потрібен додатковий трафік, оскільки резервний DHT піклується про сигналізацію втрати шляху.

Проблеми

Хоча я не маю проблем із загальним дизайном версії 0.4, усі окремі компоненти мають проблеми.

Перш за все, дизайн DHT, використаний у версії 0.4, не масштабується так добре, як ми сподівалися. Вузли повинні відстежувати не тільки шляхи до своїх ключових просторових сусідів, а й будь-які такі шляхи, що проходять через їхній вузол. Це означає, що деяка частина вузлів потрапляє в положення, де вони запам’ятовують великий відсоток усіх шляхів через свій вузол. Це призводить до високої вартості пам’яті та потенційно високого трафіку. Використання трафіку DHT у мережі 0.4 є відносно низьким, оскільки DHT є переважно жорстким станом, але всі спроби створити більш безпечний DHT призвели до дизайну м’якого стану, де витрати на трафік можуть стати значними. Без захисту DHT залишатиметься вразливим до деяких атак (або погано поводитиметься за наявності неправильно налаштованих вузлів, таких як випадкові вузли будь-якої адреси). Більш підступною проблемою є час конвергенції DHT: у гіршому випадку конвергенція вимагає O(n) кроків, і ми маємо вагомі підстави вважати, що це відбувається в деяких типових випадках використання. Крім того, конструкція жорсткого стану вимагала активного моніторингу кожного однорангового з’єднання, щоб швидко виявити, коли з’єднання не працює. Це призводить до набагато більшого неактивного трафіку між вузлами, ніж ми хотіли б бачити.

По-друге, дерево може створювати конфліктні уявлення про мережу залежно від того, на інформацію якого вузла звертає увагу вузол. Це призводить до «розриву», коли небатьківське з’єднання розривається, оскільки вузли мають тенденцію перемикатися на новий батьківський, який використовував те саме (тепер розірване) з’єднання, але ще не встиг оголосити з’єднання розірваним. Таким чином, вузли, як правило, перемикаються зі свого батьківського вузла на альтернативний вузол, а потім повертаються до оригінального батьківського вузла, коли альтернативний закінчує повідомлення про ту саму помилку. Це коливання змушує вузли в усьому дереві (усі дочірні) коливатися, що може каскадуватись по мережі. У версії 0.4 є механізми контролю швидкості змін, але це тимчасове вирішення основної проблеми в дизайні.

Нарешті, вихідна маршрутизація хороша в принципі, але формат пакету, який ми використали для неї, ні. Для зловмисника дуже легко вставити кілька надлишкових переходів, щоб створити (термінальний) цикл, що може призвести до марної пропускної здатності цільового набору вузлів.

Зміни

Багато змін було внесено в дизайн Yggdrasil для боротьби з вищезазначеними проблемами. Нові підходи не обов’язково є тим, як ми хочемо, щоб мережа функціонувала в довгостроковій перспективі, а скоріше це альтернативи, які ми хотіли б перевірити, щоб краще вивчити простір можливих рішень. Загалом, вони не призначені для користувача, за винятком деяких змін інформації, доступної в API yggdrasilctl.

Пошук шляхів

Найсуттєвішою зміною є видалення схеми маршрутизації на основі DHT, яка використовувалася для початкового налаштування маршрутів через простір дерева. Тепер ми використовуємо простіший протокол пошуку YggIP/key->coord, який подібний до пошуку ARP/NDP у широкомовній мережі Ethernet (але без трансляції трафіку по всій мережі). Вузли відстежують, які вузли доступні за посиланням у дереві (тобто батьківські та дочірні вузли), а також фільтр Блума

Незважаючи на недоліки цього підходу, він має ряд переваг. По-перше, випадкові конфігурації будь-якої адреси (з використанням того самого ключа з кількох вузлів) не порушують жодних мережевих структур даних, а просто призводять до того, що пошуковий трафік надходить до кількох вузлів. Подальші кроки, як правило, будуть невдалими (пошук маршруту, обмін ключами тощо), але не завдадуть супутньої шкоди решті мережі. По-друге, він вимагає дуже мало трафіку для неактивної служби та вимагає лише постійної кількості станів на вузол. Це означає, що вузли в центрі мережі не відповідають за підтримку стану будь-чого, окрім свого безпосереднього оточення, і не перевантажені неактивним трафіком DHT, що надходить із віддалених вузлів. Так само вузлам на межі мережі не потрібно надсилати регулярний трафік DHT для підтримки активності, що може допомогти з використанням трафіку та енергоспоживанням на мобільних пристроях. По-третє, ця структура сходиться асинхронно та за час, пропорційний глибині дерева, а не послідовно та за час, пропорційний розміру мережі, тому можна уникнути дуже поганого часу конвергенції DHT у найгіршому випадку.

Основним недоліком цього підходу є те, що фільтри Блума можуть і будуть генерувати помилкові спрацьовування, коли вони заповнюються. На практиці ми очікуємо, що фільтри в центрі мережі насичуються, коли кожен вузол доступний будь-яким шляхом. Це, у свою чергу, означає, що маршрут вузла до «ядра» мережі (зазвичай через батьківський вузол) візьме на себе роль «маршруту за замовчуванням» і отримуватиме копію кожного запиту, надісланого вузлом. Ми очікуємо, що пошуковий трафік досягне ядра мережі, фактично діятиме як широкомовний трафік у ядрі, а потім буде відфільтрований фільтрами Блума, коли він наближається до країв (тому вузол на межі мережі навряд чи отримає будь-які трафік, який для нього не призначений). Коротше кажучи, вузли в ядрі використовуватимуть менше пам’яті та трафіку під час простою, але активне використання мережі споживатиме більше трафіку. Залишається з'ясувати, чи варто це компроміс.

Трохи підсумовуючи: ми використовуємо 8192-бітні фільтри Блума з 8 хеш-функціями. Якщо є вузол, який діє як шлюз у підмережі з 200 вузлами, то частота хибних спрацьовувань становить приблизно 1 на мільйон (тобто ми очікуємо, що мережі знадобиться близько мільйона вузлів, перш ніж шлюз побачить хибно-позитивний пошук трафік) ). Більшість пошукового трафіку правильна до шлюзу в підмережі з 500 вузлами в мережі з 1 мільйоном вузлів.

Таким чином, на практиці більшість вузлів не повинні бачити значну кількість хибних спрацьовувань, якщо вони не діють як шлюз до дуже великої підмережі (або знаходяться в мережі, яка на багато порядків перевищує мережу поточної версії 0.4). У нашій поточній мережі кілька вузлів можуть опинитися в «основному» регіоні, де вони отримують хибно позитивний пошуковий трафік від більшості пошуків. Ми сподіваємося, що це все ще краще, ніж постійний трафік DHT під час простою, і потенційно дуже високі вимоги до пам’яті.

CRDT-дерево


Раніше розташування кожного вузла в дереві перевірялося ланцюжком підписів (посилань на батьківський вузол) від вузла назад до кореня. Це може призвести до неузгодженості, коли різні вузли мають взаємно несумісні уявлення про одного предка (наприклад, вузол A каже, що батьківський P має дідуся й бабусю G, але вузол B каже, що той самий батьківський P має дідуся й бабусю G'), що ускладнює вибір батьківського елемента в реагування на зміни стану мережі. Щоб вирішити цю проблему, ми розбиваємо інформацію про дерево на окремі дані для кожного посилання, які передаються між вузлами та об’єднуються в структуру CRDT. Це змушує вузли мати локально узгоджене уявлення про мережу, що запобігає непотрібному «тремтенню» в деяких випадках, коли маршрут вузла до кореня порушується. Це також зменшує кількість інформації, яку потрібно надіслати через мережу, оскільки вузлу не потрібно надсилати інформацію назад одноранговому вузлу, якщо він знає, що одноранговий вузол уже бачив його.

Жадібна маршрутизація

Маршрутизацію джерела з версії 0.4 було видалено на користь жадібної маршрутизації, як це було зроблено у версії 0.3.X. У стабільній мережі це не впливає на маршрут, яким проходять пакети, а лише на те, як приймається рішення про вибір цього маршруту. У майбутньому ми можемо повернутися до підходу маршрутизації джерела, але підхід, використаний у версії 0.4, мав деякі проблеми, які потрібно було спочатку вирішити. Маршрутизація джерела є хорошою оптимізацією продуктивності, якщо це можна зробити безпечно, але це не є явною метою цього дизайну. Хоча у мене є ідеї, як це зробити, це не є пріоритетом у короткостроковій перспективі. Оскільки схема вихідної маршрутизації, ймовірно, все ще покладається на жадібну маршрутизацію для пошуку шляху, я вважаю, що для цього випуску корисно зосередитися на стрес-тестуванні жадібної частини мережі та залишити вихідну маршрутизацію, коли інші частини стека стануть ближчими до стабільного стану.

Keep-alive для кожного видаленого вузла

Ми більше не розсилаємо пакети підтримки активності через однорангові посилання кожні кілька секунд. Натомість, коли ми надсилаємо трафік, ми вимагаємо підтвердження протягом кількох секунд (якщо надісланий трафік не був підтвердженням). Це означає, що ми не так швидко виявляємо збої зв’язку під час простою (нам потрібно чекати трафіку користувача або трафіку протоколу, щоб використовувати з’єднання), але це повинно зменшити споживання трафіку в режимі очікування (і, ймовірно, зменшити споживання енергії на мобільних пристроях). Зауважте, що це відрізняється від, наприклад, власних механізмів підтримки активності TCP, які залишаються ввімкненими (TCP Keep-alive).

Нові можливості

Версія 0.5 також додає кілька нових функцій. Тепер можна обмежити піринг за допомогою аргументу and ?password=Xline (і в конфігурації багатоадресної передачі). Це вимагає, щоб вузли узгодили пароль, перш ніж почати піринг. Зверніть увагу, що це не дозволяє ізолювати мережу: вузли все ще можуть спілкуватися з рештою мережі, якщо вони хочуть, і доступ все ще є транзитивним. Це дозволяє легко обмежити, хто може автоматично підключатися в межах підмережі, або налаштувати загальнодоступний вузол, не дозволяючи підключення всім, хто може його знайти. Також є підтримка підключень. QUIC- піринг використовуватиме лише один потік трафіку, тому його семантика майже така ж, як і TCP/TLS-піринг, але він може бути корисним у випадках, коли UDP-пакети можуть легше проходити через NAT або брандмауер. Зазвичай ми очікуємо, що він працюватиме гірше, ніж TCP/TLS, тому не рекомендуємо використовувати його, коли він не потрібен.ListenPeersquic://

Результати

За винятком непередбачених затримок, Yggdrasil v0.5 має вийти протягом наступних кількох тижнів. Ми сподіваємося, що ми вирішили найважливіші проблеми стабільності та масштабування у версії 0.4 і значно зменшили споживання пам’яті та неактивного трафіку для деяких вузлів. Деякі аспекти нового дизайну радикально відрізняються від версії 0.4, тому ще належить побачити, наскільки добре ці зміни працюватимуть у реальному світі. Попередні тести (та велика кількість симуляцій) вселяють у нас оптимізм щодо того, що версія 0.5 дасть нам стабільну основу для розвитку, оскільки ми досліджуємо будь-які обмеження цього нового підходу та працюємо над неминучою зміною дизайну для версії 0.6.

Просмотры:

Коментарі

Популярні публікації