Комментарии 52
Веб в своё время расцвёл именно благодаря текстовым протоколам. Сейчас же многие "закручивают гайки" экономя на спичках, тормозя инновации под предлогом оптимизации.
Не хотиnе ли попробовать реализовать сериализатор в формат tree? Он с одной стороны читаем человеком, с другой — весьма гибок, а с третьей позволяет передавать бинарные данные без экранирования (только сплит по сепаратору). В сериализованном виде может получиться что-то типа такого:
schema Bean Bean id int64
schema InnerBean Bean
value1 int64
value2 int64
value3 int64
value4 int64
value5 int64
value6 InnerBean id
schema OuterBean Bean
descr string
bean1 InnerBean id
bean2 InnerBean id
bean3 InnerBean id
InnerBean
id \1
value1 \3lmt8r
value2 \i23dbi
value3 \eui2f3b
value4 \ewviubi4
value5 \342
value4 \2
InnerBean
id \2
value1 \3lmt8r
value2 \i23dbi
value3 \eui2f3b
value4 \ewviubi4
value5 \7vvvvvvvvvv
value4 \2
InnerBean
id \3
value1 \3lmt8r
value2 \i23dbi
value3 \eui2f3b
value4 \ewviubi4
value5 \342
value4 \1
OuterBean
id \4
descr
\this is multiline description
\of bean #4
bean1 \1
bean2 \2
bean2 \3
Разбирается это тривиальным парсером. Избыточность нивелируется простейшим алгоритмом сжатия. Числа я тут записал в base32, но можно и сырыми данными.
При чём здесь передача данных по сети? Есть много других областей, где применяется сериализация объектов.
Чем проще и гибче протокол, тем проще сделать реализацию и прикрутить в нужном месте, тем больше будет реализаций и применений, тем выше будет конкуренция и распространённость, тем выше будет качество исполнения наиболее конкурентноспособных реализаций, стабильность и скорость работы.
Часто встречаю в своей работе что не нужен гибкий протокол и ему не нужна куча различных применений и распространенности и такие протоколы используем в С++ коде.
То, что гибкость в конкретный момент не востребована, не означает, что она не потребуется в будущем (пример из статьи — внезапно выясняется, что из 100 возможных полей заполнены лишь 10 и требуется "адаптивная схема") и уж тем более не означает, что нужно намеренно выбирать наиболее дубовый протокол имеющий лишь один вариант применения.
А как можно говорить о стабильности у универсального протокола типа JSON?
Tree — это формат представления AST. Так что он ближе к LISP и XML, чем к JSON. Впрочем, гибкость протокола не исключает использования схем. В примере выше, схема данных прилагается к самим данным.
Что даёт ему +10 к стабильности или скорости работы?
Предельная простота, поддержка потоковой обработки и отсутствие необходимости декодировать строки, например.
к стабильности
Наличие RFC(формализованный стандарт, исключающий разночтения, несовместимость => меньше проблем с фантазиями авторов библиотек) и over 9000 пользователей, которые успели пробежаться по всем потенциальнам проблемам.
скорости работы?
SIMD-парсеры. Формат настолько популярен, что для него окупилось написание сильно оптимизированных библиотек и биндингов для них.
Не говоря уже о том, что он текстовый и наверняка не имеет кодогенерации.
1. начиная с protobuf v3 одной командой в протофайле option java_multiple_files = true; отключаем генерацию большого файла, получаем набор class=>file. Править полученные протофайлы вам не запрещается, при большом желании можно расширить компилятор и он будет генерить то что вам нужно и прописывать интерфейсы какие хотите
2. как вы предлагаете изменять byte[] в котором по определенным смещениям лежат значения изменяемой длинны? (ваш же пункт 4, чтобы что-то поменять нам нужно будет хвостик сдвинуть влево-вправо и изменить размер самого массива) Если объект в системе вроде как и готов, но возможно еще будет меняться, то перекидывается ссылка на билдер, а вот если нужно отправить в wire клиенту, то тут уже и build() вызывается и получаем готовый слепок.
3. сами же и сказали решение проблемы, dto не должно думать как упаковать граф, а потом его распаковывать, или может JSON уже научился такое делать? с учетом того что proto v3 еще ближе приблизился к json, то упаковка графа в руках того кто упаковывает, а совсем не стандартная операция.
4. [PROTOBUF+ZIP] vs [JSON+GZIP] это спор на уровне: у нас есть SQL и у нас есть NoSQL, в одном схема прописана и если говно пришло то оно сразу отбросится, во втором мы что-то как-то запишем-прочитаем. И далеко не у всех текста гоняются, зачастую только ID нужных элементов. К тому же сами признали увеличенную нагрузку на CPU, что для мобильных приложений очень критично. Хотите еще быстрее, с меньшей нагрузкой на CPU и без схемы, то добро пожаловать в MessagePack, только потом не жалуйтесь, что клиенты прислали очередную кашу.
В общем у вас пожелания: я хочу бинарный формат, который работает быстро, является компактным, сохраняет и проверяет схему, сохраняет ссылочность, позволяет без копирования изменять поля прямо в byte[] и т.д.
Лично я не знаю таких форматов и вижу противоречия в требованиях: компактный vs изменения сразу упакованного массива, компактный-быстрый vs сохраняем целиком ссылки-граф.
1. Да, я про версию 3 немного написал. К сожалению править сгенерированные файлы конечно нельзя — максимум положить рядом diff.patch и применять его после генерации.
2. Нене. Проблема излишнего копирования в текущей реализации заключается в копировании данных между Bean.Builder и Bean. Такое копирование можно исключить, так как это сделал protostuff и javanano@protobuf.v3. А что еще более сильной оптимизации, там есть варианты, поскольку формат не очень сложный. Например наши инженеры написали конвертор byte[] -> byte[], который позволяет поменять список значений полей без необходимости полной десериализации.
В целом меня все устраивает. За исключением проблемы #2, которую сейчас пофиксим пул-реквестом. Цель статьи — напомнить, что серебрянной пули не существует :)
Я пока не видел людей которые считают protobuf серебрянной пулей =) чаще встречаю которые считают, что json это верх совершенства и пихают его везде, а потом ловят несогласованность форматов в рантайме. В свое время лично для меня proto решил много проблем, так как позволяет высунуть контракт протокола на сервисы и гарантировать его соблюдения.
Со строками чаще проблемы не в том что копируются туда-сюда, а в самом кодировании-декодировании в UTF8, так как в java локальное представление Unicode, вот тут CPU и проседает частенько =(
Ни один нормальный разработчик никогда полностью не доверяет какой-то технологии и всегда относится к ней с сомнением.
Если это не так — присмотритесь к такому разработчику: не пора ли его уволить
Формат/протокол сам по себе мало о чем говорит, все чаще решает конкретная реализация и распространенность. Все писали, что на андроиде не надо использовать встроенную джавовскую сериализацию, строго говоря не так уж и медленно она работала, однако попалась либа https://github.com/RuedigerMoeller/fast-serialization, которая для меня упростила жизнь многократно. Долгое время на флеше использовал AMF, прекрасный протокол: сжатие, упаковка, циклические ссылки, бинарный, потом на одном проекте надо было json, флешовый нативный json парсил строки мгновенно, меньше миллисекунды, надо было только потом замапить на модель, чуть мелденнее AMF, но не критично. А потом soap на мобильном устройстве и в принципе ничего страшного, немного оптимизаций :) Один раз попробовали заменить RMI отправкой данных (фактически байт массивов) руками по сокету, и никакого выигрыша не удалось достичь сходу, не все так просто. CORBA ну тот же ваш протобуф :) ничем не запомнился, кроме мучительного его изучения. Снова андроид — AIDL… А можно, между прочим, и парсеры XML повыбирать и подходы разные попробовать.
Но идея, конечно, верная. Это не сущности, а чистые DTO, только вот иногда хочется эти данные быстро перегнать в другой формат и с текущей реализацией это требует дополнительных усилий. Ну или сразу использовать protostuff, который умеет все из коробки.
2. Какая технология позволяет сгенерироват класс для большинства платформ, с поддержкой сериализации с XML, JSON, CSV? (кроме клонов protobuf).
3. Смотрите п.1.
2. Ну JAXB там для Java. xsd.exe для C#. На ум сразу приходят.
3. С протобуфом всё аналогично.
2. Вы так и не ответили на вопрос. У вас для каждой платформы другая технология. Protobuf — это одна технология. Вы можете переслать объект с бэкенд с++ или go до Java. И все будет работать из коробки. Вам нужно только заполнит обьект значениями.
PS У меня ощущение что вы не совсем понимаете как работает protobuf и какие задачи стояли перед его разработчиками.
2. Ну если вы хотите жести жестокой, то есть такая технология WSDL. Так вот по этой самой WSDL вы можете на любой практически платформе (думаю что на гораздо большем количеств платформ, чем протобуф умеет) нагенерировать классов и интерфейсов. Вообще слабо понимаю зачем, начиная проект с нуля,
И вы в своем разговоре привязаны к xml, но это не панацея. xml данные слишком велики по сравнению с protobuf. И конечно парсинг xml тоже в несколько раз медленнее. Для компаний типа Facebook, Microsoft, Google эти оптимизации помогают сэкономить миллионы.
Каждой технологии своё применение. Не существует идеального решения. И если вам удобнее передавать xml между сервисами то передавайте. Предлагаю закрыть это обсуждение.
Что касается ссылок друг на друга — весьма легко обходится простым изменением структуры хранения в протобафе, вводом дополнительного контейнера, где идут объекты ссылающиеся друг на друга, ну или вводом ID на ссылающийся объект.
Нет идеальных вещей, нужно уметь вещи использовать и адаптировать под себя.
3. На мой взгляд, так и должно выглядеть очевидное поведение по умолчанию. Непонятно, почему вы ожидаете от просто бинарной сериализации каких-то хитрых оптимизаций.
4. Сами критикуете и сами же оправдываете. Все так, но здесь и нет никаких недостатков, одни очевидные плюсы. Нужно сжатие — используйте дополнительно сжатие.
По моим ощущениям у вас сложились неадекватно завышенные ожидания от простого бинарного сериализатора, разве они где-то обещали что-то большее? Protobuf это не панацея, а просто удобный инструмент, который уменьшает значительное количество ручной работы.
Извините, но мне кажется, что вы преувеличиваете мои преувеличения. Я хотел обозначить важные и не всегда очевидные моменты, которые могут повлиять на принятие решения. Я не выношу вердиктов или оценок, просто стараюсь приводить факты.
Я не понял претензию к строкам.
Предложение хранить строки в национальных кодировках а-ля CP-1251 порождает гораздо больше проблем, чем решает.
Суть изложенного в том, что при наличии в DTO большого количества строк все оптимизации примитивов, реализованные в protobuf на самом деле погоды не делают.
Аля: «При наличии колес у машины, присутствие магнитолы погоды не делает.»
Как вы вообще логически увязываете всю ту кашу которую описали?
Т.е. не надо оптимизаций никаких делать если в протоколе есть строки?
А т.к. в любом протоколе строки есть, то забейте на любые оптимизации?
Вы людям голову морочите фигней какой-то банальной…
Но простобаф это библиотека общего назначения. У меня вот в нем 90% сообщений это идетнификаторы (Long). String летают редко.
И подозреваю, что я не один такой.
А вот вы далеко идущие выводы делаете только по одному юзкейсу. Непрофессионально это.
Проблему постоянного копирования данных решали в рамках реализации Cap’n Proto (https://capnproto.org).
Ну и плюс они подтверждают:
When bandwidth really matters, you should apply general-purpose compression, like zlib or LZ4, regardless of your encoding format.
те же c++, те же зависимости бинарного кодогенератора по схеме от os где запускаешь
честное признание на их же сайте: Currently it only beats Protobufs in realistic-ish end-to-end benchmarks by around 2x-5x. We can do better. То есть ни о какой разнице на порядки разговор не идет. К тому же учитывая следующий абзац сравнение было на c++ версии, что происходит в java неизвестно
для java нету оффициального сериализатора, а сторонний заброшен с февраля (Cap’n Proto’s reference implementation is in C++. Implementations in other languages are maintained by respective authors and have not been reviewed by me)
как результат: взять такой продукт в продакшен вместо протестированного protobuf лично я не решусь никогда
P.S. Лучше брать flatbuffers для этой цели.
compile у protobuf-maven-plugin'а запускает protocArtifact, а compile-custom — pluginArtifact
ЗЫ: У меня os-maven-plugin работал только на maven 3.3 и выше.
Вобще идея мне понравилась и если не пытаться приспособить протобуфер под свой проект, а построить проект под протобуфер то можно реально сэкноноить на хранении и ускорить обмен данными
Темная сторона protobuf