digital-garden/dev/architecture/highload/Ключ кэширования.md
Struchkov Mark be8fd578f3
All checks were successful
continuous-integration/drone/push Build is passing
Обновление
2024-10-09 09:23:45 +03:00

6.2 KiB
Raw Blame History

aliases tags date zero-link parents linked
maturity/🌱
2024-09-13
../../../meta/zero/00 HighLoad
Кэширование

Представим, что нам нужно кэшировать результат работы следующего метода:

public List<User> getUsersByType(String userType, Set<Long> userIds)

Метод принимает 2 аргумента: строку и коллекцию. Ключ кэширования должен учитывать значения этих входящих аргументов и должен обладать следующими свойствами:

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

Сформируем ключ кэширования для нашего метода. В качестве хранилища будем использовать ../../../../../wiki/zero/00 Redis.

В начале ключа я обычно обязательно указываю какой-то уникальный префикс сервиса, чтобы не получить коллизию между разными сервисами. Пускай в данном случае префикс будет USER_SERVICE. Также добавляю уникальный префикс метода, в данном случае будет USERS.

В качестве разделителей рекомендую использовать :, в ../../../../../wiki/zero/00 Redis это позволяет визуально сгруппировать ключи. Это позволяет визуально группировать ключи при использовании UI клиента. Таким образом начало нашего ключа выглядит следующим образом: USER_SERVICE:USERS:.

Значения аргументов метода также должны попасть в ключ. Возьмем наш первый аргумент String userType. Для аргумента также можно использовать префиксы, но это не обязательно. В данном случае пусть будет USER_TYPE. А вот для самого значения параметра есть несколько вариантов:

  • Оставить строкой и просто выполнить конкатенацию.
  • Использовать ../../cryptography/Хеш-функция с фиксированной длиной выхода, например ../../cryptography/MD5. Фиксированная длина выхода нужна, чтобы иметь предсказуемую и ограниченную длину ключа.

Оставим просто строкой, так как тип пользователя вряд ли может быть длинным. В итоге пока наш ключ выглядит как-то так: USER_SERVICE:USERS:USER_TYPE:VIP:.

Переходим ко второму аргументу Set<Long> userIds. С коллекцией все будет сложнее. Мы точно должны использовать какую-нибудь ../../cryptography/Хеш-функция, но как?

[!WARNING] Disclamer Этот способ я придумал сам, возможно он не самый удачный, но он работает. Если вы придумаете лучше, напишите в комментариях ниже 👇

Во-первых, коллекцию необходимо предварительно отсортировать. Иначе на одинаковые параметры коллекций мы будем получать разные результаты ../../cryptography/Хеш-функция.

Во-вторых, нужно представить коллекцию как что-то понятное для ../../cryptography/Хеш-функция. Для этого я преобразую коллекцию в JSON. JSON используется, потому что ваша коллекция может быть из сложных объектов.

Теперь используем ../../cryptography/SHA-256, чтобы из нашей строки получить какой-то хеш. И уже этот хеш мы добавляем к нашему ключу, получается примерно такое:

USER_SERVICE:USERS:USER_TYPE:VIP:USER_ID:315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3

[!QUESTION] Почему SHA-256, а не MD5? ../../cryptography/MD5 подвержен коллизиям, ../../cryptography/SHA-256 считается более устойчивым к коллизиям.


Мета информация

Область:: ../../../meta/zero/00 HighLoad Родитель:: ../Кэширование Источник:: Создана:: 2024-09-13 Автор::

Дополнительные материалы

Дочерние заметки