Даже если "упёрся", не вижу в этом особой проблемы. Чтение так или иначе предполагает работу с диском, а не с оперативной памятью. Стремиться к "теоретически чистым" метрикам производительности... ну не знаю, мне кажется это немного избыточно. Тогда мы дойдём до обсуждения: давайте проверим на DDR5, потом на DDR4? Ну вы поняли :)
Меня больше интересует практическая сторона - как работает в реальном сценарии. Хотя вы навели меня на интересную мысль: тесты я действительно делал на SSD (и даже не обратил на это внимание), а не на HDD. Возможно, стоит провести аналогичный тест на HDD и посмотреть разницу. Спасибо за идею!
На счёт скорости вы совершенно правы. В обычном режиме (то есть без фильтрации) brec уступает в скорости JSON. Но на то есть объективные причины :)
Brec добавляет заголовки, чтобы распознать сообщение "в мусоре", и включает CRC, чтобы гарантировать, что данные не были повреждены или искажены. Эти проверки естественно увеличивают накладные расходы, поэтому скорость падает. Но даже при такой нагрузке показатели остаются вполне конкурентными:
Как видите, brec вполне держится рядом, можно сказать, сопит на ушко :) Но при активации фильтрации ситуация меняется, и brec значительно выигрывает за счёт возможности пропускать ненужные данные без полного парсинга.
Смотрите, дело в том, что даже если JSONL позволяет построчно обрабатывать данные, внутри каждой строки у вас всё равно находится целый объект. Например, если у вас есть объект { a: number; b: string; c: Something[] }, вы не можете "заглянуть" в поле a, не пропарсив весь объект целиком. То есть вы не узнаете значение поля a, пока не получите полностью готовый объект с помощью парсинга — только тогда можно сделать проверку obj.a = ?.
Теперь представьте ситуацию: у вас 1 млн таких объектов, а вам нужны только те, у которых a == 42. Среди всего массива данных таких объектов — всего 100 (то есть 100 на 1 000 000). Вам придётся пропарсить целиком все 1 000 000 записей, чтобы найти эти 100.
При частичном парсинге (что в том числе предлагает brec, а также ряд других решений) можно заранее на уровне протокола предусмотреть такой "ключ" и поместить его в самое начало сообщения. В таком случае парсер сможет сразу проверить a == 42 и полностью пропустить парсинг остальных полей, если они не удовлетворяют условию.
Разница наглядно показана в тестах brec. Я как раз сравнивал с JSON, который построчно (как и JSONL) читается из файла. Условие теста было — принимать только те записи, которые удовлетворяют условию. В итоге только за счёт того, что brec пропускал ненужные операции парсинга, он проверил ~1 Гб данных за ~300 мс, в то время как у JSON на это ушло ~600 мс. Это не потому что JSON медленный, а потому что он вынужден парсить запись целиком.
Таким образом мы вновь возвращаемся к целеполаганию. Если вы просто обмениваетесь сообщениями и вам не надо ни хранить их, ни "пропускать" (фильтровать), то самый простой JSON вполне достаточен (пока не столкнётесь например с невалидными строками, но это другая история ;))
А ведь очень точно подмечено! Но всё же brec не вносит новый стандарт — его назначение скорее для использования в закрытой системе, где данные не выходят за пределы этой системы, а сам brec - в первую очередь инструмент. То есть я изначально не ставил перед собой такую цель ))
Спасибо за ваши вопросы. Я отвечу сразу по JSONL и JSONB.
JSONL - это классическое текстовое представление, которое не позволяет эффективно фильтровать данные по критериям без полного парсинга, от чего будет страдать производительность поиска/фильтрации. Даже если библиотека включает "читалку", механизм предфильтрации редко доступен из коробки. Большинство известных мне крейтов поддерживают только чтение и запись, а более сложные операции остаются на откуп разработчику. Brec же предоставляет такие инструменты изначально. Мне кажется, что протокол без готовых инструментов недостаточен для полноценной работы.
JSONB действительно имеет некоторое сходство с brec, но если рассматривать его отдельно от PostgreSQL, остаются вопросы поиска и фильтрации. Обычно библиотеки, крейты jsonb предоставляют лишь бинарное представление JSON без развитых инструментов.
В целом, вопрос что лучше, что эффективнее - порочен по своей природе :) JSONL, JSONB и brec решают разные задачи. Если нужен простой обмен сообщениями, я бы выбрал JSONB или даже bincode (мне он видится более лёгким). Но когда речь идёт о хранении и быстром доступе к структурированным данным, приходится думать не только о протоколе, но и о инстументах для него. Собственно brec и пытается решить эту задачу, давая не только сам по себе протокол (то есть возможность его определить), но и инструменты к нему.
Но в конечном итоге, выбор между этими (или любыми другими) форматами зависит от конкретной задачи и требований к данным.
If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins. The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own.
All that said, the reason that this functionality is not included in the Protocol Buffer library is because we have never had a use for it inside Google.
This technique requires support for dynamic messages using descriptors. Check that your platforms support this feature before using self-describing messages.
Спасибо за уточнение, но как уже было отмечено этот вопрос отдан на откуп самим разработчикам, то есть не является частью protobuf
Protobuf - это действительно отличный инструмент, но его основной сценарий использования - это обмен сообщениями, а не их хранение. Protobuf не предусматривает стандартного механизма для идентификации и распознавания сообщений в произвольном потоке данных, и предполагает, что канал связи будет заполнен исключительно protobuf-сообщениями, соответствующими единой заранее определённой схеме. Более того, protobuf не задаёт стандартного формата заголовка сообщения, поэтому эту задачу разработчики вынуждены решать самостоятельно. Ещё один момент, на который стоит обратить внимание, — это кросс-языковая поддержка. Да, она является сильной стороной protobuf, но и здесь есть свои подводные камни. Например, документация прямо указывает, что имплементация сериализации и десериализации может немного отличаться в зависимости от платформы, особенно в отношении значений по умолчанию. Конкретный пример: числовые типы в Rust имеют чётко определённые значения по умолчанию (например,0), тогда как в JavaScript такой концепции просто нет. В результате поле вида field: 0, сериализованное на Rust, и то же самое поле, сериализованное на JavaScript, могут дать совершенно разные наборы байт. Причина в том, что Rust по умолчанию не передаёт значения, совпадающие со значениями по умолчанию, считая это излишним, а JavaScript будет передавать их явно. Такой, казалось бы, незначительный нюанс может стать источником серьёзных проблем при интеграции.
А мне как раз хотелось иметь что-то под рукой, что позволит не только эффективно обмениваться сообщениями, но и надёжно хранить их и без проблем распознавать в смешанных («замусоренных») потоках. И да, "префильтрация", когда я могу "заглянуть" в часть сообщения и понять - нужно ли мне его продолжать парсить.
Проверил на windows 11. Воспроизвести проблему не могу. Работает. Попросил коллегу проверить на windows 10, но это займёт какое-то время. Если у вас есть возможность, присоединяйтесь к обсуждению на github, что бы дать немного больше дополнительной информации.
Конечно рассматривали, я даже в статье упомянул об этом - "не electron'ом единым"... На данный момент стабильной и удовлетворяющей нашим требованиям альтернативы electron'у я не вижу... могу ошибаться, конечно. Дело же не только в том, чтобы браузер обернуть во что-то, дело же ещё в OS API... ну банально - системные диалоги, пуши и прочее. В 2021 мы, например, играли с https://tauri.app/... написан на rust, шустрый до безобразия, но базируется на webview, что не приемлемо с точки зрения производительности клиента (надо проверить, может что изменилось за 2 года). Так что пока мы остались на electron, но, как я уже отметил, ядро очень легко связать с любым клиентом и никакой прямо вот привязанности к electron команда не испытывает... просто сейчас он в наибольшей степени соответствует нашим требованиям.
Спасибо, очень надеюсь chipmunk будет полезным иструментом для вас. Кстати мы добавили поддержку attachments для DLT. Так что если trace включает в себя какие-то файлы, они будут отображены на табе Attachments. Текстовые файлы и графические можно просмотреть прямо в chipmunk.
Мне кажется мы просто говорим с вами о разных вещах. Если не ошибаюсь, вы подразумеваете что-то вроде авторизации (или верификации?), поправьте если я не прав.
Назначение SelfKey и AssignedKey немного в другом, в ассоциировании (наверное будет более точно). Например, SelfKey { uuid: string, lang: string, age: number } (поле uuid добавляется всегда автоматически, даже если этого не сделал разработчик, uuid присваивается сервером после успешного подключения). И, например, AssignedKey { age_confirmed: bool }.
Клиент может выставить и язык, и возраст, как его душе будет угодно, но лишь сервер (после какой-то проверки) может заключить, что возраст 18+ подтверждён.
Я думаю, что понятнее будет, если мы посмотрим на гипотетический запрос, после ответа на который, нам надо сделать broadcast всем русско-говорящим клиентам 18+. Например, пришло сообщение в чат и мы хотим сделать рассылку другим клиентам, но только тем у кого подтвержден возраст и указан целевой язык.
import { Response } from "../implementation/responses/message.request";
import {
Identification,
Protocol,
} from "../implementation/responses";
import { Scope } from "../implementation/scope";
// Обработчик входящего сообщения
export function response(
request: Protocol.Message.Request,
scope: Scope
): Promise<Response> {
// Добавляем сообщение в БД или куда-то еще
...
return Promise.resolve(
new Response(
// Готовим ответ клиенту (отправителю сообщения)
new Protocol.Message.Accepted({
uuid: scope.consumer.uuid(),
})
)
// Создаем список клиентов для broadcast
.broadcast(scope.filter.filter((ident: Identification) => {
// Broadcast message будет отправлять только клиентам, удовлетворящим следующему
// условию
return ident.getAssigned()?.age_confirmed && ident.getKey().lang === 'ru';
}))
// Создаем сообщение которое будет отправлено (broadcast message)
.EventsMessage(
new Protocol.Events.Message({
...,
})
)
);
}
Если вы сейчас подумали о том, что подобные данные хранятся обычно в БД и вытаскиваются по мере необходимости - вы совершенно правы. Идея в том, чтобы часть подобных данных иметь "под рукой" для составления списков broadcast.
Стоит также упомянуть, что и по умолчанию наличие AssignedKey не требуется, равно как можно избежать и использование SelfKey (он будет создан автоматически с единственным полем - uuid). Просто в ввиду слишком большого размера статьи, мне пришлось многое опускать. В документации (вы её уже отругали :)) есть разделы, посвященные настройке producer и стратегий в отношении ключей.
Разница во владельцах. Владельцем SelfKey является клиент и только он может определять значение ключа; в свою очередь владельцем AssignedKey является сервер. То есть клиент может представить себя как ему угодно, а сервер может идентифицировать клиента по-своему, скажем добавить поле verified или что-то в этом духе.
На счёт документации вы совершено правы. Базовые моменты я описал здесь в различных секциях. Но описание конкретных методов всё ещё является слабым место. Я думаю, что это будет embedded документация, то есть встроенная непосредственно в код. Раз уж код генерируется и будут безусловно обновления, то и документацию следуют генерировать тоже.
Всегда стараюсь отвечать максимально деликатно на подобные вашему комментарии. Или просто игнорирую их. Но, знаете, сегодня не буду… надоело, пусть и полетят в меня минусы роем. Для себя я называю такие вот комментарии - «булькающая бабушка».
Суть проста - ты сделаешь что-то, поэкперементируешь, поиграешь с идеями и опишешь это и вот на горизонте появляется она, «булькающая бабушка»… всегда с единственно верным суждением и решимостью его предъявить миру - «это всё г$_&о, не нужно делать х*!?ю»
Она не интересна. Когда становится интересно пора переходить на протобаф, а не думать как сделать джейсон быстрее.
Я учту о чём мне не думать, но все равно поясню: JSON в данной статье упоминается в качестве наиболее распространённого варианта формата данных, что характерно особенно для небольших web проектов. Никто не оспаривает существование прекрасных парсеров для него (взять хотя бы тот же serde на rust). А clibri так и вовсе не использует JSON вообще и раз так, то и не оптимизирует его. Статья вообще не про это.
На счёт таймаутов вы правы, они отлавливаются на всех болевых точках в rust имплементации и будут добавлены также в typescript совсем скоро. Собственно поэтому и есть плашка alpha, что бы подсветить - не все детали ещё учтены, есть базовое решение, но работа ещё ведётся.
Конечно, protobuf - это первое что приходит на ум, и я ждал подобного вопроса. Но не упоминал о protobuf в статье лишь потому, что clibri не является ни конкурентом (куда уж мне в одиночку), ни тем более альтернативой; не в чистом виде, не в связке с gRPC. Это немного о другом.
Я по большей части работаю с web проектами, поэтому и на протокол смотрю именно с этой стороны. Часто нужно сделать какой-то несложный front-end для какого-нибудь сервиса. И каждый раз «под капотом» практически одно и тоже: транспорт, валидатор, реализация клиента, реализация сервера. Наблюдая порой за коллегами я не раз замечал, как реализация какой-нибудь связки «клиент-сервер» кочует от проекта к проекту, с каждой новой итерацией copy/paster, обрастая незначительными изменениями, то есть коллеги просто брали подходящее решение, копировали и заменяли содержание обработчиков, практически не трогая все остальное (ну разве что состав данных менялся безусловно). Но идея clibri именно в этом — дать возможность разработчику вообще не думать о том, что там делает метод send_something_somewhere. И я подумал, возможно будет интересно, если:
не описывать в протоколе ничего кроме данных (может он в рамках того же проекта будет использоваться для чего-то иного, импорта/экспорта, например)
описывая логику коммуникации (workflow) не описывать никаких функций, а описывать только возвраты и последствия возвратов. Добиться от схемы workflow однозначного и единственного толкования.
сделать так, чтобы разработчик в большей части случаев мог бы просто добавить свой код в уже готовый обработчик. То есть сгенерированное решение должно компилироваться сразу же, ещё до того, как добавлено «мясо» в обработчики.
Я не сравнивал clibri по производительность с protobuf ни с точки зрения кодирования/декодирования, ни с точки зрения экономичности, хотя, наверное, это следует сделать, но быть может немного позднее, ибо сейчас это будет сравнение автомобиля с шаттлом челленджер.
Надеюсь ответил. Ещё раз спасибо за хороший вопрос.
Спасибо за ваш комментарий.
Текущая картина такая:
TS: ~74%
Rust: ~16%
HTML, LESS, CSS, Ruby — rest
На rust сейчас наиболее ресурсоёмкие операции: индексация, декодирование/кодирование и другие. Но сессии и поиск модерируются на nodejs. Миграция ядра на rust подразумевает модерацию сессий, включая поиск, на уровне rust; на nodejs останутся лишь какие-то общие задачи. И даже в версии 3.0, я уверен доля rust не вырастет выше 30-35% и это вполне ок, ибо на front-end довольно много кода.
Уточнить: rust не «сбоку», на нем уже сейчас лежит основополагающий функционал по подготовке контента к отображению (как было сказано выше: индексация, кодирование/декодирование). Ну а с версией 3 так и все ядро будет на нем.
Даже если "упёрся", не вижу в этом особой проблемы. Чтение так или иначе предполагает работу с диском, а не с оперативной памятью. Стремиться к "теоретически чистым" метрикам производительности... ну не знаю, мне кажется это немного избыточно. Тогда мы дойдём до обсуждения: давайте проверим на DDR5, потом на DDR4? Ну вы поняли :)
Меня больше интересует практическая сторона - как работает в реальном сценарии. Хотя вы навели меня на интересную мысль: тесты я действительно делал на SSD (и даже не обратил на это внимание), а не на HDD. Возможно, стоит провести аналогичный тест на HDD и посмотреть разницу. Спасибо за идею!
На счёт скорости вы совершенно правы. В обычном режиме (то есть без фильтрации) brec уступает в скорости JSON. Но на то есть объективные причины :)
Brec добавляет заголовки, чтобы распознать сообщение "в мусоре", и включает CRC, чтобы гарантировать, что данные не были повреждены или искажены. Эти проверки естественно увеличивают накладные расходы, поэтому скорость падает. Но даже при такой нагрузке показатели остаются вполне конкурентными:
Сплошное чтение (читаем каждый пакет):
brec, использование хранилища: 908 МБ, 1 000 000 записей — 987 мс
brec, чтение пакетов как потока: 831 МБ, 1 000 000 записей — 764 мс
JSON: 919 МБ, 1 000 000 записей — 597 мс
Чтение с фильтрацией (ищем пакеты по критерию):
brec, использование хранилища: 908 МБ, 140 000 записей — 612 мс
brec, чтение пакетов как потока: 831 МБ, 140 000 записей — 340 мс
JSON: 919 МБ, 140 000 записей — 608 мс
Как видите, brec вполне держится рядом, можно сказать, сопит на ушко :) Но при активации фильтрации ситуация меняется, и brec значительно выигрывает за счёт возможности пропускать ненужные данные без полного парсинга.
Смотрите, дело в том, что даже если JSONL позволяет построчно обрабатывать данные, внутри каждой строки у вас всё равно находится целый объект. Например, если у вас есть объект
{ a: number; b: string; c: Something[] }
, вы не можете "заглянуть" в полеa
, не пропарсив весь объект целиком. То есть вы не узнаете значение поляa
, пока не получите полностью готовый объект с помощью парсинга — только тогда можно сделать проверкуobj.a = ?
.Теперь представьте ситуацию: у вас 1 млн таких объектов, а вам нужны только те, у которых
a == 42
. Среди всего массива данных таких объектов — всего 100 (то есть 100 на 1 000 000). Вам придётся пропарсить целиком все 1 000 000 записей, чтобы найти эти 100.При частичном парсинге (что в том числе предлагает brec, а также ряд других решений) можно заранее на уровне протокола предусмотреть такой "ключ" и поместить его в самое начало сообщения. В таком случае парсер сможет сразу проверить
a == 42
и полностью пропустить парсинг остальных полей, если они не удовлетворяют условию.Разница наглядно показана в тестах brec. Я как раз сравнивал с JSON, который построчно (как и JSONL) читается из файла. Условие теста было — принимать только те записи, которые удовлетворяют условию. В итоге только за счёт того, что brec пропускал ненужные операции парсинга, он проверил ~1 Гб данных за ~300 мс, в то время как у JSON на это ушло ~600 мс. Это не потому что JSON медленный, а потому что он вынужден парсить запись целиком.
Таким образом мы вновь возвращаемся к целеполаганию. Если вы просто обмениваетесь сообщениями и вам не надо ни хранить их, ни "пропускать" (фильтровать), то самый простой JSON вполне достаточен (пока не столкнётесь например с невалидными строками, но это другая история ;))
А ведь очень точно подмечено! Но всё же brec не вносит новый стандарт — его назначение скорее для использования в закрытой системе, где данные не выходят за пределы этой системы, а сам brec - в первую очередь инструмент. То есть я изначально не ставил перед собой такую цель ))
Спасибо за ваши вопросы. Я отвечу сразу по JSONL и JSONB.
JSONL - это классическое текстовое представление, которое не позволяет эффективно фильтровать данные по критериям без полного парсинга, от чего будет страдать производительность поиска/фильтрации. Даже если библиотека включает "читалку", механизм предфильтрации редко доступен из коробки. Большинство известных мне крейтов поддерживают только чтение и запись, а более сложные операции остаются на откуп разработчику. Brec же предоставляет такие инструменты изначально. Мне кажется, что протокол без готовых инструментов недостаточен для полноценной работы.
JSONB действительно имеет некоторое сходство с brec, но если рассматривать его отдельно от PostgreSQL, остаются вопросы поиска и фильтрации. Обычно библиотеки, крейты jsonb предоставляют лишь бинарное представление JSON без развитых инструментов.
В целом, вопрос что лучше, что эффективнее - порочен по своей природе :) JSONL, JSONB и brec решают разные задачи. Если нужен простой обмен сообщениями, я бы выбрал JSONB или даже bincode (мне он видится более лёгким). Но когда речь идёт о хранении и быстром доступе к структурированным данным, приходится думать не только о протоколе, но и о инстументах для него. Собственно brec и пытается решить эту задачу, давая не только сам по себе протокол (то есть возможность его определить), но и инструменты к нему.
Но в конечном итоге, выбор между этими (или любыми другими) форматами зависит от конкретной задачи и требований к данным.
Спасибо за уточнение, но как уже было отмечено этот вопрос отдан на откуп самим разработчикам, то есть не является частью protobuf
Спасибо за вопрос!
Protobuf - это действительно отличный инструмент, но его основной сценарий использования - это обмен сообщениями, а не их хранение. Protobuf не предусматривает стандартного механизма для идентификации и распознавания сообщений в произвольном потоке данных, и предполагает, что канал связи будет заполнен исключительно protobuf-сообщениями, соответствующими единой заранее определённой схеме. Более того, protobuf не задаёт стандартного формата заголовка сообщения, поэтому эту задачу разработчики вынуждены решать самостоятельно.
Ещё один момент, на который стоит обратить внимание, — это кросс-языковая поддержка. Да, она является сильной стороной protobuf, но и здесь есть свои подводные камни. Например, документация прямо указывает, что имплементация сериализации и десериализации может немного отличаться в зависимости от платформы, особенно в отношении значений по умолчанию. Конкретный пример: числовые типы в Rust имеют чётко определённые значения по умолчанию (например,
0
), тогда как в JavaScript такой концепции просто нет. В результате поле видаfield: 0
, сериализованное на Rust, и то же самое поле, сериализованное на JavaScript, могут дать совершенно разные наборы байт. Причина в том, что Rust по умолчанию не передаёт значения, совпадающие со значениями по умолчанию, считая это излишним, а JavaScript будет передавать их явно. Такой, казалось бы, незначительный нюанс может стать источником серьёзных проблем при интеграции.А мне как раз хотелось иметь что-то под рукой, что позволит не только эффективно обмениваться сообщениями, но и надёжно хранить их и без проблем распознавать в смешанных («замусоренных») потоках. И да, "префильтрация", когда я могу "заглянуть" в часть сообщения и понять - нужно ли мне его продолжать парсить.
Thanks!
Проверил на windows 11. Воспроизвести проблему не могу. Работает. Попросил коллегу проверить на windows 10, но это займёт какое-то время.
Если у вас есть возможность, присоединяйтесь к обсуждению на github, что бы дать немного больше дополнительной информации.
Спасибо за рапорт. Создал issue с высоким приоритетом. Проверим обязательно в самое ближайшее время.
Конечно рассматривали, я даже в статье упомянул об этом - "не electron'ом единым"... На данный момент стабильной и удовлетворяющей нашим требованиям альтернативы electron'у я не вижу... могу ошибаться, конечно.
Дело же не только в том, чтобы браузер обернуть во что-то, дело же ещё в OS API... ну банально - системные диалоги, пуши и прочее. В 2021 мы, например, играли с https://tauri.app/... написан на rust, шустрый до безобразия, но базируется на webview, что не приемлемо с точки зрения производительности клиента (надо проверить, может что изменилось за 2 года). Так что пока мы остались на electron, но, как я уже отметил, ядро очень легко связать с любым клиентом и никакой прямо вот привязанности к electron команда не испытывает... просто сейчас он в наибольшей степени соответствует нашим требованиям.
спасибо!
Спасибо, очень надеюсь chipmunk будет полезным иструментом для вас. Кстати мы добавили поддержку attachments для DLT. Так что если trace включает в себя какие-то файлы, они будут отображены на табе Attachments. Текстовые файлы и графические можно просмотреть прямо в chipmunk.
Спасибо за хорошее замечание. В переименовании действительно есть смысл.
Нет клиент не может изменить
uuid
(хоть это и поле ключа),uuid
назначается только сервером.Мне кажется мы просто говорим с вами о разных вещах. Если не ошибаюсь, вы подразумеваете что-то вроде авторизации (или верификации?), поправьте если я не прав.
Назначение
SelfKey
иAssignedKey
немного в другом, в ассоциировании (наверное будет более точно). Например,SelfKey { uuid: string, lang: string, age: number }
(поле uuid добавляется всегда автоматически, даже если этого не сделал разработчик, uuid присваивается сервером после успешного подключения). И, например,AssignedKey { age_confirmed: bool }
.Клиент может выставить и язык, и возраст, как его душе будет угодно, но лишь сервер (после какой-то проверки) может заключить, что возраст 18+ подтверждён.
Я думаю, что понятнее будет, если мы посмотрим на гипотетический запрос, после ответа на который, нам надо сделать broadcast всем русско-говорящим клиентам 18+. Например, пришло сообщение в чат и мы хотим сделать рассылку другим клиентам, но только тем у кого подтвержден возраст и указан целевой язык.
Если вы сейчас подумали о том, что подобные данные хранятся обычно в БД и вытаскиваются по мере необходимости - вы совершенно правы. Идея в том, чтобы часть подобных данных иметь "под рукой" для составления списков broadcast.
Стоит также упомянуть, что и по умолчанию наличие
AssignedKey
не требуется, равно как можно избежать и использованиеSelfKey
(он будет создан автоматически с единственным полем -uuid
). Просто в ввиду слишком большого размера статьи, мне пришлось многое опускать. В документации (вы её уже отругали :)) есть разделы, посвященные настройке producer и стратегий в отношении ключей.Разница во владельцах. Владельцем
SelfKey
является клиент и только он может определять значение ключа; в свою очередь владельцемAssignedKey
является сервер. То есть клиент может представить себя как ему угодно, а сервер может идентифицировать клиента по-своему, скажем добавить полеverified
или что-то в этом духе.На счёт документации вы совершено правы. Базовые моменты я описал здесь в различных секциях. Но описание конкретных методов всё ещё является слабым место. Я думаю, что это будет embedded документация, то есть встроенная непосредственно в код. Раз уж код генерируется и будут безусловно обновления, то и документацию следуют генерировать тоже.
Спасибо за ваш комментарий.
Всегда стараюсь отвечать максимально деликатно на подобные вашему комментарии. Или просто игнорирую их. Но, знаете, сегодня не буду… надоело, пусть и полетят в меня минусы роем. Для себя я называю такие вот комментарии - «булькающая бабушка».
Суть проста - ты сделаешь что-то, поэкперементируешь, поиграешь с идеями и опишешь это и вот на горизонте появляется она, «булькающая бабушка»… всегда с единственно верным суждением и решимостью его предъявить миру - «это всё г$_&о, не нужно делать х*!?ю»
Я учту о чём мне не думать, но все равно поясню: JSON в данной статье упоминается в качестве наиболее распространённого варианта формата данных, что характерно особенно для небольших web проектов. Никто не оспаривает существование прекрасных парсеров для него (взять хотя бы тот же serde на rust). А clibri так и вовсе не использует JSON вообще и раз так, то и не оптимизирует его. Статья вообще не про это.
На счёт таймаутов вы правы, они отлавливаются на всех болевых точках в rust имплементации и будут добавлены также в typescript совсем скоро. Собственно поэтому и есть плашка alpha, что бы подсветить - не все детали ещё учтены, есть базовое решение, но работа ещё ведётся.
Спасибо. Добра вам и терпимости к инакомыслию.
Большое спасибо за хороший вопрос.
Конечно, protobuf - это первое что приходит на ум, и я ждал подобного вопроса. Но не упоминал о protobuf в статье лишь потому, что clibri не является ни конкурентом (куда уж мне в одиночку), ни тем более альтернативой; не в чистом виде, не в связке с gRPC. Это немного о другом.
Я по большей части работаю с web проектами, поэтому и на протокол смотрю именно с этой стороны. Часто нужно сделать какой-то несложный front-end для какого-нибудь сервиса. И каждый раз «под капотом» практически одно и тоже: транспорт, валидатор, реализация клиента, реализация сервера. Наблюдая порой за коллегами я не раз замечал, как реализация какой-нибудь связки «клиент-сервер» кочует от проекта к проекту, с каждой новой итерацией copy/paster, обрастая незначительными изменениями, то есть коллеги просто брали подходящее решение, копировали и заменяли содержание обработчиков, практически не трогая все остальное (ну разве что состав данных менялся безусловно). Но идея clibri именно в этом — дать возможность разработчику вообще не думать о том, что там делает метод send_something_somewhere. И я подумал, возможно будет интересно, если:
не описывать в протоколе ничего кроме данных (может он в рамках того же проекта будет использоваться для чего-то иного, импорта/экспорта, например)
описывая логику коммуникации (workflow) не описывать никаких функций, а описывать только возвраты и последствия возвратов. Добиться от схемы workflow однозначного и единственного толкования.
сделать так, чтобы разработчик в большей части случаев мог бы просто добавить свой код в уже готовый обработчик. То есть сгенерированное решение должно компилироваться сразу же, ещё до того, как добавлено «мясо» в обработчики.
Я не сравнивал clibri по производительность с protobuf ни с точки зрения кодирования/декодирования, ни с точки зрения экономичности, хотя, наверное, это следует сделать, но быть может немного позднее, ибо сейчас это будет сравнение автомобиля с шаттлом челленджер.
Надеюсь ответил. Ещё раз спасибо за хороший вопрос.
Текущая картина такая:
На rust сейчас наиболее ресурсоёмкие операции: индексация, декодирование/кодирование и другие. Но сессии и поиск модерируются на nodejs. Миграция ядра на rust подразумевает модерацию сессий, включая поиск, на уровне rust; на nodejs останутся лишь какие-то общие задачи. И даже в версии 3.0, я уверен доля rust не вырастет выше 30-35% и это вполне ок, ибо на front-end довольно много кода.
Уточнить: rust не «сбоку», на нем уже сейчас лежит основополагающий функционал по подготовке контента к отображению (как было сказано выше: индексация, кодирование/декодирование). Ну а с версией 3 так и все ядро будет на нем.