Как эффективно хранить и считывать иерархию из кеша

Моя ситуация такова, что я в настоящее время храню иерархию в базе данных SQL, которая быстро приближается к 15000 узлов (5000 ребер). Эта иерархия определяет мою модель безопасности на основе положения пользователей в дереве, предоставляя доступ к элементам ниже. Поэтому, когда пользователь запрашивает список всех защищенных элементов, я использую CTE для рекурсии его в базе данных (и сглаживания всех элементов), которая начинает показывать свой возраст (медленно).

Иерархия меняется не часто, поэтому я попытался переместить ее в оперативную память (redis). Имея в виду, у меня есть много подсистем, которые нуждаются в этом для вызовов безопасности, и пользовательский интерфейс для построения дерева для операций CRUD.

Первая попытка

Моя первая попытка - сохранить отношения в виде пары ключ-значение (так она хранится в базе данных)

       E
     /   \
    F     G
   / \   /  \
  H  I  J    K

mapped to:
    E - [F, G]
    F - [H, I]
    G - [J, K]

Итак, когда я хочу, чтобы E и все его потомки, я рекурсивно получить его дочерний элемент и его дочерний элемент с помощью ключей, и это позволяет мне начать движение вниз с любого узла. Это решение дало хорошее увеличение скорости, но с 15000 узлов потребовалось примерно 5000 обращений к кешу для восстановления моего дерева в коде (худший сценарий ... начиная с E. производительность зависит от местоположения начальных узлов, в результате чего суперпользователи видят худшая производительность). Это все еще было довольно быстро, но, похоже, болтало.Мне нравится тот факт, что я могу удалить узел в любое время, вытащив его из списка ключей, не перестраивая весь мой кеш. Это также быстро помогло построить дерево по запросу визуально в пользовательском интерфейсе.

Вторая попытка

Другая моя идея - взять иерархию из базы данных, построить дерево и сохранить его в ОЗУ (redis), а затем вытащить все это из памяти (размер примерно 2 МБ, сериализованный ). Это дало мне единственный вызов (не такой болтливый) в redis, чтобы вытащить все дерево, найти родительский узел пользователя и спуститься, чтобы получить все дочерние элементы. Эти вызовы являются частыми, и передача 2 МБ на сетевом уровне казалась большой. Это также означает, что я не могу легко добавить / удалить элемент, не вытащив дерево, не отредактировав и не вернув все обратно. Кроме того, построение деревьев по запросу через HTTP означало, что каждый запрос должен был вытаскивать 2 МБ, чтобы получить только прямые дочерние элементы (очень маленькие, используя первое решение).


Итак, какое решение, по вашему мнению, является лучшим подходом (в долгосрочной перспективе, поскольку он продолжает расти). Оба они заметно быстрее и снимают некоторую нагрузку с базы данных. Или это лучший способ сделать это, о чем я не думал?

Спасибо

8
задан Waterboy4800 15 November 2011 в 23:37
поделиться