INTEGRITY Документация

Архитектурный шаблон разделения плоскости управления и плоскости данных для Durable Objects

Введение

Durable Objects построены на основе Cloudflare Workers охватывающих несколько локаций нашей глобальной инфраструктурной сети. Каждый экземпляр Durable Object имеет собственное постоянное хранилище, сохраняющееся между запросами, состояние в памяти, однопоточное выполнение и может быть размещён в определённом регионе.

У отдельного экземпляра Durable Object есть определённые возможности производительности и хранения данных. Поэтому, чтобы масштабировать приложение и не быть ограниченным возможностями одного экземпляра, необходимо максимально шардировать данные приложения и использовать Инфраструктура Cloudflare ↗ благодаря распределению наших экземпляров Durable Object по всему миру, что приближает и данные, и вычисления к пользователям, насколько это возможно.

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

Шаблон разделения плоскости управления и плоскости данных

В этом шаблоне приложение содержит как минимум один экземпляр Durable Object на каждый тип ресурса, который отвечает за все операции control plane, а также столько экземпляров Durable Object, сколько нужно для операций data plane, по одному на каждый созданный в приложении экземпляр ресурса.

Можно масштабироваться до миллионов экземпляров Durable Object, по одному на каждый ресурс.

Главное преимущество этой архитектурной модели в том, что операции уровня data plane, обычно связанные с большим объёмом запросов, чем операции control plane, обрабатываются непосредственно экземплярами Durable Object, хранящими данные ресурса, без обращения к экземпляру Durable Object уровня control plane. Таким образом, производительность и доступность приложения не ограничены одним экземпляром Durable Object, а распределены между тысячами или миллионами Durable Object.

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

Рисунок 1: архитектурная модель плоскости управления и данных для Durable Objects
Рисунок 1: архитектурная модель плоскости управления и данных для Durable Objects
  1. Пользователь в Лондоне (LHR) инициирует запрос к ресурсу XYZ запрос на создание. Запрос направляется в ближайший дата-центр Cloudflare и принимается парком Workers, обслуживающим API приложения.
  2. Код Worker направит запрос к нужному экземпляру Durable Object плоскости управления, который управляет ресурсами типа XYZ. Мы будем использовать idFromName подход к обращению к экземпляру Durable Object по имени (control-plane-xyz). Это дает немедленный доступ к экземплярам Durable Object уровня управления без необходимости поддерживать сопоставление.
    • Расположение Durable Object уровня control plane будет близким к месту первого запроса, обратившегося к нему, либо к региону, явно указанному с помощью Подсказки о местоположении.
  3. Экземпляр Durable Object плоскости управления (control-plane-xyz) получает запрос и сразу создает еще один экземпляр Durable Object (data-plane-xyz-03) ближе к месту запроса пользователя (с помощью Location Hints), чтобы фактический экземпляр Durable Object, хранящий содержимое ресурса, находился рядом с создавшим его пользователем. - Мы называем пользовательский init(...) функцию для созданного экземпляра Durable Object (data-plane-xyz-03) передавая все метаданные, необходимые для начала обработки запросов пользователя. Экземпляр Durable Object сохраняет эту информацию в своем локальном хранилище и выполняет необходимую инициализацию. Этот шаг можно пропустить, если каждый последующий запрос к созданному ресурсу уже содержит всю информацию, нужную для его обработки. Например, если URL запроса содержит всю информацию в виде параметров пути и запроса. - Мы используем idFromName подход к обращению к Durable Object (data-plane-xyz-03) что позволяет использовать идентификаторы ресурсов на основе имен. - Как вариант, можно использовать newUniqueId подход к обращению к Durable Object, при котором мы получаем случайный идентификатор ресурса вместо идентификатора на основе имени. Этот случайный идентификатор потребуется передать пользователю, чтобы он указывал его в последующих запросах при обращении к ресурсу.
  4. Экземпляр Durable Object плоскости управления (control-plane-xyz) сохраняет сгенерированный идентификатор (data-plane-xyz-03) в свое локальное хранилище, чтобы иметь возможность просматривать и удалять все созданные ресурсы, а затем возвращает его Worker'у.
  5. Пользователь получает успешный ответ о создании ресурса и соответствующий идентификатор, а также (опционально) перенаправляется на сам ресурс.
  6. Пользователь отправляет запрос на запись в API для идентификатора ресурса, возвращённого на предыдущем шаге, чтобы обновить содержимое ресурса.
  7. Код Worker использует переданный идентификатор ресурса, чтобы напрямую обратиться к экземпляру Durable Object плоскости данных для этого ресурса (data-plane-xyz-03). Экземпляр Durable Object обработает запрос соответствующим образом, записав содержимое в свое локальное постоянное хранилище, и вернет соответствующий ответ.
  8. Ещё один пользователь из Портленда (PDX) отправляет запрос на чтение ранее созданного ресурса (data-plane-xyz-01).
  9. Код Worker напрямую обращается к экземпляру Durable Object, который хранит данные для указанного идентификатора ресурса (data-plane-xyz-01), и экземпляр Durable Object вернет свое содержимое, прочитав его из локального хранилища.

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

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

Например, в зависимости от нагрузки можно дополнительно шардировать Durable Object уровня управления на несколько Durable Object. Вместо одного экземпляра Durable Object для всех ресурсов типа XYZ, мы могли бы создать отдельный экземпляр для каждого региона. Обращение к экземпляру Durable Object по имени упрощает выбор нужного экземпляра.

В итоге, если вам удастся разбить модель данных приложения на мелкие самодостаточные ресурсы, вы сможете выделить как минимум один экземпляр Durable Object на каждый ресурс и масштабироваться горизонтально.