Ответы пользователя по тегу Node.js
  • Почему тормозит NGINX + NodeJS WebSocket + MySQL при 2000+ подключениях?

    1. Не сказана, какая нагрузка на сервер. Может быть, в этот момент процессор или диск загружен на 100% — поэтому и тормозит.
    2. Если Вы уже прошлись по всем узким горлышкам, и видите, что нигде загрузки нет, вероятно, у Вас просто неправильные настройки. Например, в nginx по умолчанию стоит очень маленькое количество соединений, и как только к Вам подключится такое количество пользователей, всё начнёт виснуть. Например, если worker_processes стоит 2, а worker_connections — 1000, то nginx сможет одновременно обслуживать не больше 2000 запросов, остальные запросы будут ставиться в очередь. Решение — поставить их на максимум (сколько не жалко оперативки). Соединение отъедает где-то 10 КБ памяти, поэтому если Вы поставите 100 тыс соединений, то nginx сможет отожрать до 1 ГБ памяти.
    Ответ написан
  • Как с помощью async выполнить n-ое количество параллельных запросов?

    Либо так:
    await Promise.all(...promises)

    Либо так:
    const p1 = callSomeAsyncFunction(),
          p2 = callAnotherAsyncFunction(),
          p3 = callAnotherAsyncFunction();
    
    await p1;
    await p2;
    await p3;


    Во втором примере мы сразу запустили три функции одновременно. Далее, когда они уже начали работу, мы ожидаем завершение всех трёх функций. При этом, поскольку они уже исправно запущены и выполняют нужные действия, никакой лишней задержки не будет, ведь они уже запущены.
    Ответ написан
    Комментировать
  • Почему нельзя определить функцию через global?

    С чего вы взяли, что нельзя? Более чем можно, и работает всё исправно. Вы что-то путаете.
    Ответ написан
    Комментировать
  • Async/await и правильность codestye?

    Первое что бросается в глаза — использованы пробелы вместо табов, это быдлокодерство (почему — гуглить по запросу "Tab indent space alignment"). Также после if нужен пробел.

    if (createUser(123, 123, 1, 123)) писать бессмысленно, т. к. функция createUser() всегда сразу же возвращает промис ещё до начала фактического выполнения функции. Только потом спустя функция начнёт выполняться, и в тот момент, когда выполнение дойдёт до return или throw, функция заполнит этот промис результатом или ошибкой. Т. е. суть в том, что async-функция — это функция, возвращающая промис. Раньше вам приходилось самому возвращать промис, а теперь функция возвращает его за вас. (PS. В реальности, если вдаваться в подробности, то на самом деле функция начнёт выполняться сразу же до первого await, но даже если await'ов не будет, возвращён будет всё-равно промис).

    Чтобы решить проблему, нужно либо написать createUser(123, 123, 1, 123).then(bool => { ... }), либо обернуть вызов функции в другую async-функцию, чтобы была возможность использовать await. Конечно же, такая обёртка тоже вернёт промис.

    Также нужно отметить, что try catch писать необязательно, вместо этого можно отловить ошибку прямо в указанной выше обёртке (или с помощью .then(value => {}, err => {})). Т. е. отловить ошибку рано или поздно придётся, но необязательно это делать в каждой функции — чаще всего достаточно один раз в конце.
    Ответ написан
  • Как сохранить файл из request?

    А причём тут node? Точно не помню, но инфа в интернете есть, наверное, надо загрузить файл (как по обычной ссылке) и дальше уже работать как с обычным файлом.
    Ответ написан
    Комментировать
  • Почему эта ошибка появилась?

    Там же написано: EADDRINUSE. Порт уже используется, а вы снова хотите его открыть. Вначале закройте программу, которая использует этот порт, а потом запускайте ваш скрипт. Не исключено, что ваш же скрипт его и использует, просто вы пытаетесь запустить скрипт второй раз, а первый ещё не закрыли.

    Ну и если читать не умеете, хотя бы гуглом научитесь пользоваться.
    Ответ написан
    3 комментария
  • Как вызывать скрипт каждые 30 минут?

    cron подойдёт для вызова любых скриптов, в т. ч. и node
    Ответ написан
    Комментировать
  • Почему после вызова промиса код не выполняется и процесс не умирает?

    Потому что Model.findOne() возвращает промис, который никогда не выполняется. В итоге оператор await ждёт этот промис вечно. Ну пусть ждёт, вдруг промис всё-таки когда-нибудь выполнится, и выполнение функции find() продолжится, а после него и скрипт завершится.
    Ответ написан
    2 комментария
  • Почему могут быть такие медленные показатели 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. Если доступ к данным требуется сразу из нескольких скриптов. В этом случае если Вы вместо редиса поюзаете хранение в обычных переменных, то получите следующие проблемы:
      • Данные придётся дублировать сразу в нескольких скриптах, что может значительно увеличить расход памяти
      • Нужно следить, что во всех скриптах находится актуальная версия данных.
      • Это сильно усложняет проект и его поддержку. Если раньше нам чтобы что-то изменить, достаточно было записать это в базу данных из любого скрипта, то теперь нам придётся провзаимодействовать с каждым из таких скриптов. Причём просто провзаимодействовать не получится, надо ещё в сами скрипты добавить код, который ответит на это взаимодействие, и обновит данные в своей памяти, а также ещё, возможно, провзаимодействует с другими скриптами.

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

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


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

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

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

    сложность/скорость разработки не так интересует

    Если сложность/скорость разработки не так интересует, могу посоветовать написать на ассемблере.
    Ответ написан
    Комментировать