🧑‍💻DevDays
10 subscribers
4 photos
29 links
Практичні нотатки про кібербезпеку, мережі, self-hosting, проксі та AI-інфраструктуру українською. Реальні кейси, код і розбори.
Download Telegram
Оновлення без другого знайомства з конфігами 🔄

Трохи випав із серії про Transparent Gateway — брав участь у HackerRank Orchestrate, про який писав вище. Тепер повертаюся до проєкту: встановлення вже розібрав, на черзі — оновлення 🔄

У попередній серії довів установлення Transparent Gateway до нормального вигляду: завантажив код, увів налаштування, запустив. Після перезавантаження він теж повертався сам. Уже приємно 🙂

Але проєкт продовжує змінюватися. З’являються виправлення й нові можливості, які потрібно якось доставити на вже встановлений gateway.

І тут заново вводити адресу проксі, пароль та параметри мережі зовсім не хочеться. Один раз уже натанцювалися з тими налаштуваннями, досить 😅

Тому додав до скрипта керування scripts/tgctl.py команду оновлення. На машині з установленим gateway, із каталогу проєкту:

sudo python3 scripts/tgctl.py update main --timeout 300


main — гілка, з якої команда забере нову версію. --timeout 300 — до п’яти хвилин на перевірку готовності після її запуску.

Код і контейнери замінюються. Налаштування мережі, список проксі, паролі й дані в Redis залишаються на місці. Повторно проходити діалог налаштування не потрібно 🔑

Якщо змінював сам код проєкту, команда покаже змінені файли й зупиниться. Затирати чужі правки заради зручного оновлення — це не наш метод.

Але найцікавіше тут — порядок дій. Спочатку потрібно підготувати нову версію й лише потім зупиняти робочу. Бо залишитися без gateway через образ, який навіть не зібрався, було б якось образливо.

Як це організував — покажу наступним постом ⚙️
Нова версія готується, стара ще працює 🔄

У минулому пості показав команду оновлення Transparent Gateway. Поки вона готує нову версію, поточний gateway продовжує передавати трафік.

Спочатку завантажує новий код в окремий каталог. Робочий gateway продовжує передавати трафік, а поруч готується його заміна ⚙️

Нова версія використовуватиме ті самі налаштування мережі та проксі. Тому перед запуском команда перевіряє, чи вони їй підходять. Наприклад, якщо в коді з’явився новий обов’язковий параметр, краще побачити повідомлення про нього до зупинки gateway, а не після.

Далі Docker збирає образи — пакує новий код разом із залежностями для запуску. Старі контейнери поки працюють.

Увесь цей час попередня версія залишається в роботі.

Коли нові образи готові, команда зберігає попередній код та образи для відкату. Якщо нова версія не запрацює, буде з чого повернути стару 🔙

І лише після підготовки зупиняє старі контейнери, запускає нові та перевіряє їхню роботу:

Завантажити нову версію
↓
Перевірити її з наявними налаштуваннями
↓
Зібрати нові образи
↓
Зберегти стару версію для відкату
↓
Замінити контейнери й перевірити роботу


Так завантаження та збирання не забирають час у працюючого gateway. Якщо на цих етапах щось не вдалося — оновлення зупиниться з помилкою, але поточна версія залишиться працювати.

На стенді саме так і сталося. Перед заміною контейнерів скрипт спробував зберегти старі образи для повернення попередньої версії. Docker відповів, що одного з образів не знайшов. Оновлення зупинилося, gateway продовжив роботу.

З’ясувалося, що образ був на місці, але скрипт шукав його за ідентифікатором, який Docker на цьому стенді не приймав. Що змінив у пошуку — розповім наступним постом 🔧
❤1
№707 із 4090: остаточні результати HackerRank Orchestrate 🧑‍💻

Оцінювання завершилося: 707-ме місце та 62,6 бала зі 100 🎯

Початково учасників було понад п’ять тисяч. Частину дискваліфікували за плагіат, у фінальній таблиці залишилося 4090.

У попередньому пості був №815. Бали не змінилися, а підсумкове місце стало кращим 🙂

Завданням було створити AI-агента, який перевіряє, чи компанія виконала прохання користувача видалити його дані. Якщо щось залишилося в базах, журналах або резервних копіях — агент має знайти це й пояснити, що потрібно зробити.

Найбільше втратив на англомовній співбесіді — 9 із 30. І головна проблема тут — мій рівень англійської: не завжди розумів питання й не міг нормально пояснити рішення. Наступного разу більше перепитуватиму, але й мову потрібно підтягувати. Код себе англійською не захистить 😅

707-ме серед понад чотирьох тисяч — мене радує. Є результат і зрозуміло, над чим працювати далі 💪

Остаточний лідерборд
Виправив збереження образів для відкату 🔧

Перше оновлення Transparent Gateway зупинилося ще до заміни контейнерів. Скрипт не зміг підготувати попередню версію для відкату.

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

Але Docker відповів, що потрібного образу не знайшов. Хоча запущений контейнер був створений саме з нього 🤔

Причина виявилася в тому, як скрипт шукав образ.

Він брав ідентифікатор із відомостей про контейнер і передавав його команді docker tag, яка додає образу назву. На тестовому Docker 26 це працювало. На Docker 29 зі стенда — ні: отриманий ідентифікатор не підходив для цієї операції.

Тобто образ не зник. Скрипт неправильно до нього звертався.

Замість перевірки «яка тут версія Docker?» додав пошук самого образу:

Спробувати знайти за ідентифікатором контейнера
↓ якщо не вдалося
Знайти за назвою й перевірити відповідність
↓ якщо назва вже вказує на новий образ
Пошукати потрібний серед інших локальних образів


Перевірка відповідності тут потрібна: після збирання назва може вже належати новій версії. Зберегти її замість старої — означає підготувати відкат назад у те саме оновлення 😅

Якщо потрібний образ знайти не вдалося, скрипт зупиняється й називає сервіс, для якого не може підготувати відкат. Робочі контейнери залишаються на місці.

Після виправлення збереглися образи всіх шести сервісів, а повторне оновлення завершилося UPDATE PASS ✅

Залишилося перевірити, чи збережена версія справді повернеться, якщо нова не запрацює. Для цього вже навмисно підготував поламаний запуск. Про нього — наступним постом 🔙
❤1
Один рядок і п’ятнадцять хвилин архітектури 🎮

Гра, над якою працюю як розробник, зараз проходить перевірку на вебплатформі. Тестувальники знайшли баг, виправлення якого мало зайняти один рядок коду.

За задумом, коли антагоніст ловить персонажа, програється катсцена. Після неї гравець має опинитися в безпечному місці й продовжити гру.

Але персонаж з’являвся прямо в руках антагоніста.

Той знову його ловив, катсцена повторювалася, персонаж повертався туди ж. І так, поки не закінчувалися життя.

Для виправлення потрібно було на початку катсцени задати персонажу вже відомі координати безпечного місця. Нічого обчислювати чи шукати не потрібно: викликати метод і передати два готові значення.

Копирсатися самому було лінь, тому доручив Астрі.

Повертаюся через п’ятнадцять хвилин — ще працює. Вирішив подивитися, що там узагалі відбувається 🤔

А там уже ціла система. Агент додав перевірки купи змінних, нові умови в методи й події для передачі сигналів між частинами коду. Частину поведінки персонажа вимикає, його параметрами керує, за змінами стану стежить.

І все це — щоб у потрібний момент змінити положення персонажа.

Пояснив, що достатньо зробити це на початку катсцени. Без усієї цієї конструкції.

У відповідь: «А, ну точно. Це було зайве переускладнення, можна й без цього».

Та невже 😁

Останнім часом часто бачу захоплені розповіді про агентів, які можуть годинами самостійно писати код і збирати цілі проєкти за коротким описом. У мене найдовший безперервний запуск поки був близько сорока хвилин. І після нього теж вистачало помилок, які доводилося виправляти.

Тому сама тривалість роботи мене вже не дуже вражає. За п’ятнадцять хвилин можна знайти складну помилку. А можна обкласти просте виправлення такою кількістю нового коду, що перевіряти доведеться вже його 😅

Добре, що зазирнув через п’ятнадцять хвилин. Ще трохи — і замість виправлення бага отримав би нову ігрову механіку.
❤1
Навмисно зламав запуск, щоб перевірити відкат 🔙

Старі образи для відкату вже зберігаються. Тепер потрібно було перевірити, чи скрипт справді зможе повернути з них робочий gateway.

Щоб перевірити відкат, навмисно зламав запуск gateway у тестовій версії: замість звичайного старту контейнер одразу завершувався з помилкою. Docker міг зібрати образ і створити контейнер, але сам gateway у ньому не працював. Саме таку несправність мала помітити перевірка після оновлення 🧪

Саме її й установив на тестову машину.

Після заміни контейнерів команда запустила перевірку готовності. Вона побачила, що gateway не працює, і замість успішного завершення почався відкат.

Далі скрипт сам:

• повернув попередню версію коду;
• запустив контейнери зі збережених старих образів;
• залишив на місці налаштування, паролі й підключені томи даних;
• повторив перевірку готовності.

Цього разу отримав:

READINESS PASS
ROLLBACK PASS previous_version_running=1


READINESS PASS означає, що відновлена версія пройшла перевірку роботи сервісів, свіжості пулів проксі та запиту через проксі.

previous_version_running=1 — що після відкату працює саме попередня версія.

А фінальний результат самої команди оновлення — усе одно UPDATE FAIL. І це правильно: нову версію встановити не вдалося. Просто тепер ця помилка не залишає мене з непрацюючим gateway 🙂

Є й межа: відкат повертає код та образи, але не перемотує назад вміст Redis. Тому оновлення, які змінюють його конфігурацію або підключення томів, скрипт зараз відхиляє. Для таких змін потрібно окремо продумати збереження й сумісність даних.

У цьому тесті вручну повертати стару версію не довелося. Спеціально встановив поламану, дочекався результату — і знову отримав робочий gateway.

Оце вже помилка оновлення, з якою можна спокійно розбиратися. Без термінового ремонту всього, що щойно працювало 😅
👏3
Оновлення Transparent Gateway — однією командою 🔄

Для переходу на нову версію тепер достатньо запустити з каталогу проєкту:

sudo python3 scripts/tgctl.py update main --timeout 300


Наявні налаштування зберігаються. Тобто після оновлення не потрібно заново вказувати клієнтську мережу, додавати проксі та вводити паролі — gateway продовжить використовувати вже підготовлену конфігурацію 🔑

Команда готує нову версію, замінює контейнери та перевіряє роботу. Якщо нова версія не проходить перевірку — повертає попередню 🔙

По дорозі Docker 29 підкинув проблему зі збереженням старих образів. Виправив пошук, а потім навмисно зламав запуск тестової версії, щоб перевірити відкат. Попередній gateway повернувся без ручного ремонту ✅

Приємно бачити, як проєкт поступово стає інструментом, яким можна користуватися без моїх підказок через плече. Пригоди під час розробки нікуди не поділися, але повторювати їх кожному користувачу вже не обов’язково 😅

Увесь шлях із командами, скрінами та поясненнями зібрав у статті:

Оновлення Transparent Gateway без повторного налаштування

Код проєкту на GitHub

Далі — діагностика. Планую додати команду doctor, яка перевірятиме налаштування, стан сервісів і підключення через проксі та пояснюватиме, на якому етапі виникла проблема.

Щоб після повідомлення про помилку було зрозуміло, де шукати причину, а не доводилося відкривати журнали всіх контейнерів по черзі 🔎
Як добре, що мене ще хтось розуміє 😅

Зашиваюся так, що вже й повідомлення пишу запчастинами. Добре, що хоч хтось збирає їх без інструкції 😂

Нейронки дозволили робити значно більше роботи за той самий час. Те, до чого раніше руки дійшли б через тиждень, тепер уже виконується паралельно з іншими задачами.

Виконаної роботи більше. Помилок в абсолютних числах — теж. Особливо коли встигаєш роздати задачі швидше, ніж перевірити результати 😅

Робота в паралельних проєктах тепер нагадує моє уявлення про життя із СДУГ. Не діагноз, просто асоціація.

Крутиш гайки в одному проєкті — падає база в іншому. Біжиш піднімати базу, бо дав агенту невдалу команду. Дорогою коригуєш агентів у третьому проєкті. Потім перевіряєш оновлення четвертого. До першого повертаєшся з думкою: «Так, а що тут узагалі робив?» 🔄

І так по колу.

А потім іноді вдається підняти голову від помилок і подивитися, скільки всього вже працює. І щиро здивуватися: оце все вдалося зробити за такий короткий час? 🤯

Тому не можу сказати, що з нейронками стало менше роботи. Стало більше можливостей узяти її на себе.

А от перевіряти, чи не набрав зайвого, поки доводиться власною головою. Тією самою, яка вже пише повідомлення запчастинами 😂
Навіщо даним зайвий біт? 🧩

Зараз готуюся до заліків та екзаменів, а отже буде серія розборів фахових речей. Почну з надлишковості.

Цієї теми вже трохи торкався, коли розповідав про формулу Шеннона. Тепер захотілося розібратися, як вона працює на практиці.

Визначення з «Теорії інформації» нічого, крім сонливості, не викликало. Довелося шукати практичні приклади. І знаєте що? Це просто повсюди 😅

Наприклад, серверна оперативна пам’ять використовує ECC — механізм виявлення та виправлення помилок. Для цього разом із даними зберігаються додаткові перевірочні біти.

Беремо вісім бітів даних і додаємо дев’ятий — біт парності. Його значення підбираємо так, щоб загальна кількість одиниць у всіх дев’яти бітах була парною:

Дані       Біт парності
00000000 0
00000001 1
00000011 0
00000111 1


У першому рядку одиниць немає. Нуль — парне число, тому додатковий біт теж нуль.

У другому є одна одиниця. Додаємо ще одну — отримуємо дві.

У третьому вже дві одиниці, нічого додавати не потрібно. У четвертому їх три, тому перевірочний біт дорівнює одиниці — разом буде чотири.

Під час читання даних кількість одиниць перевіряється знову. Якщо вона стала непарною — дані або сам перевірочний біт пошкодилися 🔍

Припустимо, записали:

00000001 | 1


Разом дві одиниці — усе правильно.

А потім один біт змінився, і під час читання отримали:

00000000 | 1


Тепер одиниця лише одна. Парність порушена — отже, сталася помилка.

Але є нюанс: один біт парності не скаже, де саме помилка, і не виправить її. А якщо зміняться два біти, кількість одиниць може знову залишитися парною — перевірка пропустить пошкодження.

Щоб знаходити пошкоджений біт і відновлювати його значення, потрібні складніші перевірки. Як це працює в ECC — розберу наступним постом, теж на конкретних числах.

Оце й був приклад, якого мені не вистачало. Математичне визначення прочитав — і наступного дня вже не пам’ятаю, що там було. А тут сам порахував біти, змінив один і побачив, як знайшлася помилка. Тепер ця інформація зі мною надовго 🙂

Залишилося на заліку пояснити це так само зрозуміло, як нарешті пояснив собі і вам 😅
Як знайти пошкоджений біт 🔍

Один біт парності дозволив помітити помилку. Але щоб її виправити, потрібно знати, який саме біт змінився.

Для цього перевірятиму парність не всього запису одразу, а кількох груп. Групи перетинатимуться так, щоб кожна позиція мала власну комбінацію перевірок.

Візьму чотири біти даних:

1011


Додам три перевірочні біти й розкладу все на сім позицій:

Позиція:  1  2  3  4  5  6  7
Вміст: A B 1 C 0 1 1


A, B і C — біти парності. Кожен відповідає за свою групу:

A → позиції 1, 3, 5, 7
B → позиції 2, 3, 6, 7
C → позиції 4, 5, 6, 7


Як і в попередньому прикладі, кількість одиниць у кожній групі має бути парною.

Підбираю значення:

A = 0
B = 1
C = 0

Запис: 0110011


У групі A тепер дві одиниці, у B — чотири, у C — дві. Усі перевірки проходять ✅

А тепер навмисно зміню шостий біт:

Позиція: 1 2 3 4 5 6 7
Було: 0 1 1 0 0 1 1
Стало: 0 1 1 0 0 0 1


Повторюю перевірки:

A → 2 одиниці → правильно
B → 3 одиниці → помилка
C → 1 одиниця → помилка


Отже, пошкоджений біт входить до груп B і C, але не входить до A.

Дивлюся на списки позицій: під цей опис підходить тільки шоста.

Змінюю її значення назад із 0 на 1. Потім забираю дані з позицій 3, 5, 6 і 7 — знову отримую початкові 1011 🎯

Не вгадав і не взяв правильну копію з іншого місця. Знайшов помилку завдяки тому, які саме перевірки не пройшли.

Це приклад коду Геммінга (7,4): чотири біти даних, три перевірочні. Він дозволяє виправити одну помилку в семибітному записі.

У серверній пам’яті використовуються й складніші схеми. Наприклад, поширений варіант ECC для DDR4 зберігає 64 біти даних і 8 перевірочних та дозволяє виправити одиночну помилку й виявити подвійну. Пояснення Synopsys.

Ось навіщо потрібні різні групи: одна перевірка каже «десь помилка», а їхня комбінація вже вказує конкретне місце.

Три додаткові біти — і замість «щось зламалося» вже зрозуміло, що саме виправляти. Хотілося б так само з повідомленнями про помилки в коді 😅
❤1
Контрольна цифра: надлишковість без нулів та одиниць 🔢

Із бітами трохи розібрався. Тепер перейду до звичних десяткових цифр.

Контрольна цифра зустрічається в номерах банківських карток і товарів під штрихкодами. Це ще один приклад надлишковості: до самого номера додається цифра, яка допомагає помітити помилку.

Покажу принцип на простій моделі. Візьму три цифри:

1 2 3


Їхня сума — шість. На четверту позицію додам таку цифру, щоб загальна сума ділилася на десять:

1 + 2 + 3 + 4 = 10


Отримав запис 1234, де остання четвірка — контрольна цифра.

Тепер припустимо, що під час введення або зчитування друга цифра змінилася:

Було:    1 2 3 4
Стало: 1 7 3 4

1 + 7 + 3 + 4 = 15


На десять не ділиться — перевірка виявила помилку. Можна попросити повторно ввести номер або зчитати штрихкод 🔍

Але якщо сума ділиться на десять, це ще не гарантія, що все правильно.

Наприклад, поміняю перші дві цифри місцями:

1 2 3 4 → 2 1 3 4

2 + 1 + 3 + 4 = 10


Номер уже інший, а перевірка задоволена 😅

Звичайна сума не залежить від порядку цифр — тому перестановку вона не помітила.

Щоб знаходити й такі помилки, цифрам на різних позиціях можна дати різну вагу: наприклад, одні множити на один, інші — на три, а вже потім додавати. Тоді перестановка сусідніх цифр може змінити результат перевірки.

Як саме з цього виходить контрольна цифра штрихкоду — покажу наступним постом на числах.

Але основна ідея та сама: контрольна цифра залежить від решти номера. Коли номер змінюється через помилку, результат перевірки може перестати сходитися.

Це не пароль і не захист від підробки. Людина, яка знає правило, може сама порахувати правильну контрольну цифру. Її задача — знаходити випадкові помилки, а не доводити справжність картки чи товару.

Одна додаткова цифра — і вже можна перевірити номер, а не просто сподіватися, що його правильно ввели 🙂
Як рахується контрольна цифра штрихкоду 🔢

У попередньому пості звичайна сума пропустила перестановку цифр: від зміни місць доданків результат не змінився.

Тепер врахую не лише значення цифри, а й її позицію.

Покажу на прикладі восьмизначного коду товару EAN-8. У ньому сім цифр номера та восьма — контрольна.

Візьму навчальний приклад, не номер реального товару:

1 2 3 4 5 6 8 ?


Перші сім цифр по черзі множаться на 3 і 1:

Цифра:       1  2  3  4  5  6  8
Множник: 3 1 3 1 3 1 3
Результат: 3 2 9 4 15 6 24


Додаю результати:

3 + 2 + 9 + 4 + 15 + 6 + 24 = 63


До числа, яке ділиться на десять, бракує сімки:

63 + 7 = 70


Отже, контрольна цифра — 7. Повний запис:

12345687


Якщо сума вже ділиться на десять, контрольна цифра буде 0. Додавати ще десять не потрібно 🙂

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

Тепер переставлю перші дві цифри:

Було:    1 2 3 4 5 6 8 | 7
Стало: 2 1 3 4 5 6 8 | 7


Перераховую:

2×3 + 1×1 + 3×3 + 4×1 + 5×3 + 6×1 + 8×3 + 7
= 6 + 1 + 9 + 4 + 15 + 6 + 24 + 7
= 72


На десять не ділиться — помилку виявлено ✅

Чому цього разу спрацювало?

До перестановки перші дві цифри давали:

1×3 + 2×1 = 5


Після перестановки:

2×3 + 1×1 = 7


Цифри ті самі, але тепер вони множаться на інші коефіцієнти. Тому змінилася й сума.

Це правило використовується в системі ідентифікації товарів GS1. Для довших кодів важливо правильно розташувати множники: від останньої цифри перед контрольною вони чергуються справа наліво як 3, 1, 3, 1….

Утім, перевірка не всесильна. Наприклад, перестановка двох цифр, які мають однаковий множник, знову не змінить суму.

Тобто додаткова цифра залишилася одна, але завдяки іншому способу розрахунку вже можна виявляти більше помилок. Надлишковість важлива, але як саме її використати — не менш важливо 🧩
❤1
Інверсійний код: навіщо передавати дані двічі? 🔄

Наступна схема надлишковості спочатку здалася мені занадто щедрою.

Разом із даними передаємо їхню інвертовану копію: кожен 0 замінюємо на 1, а кожну 1 — на 0.

Дані:       1010
Інверсія: 0101


Чотири корисні біти перетворилися на вісім переданих. На терабайт даних доведеться передати ще терабайт перевірочної копії.

Перша думка: «А навіщо так багато?» 🤔

Але для короткої команди ці витрати виглядають інакше. Передати ще один байт нескладно, зате перевірка виходить дуже простою.

Наприклад, у протоколі NEC для інфрачервоних пультів передаються вісім бітів команди та вісім бітів її інверсії.

Приймач порівнює команду з перевірочною копією. На кожній позиції біти мають бути протилежними:

0 і 1 — правильно
1 і 0 — правильно
0 і 0 — помилка
1 і 1 — помилка


Для перевірки підходить операція XOR. Вона повертає 1, якщо два біти різні, і 0, якщо однакові.

Для нашого прикладу:

  1010
⊕ 0101
------
1111


Усі позиції пройшли перевірку ✅

А тепер один біт перевірочної копії пошкодився:

  1010
⊕ 0100
------
1110


У результаті з’явився нуль. Отже, отримані частини вже не є інверсіями одна одної — таку команду можна відкинути.

Цю перевірку легко виконати на простому мікроконтролері або реалізувати апаратною логікою. Не потрібно будувати складну систему виправлення помилок: перевірив відповідність і вирішив, чи приймати команду.

І безвідмовності тут теж немає. Якщо одночасно зміняться обидва біти однієї пари, вони залишаться протилежними — перевірка може пропустити помилку.

Тому це не універсальний спосіб захистити будь-які дані. Для великих обсягів є значно економніші підходи. А для коротких команд така схема корисна саме своєю простотою.

Спочатку побачив подвоєння даних і здивувався витратам. Потім побачив, наскільки просто їх перевіряти, — і вибір уже не здається дивним 🙂
❤1
Код із простим повторенням 🔁

Коли читав про інверсійні коди, виникла думка: а чому б просто не передати короткі дані двічі?

А якщо передати тричі, то можна було б не лише помітити помилку, а й відновити дані за більшістю.

Як виявилося, такий підхід уже існує. Хто б міг подумати 😅

Почну з одного біта. Замість однієї одиниці передаю три:

Було:         1
Передаю: 1 1 1


Під час передавання один біт змінився:

Отримав:    1 0 1


Дві одиниці проти одного нуля. За більшістю відновлюю 1.

Із двома копіями так не вийшло б:

Отримав:    1 0


Видно, що значення різні. Але яке правильне — невідомо.

Для довшого повідомлення таке голосування можна виконати окремо на кожній позиції:

Копія 1:    1 0 1 0
Копія 2: 1 0 0 0
Копія 3: 1 0 1 0
-------
Результат: 1 0 1 0


У третій позиції два значення 1 і одне 0. Беру одиницю — початкові дані відновлено ✅

Схожа ідея використовується не тільки під час передавання даних, а й усередині обчислювальних систем.

TMR — Triple Modular Redundancy, або потрійне модульне резервування: одну задачу паралельно виконують три копії обчислювального модуля. Їхні результати надходять до схеми голосування, яка вибирає значення більшості.

Це можуть бути три процесори або три копії певної логічної схеми, а не обов’язково три ядра одного процесора.

Один із напрямів застосування — космічна техніка. Радіація може змінити стан елементів електроніки й спричинити помилку в обчисленні. Якщо збій зачепив один модуль, два інші можуть дати правильний результат, який і пройде далі. Такий підхід описаний, зокрема, у матеріалах NASA про захист програмованих мікросхем від радіаційних збоїв.

Але більшість — не гарантія істини. Якщо в трьох копіях програми однакова помилка, вони можуть дружно отримати неправильну відповідь. Так само повторення біта не врятує, якщо пошкодяться дві копії з трьох.

За стійкість до окремих збоїв доводиться платити: передавати більше бітів або використовувати більше обчислювальних ресурсів.

Тобто три однакові обчислення — не завжди марна робота. Іноді це спосіб продовжити роботу після збою, а не просто отримати три повідомлення про помилку 🙂
Манчестерський код і сто нулів поспіль 📡

Наступна схема виглядає просто:

1 → 10
0 → 01


Один інформаційний біт передається двома послідовними рівнями сигналу. Але навіщо?

Уявімо найпростіший спосіб передавання: нижчий рівень напруги означає 0, вищий — 1.

Якщо передати сто нулів поспіль, рівень увесь цей час не змінюватиметься.

Приймач знає, скільки приблизно має тривати один біт. Але передавач і приймач мають власні тактові генератори, які можуть трохи розходитися за швидкістю. На довгій послідовності без змін сигналу стає складніше визначати межі бітів: тут уже закінчився один нуль чи ще триває попередній? 🤔

Манчестерське кодування додає зміну рівня всередині кожного біта.

Для нашої домовленості:

1 → перша половина: високий рівень
друга половина: низький рівень

0 → перша половина: низький рівень
друга половина: високий рівень


Тобто 10 і 01 тут позначають дві половини часу передавання одного біта, а не два окремі корисні біти.

Передаю чотири нулі:

Дані:     0  0  0  0
Сигнал: 01 01 01 01


Тепер замість незмінного рівня є регулярні переходи. За ними приймач підлаштовує свій такт і визначає, коли зчитувати дані.

Навіть сто однакових бітів уже не перетворюються на довгу ділянку без жодної зміни сигналу ✅

Початок і кінець пакета визначаються окремими правилами протоколу. Манчестерський код насамперед допомагає не втратити синхронізацію під час передавання.

Ось і ще одне призначення надлишковості. Раніше додаткові біти допомагали знаходити помилки. Тут додаткові зміни сигналу допомагають правильно визначати, де закінчується один біт і починається наступний 🙂