Масштабируемость RESTful web-сервисов

Representational State Transfer это не только эффективный стиль для архитектуры данных и приложений. Безусловно, очень удобно, когда у каждого информационного ресурса есть неизменный URL.  Такую гиперссылку можно сохранить или переслать коллеге, избавив информационные системы от повторного поиска. Но придумывался REST, как впрочем и HTTP, не только для этого. Основная задача этой архитектуры заключалась в построении масштабируемых многоуровневых приложений. Не смотря, на очевидность и простоту этой архитектуры, очень многие разработчики корпоративных информационных систем её не понимают (или делают вид, что не понимают). Поэтому, очередной взгляд на эту архитектуру. На этот раз с точки зрения инфраструктуры.

Протокол HTTP предоставляет нам набор методов для работы с информационными ресурсами. Некоторые методы, например метод PUT, являются идемпотентными. Т.е. если мы не уверены, отработал ли наш вызов этого метода, мы можем вызвать его повторно. Результат многократных вызовов идемпотентного метода не приведет к разным состояниям ресурса. Методы GET и HEAD, кроме того, являются безопасными. Т.е. их использование никак не повлияет на исходный ресурс.

Коснемся этих методов чуть подробнее. Метод GET предназначен для чтения ресурса. Метод HEAD это то же самое, только непосредственно сам ресурс не загружается, а загружается только его заголовок (метаданные). Выделение в протоколе методов чтения преследует вполне понятную цель. Такие данные можно кэшировать. Между клиентом и сервером вы можете поставить произвольно количество прокси-серверов, на которых хранить копии ресурсов. Значительная часть клиентских запросов обработается на уровне прокси и не будет создавать на нагрузку на сервер исходных данных. Кроме того, у метода GET есть дополнительные заголовки If-Modified-Since, If-Range и т.д., позволяющие не загружать ресурс, если он не изменился с указанного в запросе времени или загружать только часть ресурса. В общем, все сделано для того, чтоб строить достаточно эффективные архитектуры. Просто пока стоимость жестких дисков снижается быстрее, чем зарплата ИТ-архитектора в этом нет экономической необходимости.

Следующим фундаментальным свойством RESTful сервиса является то, что он не поддерживает сессию (stateless). Все данные, обрабатываемые в одном запросе-ответе должны быть самодостаточны. Взаимодействие не предполагает наличие какой-либо предыстории. Т.е. нет никаких курсоров, текущих элементов, заданных ранее в ходе взаимодействия значений и т.д. В принципе, это верно и просто для HTTР но начинающий веб-программист, обязательно, возразит мне, что в любом инструменте для разработки веб-приложений есть переменная «сессия». В этой переменной удобно хранить логин аутентифицировавшегося пользователя, коннект с базой данных, введенные пользователем ранее параметры и т.д. С точки зрения программиста выглядит это хорошо. С точки зрения балансировки нагрузки – не очень. RESTful явно запрещает такие сессии, избавляя нас от проблем масштабируемости. Вы можете поставить произвольно количество одинаковых серверов и «разбрасывать» по ним вызовы произвольным образом. Вы можете разделить хранилище данных на любое количество частей и легко построить маршрутизацию запросов к нужному серверу. Причем речь идет не только о запросах на чтение, но и на модификацию и добавление данных. Записи с четными номерами положить в одну базу данных, с нечетными – в другую, а с номерами, кратными 42 разместить в облачном датацентре на Луне (или на барже в Индийском океане, говорят это сейчас модно). И вам не придется синхронизировать состояния этих серверов. Таких состояний просто нет. У ресурсов состояния есть, а у операций – нет.

Здесь надо вернуться на прикладной уровень и вспомнить Hypermedia as the Engine of Application State. Эта идея еще и о том, что связи между ресурсами хранятся внутри самих этих ресурсов, в виде гиперссылок. Т.е. нет каких-то отдельных таблиц отношений, показывающих, что «сотрудник А работает в отделе B», все внутри ресурса. И  изменение связей между ресурсами производится операцией изменения ресурса (POST). Вы, конечно, можете создать отдельную связь между двумя ресурсами, но это будет новый ресурс и включать он будет исключительно ссылки на объединяемые ресурсы. Исходные ресурсы эта операция не затрагивает. Им все равно, в какое количество ассоциаций, иерархий или категорий их включили. По сути, это означает, что структуры данных потеряли границы. Первый элемент связного списка лежит на одном сервере, следующий на другом, а третий плывет на барже в Индийском океане. Глобальное адресное пространство. Главное, избавиться от старой программисткой привычки десятками создавать копии данных, тогда и синхронизировать их не придется.

Масштабируемость RESTful web-сервисов: 3 комментария

  1. >>Безусловно, очень удобно, когда у каждого информационного ресурса есть неизменный URL

    Удобно, классно, но недостаточно.
    URL – это АДРЕС. Кроме адреса, еще нужно ИМЯ, глобальный уникальный идентификатор ресурса во Вселенной, так как одинаковые ресурсы могут копироваться, соответственно, иметь разные адреса, и нужны уникальные имена, чтобы такие копии с разными URL могли идентифицироваться

    >>RESTful явно запрещает такие сессии, избавляя нас от проблем масштабируемости

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

    >>Несмотря на очевидность и простоту этой архитектуры, очень многие разработчики корпоративных информационных систем её не понимают

    Из-за вышеназванных причин использование такой архитектуры для построения реальных систем проблематично даже для разработчиков, которые ее понимают – так же как и чистого HTTP, “не замутненного” сессиями 🙂

    >>Метод GET предназначен для чтения ресурса

    Да, теоретически, так же как POST предназначен для изменения/дополнения ресурса. Но практически бывает и наоборот, в зависимости от ресурса. Сейчас повсеместно GET используется для собирания/дополнения информации о пользователях на сервере

    >>связи между ресурсами хранятся внутри самих этих ресурсов, в виде гиперссылок

    Да, идея весьма перспективная, кореллирует с HTML Microdata или, например, с понятием дейта-тегов (data-tags) в одной системе Case Management :). Дейта-теги — это теги, значения которых не вводятся вручную, а выбираются из корпоративных справочников или любых других баз данных. В данной системе Case Management дейта-теги используются для маркировки и классификации кейсов. Каждый дейта-тег содержит как ссылку на корпоративных справочник, откуда его вставили в неструктурированный HTML-текст кейса, так и набор других атрибутов, ну, например, название контрагента, код контрагента, еще что-нибудь. В результате решаем проблему, которая всегда была при использовании корпоративных справочников (хранить значение или ссылку?) – храним значение, ссылку и другие данные одновременно в самом тексте и можем перейти к справочнику, их содержащему.

    >избавиться от старой программисткой привычки десятками создавать копии данных

    Не получится.
    Идеальная картина мира, в котором каждый ресурс существует во Вселенной в одном экземпляре и доступен всем по URL – недостижима. Гораздо перспективнее построить работающую модель, в которой у ресурса могут быть копии – но мы всегда знаем имя этого ресурса, позволяющее идентифицировать все такие копии по разным адресам. Вот оно, недостающее звено, позволяющее построить новый мир распределенных, максимально независимых, но в то же время связанных структур данных

    1. Практикам-разработчикам только дай волю, они и процессов настроят и сущностей насоздают 🙂 URL – это и имя и адрес и протокол. А с дополнительными идентификаторы построить новый мир не получится, т.к. такая стройка сведется к бесконечным разборкам между командами разработчиков о том, чей идентификатор более правильный.

      GUID не нужен!

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

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