惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
T
ThreatConnect
SecWiki News
SecWiki News
F
Future of Privacy Forum
AWS News Blog
AWS News Blog
C
Cisco Blogs
A
Arctic Wolf
Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
V2EX
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
K
Kaspersky official blog
G
Google Developers Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
N
News | PayPal Newsroom
Schneier on Security
Schneier on Security
NISL@THU
NISL@THU
Microsoft Azure Blog
Microsoft Azure Blog
量子位
The Hacker News
The Hacker News
Stack Overflow Blog
Stack Overflow Blog
Security Latest
Security Latest
M
Microsoft Research Blog - Microsoft Research
Google Online Security Blog
Google Online Security Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
I
InfoQ
Google DeepMind News
Google DeepMind News
Y
Y Combinator Blog
The Cloudflare Blog
Microsoft Security Blog
Microsoft Security Blog
Martin Fowler
Martin Fowler
Cisco Talos Blog
Cisco Talos Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Troy Hunt's Blog
F
Fox-IT International blog
S
Security @ Cisco Blogs
博客园 - 司徒正美
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
C
Comments on: Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
L
LINUX DO - 最新话题
GbyAI
GbyAI
Project Zero
Project Zero
腾讯CDC
T
Tailwind CSS Blog

Все публикации подряд на Хабре

AI обнулил benchmark и пытался шантажировать инженера. И почему это решаемо Почему пластиковый корпус оказался в 3 раза дороже металлического Как спроектировать API, которое не придется переписывать через полгода Трекинг посетителей на fisheye-камерах: задача “со звездочкой” Красивый скриншот вашего кода. Большое обновление Я создаю проекты без единого созвона с командой Content Pipeline в MonoGame: почему я его не использую Гемблинг партнерки: Как выбрать, ТОП 5 в 2026 За пределами LLM, часть 2: якорная таблица Кэли, которая не является ни полем, ни моноидом Pixverse купить подписку: для чего нужна Пиксверс подписка, как выбрать тариф и оплатить в рублях Meshy AI нейросеть: как создавать 3D-модели из текста и изображений в Меши АИ на русском бесплатно Skywork AI: как использовать Скайворк АИ нейросеть на русском бесплатно, работать с промтами и создавать видео Технотекст 8: победа естественного интеллекта Capacitor: от веба к мобильным приложениям. Часть 4. Интегрируем локальный LLM в проект 20 лет видеокарт в цифрах: как росли FLOPS и TDP и кто вёл в дуэли NVIDIA vs AMD (+ открытый датасет на 13 500 GPU) Архитектура крипто-сканера для биржи: Open Interest, Funding Rate, EMA и MACD в реальном времени @tanstack/vue-table: почему я почти отказался от этого… WHERE превращает ваш LEFT JOIN в INNER JOIN. И никто вам об этом не скажет Гравитация не существует. Вы задали 454 вопроса о времени. Вот ответы с уравнениями Эйнштейна Конец бесплатного кремния: как Google AI Studio превратилась из рая для инженеров в симулятор смены аккаунтов Свой AI-агент из почты, systemd и LLM MemForge2: загрузочная флешка, которая за минуту говорит — какую планку памяти менять Лицензии важны. Разбор ошибок авторов и пользователей программ От RAG-прототипа к агенту в продакшн: путь по метрикам, а не по моде Serial Terminal: кастомный веб-терминал для последовательного порта на Web Serial API Китайский стартап GigaAI обещает робота-домработника за 1 млн рублей уже в 2027 году — правда или PR? Open-source VPN клиент Tunguska Роман за 6 недель без идеи на старте: миф или реальность? ИИ построит ваш план действий за 10 секунд Security Week 2622: эффективность Claude Mythos по версии Cloudflare Reactive Forms vs Signal Forms: Эволюция сложных форм в Angular TorFlash — приложение для Linux: поиск торрентов, скачивание и копирование на флешку в одно нажатие Как я решил проблему русской диктовки для ИИ Оверинжиниринг, потопивший немецкую подлодку или некоторые «баги» не чинятся десятилетиями Как ставить цели и не забывать о них: пошаговая система с примерами в таск-менеджере Как настроить observability в Spring Boot 3 HackTheBox. Прохождение Mini Pro Lab Puppet Обзор серверного ускорителя NVIDIA Tesla V100 16 Gb в корпусе от RTX 4090: Часть 3 — Запуск локальных моделей ИИ Редактирование текста нейросетью: как сделать диплом и курсовую более человечными Самодельный ARM ноутбук, реально ли? Как 100+ авторов пишут 100+ процессов в 3 версиях и не путаются. Или как мы переехали с Wiki на Git Прошла AnalystDays – хорошие выступления и нетворкинг VSCode как IDE для embedded разработки Моделирование широкополосной антенны с двойной круговой поляризацией и высокой изоляцией Ваше прошлое физически существует прямо сейчас. И вы заморожены там навсегда От списка инструментов к technical output: как security engineer’у описывать hands-on опыт в CV и на интервью I just want an agent. Часть 1. Как я научил ИИ собирать ИИ-агентов за пользователей и выиграл конкурс I just want an agent. Часть 1. Как я научил ИИ собирать ИИ-агентов за пользователей и выиграл конкурс Вайбкодинг спас меня от подрядчиков. А потом я поняла, что сама стала подрядчиком для своих агентов Святой Августин и GAN: почему борьба добра и зла — это генеративная состязательная сеть В каждом QR-коде зашита половина лишней информации. Намеренно Я открываю автомат ключом, меняю рулон бумаги и зарабатываю 180 тысяч в месяц с точки Мастер восстановления. Культура достиженства и выгорание Недельный геймдев: #279 — 24 мая, 2026 Защита от дублирования кода агентами: семантические концепции Frontend Status: свежий дайджест фронтенда и AI — 25.05.2026 Где искать IT-работу кроме HH: подборка платформ 2026 Почему простые числа собираются в спирали? OCR для Data Lakehouse: от Apache Tika к собственному решению на базе Docling Jira — Тьюринг-полная Kubernetes-аудит после Wiz и Prisma: как живут без CNAPP в 2026 «Тестируем MVP в 4 раза быстрее»: как нейросети изменили жизнь предпринимателей На каком стеке и железе работает умное наблюдение в вашем городе: обзор технологий от разработчиков видеоаналитики Как мы ускорили согласования на двух заводах в 24 раза Heartbeat-мониторинг cron-job'ов: dead-man-switch на FastAPI [Перевод] Сегодня нет джуниоров, а в 2031 году не станет и синьоров Профайлер для PostgreSQL: от идеи до работающего MVP за сутки [Перевод] Ограничения размера cookie в ASP.NET Core в продакшене: причины и способы решения Проблема «божественного» Obsidian: почему я отказался от централизованного подхода в работе Лицензии GNU GPL: как пройти проверку Минцифры и заказчика для госзакупок и КИИ Хакатон Samsung IT Academy Hack 2026: как студенты оптимизировали поиск в корпоративном мессенджере Хакатон Samsung IT Academy Hack 2026: как студенты оптимизировали поиск в корпоративном мессенджере MTProxy jumper — делаем автоматическое переключение прокси-серверов Telegram Ты уже используешь агента. Просто не заметил Книжный салон. Послевкусие и благодарности Как отлаживать мини‑приложения в MAX и почему без DevTools это боль Cбор биометрических данных. Как защищается наша биометрия на практике Как запустить учет активов без цифровой свалки: первые 90 дней CGE: визуализация кравлера и скрытых связей между поддоменами Зачем банки тратят миллиарды на науку (спойлер: не благотворительности ради) Книга: «Современный Java Concurrency. Глубокое погружение в Virtual Threads, Structured Concurrency и Scoped Values» Как использовать подписку ChatGPT и Claude в Cursor без оплаты за API токены Специализированная ИСУП или модуль в универсальной платформе: вот в чем вопрос Обход белых списков через WebRTC на стероидах (с поддержкой iOS и десктопа) Регата INFOSTART CIO CAMP: когда команда проверяется не в переговорной, а на воде Пет-проект, который не умер: система бронирования устройств как полигон для AI-разработки Не надо встраивать ИИ в каждую корпоративную систему, это архитектурная ошибка Нейросети для дизайна интерьера: Выбираем лучший ИИ для генерации концептов и планировок квартиры Что там с Ил-114-300 Что такое DAS: как и зачем продукт-менеджеры саботируют запуск новых продуктов 8% компаний измеряют критическое мышление руководителей. Что делают остальные 92% CVE, Shell и побег из контейнера: испытываем возможности PT Cloud Application Firewall Как я научил Алису петь: генерация музыки по голосовой команде Восстановление данных с помощью бесплатной утилиты Easy Disk Checker Как мы построили сквозную аналитику в Power BI Год разработки iOS-игры, 266 тысяч показов и $33: как я делал Vault и почти ничего не заработал Ты прокрастинируешь потому, что избегаешь напрасных усилий, а не чрезмерных нагрузок Я построила диагностику «стоит ли это автоматизировать» — и она трижды говорила глупости. Разбор ошибок Как устроены world models, что показал Google на прошлой неделе и где это меняет gamedev и робототехнику Двухдневная рабочая неделя — будущий стандарт
brec: контролируемая обратная совместимость протокола
AlexWriter · 2026-05-26 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение5 мин

Охват и читатели2

Обзор

С момента последней (и вроде единственной) статьи о brec прошло какое-то время, и мне кажется, что будет полезно лишний раз напомнить о проекте. Даже неожиданно для меня самого он продолжает развиваться. Пусть я пока не могу похвастаться значимым интересом со стороны сообщества, но в паре локальных проектов он уже появился. Да, скорее как эксперимент. Тем даже лучше: можно провести, что называется, полевые испытания.


Кратко напомню, в чем суть. brec - это инструмент для создания бинарного протокола. Две основные сущности - это Block и Payload. Объявляются они максимально просто:

use serde::{Deserialize, Serialize};

#[block]
pub struct MetaBlock {
    pub request_id: u32,
}

#[block]
pub struct PriorityBlock {
    pub level: u8,
}

#[payload(bincode)]
#[derive(Serialize, Deserialize)]
pub struct GreetingPayload {
    pub message: String,
}

#[payload(bincode)]
#[derive(Serialize, Deserialize)]
pub struct BinaryPayload {
    pub tag: String,
    pub compressed: bool,
    pub bytes: Vec<u8>,
    pub status: u16,
}

Все. Теперь можно формировать "сообщение" или, если хотите, "запись", состоящую из 0-255 блоков и опционального Payload. Блоки можно комбинировать свободно: использовать как разные, так и одинаковые, в любом порядке, если это имеет смысл для вашего протокола.

let packet = Packet::new(
    vec![
        Block::MetaBlock(MetaBlock { request_id: 7 }),
        Block::PriorityBlock(PriorityBlock { level: 2 }),
    ],
    Some(Payload::GreetingPayload(GreetingPayload {
        message: "this one carries both blocks and text".to_owned(),
    })),
);

Готовый пакет можно записывать в буфер, отправлять куда нужно и на другом конце декодировать обратно в типизированные структуры.

Описав свои блоки и полезную нагрузку с помощью #[block] и #[payload], brec сделает большую часть рутинной работы:

  • создаст глобальное перечисление Block, включающее все варианты блоков;

  • создаст глобальное перечисление Payload, включающее все варианты полезной нагрузки;

  • добавит к пакету, блокам и payload-данным сигнатуры и CRC-проверки целостности, если вы явно не отключили их атрибутами вроде no_crc;

  • создаст тип Packet, который можно использовать для получения бинарного представления пакета и чтения его обратно.

Но одна из особенностей brec в том, что кроме ядра протокола в нем есть набор инструментов для работы с этим протоколом на практике.

Это, в первую очередь, PacketBufReader и Storage. Более подробно об этих "ребятах" можно посмотреть в предыдущей статье, если интересно. Сейчас же я хочу кратко представить новый режим работы, который связан с фичей resilient.

PacketBufReader и так умеет читать "замусоренный" поток: то есть находить пакеты brec внутри массива сторонних данных. Но resilient решает другую задачу - более мягкую эволюцию протокола, когда старый reader встречает новые, еще неизвестные ему блоки или payload-данные.

Представьте, что вы сделали протокол с блоками BlockA, BlockB, BlockC и payload-типами PayloadA, PayloadB. Сообщения в системе могут выглядеть примерно так:

packet: [BlockA, BlockB] + Some(PayloadA)
packet: [BlockA, BlockB] + Some(PayloadB)
packet: [BlockC] + None

Спустя время вы вводите в систему BlockD и PayloadC. В большинстве случаев это приводит к потере совместимости: старый reader уже не может прочитать сообщение с новой сущностью.

packet: [BlockA, BlockB, BlockD] + Some(PayloadA)
packet: [BlockA, BlockB] + Some(PayloadC)

То есть приходится обновлять все компоненты системы почти одновременно. В обычном режиме brec тоже остановится на неизвестной сигнатуре и вернет ошибку.

В режиме resilient поведение меняется: brec пытается прочитать пакет хотя бы в той части, которая известна текущей версии протокола. Неизвестные блоки и неизвестный payload не превращаются в фиктивный UNKNOWN внутри Block или Payload: они пропускаются, а информация о них возвращается отдельно как список Unrecognized в PacketReadStatus.

Упрощенно это выглядит так:

packet: [BlockA, BlockB, BlockD] + Some(PayloadA)
    -> [BlockA, BlockB] + Some(PayloadA), skipped: [BlockD]

packet: [BlockA, BlockB] + Some(PayloadC)
    -> [BlockA, BlockB] + None, skipped: [PayloadC]

И это важная деталь. Если старый компонент не знает новый payload, он не сможет магически обработать его содержимое. Но он может не упасть на чтении всего пакета, сохранить известные блоки, увидеть факт пропуска и принять нормальное решение: проигнорировать запись, отправить ее в отдельный поток, переложить в storage, залогировать несовместимость или обработать только известную индексную часть.

Под капотом для блоков это работает за счет дополнительного поля длины тела блока в resilient-режиме. Когда reader видит неизвестную сигнатуру блока, он все еще может понять, сколько байт нужно пропустить, не зная структуры этого блока. Для payload-данных похожая идея опирается на заголовок: если сигнатура неизвестна, но длина payload корректна и помещается в границы пакета, тело можно пропустить.

При этом resilient не означает "проглотить любую битую запись". Если CRC-проверку не проходит известный блок или известный payload, это остается жесткой ошибкой. Если длина неизвестного блока или payload некорректна, выходит за границы пакета или данных не хватает, это тоже ошибка или NotEnoughData. Фича нужна не для маскировки повреждений, а для forward compatibility: старый код может пережить появление новых типов, если протокол к этому готов.

Где это реально может быть полезно:

  • Rolling update сервисов. Новый producer уже пишет дополнительный блок с диагностикой, версией алгоритма или tenant-метаданными, а часть consumer'ов еще работает на старом протоколе. Старые consumer'ы могут продолжить читать известные блоки и известный payload, вместо того чтобы падать на первой новой записи.

  • Логи и event storage. В storage годами лежат записи разных версий, а утилиты анализа обновляются не всегда синхронно с producer'ами. Старый CLI или offline-задача может продолжить сканировать поток по известным индексным блокам, даже если новые записи уже содержат расширенные блоки.

  • Edge-клиенты и встраиваемые агенты. Не все клиенты можно обновить одновременно. Если сервер начал добавлять новый optional-блок, старый агент не обязан сразу становиться несовместимым со всем потоком.

  • Плагины и расширения. Базовый обработчик может понимать основной протокол, а отдельные команды или плагины могут добавлять свои блоки. Без resilient такие расширения легко ломают старые инструменты, которые вообще не обязаны знать о plugin-specific данных.

Есть и обратная сторона: фичу стоит включать осознанно. У нее есть небольшой overhead в wire format для блоков, а проектировать протокол все равно нужно аккуратно. Например, если новая версия переносит критически важный смысл только в новый payload, старый reader честно вернет None для payload, и дальше уже ваша логика должна решить, что делать с такой записью.

Подробнее про resilient лучше читать в документации. Здесь я не хочу утомлять деталями wire format, но главная идея именно такая: неизвестное можно пропустить, известное можно прочитать, поврежденное нельзя выдавать за корректное.

Напоследок скажу, что первые версии brec по производительности я сравнивал с JSON, но позже решился сравнить и с Protobuf/FlatBuffers. Я не претендую на первенство ни в коем случае, но результаты выглядят достойно в ряде сценариев. Например, использование brec как протокола для логирования с последующим быстрым поиском и фильтрацией по блокам - вполне оправданная идея.

Как всегда, призываю поделиться "звездочкой" на GitHub. Для вас это просто клик, а для меня - обратная связь и мотивация не забрасывать проект, а развивать его дальше. Лучи добра и света каждому, кто не пройдет мимо.

Спасибо.