From: Sergey Matveev Date: Thu, 16 Nov 2017 19:14:57 +0000 (+0300) Subject: Форматы кодирования данных X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=55935d7c520287c6127014e305f62d52eac4610b;p=stargrave-blog.git Форматы кодирования данных В рассылке http://www.metzdowd.com/pipermail/cryptography/2017-November/033025.html и на работе уже не первый день поднята тема про вообще форматы кодирования данных. Имеется в виду для отправки по сети между гетерогенными системами. Всяких Protocol Buffers, Apache Thrift, MsgPack и прочего -- уйма. Огромная уйма. Но я уже, видимо старею, но склоняюсь к тому чтобы использовать семейство возможно чуть ли не самых старых форматов: ASN.1 либо XDR. Вот просто по сути своей чем тот же Protocol Buffer отличается от ASN.1 BER? Или MsgPack от BER? Да ничем. Всё это TLV! Одно но: в ASN.1 куча всяких типов данных которые можно и не реализовывать. Но, в отличии от многих, в нём есть DATETIME, так необходимый чуть ли не постоянно и всегда на практике. Да, ASN.1 BER можно было бы упростить в плане кодирования -- получим BSON или MsgPack (если без схемы) или Protobuf (если с ней). Но так ли это должно терзать и мучать людей? Сложность это конечно плохо, но всё-равно регулярно все безропотно используют XML или JSON. Будь возможность заменяют на что-то другое, попроще, но ё моё, не каждый же раз в каждой компании и каждом стартапе писать очередной сериализатор? liblber из состава OpenLDAP, говорят, может много гигабит спокойно просасывать. Так что вопрос скорости тут уже не так важен. BER далеко не самый компактный -- ok, берём ASN.1 PER. Да, сложен, даже сейчас мало FOSS библиотек для работы с ним. Но я на полном серьёзе склоняюсь к тому что надо бы взять и допилить или написать! PER ОЧЕНЬ компактен. Если так волнует трафик -- нефига изобретать велосипед. PER вовсю например во всей сотовой связи используется -- именно в нём между сотовым и станцией передаются сообщения, так как там ёмкость канала важно экономить. Есть aligned PER, где выравнивание произойдёт по байтам -- будет менее эффективен чем unaligned вариант, зато на обычных процессорах/компьютерах куда удобнее обрабатывать будет. Есть canonical вариант PER -- можно будет применять в криптографии. Недостаток BER в том, что одно и то же представление можно получиться разными способами и поэтому там где происходит аутентификация или подпись -- его не поиспользуешь. Для этого есть DER. DER это подмножество BER -- BER его всегда сможет прочитать. Но он создаёт другую фигню: его нельзя потоково передавать и обрабатывать. Для решения этой проблемы есть CER -- почти ничем не отличается от DER, но позволяет потоково обрабатывать данные. Имея в руках BER кодек, можно легко сделать и DER и CER из него. PER значительно сложнее, но в компактности с ним не потягаешься. Но кроме ASN.1 я однозначно ещё считаю что стоит смотреть в сторону XDR. Изобретён аж тоже в 80-х Sun Microsystems и почти во всём что они делают используется этот формат (а также автоматом у всех в NFS и ZFS). Его главное отличие, как мне кажется, это простота! Реализовать BER -- не один день работы. А XDR -- пару часов. Выравнивание по четыре байтам, говорят, ОЧЕНЬ помогает с обработкой данных на 32-бит и старше процессорах. Очень просто и очень эффективно. Просасывать фигову тучу гигабит на нём не проблема. Реализовать -- любой сможет с нуля. И лично я в своих проектах (например NNCP) использую именно его. Но всё-равно у XDR есть недостатки: нельзя потоково обрабатывать (длину и количество элементов нужно знать сразу же при посылке), нельзя передавать большие integer-ы (хотя конечно может быть кто-то и никогда в жизни не столкнётся с такой задачей) и максимальный объём бинарного блоба или количества элементов в массиве может быть только 2^32. То есть, на практике большие файлы просто так одним куском не всегда можно будет засунуть и придётся городить сверху этого ещё что-то. Но BER, DER/CER, PER, XDR требуют схемы. Чтобы без схемы жить, то лично я поклонник bencode. Один экран кода на Python -- вся его реализация. Типов данных мало. Кодировать списки можно потоково -- остальные элементы потоково нельзя. Но декодировать можно всё в потоке. Не самый компактный, но и не жирный, как JSON. Но, что мне очень нравится, так это то, что у него каноническое представление -- применим в криптографии! Ну и, в отличии от JSON, в нём можно передавать бинарные данные. Есть вот например MsgPack или CBOR или BSON. Ну обычные yet another TLV кодеки. Да, попроще чем ASN.1, но из-за этого городить таакой зоопарк? У Google действительно есть объективные причины писать Protobuf или Cap'n'proto, но Google один и у него свои условия эксплуатации. Это очередная статья из серии "вы не Google -- не надо делать как Google, потому-что они так делают". Если они используют сложный распределённый map-reduce это не значит что для обработки отчётов вам тоже самое надо делать. 99% подойдёт и просто обычный PostgreSQL какой-нибудь, с набором скриптов обсчитывальщиков. Если Netflix-ы пилят свои sendfile примитивы, внедряются в драйвера сетевых карт чтобы сделать DMA доступ, настраивают хитро прерывания и CPU affinity для сетевых процессов это не значит что не сделав этого у вас будет всё плохо. Так же как если у вас нет zero-copy сериализации данных, то возможно вы никогда в жизни на своих проектах в сериализацию и не упрётесь. ---