Я подозреваю, что изобретаю велосипед, что проблема не нова как минимум, в мире онлайн-игр.
Перед клиентом поставлен кеширующий прокси, который передаёт запрос на бек, но, если такой запрос уже был, то он отдаёт сразу из кеша. Это позволяет аппликухе выглядеть быстрее, чем если она бы дожидалась пачки запросов со всеми причитающимися нетворк лагами.
Ничто в мире не бесплатно. Плата здесь — аппликуха получает слегка подгнившие, иногда совсем некорректные данные.
Что я думаю, как это адресовать.
1) Хук в аппликухе по URL заглядывает в кеш у прокси, считывает дату данных и само тело- если оно существует и если дата не превысила срок годности, потому что если привысила- тогда прокси заставит аппликуху дожидаться ответа с бека в любом случае.
2) Если данные существуют в кеше и ещё не совсем протухли, тогда записывает в свой собственный аппликуховый LRU кеш объект и его дату стухания из прокси-кеша и запускает таймер скажем, на 10 секунд.
3) Через 10 секунд по таймеру, по одному, достаёт key-value в аппликуховом LRU, и сверяет дату стухания сохранённую с датой стухания в кеше. Если в кеше больше старой даты нет — выбрасывает key-value и переходит к следующему. Если в кеше старая дата стухания есть и она равна сохранённой в аппликуховом кеше — тогда переходит к следующему key-value.
Если в прокси-кеше дата стухания больше, чем сохранённая в аппликуховом, тогда выбрасывает из аппликухового кеша дату и объект, и сравнивает (deep equals) объект аппликухового кеша с объектом прокси кеша. Если объекты отличаются — тогда извещает подписчиков, что какие-то данные подгнили и нужно данные перезапросить с бека и обновить состояние аппликухи.
4) Если аппликуховый LRU непустой — снова запускается таймер на 10 секунд в пункт 3).
Вопрос- это слишком закручено и есть более прямые пути? есть какой-то паттерн проектирования, который описывает подобную оптимизацию отзывчивости приложения путём скармливания потенциально несвежих данных, не дожидаясь ответа с бекенда?
Здравствуйте, Артём, Вы писали:
Аё>Вопрос- это слишком закручено и есть более прямые пути? есть какой-то паттерн проектирования, который описывает подобную оптимизацию отзывчивости приложения путём скармливания потенциально несвежих данных, не дожидаясь ответа с бекенда?
There are 2 hard problems in computer science: cache invalidation, naming things, and off-by-1 errors.
Инвалидация кэша крайне зависит от бизнес-логики системы: курс валюты протухает крайне быстро (при этом в выходные/праздники остается неизменным на несколько дней), тогда как система, которая отдает государственные праздники, может хранить считай целый год.
Не зная твоих данных и их особенностей сложно что-то предлагать
Единственное, я бы в твоем конкретно кейсе делал запрос с некоторой регулярностью (если это позволительно и данные не зависят от многих параметров) к бэку в отдельном треде, а не только когда данные понадобятся. Это сгладит длительность запроса для пользователя. В противном случае будет "то густо, то пусто".
Патриот здравого смысла
Re: Локальный кеш, использование подгнивших данных, обновление
Я небольшой спец по http кэшам. В силу специфики приходится наоборот, только их обходить и делать свои. Но могу посоветовать две вещи:
1. Ни в коем случае не хранить данные зависимые от клиента на сервере, или максимально минимизировать такие зависимости. Лучше если клиент зависит функционально от сервера, а сервер от клиентов не зависит. Это важно как в разрезе надежности (ожидание ответов от клиента) так и в разрезе гибкости архитектуры (изменения в внутренних функциях клиента могут вести к внесению изменений сервера). Рассылка клиентам о стухании данных — выглядит какашкой. В протоколе http есть достаточно средств чтобы отправлять информацию о кэшировании на клиент, и уже клиенту обновлять данные по мере надобности. (см всякие Conditional RequestsОтсюда
e.t.c).
2. Кэширование не должно быть абстрактным, а должно основываться на полученных данных о нагрузке. И в каждом случае решается конкретно — сколько времени актуально, это LRU или FIFO или смесь, и как себя чувствуют ресурсы памяти, вдруг они забьются одним запросом. На этапе разработки необходимо давить в себе оптимизатора и страсть к "угадал — не угадал". Зачастую оптимизация только одного запроса освобождает ресурсов больше, чем все предварительные угадайки. В то же время угадайки всегда портят жизнь своей ограниченной консинсентностью, что есть зло. А вот средства трассировки высоких нагрузок и слежения за ними, типа эластика, заббикса и множества подобных инструментов — это добро.
Re[2]: Локальный кеш, использование подгнивших данных, обнов
Здравствуйте, DiPaolo, Вы писали:
DP>Не зная твоих данных и их особенностей сложно что-то предлагать
DP>Что касается общеизвестных методов, то они легко гуглятся. Вот, к примеру, https://www.designgurus.io/blog/cache-invalidation-strategies
Да. Есть TTL и Stale-while-revalidate. Тема про Stale-while-revalidate.
DP>Единственное, я бы в твоем конкретно кейсе делал запрос с некоторой регулярностью (если это позволительно и данные не зависят от многих параметров) к бэку в отдельном треде, а не только когда данные понадобятся. Это сгладит длительность запроса для пользователя. В противном случае будет "то густо, то пусто".
Особенности такие: Web UI загружается медленно, крутит колёсиком ибо типа большая система. Потом он все запросы держит в памяти этой страницы, чтоб работать быстро. Там, когда данные записываются, есть логика чтоб кэши в памяти сбрасывались, это всё давно отлажено и вылизано. Там, когда данные изменены с другого компа — от пользователя ожидается, что он перезагрузит страницу, чтоб подхватить новые данные.
Новая фича — это кеш за пределами инстанса страницы, т.е. Web UI загружается мгновенно на старых закешированных данных.
Прокси ревалидирует данные и записывает в прокси-кэш, но логика аппликухи ещё не допилена, чтобы обновить после revalidate.
Артикли, которые гуглятся у меня, все копи-паста с перечислением стратегий performance, freshness, staleWhileRevalidate но без рецепта по моему случаю с staleWhileRevalidate.
Здравствуйте, Артём, Вы писали:
Аё> Там, когда данные изменены с другого компа — от пользователя ожидается, что он перезагрузит страницу, чтоб подхватить новые данные.
А зачем это через кэш делать, возможно проще и понятнее будет websocket для нотификаций об обновлениях прикрутить?
Приложение пользователя, который изменяет данные, при обновлении данных также отправляет сообщение всем остальным кто на эти данные смотрит, чтобы те перезагрузили.
На azure на минималках это PubSub (если свой сервер не хочешь или его нет)
Здравствуйте, bnk, Вы писали:
bnk>А зачем это через кэш делать, возможно проще и понятнее будет websocket
Чем дальше в лес, тем толще партизаны
Нет, пуша мне ещё там точно не нужно. Рефреша страницы достаточно. Вынесение кеша в Service Worker породило потенциальный кейс, когда нужно 2 рефреша чтобы точно подхватить изменение.
Re: Паттерн программирования для обновления UI при Stale-while-r
Здравствуйте, Артём, Вы писали:
Аё>Вопрос- это слишком закручено и есть более прямые пути? есть какой-то паттерн проектирования, который описывает подобную оптимизацию отзывчивости приложения путём скармливания потенциально несвежих данных, не дожидаясь ответа с бекенда?
По-моему, это всё слишком закручено.
Как по мне, стандартная веб-схема с conditional get и expires-заголовками должна работать нормально.
Единственное, чем её можно было бы расширить — это дополнительным уровнем "не вполне протухших данных":
— для каждого ресурса храним два таймстемпа: expiresMin, expiresMax.
— ресурс гарантированно свежий, если expiresMin ещё не наступил
— ресурс гарантированно устаревший, если expiresMax уже наступил.
Соответственно, алгоритм "получить ресурс" — такой:
1. Если ресурса нет в кэше, идём на ветку 6.
2. Если ресурс есть в кэше, и expiresMin ещё не наступил, то отдаём его из кэша.
4. Если ресурс есть в кэше, expiresMin наступил, а expiresMax — нет, то отдаём ресурс из кэша и форкаем асинхронный условный запрос в апстрим. Форк не происходит, если у нас есть неотвеченный асинхронный запрос этого же ресурса. По завершению условного запроса:
— если ответ — 304 not modified, то ничего не делаем.
— если ответ — тело, то замещаем нашу закешированную версию новой, заодно заменяя expiresMax и expiresMin новыми значениями
5. Если ресурс есть в кэше, но expiresMax уже наступил, то идём на ветку 6.
6. Если ещё нет асинхронного запроса этого ресурса, то порождаем новый; дожидаемся окончания асинхронного запроса и возвращаем его результат.
(схема сводится к стандартной HTTP-шной, если поставить expiresMin=expiresMax=expires).
Все кэши делаем по этой схеме — внутренний кэш приложения, кэш прокси, кэш реверс-прокси.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Локальный кеш, использование подгнивших данных, обновление
Здравствуйте, GlebЗ, Вы писали:
GЗ>Я небольшой спец по http кэшам. В силу специфики приходится наоборот, только их обходить и делать свои. Но могу посоветовать две вещи: GЗ>1. Ни в коем случае не хранить данные зависимые от клиента на сервере, или максимально минимизировать такие зависимости. Лучше если клиент зависит функционально от сервера, а сервер от клиентов не зависит. Это важно как в разрезе надежности (ожидание ответов от клиента) так и в разрезе гибкости архитектуры (изменения в внутренних функциях клиента могут вести к внесению изменений сервера). Рассылка клиентам о стухании данных — выглядит какашкой. В протоколе http есть достаточно средств чтобы отправлять информацию о кэшировании на клиент, и уже клиенту обновлять данные по мере надобности. (см всякие Conditional RequestsОтсюда
e.t.c). GЗ>2. Кэширование не должно быть абстрактным, а должно основываться на полученных данных о нагрузке. И в каждом случае решается конкретно — сколько времени актуально, это LRU или FIFO или смесь, и как себя чувствуют ресурсы памяти, вдруг они забьются одним запросом. На этапе разработки необходимо давить в себе оптимизатора и страсть к "угадал — не угадал". Зачастую оптимизация только одного запроса освобождает ресурсов больше, чем все предварительные угадайки. В то же время угадайки всегда портят жизнь своей ограниченной консинсентностью, что есть зло. А вот средства трассировки высоких нагрузок и слежения за ними, типа эластика, заббикса и множества подобных инструментов — это добро.
Glebz, извините за оффтоп, можете написать мне на email nickolay5544[одомашненный волк]gmail.com? Я планирую уйти с rsdn и хотел вам задать пару вопросов.
"Ты должен сделать добро из зла, потому что его больше не из чего сделать." Р.П. Уоррен