Некоторое время назад я спросил, как сделать Инкрементные обновления с использованием кэша браузера .
Здесь я кратко излагаю проблему - для большего контекста, особенно для причины, по которой я хочу это сделать, обратитесь к старому вопросу.
Я бы хотел, чтобы вы рассмотрели и улучшили мою идею решения (просто идею, поэтому не отправляйте меня на проверку кода : D).
Проблема
Клиент (одностраничное приложение) получает довольно большие списки с сервера.
Это работает нормально и на самом деле экономит ресурсы сервера как
- один и тот же список может обслуживаться несколькими клиентами
- и клиенты выполняют фильтрацию и сортировку, не беспокоя сервер снова и снова.
Некоторые из этих списков относятся к конкретному пользователю, другие являются общими для группы пользователей, другие являются глобальными.
Все эти списки могут измениться в любое время, и мы никогда не хотим обслуживать устаревшие данные (HTTP-заголовок Cache-Control
и Expires
здесь не используются).
Мы используем 304 NOT MODIFIED
, что помогает в случае, если ничего не изменилось.
Когда что-то меняется, изменения обычно небольшие, но HTTP вообще не поддерживает этот случай, поэтому мы должны отправить весь список, включая неизмененные части.
Вместо этого мы можем отправить дельту, но нет никакого очевидного способа, как это может быть эффективно кэшировано браузером (кэширование в localStorage
или аналогично далеко не так хорошо, как я объяснил в моем связанном вопросе).
Важным свойством наших списков является то, что каждый элемент имеет уникальный id
и последний измененный timestamp
.
timestamp
позволяет нам легко вычислять дельту, находя элементы, которые недавно изменились.
id
позволяет нам применить дельту, просто заменив соответствующие элементы (список внутренне Map<Id, Item>
).
Это не будет работать для удалений, но давайте пока проигнорируем их.
Идея
Я предлагаю использовать несколько списков (любое число должно работать) разных размеров, с большим списком, который можно долго кэшировать.
Давайте предположим, что день - подходящая единица времени, и давайте использовать следующие три списка:
WEEK
Это базовый список, содержащий всех элементов, которые существовали в произвольный момент времени на текущей неделе .
DAY
Список, содержащий все элементы, у которых изменился на этой неделе , за исключением сегодняшнего дня, поскольку они существовали в произвольное время в текущий день .
Элементы, измененные сегодня, могут включаться или не включаться.
CURRENT
Список, содержащий все элементы, которые изменились сегодня , как они существуют только сейчас .
Клиент получает все три списка. Он начинается с WEEK
, применяется DAY
(т.е. вставляет новые элементы и заменяет старые) и, наконец, применяет CURRENT
.
Пример
Предположим, в списке есть 1000 элементов, причем 10 элементов меняются в день.
Список WEEK
содержит все 1000 элементов, но его можно кэшировать до конца недели.
Его точное содержание не указано, и разные клиенты могут иметь разные его версии (при условии, что выполняется условие из вышеупомянутого пункта).
Это позволяет серверу кэшировать данные в течение целой недели, но также позволяет ему отбрасывать их, поскольку обслуживание текущего состояния тоже подойдет.
Список DAY
содержит до 70 элементов и может кэшироваться до конца дня.
Список CURRENT
содержит до 10 элементов и может кэшироваться только до тех пор, пока что-либо не изменится.
Связь
Клиент должен ничего не знать об используемой шкале времени, но ему нужно знать количество списков, которые нужно запросить. «Классический» запрос типа
GET /api/order/123 // get the whole list with up to date content
будет заменено тремя запросами, такими как
GET /api/0,order/123 // get the WEEK list
GET /api/1,order/123 // get the DAY list
GET /api/2,order/123 // get the CURRENT list
Вопросы
Обычно изменения действительно такие, как описано, но иногда все элементы изменяются одновременно.
Когда это происходит, тогда все три списка содержат все элементы, что означает, что мы должны обслуживать в три раза больше данных.К счастью, такие события очень редки (например, когда мы добавляем атрибут), но я хотел бы найти способ, позволяющий нам избежать таких всплесков?
Видите ли вы другие проблемы с этой идеей?
Существует ли какое-либо решение для удалений, кроме простой маркировки элементов как удаленных и откладывания физического удаления до истечения срока действия кэшей (т.е. в моем примере до конца недели).
Какие-нибудь улучшения?