пятница, 25 февраля 2011 г.

boost::serialization hell

Никогда не используйте boost::serialize! Никогда...

Ну нельзя так работать, ну честное слово! Или может быть у них какие колебания в проекте, нехорошие? Не знаю...

Мы используем сериализацию...
"Мыши плакали, кололись, но продолжали есть кактус!.."


Самая большая проблема boost::serialize - это отсутствие совместимости на понижение. Мы не можем сформировать архив старой версии. И если вы вдруг задумаете строить клиент-серверную архитектуру на основе boost::serialization - одумайтесь.

Мы сидели на boost-1.35.0 достаточно долго, потом поняли, что продолжаться так больше не может и создали отдельный вариант boost::serialization, для старых версий. Для новых клиентов архивируем по новому, для старых по старому. Но новая версия попадет в ту же ловушку, как только выйдет. Нам придется иметь три, или четыре версии сериализации для совместимости.

Вообще с совместимостью в boost::serialization плохо. Обновились до 1.45.0 - система не работает. Стали выяснять почему - что-то разъехалось с темплейтами. Сериализация пользовательских структур обрабатывается некорректно.

Но тут, неожиданно вышла версия 1.46. В общем списке изменений которой вообще не написано что что-то менялось в данной либе. Но в списке изменений самой либы написано - что версии 1.42,1.43,1.44 содержали ошибку, и отныне считаются некошерными. Вплоть до того что архивы указанных версий не прочитаются на текущей. Это же жесть! Тестировать то не пробовал его никто?

У нас пока все заработало. Но что делать дальше - не понятно. Надо бы уходит от этой сериализации в сторону какого нибудь google protocol. Но не все так просто. Для начала нужно в достаточной степени развязать все в исходных текстах, чтобы новые версии не зависели от старых. Пока там все очень сильно перемешано.

17 коммент.:

Sergey Nikulov комментирует...

и что же думаете с этим делать?
Google protocol buffers?

Андрей Валяев комментирует...

Думаем на эту тему... В том смысле, что protocol buffers наверное лучший вариант. Кроме совместимости - он еще и другими языками хорошо поддерживается.

boost::serialize из под питона например заюзать - можно наверное, но задача не для слабонервных... :)

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

Qehgt комментирует...

Мы у себя используем msgpack.

Андрей Валяев комментирует...

Надо будет поглядеть и на него.

Хотя я так понял основное у него - скорость. Нам скорость не очень нужна. У нас управляющий трафик.

alexp комментирует...

а нам запретили пользоваться сериализацией. только БД.

Максим Моторный комментирует...

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

Oliora комментирует...

можно же взять текстовый архив и тогда проблем с совместимостью резко поубавится. как вариант, написать свой архив - это не сложно. мы, в свое время, json-архив прикрутили дней за 5.
кстати, если будете смотреть замены, то поглядите на apache thrift и apache etch. а если продукт open-source, то еще на zeroc ice. не одним google-buffers интернет богат :)

evlad комментирует...

Систему, связанную с долговременным хранением чего-либо, можно делать только с явным формированием потока записи и чтением из него. Любые попытки сделать что-то на этом поприще неявно обязательно содержат закопанные грабли. Так что, boost, в сущности, не виноват.

Anton комментирует...

evlad: в нормальных библиотеках (в классах сериализации) предусмотрена обратная совместимость путём указывания версии: http://doc.qt.nokia.com/latest/qdatastream.html

Евгений Охотников комментирует...

Позволю себе прорекламировать себя самого. Когда-то давно, когда boost::serialization был еще в зародыше, мне пришлось озадачиться проблемой версий. Из чего получилось вот это и вот это.

В качестве альтернативы Google Protobuf можно посмотреть еще и Thrift, он родом из Facebook, кажется.

Kirikaza комментирует...

Мои 5+ копеек.

[1]

«написано что версии 1.42,1.43,1.44 содержали ошибку, и отныне считаются некошерными. Вплоть до того что архивы указанных версий не прочитаются на текущей. Это же жесть! Тестировать то не пробовал его никто?»

А теперь процитирую оригинал:

«it has been discovered that binary archives created by versions 1.42-1.44 cannot always be read by the recent binary archive code. Work has proceeded in detecting the source of these anomolies and those which have been reported with test cases have been fixed. As of this writing, it is not known whether all binary archives created with these versions can be loaded»

Дабы не вводить никого в заблуждение.

[2]

«в нормальных библиотеках (в классах сериализации) предусмотрена обратная совместимость путём указывания версии: http://doc.qt.nokia.com/latest/qdatastream.html»

Давайте не будет делить ПО на две категории "нормальное" и "то, которое я использовал один раз, оно мне не понравилось, потому что там всплывают косяки и я не знаю, что с ними делать, потому что последние N лет имел дело с другими косяками".

[3]

Qt -- монолитная, цельная платформа. Хочешь пользоваться ею -- играй по её правилам. Если взять упомянутый выше QDataStream, то не совсем понятно, как можно сериализовать какой-то свой не-QObject-ный тип. Поклонник Qt тут же скажет: "А в чём проблема? Ну наследуй QObject, вот беда". Противник тут же возопит: "И что, я всё и вся должен отнаследовать от QObject?!" Постараюсь сохранитить нейтральность и процитирую себя: "Хочешь пользоваться ею [Qt] -- играй по её правилам". Кого-то это устраивает, а кого-то -- нет.

[4]

boost::serialization -- небольшая библиотека. Она поддерживается небольшой группой лиц и не слишком распространена, отчего баги находятся медленно. Но если разработчик предпочёл её, значит, он так решил, т.е. взял на себя ответственность и смелость с ней возиться. (Если вы решили изучать хинди, то индийцы не виноваты, что в вашем городе нет преподавателя этого языка.)
С другой стороны, boost::serialization не навязывает своих правил, позволяя расширение в практически любом направлении и предоставляя различные варианты использования: с RTTI или без, с автомагической или ручной регистрацией типов, с расширением класса или с введением внешней функции.
Так что выбор остаётся за разработчиком, будет ли он писать свою реализацию архива (как предлагал(а) Oliora)

[5]

Thrift обязывает использовать явное описание передаваемых данных. С одной стороны, лишняя писанина, с другой -- всё понятно и однозначно, даже когда на разных сторонах различные языки.

[5+]

Извините, что так длинно

Анонимный комментирует...

Зачем обновлять библиотеку сериализации? Там что-то меняется? Почему нельзя её просто заморозить навсегда, и по крайней мере не волноваться о совместимости между версиями библиотеки?

Владимир комментирует...

Надо было делать свою прослойку между вашим кодом и "boost::serialization hell") чтобы не было проблем.

Андрей Валяев комментирует...

Евгений, нам нет смысла изобретать велосипед. Лучше выбрать что нибудь готовое. Вообще все велосипеды из проекта надо искоренять. :) Там их и без того много.

tt2507, застабилизировать boost навсегда - это всеравно что не пользоваться им вообще. Там постоянно появляется что-то новое и интересное. Обидно. :)

Застабилизировать serialization можно, отчасти. Он завязан на остальные возможности boost. У нас сейчас для совместимости есть serialization 1.35, пока вроде работает, но с очередной версией буста может и перестать работать.

Спасибо всем за мощный фидбек, есть много материалов для размышления и исследования. :)

Андрей Валяев комментирует...

Kirikaza:
it has been discovered that binary archives created by versions 1.42-1.44 cannot always be read by the recent binary archive code. ... As of this writing, it is not known whether all binary archives created with these versions can be loaded»

Реально получилось так, что версия 1.45 не смогла распарсить архив, созданный версией 1.35. Какая-то заморочка с binary_object, не стал тратить много времени. 1.46 нормально заработала.

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

Anton комментирует...

Если взять упомянутый выше QDataStream, то не совсем понятно, как можно сериализовать какой-то свой не-QObject-ный тип.

Чтобы сериализовать свои типы от QObject наследоваться не нужно.


"Хочешь пользоваться ею [Qt] -- играй по её правилам"

Дело не в правилах, а конкретной проблеме. В Qt описанная проблема отсутствует.

Давайте не будет делить ПО на две категории "нормальное" и "то, которое я использовал один раз, оно мне не понравилось, потому что там всплывают косяки и я не знаю, что с ними делать, потому что последние N лет имел дело с другими косяками".

Если косяки всплывают НЕ только у меня, то это уже паталогия, а паталогия это ненормально. Так что можно и поделить ;)

Sergey Shandar комментирует...

В таких делах нужно сначала строго специфицировать формат данных (или взят готовый типа ASN.1, InfoSet и т.п.), а потом уже кидаться за написание библиотеки сериализации. Это было одной из причин из за чего boost::serialization был отвергнут почти сразу.