Телеметрія там, де звʼязок падає на години
Телеметрію зазвичай проєктують в офісі, де інтернет є завжди. Потім її ставлять на придорожню мийку або промисловий майданчик, де мобільний звʼязок зникає щотижня, іноді на пів дня, і виявляється, що система вміє лише два стани: «усе добре» і «немає даних». Нижче — як зробити так, щоб обрив звʼязку був звичайною подією, а не аварією, і щоб після нього дані були повними, а не дірявими.
Обрив — це нормальний стан
Перше рішення, від якого залежить усе інше: обʼєкт має працювати сам, без сервера. Термінал приймає оплату, контролер запускає пост, події пишуться локально. Сервер — це місце, куди дані доходять, а не місце, де вони народжуються. Якщо обʼєкт не може працювати без сервера, ніяка телеметрія не врятує: вона просто зафіксує простій.
У мережі мийок, яку ми супроводжуємо, термінали побудовані саме так: приймають оплату без звʼязку і досилають транзакції, коли канал повертається. Через них пройшло 14 мільйонів платіжних транзакцій, і частина з них ішла саме цим шляхом — спершу локально, потім на сервер.
Друге рішення: дані мають бути повними, а не свіжими. Пропущені пʼять хвилин показників — не страшно. Пропущена оплата — це гроші, які не зійдуться на звірці. Тому черга подій має бути надійною для платежів і може бути «з втратами» для показників, які все одно оновлюються щохвилини.
Буфер: що зберігати і скільки
Локальний буфер — це не структура в памʼяті, яка зникне при перезавантаженні, а сховище на диску, що переживає відключення живлення. На обʼєкті живлення падає частіше, ніж звʼязок, і саме в момент, коли звʼязку теж немає.
Розмір буфера рахується від найдовшого обриву, який ви готові пережити без втрат, а не від середнього. Якщо звʼязок може зникнути на добу, буфер має вмістити добу подій усіх типів на найзавантаженіший день. Це небагато байтів, але це має бути порахованим числом, а не припущенням.
Коли буфер повний, потрібне правило: що викидати. Правильна відповідь — старі показники, ніколи не платежі. І це правило має бути в коді, а не в голові. Окремо: буфер, який ніколи не спорожняється, бо сервер повертає помилку на одну подію і черга зупиняється на ній, — найчастіший спосіб втратити тиждень даних. Проблемна подія відкладається вбік, решта йде далі.
Годинник, який бреше
Контролер без синхронізації часу дрейфує, і за місяць може розійтись із сервером на хвилини. Поки звʼязок є, це непомітно: сервер ставить свою мітку при отриманні. Коли події досилаються після обриву, мітка отримання вже нічого не означає, і залишається лише мітка обʼєкта — та, що дрейфує.
Тому кожна подія має нести дві мітки: час обʼєкта і час отримання сервером. Різниця між ними в момент, коли звʼязок є, — це виміряний дрейф, і його можна застосувати до подій, досланих із буфера. Час зберігається в UTC; місцевий час — лише для показу.
Окремий випадок — обʼєкт, який перезавантажився без батарейки годинника і прокинувся в 1970 році. Такі події видно одразу, якщо система їх шукає, і вони губляться назавжди, якщо не шукає. Правило просте: мітка часу, раніша за дату встановлення системи, — це помилка, а не подія.
Дедуплікація
Досилання після обриву майже гарантує дублікати: обʼєкт відправив, сервер отримав, підтвердження не дійшло, обʼєкт відправив ще раз. Якщо сервер рахує обидві, виручка за день подвоюється саме в ті дні, коли звʼязок був поганий, — і це найгірший момент для помилки, бо ті дні і так важко звірити.
Кожна подія повинна мати ідентифікатор, який обʼєкт створює сам у момент події, а не сервер у момент отримання. Сервер, отримавши подію з відомим ідентифікатором, відповідає «прийнято» і нічого не робить. Обʼєкт, отримавши «прийнято», видаляє подію з буфера. Це весь механізм, і він має бути з першого дня, бо додати його пізніше означає перерахувати історію.
Ідентифікатор має бути унікальним між обʼєктами, а не лише всередині одного. Номер поста плюс лічильник, який скидається при перезавантаженні, — не унікальний. Ідентифікатор обʼєкта, час і випадкова частина — так.
Що має показувати панель
Найважливіше число на панелі обʼєкта — не виручка і не температура, а вік останніх даних. «Пост 3: оновлено 4 хвилини тому» і «Пост 3: оновлено 6 годин тому» — це два різні стани, і панель, яка показує в обох випадках одне й те саме зелене значення, бреше.
Кожен показник має вік, і панель показує його явно — кольором, підписом, як завгодно, але помітно. Значення, старше за певний поріг, показується як застаріле, а не як актуальне. Це стосується і зведених чисел: виручка за сьогодні по мережі, в якій один обʼєкт шість годин без звʼязку, — це не виручка, а нижня межа, і панель має так і казати.
Друга річ — розмір буфера на кожному обʼєкті. Буфер, що росте, означає обрив, який ще триває. Буфер, який не спорожнився після відновлення звʼязку, означає помилку в досиланні. Обидва стани мають бути видимі без того, щоб хтось заходив на обʼєкт по SSH.
Сповіщення, які не кричать даремно, і вибір каналу
Сповіщення про обрив звʼязку, яке приходить при кожному обриві, перестають читати за тиждень. Правило, яке працює: сповіщати не про факт обриву, а про його тривалість понад поріг, і поріг ставити від того, скільки обʼєкт може працювати сам. Обрив на десять хвилин — нічого. Обрив, довший за половину буфера, — так.
Друге правило: сповіщати про те, що вимагає дії, і мовчати про решту. «Звʼязок відновлено» — не вимагає дії, це для журналу. «Буфер не спорожнюється після відновлення» — вимагає. «Пост не дав жодної події за годину в робочий час» — вимагає, і це часто корисніше за будь-яке сповіщення про звʼязок, бо ловить і обрив, і зламаний пост, і зламаний термінал.
Щодо каналу. Мобільний звʼязок дешевий, ставиться за день і падає. Дротовий — дорогий у прокладанні, але стабільний. Наш досвід: якщо на обʼєкті є можливість дротового каналу, він окупається; якщо ні — мобільний із резервом від другого оператора і телеметрія, побудована як описано вище. Помилка — розраховувати на мобільний канал як на постійний і будувати систему, яка без нього стоїть.
Часті питання
Скільки має вміщати буфер
Чому виручка після обриву звʼязку вища, ніж мала б бути
Мобільний канал чи дріт
Ще відповіді
Оновлено: 2026-09-22