Comments 29
Json-rpc ещё проще, лапши меньше.
Вот вам несколько выдержек из официальной спецификации на JSON, вдруг решите свой парсер написать.
Про юникод:
JSON syntax describes a sequence of Unicode code points. JSON also depends on Unicode in the hex numbers used in the \u escapement notation
Про цифры:
JSON is agnostic about the semantics of numbers. In any programming language, there can be a variety of number types of various capacities and complements, fixed or floating, binary or decimal. That can make interchange between different programming languages difficult. JSON instead offers only the representation of numbers that humans use: a sequence of digits.
Про совместимость:
It is expected that other standards will refer to this one, strictly adhering to the JSON syntax, while imposing semantics interpretation and restrictions on various encoding details. Such standards may require specific behaviours. JSON itself specifies no behaviour.
Так что JSON сложнее и объемнее чем кажется, причем любая его реализация фактически подразумевает undefined behavior, поскольку стандарт описывает и гарантирует лишь синтаксис.
Что касается упомянутого протокола JSON-RPC, то помимо описанных выше проблем есть еще вот такое:
All transfer types are single objects, serialized using JSON.[1] A request is a call to a specific method provided by a remote system. It can contain three members:
..
И ниже про обработку ответа:
The receiver of the request must reply with a valid response to all received requests. A response can contain the members mentioned below.
..
id
- The id of the request it is responding to.
Получается что никакая реализация JSON-RPC не может быть stateless, поскольку эти самые id нужно где-то хранить.
Эта на первый взгляд мелочь обязательно всплывет при попытке масштабирования такого сервиса.
Не хочу спорить. Мне кажется, вы не применяли на практике. Вручную не надо ничего парсить и хранить айди. Ну только если очень хочется.
Если уж в описании самого протокола (цитату из которого я приводил выше) написано, что для запроса и ответа нужно формирование ID - тут никаких споров быть не может.
Вот для примера реализация JSON‑RPC на Java, в этом месте происходит чтение ID запроса, вот тут и ниже по коду он используется для формирования ответа.
Разумеется за все это отвечает фреймворк с реализацией JSON-RPC а не клиентский код, так что "Вручную не надо ничего парсить и хранить айди" действительно не надо - это сделают за вас и в обязательном порядке.
Там "фреймворк" на три дтошки. В общем, если будете реализовывать RPC на практике, не забудьте про альтернативу XML. Она проще.
Этот "фреймворк на три дтошки" мало того что тянет за собой парсер JSON в виде зависимости, так еще и накладывает определенные обязательства по разработке, одно из которых я описал выше.
Если у вас современная система, веб и популярный язык вроде Java/C# в JSON RPC нет никакого смысла — возьмите обычный REST, для которого JSON объекты лишь один из доступных типов данных.
Самый обычный REST позволит например часть данных брать из HTTP-заголовков, использовать все методы HTTP а один только POST, загрузку/скачивание бинарных файлов без цирка с сериализацией.
Зачем связывать себя по рукам и ногам жесткой схемой RPC просто так?
Иначе будет как у товарища выше по переписке, где он гоняет гигабайты данных через RPC протокол и жалуется на производительность.
Мне лично XML-RPC нужен в виде универсального инструмента для сложных и неадекватных условий, разумеется я не применяю его для всего вообще и например корпоративную разработку веду на самом обычном Java + Spring.
Странно видеть описание протокола четвертьвековой давности. Например, gRPC у него выигрывает по всем статьям.
Ну покажите как ваш gRPC работает на десяти разных ОС, включая сильно устаревшие, из разных диких языков а не только там где есть готовая реализация.
Не понял, какие проблемы? Приведите хотя бы один пример, где невозможно заменить XML-RPC на gRPC.
на десяти разных ОС, включая сильно устаревшие
Вы знаете платформу, для которой нет C/C++ компилятора или бекенда для LLVM?
диких языков
В том же FORTRAN или COBOL куда проще реализовать вызов через gRPC, чем сериализацию и десериализацию XML.
Навскидку:
Lisp, TCL, окружения Linux старше 15 лет, практически все коммерческие Unix, промавтоматика, встраиваемые системы, где как раз имеет смысл миниатюризация всех используемых библиотек. Устаревшие Windows.
Разумеется там будет компилятор, но только устаревший, у которого проблемы компиляции даже не находятся поисковиками.
Lisp, TCL, окружения Linux старше 15 лет, практически все коммерческие Unix, промавтоматика, встраиваемые системы
Сами погуглить не могли?
Разумеется там будет компилятор, но только устаревший, у которого проблемы компиляции даже не находятся поисковиками.
Кросскомпиляцию никто не отменял. А на K&R С, не говоря уже об упомянутых выше FORTRAN и COBOL, сериализацию и десериализацию XML сложнее будет реализовать, чем gRPC. Что я тоже показал выше.
Уважаемый ptr128, в интернете давно существует большая проблема с валидацией публикуемых данных, тем более когда речь заходит о сложных технических вещах.
То что вы «нагуглили» это разумеется замечательно, но это не истина в первой инстанции.
Если вы заметили, половина данной статьи состоит из конкретных примеров реально работающего кода на разных языках — все это я на самом деле собрал и запустил.
По этой причине могу подтвердить что оно действительно работает на момент написания статьи.
Если вы в силах повторить подобное для gRPC — пишите статью, коллеги оценят.
P.S.
Я не выступаю против gRPC, да и против вас лично ничего не имею, просто не хочу скатывания разумной технической дискуссии в очередной бессмысленный срач.
То что вы «нагуглили» это разумеется замечательно, но это не истина в первой инстанции.
Так как большинство ссылок на github, истинность проверяется элементарно. А ссылки на сайты производителей коммерческих продуктов, вполне себе валидные по определению.
По этой причине могу подтвердить что оно действительно работает на момент написания статьи.
На платформах, не поддерживающих Java, вроде упомянутого выше ESP32?
Я просил пример, где, по Вашему мнению, gRPC не применим. Вы же выдали целый ворох групп. Вы действительно ожидали, что для каждой из систем, покрываемых этими общими группами, я приведу работающий код?
не хочу скатывания разумной технической дискуссии в очередной бессмысленный срач.
Простите, но уже скатились, предложив сериализацию и десериализацию XML на встраиваемых системах, где каждый байт оперативки на счету и CPU слабые. Надеюсь, понимаете, что gRPC требует на порядок меньше оперативной памяти и в разы меньше процессорных ресурсов, чем XML-RPC. Я знаю о чем говорю, так как когда мы переходили с REST на gRPC, то получили прирост производительности, в среднем, в 8-9 раз.
На этом предлагаю закончить.
Я вообще не понимаю причем тут сериализация, ее если что нет ни в моей реализации ни в большинстве использованных клиентских библиотек.
Там просто парсер XML-запроса и генерация ответа в виде строки.
И то и другое отлично ограничивается по используемым ресурсам.
так как когда мы переходили с REST на gRPC, то получили прирост производительности, в среднем, в 8-9 раз.
Не знаю что у вас за случай, но очень сомневаюсь что причина лишь в одном только протоколе.
Вы бы тогда скорее снижением объема трафика хвастались - размеры передаваемых данных по бинарному протоколу разумеется заметно меньше.
Там просто парсер XML-запроса и генерация ответа в виде строки.
Первое - и есть десериализация. Второе - сериализация. А то что примеры в публикации не содержат в запросах и ответах ни массивов, ни массивов структур - это уже точно не ко мне.
сомневаюсь что причина лишь в одном только протоколе
Сомневаться - дело хорошее. Плохо, когда человек при этом ничего не делает. Хотя найти подтверждения моих слов очень легко. Например в этой публикации в тестах получили разницу в 7-10 раз, что вполне согласуется с моими данными. Код там есть, так что можете проверить сами.
Вы бы тогда скорее снижением объема трафика хвастались - размеры передаваемых данных по бинарному протоколу разумеется заметно меньше.
Во-первых, объем траффика тут тоже играет роль, так как если внутри ЦОД может быть до 400 гигабит на паре двухпортовых адаптеров, то между клиентом и сервером gRPC часто будет десятигигабитка, а порой даже гигабитка. Во-вторых, объем данных - это еще нагрузка на TLS, сериализацию и десериализацию. В-третьих, сам по себе HTTP/2 существенно эффективней HTTP/1.1. Тем более при использовании двунаправленного потокового gRPC и пакетной конвеерной обработки. А у нас запросы в Protobuf на несколько мегабайт с ответами на гигабайт - вполне себе обычны. В REST это было на порядок больше, так как в основном там массивы чисел. В XML-RPC было бы еще в 2-3 раза больше из-за его многословности в массивах.
Первое - и есть десериализация. Второе - сериализация. А то что примеры в публикации не содержат в запросах и ответах ни массивов, ни массивов структур - это уже точно не ко мне.
Не хочу уподобляться местным обитателям и придираться к точности терминов, но полагаю что под сериализацией/десериализацией XML подразумевалось использование как минимум DOM и какого-то механизма связывания с объектами языка - DTO, POJO и так далее.
Так вот всего этого тут нет, один только потоковый парсер.
"Массивы и массивы структур" были в тестах, но поскольку никаких проблем замечено не было — убрал.
Для C/C++ версий код был сильно объемнее, по очевидным причинам.
Тем более при использовании двунаправленного потокового gRPC и пакетной конвеерной обработки.
Двунаправленный потоковый вызов процедур? Вы фактически превратили атомарную по своей сути систему вызовов во что-то вроде видеострима. Полагаю следующим этапом придется добавлять какой-то контроль целостности данных, повторную отправку, докачку при обрыве и все прочие подобные радости.
А у нас запросы в Protobuf на несколько мегабайт с ответами на гигабайт - вполне себе обычны.
Не очень понимаю зачем все это было делать в рамках RPC протокола.
Если возникает большой объем передаваемых данных - существует вполне стандартный механизм для их передачи: через отдельную ссылку на скачивание.
В передаваемом ответе фигурирует лишь ссылка на скачивание, само скачивание клиент осуществляет отдельным запросом вне логики RPC.
Это вообщем-то стандартная практика даже для SOAP и REST.
В REST это было на порядок больше, так как в основном там массивы чисел.
Опять же не зная задачи могу ошибиться, но есть банальный работающий способ для такого: формируется текстовый файл с такими массивами чисел, который затем сжимается в архив и передается в виде бинарного файла.
Цифры сжимаются очень хорошо, на больших объемах будет существенный выигрыш.
С другой стороны происходит распаковка и чтение.
Если данных много то лучше формировать CSV с построчной разбивкой а не пытаться "сериализовать" все сразу и целиком.
полагаю что под сериализацией/десериализацией XML подразумевалось
После такого, я уже точно не вижу смысла в продолжнии дискуссии. Почитайте, хотя бы в тут. Любой RPC вызов - это сериализация объектов на одной стороне и десериализация на другой.
Остальное даже комментировать не буду, так как не вижу понимания того, что такое конвейер, протокол, контракт, их версии и для чего они нужны.
Собственно вся библиотека реализующая как клиентскую так и серверную стороны XML-RPC состоит из трех файлов
И это на фоне кучи умных слов и абревиатур. Если всё так просто то в чем же была сложность???
А ведь чтобы сформулировать решение надо сформулировать в чем же была проблема, но вместо этой формулировки нам придётся довольствоваться эмоциями автора которые в общем то сводятся к восклицанию:
Ах как это сложно <тут названия - RPC,...>
И предлагается решение в виде:
А вот есть библиотека, с ней это (то почему сложно, и про что мы ни слова не увидели) становится не сложно!
Ну круто же!
Но по моему то что было сложным так и осталось нерешённым, но это совсем другая история, видимо.
И это на фоне кучи умных слов и абревиатур. Если всё так просто то в чем же была сложность???
В чем сложность вызова удаленных процедур?
Сейчас расскажу.
Допустим у вас клиент и сервер, с которого вызываются процедуры написаны на разных технологиях, что чаще всего и бывает.
Один умеет работать с Unicode, другой нет.
В этом месте JSON по-хорошему заканчивается, поскольку по стандарту любая клиентская реализация JSON должна поддерживать юникод.
А еще есть различия в типах данных, когда у вас один технологический стек считает что строка это набор символов, а другой что строка это массив байт. Где-то есть отдельный булевый тип, где-то его нет и нужно передавать 1\0. Есть отличия в трактовке дат, меток времени и длинных чисел.
Именно из‑за такого количества сложностей большинство RPC фреймворков объемные и сложные — они скрывают все эти детали под капотом и вы просто не задумываетесь о них при работе.
До судного дня Х, когда они вылезают на поверхность.
Фишка XML-RPC как протокола как раз и заключается в том что он не пытается скрывать всю эту сложность, четко обозначая минимально поддерживаемый набор типов.
Поэтому он до сих пор жив и используется, хотя огромная корпорация пытается его задушить с 1998го года.
Как-то так.
Допустим у вас клиент и сервер, с которого вызываются процедуры написаны на разных технологиях, что чаще всего и бывает.
Ну я где-то видел про то что клиент как то должен получить список функций которые он может вызывать, в первую очередь.
Представьте что этот список функций у клиента устарел, а вы начнёте решать проблемы Юникода, булевых типов, ... Вот чем и главное когда это закончится? Как вы думаете?
Скорее всего вы описываете Web Services Discovery — это такая попытка создания «DNS для вебсервисов», с моей точки зрения не очень удачная.
что этот список функций у клиента устарел, а вы начнёте решать проблемы
Куда чаще проблема заключается не в устаревании списка методов, а в изменении их сигнатуры без предупреждения.
Разумеется только техническими средствами это не решить, такое считается за ошибку и работа останавливается.
Разумеется только техническими средствами это не решить
В смысле не решить, не возможно контролировать? А если версии интерфейсов ввести например?
изменении их сигнатуры без предупреждения.
Вроде как изменение сигнатуры это и есть одно из проявлений устаревшего или просто не валидного интерфейса но есть и много других. Как раз в этом разнообразии и заключается одна сторона сложности (но только одна), на сколько я знаю.
В смысле не решить, не возможно контролировать?
В смысле что такое состояние нестыковки клиентского и сервисного интерфейсов в рамках одной системы (те когда вы контролируете и клиентскую и серверную сторону) должно трактоваться как серьезный системный сбой.
На практике это чаще всего будет означать что кто-то из участников процесса выложил не ту сборку или релиз оказался битым, а значит несовпадение сигнатуры вызова лишь последствия а не причина.
А если версии интерфейсов ввести например?
Если кратко любые версии интерфейсов не более чем иллюзия, не дающая никакой защиты от внутренних изменений.
Если длинно то вот моя статья на эту тему.
Скорее всего вы описываете Web Services Discovery — это такая попытка создания
Нет одно время я очень плотно работал с DirectX -ом и с другими дИректами. Я точно знаю что версии интерфейсов имеют смысл так как я их очень эффективно использовал. Это не значит что ваша статья плохая, но по моему это взгляд только с одной стороны.
Я бы тоже сам до этого никогда не дошёл, мне повезло поработать с системой где это было сделано до конца и правильно во всём множестве аспектов и ещё и с классной документацией.
Там много аспектов и надо ничего не упустить. В этом сложность.
Нет одно время я очень плотно работал с DirectX -ом и с другими дИректами. Я точно знаю что версии интерфейсов имеют смысл
Объясняю: две разных версии DirectX это две разных не связанных между собой сущности - две физически разных и независимых друг от друга библиотеки. Т.е одну версию можно удалить и другая от этого не сломается.
Две версии API вебсервиса это на самом деле одна сущность — одна программа (если так будет понятней), внутри которой на одном из уровней обязательно происходит смешение.
Даже если за разные версии API отвечают физически разные сервисы — данные у них все равно будут общие: общая база, общие сервисы, общее файловое хранилище и тд.
Полное разделение версий одного сервиса вплоть до данных я на практике не видел ни разу.
Так что две версии API это на самом деле две головы одной и той же гидры, только вместо отрастания по-новой (как в сказке), отрубание одной приведет к падению всего сервиса.
Почему не взяли gRPC? Там и библиотеки подо всё что только возможно из языков и эффективный быстрый бинарный формат protobuf с версионированием, и двунаправленные стримы данных... зачем в 2024 текстовый XML с диким оверхедом по процу и памяти при преобразовании бинарных данных в какой-нибудь base64 и неэффективному увеличению объема на треть в секциях CDATA?
Thrift у Apache ещё есть, например
Вы на них не обратили внимания?
В теме не шарю, но вот можно оригинал обоев с обложки?
XML-RPC: вызываем все, везде и сразу