Хабрахабр

JSON-RPC? Возьмите хитрый REST

Уверен, что заголовок вызвал здоровую реакцию — “ну опять началось…” Но позвольте завладеть вашим вниманием на 5-10 минут, и я постараюсь не обмануть ожидания.

Надеюсь, это позволит взглянуть на выбор парадигмы обмена данными в ваших проектах под новым углом. Структура статьи будет такова: берется стереотипное утверждение и раскрывается “природа” возникновения этого стереотипа.

0. Для того, чтобы была ясность в том, что такое RPC, предлагаю рассматривать стандарт JSON-RPC 2. И не должно быть. C REST ясности нет. Все, что нужно знать о REST — он неотличим от HTTP.

RPC запросы быстрее и эффективнее, потому, что позволяют делать batch-запросы.

Например, создать пользователя, добавить ему аватар и в том же запросе подписать его на какие-то топики. Речь идет о том, что в RPC можно в одном запросе выполнить вызов сразу нескольких процедур. Всего один запрос, а сколько пользы!

Потому, что три REST запроса потребуют в три раза больше ресурсов от одной ноды на установку соединений. Действительно, если у вас будет всего одна нода backend, это будет казаться быстрее при batch-запросе.

Что также негативно влияет на общий результат. Обратите внимание, что первый запрос в случае с REST должен вернуть идентификатор пользователя, для выполнения последующих запросов.

В крайнем случае, в небольших WEB проектах. Но такие инфраструктуры можно встретить, разве что, в in-house решениях и Enterprise. Их инфраструктура должна отвечать критериям высокой доступности и нагруженности. А вот полноценные WEB решения, да еще и именуемые HighLoad так строить не стоит. И картина меняется.

Обратите внимание, как ведет себя RPC теперь. Зеленым отмечены каналы активности инфраструктуры при том же сценарии. В то время, как REST все также проигрывает в первом запросе, но наверстывает упущенное используя всю инфраструктуру. Запрос использует инфраструктуру только по одному плечу от балансировщика к backend.

Достаточно в сценарий ввести не два запроса на обогащение, а, скажем, пять или десять… и ответ на вопрос “кто выигрывает теперь?” становится неочевиден.

На схеме видно, как используются каналы инфраструктуры, но инфраструктура не ограничивается каналами. Предлагаю глянуть еще шире на проблему. Давайте теперь получим какой-то артефакт пользователя. Важной составляющей высоконагруженной инфраструктуры являются кэши. Скажем 32 раза. Несколько раз.

Все дело в том, что REST использует всю мощь HTTP протокола в отличие от RPC. Посмотрите, как заметно “поправилась” инфраструктура на RPC для того, чтобы отвечать требованиям высокой нагрузки. На приведенной схеме эта мощь реализуется через метод запроса — GET.

Познакомиться с ними можно в документации на HTTP. У HTTP методов, помимо прочего, есть стратегии кеширования. Для RPC используются POST запросы, которые не считаются идемпотентными, то есть многократное повторение одних и тех же запросов POST может возвращать разные результаты (например, после каждой отправки комментария будет появляться очередная копия этого комментария) (источник).

Это приводит к тому, что приходится “завозить” софтовые кэши. Следовательно, RPC не в состоянии эффективно использовать инфраструктурные кэши. Софтовый кэш, в свою очередь, требует от разработчика дополнительный кодовый слой и заметные изменения в архитектуре. На схеме в этой роли представлен Redis.

Давайте теперь посчитаем, сколько же запросов “родил” REST и RPC в рассматриваемой инфраструктуре?

[*] в лучшем случае (если локальный кэш используется) 1 запрос (один!), в худшем 32 входящих запроса.

Теперь становится очевидным выигрыш REST. В сравнении с первой схемой разница разительная. Развитая инфраструктура включает в себя CDN. Но предлагаю не останавливаться на достигнутом. Получим: Часто он же решает вопрос противодействия DDoS и DoS атакам.

RPC просто не в состоянии делегировать работу с нагрузкой CDN. Тут для RPC все становится совсем плачевно. Остается надеяться только на системы противодействия атакам.

И опять, нет. Можно ли на этом закончить? И неспроста метод GET является тотально используемым в Internet. Методы HTTP, как выше уже говорилось, имеют свою “магию”. Все это позволяет создавать гибкие, управляемые инфраструктуры, способные переваривать действительно большие потоки запросов. Обратите внимание на то, что этот метод способен обращаться к части контента, способен ставить условия, которые смогут интерпретировать инфраструктурные элементы еще до передачи управления вашему коду и т.д. А в RPC этот метод… игнорируется.

Лично мне кажется, что большинство проектов просто не достигают такого уровня развития, когда REST способен показать свою силу. Так почему так устойчив миф о том, что batch запросы (RPC) быстрее? Более того, в небольших проектах, он охотнее показывает свою слабость.

Этот выбор должен отвечать требованиям проекта. Выбор REST или RPC это не волевой выбор отдельного человека в проекте. Если проект способен выжать из REST все то, что он действительно может, и это действительно нужно, то REST будет отличным выбором.

этот протокол более утилитарный. Но если на то, чтобы получить все профиты REST, нужно будет нанять в проект девопсов, для оперативного масштабирования инфраструктуры, админов для управления инфраструктурой, архитектора для проектирования всех слоев WEB сервиса… а проект, при этом, продает три пачки маргарина в день… я бы остановился на RPC, т.к. Бизнес будет доволен. Он не потребует глубоких знаний работы кэшей и инфраструктуры, а сфокусирует разработчика на простых и понятных вызовах нужных ему процедур.

RPC запросы надежнее, потому, что могут выполнять batch-запросы в рамках одной транзакции

легко удерживать БД в консистентном состоянии. Это свойство RPC является несомненным плюсом, т.к. Запросы могут приходить непоследовательно на разные ноды backend. А вот с REST выходит все сложнее.

Если инфраструктура спроектирована плохо, а тем более, если спроектирована плохо архитектура проекта и БД в частности, то это действительно большая боль. Этот “недостаток” REST является обратной стороной его преимущества описанного выше — способность эффективно использовать все ресурсы инфраструктуры.

Давайте рассмотрим кейс: создаем пользователя, обогащаем его профиль каким-то описанием и отсылаем ему SMS с секретом для завершения регистрации. Но так ли надежны batch-запросы как кажутся? три вызова в одном batch-запросе. Т.е.

На ней представлена инфраструктура с элементами высокой доступности. Рассмотрим схему. Но… что мы видим? Есть два независимых канала связи с SMS шлюзами. Т.к. При отправке SMS возникает ошибка 503 — сервис временно недоступен. Действия в СУБД аннулируются. отправка SMS упакована в batch-запрос, то весь запрос должен откатиться. Клиент получает ошибку.

Либо запрос опять попадет на ту же ноду и опять вернет ошибку, либо повезет, и он выполнится. Следующая попытка — лотерея. Нагрузка была, а профита нет. Но главное, что как минимум один раз наша инфраструктура уже потрудилась зря.

А остаток, мы вновь попытаемся выполнить через какой-то интервал времени (Какой? Хорошо, давайте представим, что мы напряглись (!) и продумали вариант, когда запрос может успешно выполниться частично. Но лотерея так и осталась. Решает фронт?). Запрос на отправку SMS с вероятностью 50/50 вновь провалится.

Согласитесь, со стороны клиента, сервис не кажется таким надежным как хотелось бы… а что REST?

При возникновении ошибки 503 на SMS шлюзе, backend транслирует эту ошибку балансировщику. REST опять использует “магию” HTTP, но теперь с кодами ответов. Т.е. Балансировщик получая эту ошибку, и не разрывая соединение с клиентом направляет запрос на другую ноду, которая успешно отрабатывает запрос. Пользователь счастлив. клиент получает ожидаемый результат, а инфраструктура подтверждает свое высокое звание “восокодоступной”.

Балансировщик не просто получил код ответа 503. И опять это не все. Заголовок дает понять балансировщику, что не стоит беспокоить эту ноду по этому роуту в течении заданного времени. Этот код при ответе, по стандарту, желательно снабдить заголовком “Retry-After". И следующие запросы на отправку SMS будут направляться сразу на ноду, у которой нет проблем с SMS шлюзом.

Действительно, легче организовать консистентность в БД. Как мы видим, надежность JSON-RPC переоценена. Но жертвой, в таком случае, станет надежность системы в целом.

Когда инфраструктура проста, очевидность JSON-RPC несомненно его плюс. Вывод во многом аналогичен предыдущему. Если проект предполагает высокую доступность с высокой нагруженностью, REST смотрится более верным, хотя и более сложным решением.

Порог входа в REST ниже

Связанно это с необходимостью глубокого понимания работы HTTP, а также, с необходимостью обладать достаточными знаниями о существующих инфраструктурных элементах, которые можно и нужно применять в WEB проектах. Я думаю, что выше проведенный анализ, развенчивающий устоявшиеся стереотипы о RPC наглядно показал, что порог входа в REST несомненно выше, чем в RPC.

Лично мое мнение заключается в том, что эта кажущаяся простота исходит из самих манифестов REST. Так почему многие думают, что REST попроще будет? REST это не протокол, а концепция… у REST нет стандарта, есть некоторые рекомендации… REST не сложнее HTTP. Т.е. Кажущаяся свобода и анархия манит “свободных художников”.

Но сам HTTP это хорошо продуманный протокол, который доказал свою состоятельность десятилетиями. Несомненно, REST не сложнее HTTP. Если нет глубокого понимания самого HTTP, то и о REST судить нельзя.

Достаточно взять его спецификацию. А вот о RPC — можно. Или все же хитрый REST? Так нужен ли вам тупой JSON-RPC? Решать вам.

Искренне надеюсь, что я не потратил ваше время зря.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть