Ответы пользователя по тегу Redis
  • Почему могут быть такие медленные показатели nodejs + redis?

    В момент запроса redis спит, и надо, чтобы он проснулся, причём если запросы к редису посылаются редко, то и просыпание будет дольше. Хотя по идее при запросе должно быть прерывание, из-за чего он должен проснуться достаточно быстро.

    А console.log действительно может работать долго, лучше между замерами его не вызывать.

    Конечно же, после редиса должен ещё проснуться node.js-скрипт :)
    Но обычно просыпание должно занимать до 1 мс, а два просыпания — до 2 мс. 6–12 мс — действительно многовато. Вероятно, просыпание выполняется долго из-за того, что большую часть времени скрипт и redis бездействуют. Ну или прерывания не срабатывают вообще или срабатывают, но из-за сильного бездействия система всё-таки решает, что лучше так быстро не будить скрипт.

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

    Кто-то может подумать, а чего вообще так долго всё будится. Потому что каждое бужение отнимает процессорное время, и система, допустим, может сделать максимум 50 тыс бужений в секунду, загрузив одно ядро на 100%. Теперь представьте 10 скриптов и 10 редисов, которые что-то делают каждую 1 мс — это уже 20 тыс бужений, что загрузит одно ядро на 40%. И при этом суммарный пинг будет 2 мс. Для пинга 1 мс придётся сделать 40 тыс бужений — это 80% загрузки.

    Лучше всего эту проблему решают прерывания — скрипт будится только тогда, когда ему на сокет пришли данные или он, допустим, слушает клавиатуру, и пользователь нажал клавишу на клавиатуре, и т. д. В итоге получится, что если 10 скриптов ничего не делают и ничего не слушают, то и процессор не будет загружен. А если делают, то 80% загрузки — не так страшно, ведь у нас на сервере не одно ядро.

    PS. Ещё кстати может влиять ваша виртуалка. Я бы посоветовал потестить напрямую, ведь это та особенность, где виртуалка реально может влиять.

    PS. В node.js console.log блокирует скрипт, по крайней мере при выводе в файл. Т. е. считайте, что это примерно как вызвать fs.appendFileSync(). Да и при выводе в консоль тоже вроде медленно работает, хотя лучше проверить. И ещё не факт, что сама функция быстрая, хотя это уже должно слабже влиять.

    Да, действительно, убрал консольный вывод и стало сразу 1-2 мс. Если честно, то ожидал увидеть 0, как заявлено разработчиками 100000 в сек

    100к в секунду redis действительно без проблем выполнит. Но запрос дойдёт до редиса же не сразу, а после выполнения результат дойдёт до скрипта тоже не сразу. Т. е. каждый запрос всё-равно будет занимать порядка 1 мс, но при этом таких запросов можно послать 100 тыс в секунду. Это как в интернете у вас 100 мбит, но когда вы заходите на сайт, всё-равно 10–1000 мс из-за пинга. Но зато вы можете зайти на 10 таких сайтов сразу — тогда получится использовать канал намного эффективнее.
    Ответ написан
    2 комментария
  • Как вернуть promise из redis?

    К ответу выше: вместо new Promise можно просто пометить функцию как async — она автоматически вернёт Promise, который будет заполнен по достижении return или throw (но сам Promise будет возвращён сразу же ещё до начала фактического выполнения функции):

    exports.findOrCreate = async function findOrCreate(userID, provider){
        const accountID = await client.getAsync('accounts:' + provider + ':' + userID);
        
        if (accountID !== null) {
            return client.hgetallAsync('account:' + accountID); // 1
        }else{
            throw 'user not found';
        }
    };
    
    (async () => {
        const promise = findOrCreate(1); //Возвратит promise
        const users = await findOrCreate(1); //Возвратит пользователей
        const users = await promise; //Возвратит пользователей, аналог предыдущей строчки
    })();

    Гуглить по запросу async await.
    Ответ написан
    1 комментарий
  • Где лучше хранить сокет соединение с каждым клиентом, в обычном массиве или в redis?

    Очевидно, что редис намного медленнее, чем обычный доступ к переменной, поэтому оптимальнее всё хранить в переменных. Особенно большой оверхед даст посылка запросов. Например, 100-200 тыс простых запросов в секунду они вполне могут загрузить ваш скрипт на 100% и redis процентов на 30.

    Тем не менее, redis всё-равно очень полезная вещь по следующим причинам:
    1. Удобно хранить постоянные данные, которые не должны теряться после остановки/перезапуска скрипта или сервера.
    2. Если доступ к данным требуется сразу из нескольких скриптов. В этом случае если Вы вместо редиса поюзаете хранение в обычных переменных, то получите следующие проблемы:
      • Данные придётся дублировать сразу в нескольких скриптах, что может значительно увеличить расход памяти
      • Нужно следить, что во всех скриптах находится актуальная версия данных.
      • Это сильно усложняет проект и его поддержку. Если раньше нам чтобы что-то изменить, достаточно было записать это в базу данных из любого скрипта, то теперь нам придётся провзаимодействовать с каждым из таких скриптов. Причём просто провзаимодействовать не получится, надо ещё в сами скрипты добавить код, который ответит на это взаимодействие, и обновит данные в своей памяти, а также ещё, возможно, провзаимодействует с другими скриптами.

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

        Другой пример — код становится зависимым. Раньше, у нас ничего не хранилось в памяти скрипта и все запросы были полностью обособлены друг от друга. Теперь же они зависят от каких-то глобальных данных, хранящихся в памяти скрипта. Во-первых, обработчики запросов становятся привязаны друг к другу, во-вторых, усложняется состояние каждой такой подпрограммы, т. к. теперь есть зависимость от глобальных данных, в-третьих, их теперь нельзя так просто взять и перенести в другое место.


    Как результат — оба варианта хранения хороши, просто каждый вариант должен использоваться в своей ситуации. Также допустим третий вариант — хранение в редисе с кэшированием в памяти скрипта.

    Сокеты конечно же лучше хранить в памяти скрипта, т. к. они не требуют постоянного хранения даже после рестарта сервера и не нужны в других скриптах.
    Ответ написан
    Комментировать