Кеширование реляционных данных с использованием Redis - PullRequest
0 голосов
/ 14 января 2019

Я строю небольшую социальную сеть (у пользователей есть посты, а у постов есть комментарии - очень простые), используя кластерный сервер nodejs и redis в качестве распределенного кэша.
Мой подход к кэшированию сообщений пользователей состоит в том, чтобы иметь sorted set, который содержит все идентификаторы сообщений пользователя, упорядоченные по рейтингу (который должен обновляться каждый раз, когда кто-то добавляет лайк или комментарий), и фактические объекты, отсортированные как hash objects.
Таким образом, поток сообщений пользователя get должен выглядеть следующим образом:
1. используя zrange, чтобы получить диапазон идентификаторов из sorted set.
2. используя multi/exec и hgetall, чтобы получить все объекты одновременно.

У меня есть пара вопросов:
1. Что касается проблем с производительностью, будет ли мой подход масштабироваться при увеличении размера кеша, или, может быть, мне стоит использовать lua или что-то еще?
1. в случае, если я хочу продолжить текущий подход, где я должен сохранить отсортированный набор в случае сбоя redis, если я использую постоянство redis, это повлияет на общую производительность, я подумал об использовании выделенного сервера redis для sets (Я искал, если возможно сделать резервную копию только части данных redis, но ничего не нашел об этом.

Мой подход => getTopObjects ({userID}, 0, 20):

self.zrange = function(setID, start, stop, multi)
{
    return execute(this, "zrange", [setID, start, stop], multi);
};

self.getObject = function(key, multi)
{
    return execute(this, "hgetall", key, multi);
};

self.getObjects = function(keys)
{
    let multi = thisArg.client.multi();
    let promiseArray = [];

    for (var i = 0, len = keys.length; i < len; i++)
    {
        promiseArray.push(this.getObject(keys[i], multi));
    }
    return execute(this, "exec", [], multi).then(function(results)
    {
        //TODO: do something with the result.
        return Promise.all(promiseArray);
    });
};

self.getTopObjects = function(setID, start, stop)
{
    //TODO: validate the range 
    let thisArg = this;
    return this.zrevrange(setID, start, stop).then(function(keys)
    {
        return thisArg.getObjects(keys);
    });
};

Ответы [ 2 ]

0 голосов
/ 15 мая 2019

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

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

Что происходит, когда redis или любой другой инструмент данных в памяти, который вы используете, дает сбой, вы просто перезагружаете данные обратно в память. Все они имеют функции, позволяющие сохранять данные в файлы в качестве резервной копии. Я думаю о реализации другого слоя базы данных, не знаю, скажем, Cassandra или Mongodb , который содержит временные рамки каждого пользователя с момента его создания. Конечно, это создает дополнительные издержки, потому что вам нужно синхронизировать три слоя данных (например, mysql, redis и mongodb)!

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

Тем не менее, это очень самоуверенно. Надоело, что люди говорят мне подождать, пока мой сайт не взорвется пользователями или так называемая преждевременная оптимизация ответ, который вы получили:)

0 голосов
/ 14 января 2019

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

1) Вероятно, слишком рано даже вводить redis , не говоря уже о том, достаточно ли быстрая redis. Ваша социальная сеть почти наверняка в порядке - до 1000 пользователей, выполняющих необработанные SQL-запросы к Mysql / Postgres / Random RDS. Если он начинает замедляться, получите данные о медленно выполняющихся запросах и исправьте их с помощью оптимизации запросов и соответствующих индексов. Это даст вам 10 000 пользователей.

2) Теперь вы можете начать вводить Redis. В общем я бы рекомендовал вам думать о вашем Redis как о чисто кеширующем, а не постоянном хранилище; это не должно иметь значения, если он сдувается, это просто означает, что ваш сайт работает медленнее в течение следующих нескольких секунд, потому что ваши пользователи получают свои страницы загружаются из запросов SQL вместо повторных обращений (каждый запрос повторно заполняет отсортированный список сообщений этого пользователя). в редис, конечно).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...