node.js, mongodb, redis, снижение производительности Ubuntu на производстве, ОЗУ свободна, ЦП 100%

11

Как следует из названия вопроса, мне трудно понять, что можно улучшить в моем приложении (или настроить в ОС, Ubuntu) для достижения приемлемой производительности. Но сначала я объясню архитектуру:

Внешний сервер - это 8-ядерный компьютер с 8 ГБ оперативной памяти под управлением Ubuntu 12.04. Приложение полностью написано на javascript и выполняется в node.js v 0.8.22 (так как некоторые модули, похоже, жалуются на более новые версии узла), я использую nginx 1.4 для прокси-трафика http с порта 80 и с 443 до 8 рабочих узлов, которые управляются и начал использовать кластер узлов API. Я использую последнюю версию socket.io 0.9.14 для обработки соединений веб-сокетов, для которых я включил только веб-сокеты и опрос xhr в качестве доступных транспортов. На этой машине я также запускаю экземпляр Redis (2.2)

Я храню постоянные данные (например, пользователей и оценки) на втором сервере на mongodb (3.6) с 4 Гб оперативной памяти и 2 ядрами.

Приложение работает в течение нескольких месяцев (оно работало на одном устройстве до нескольких недель назад), и его используют около 18 000 пользователей в день. Он всегда работал очень хорошо, за исключением одной основной проблемы: снижение производительности. При использовании количество процессоров, используемых каждым процессом, увеличивается до тех пор, пока он не проработает статую рабочего (что больше не будет обслуживать запросы) Я временно решил, что каждую минуту проверяю процессор, используемый каждым работником, и перезагружаю его, если он достигает 98%. Так что проблема здесь в основном процессор, а не оперативная память. Оперативная память больше не является проблемой, так как я обновил файл socket.io 0.9.14 (более ранняя версия имела утечку памяти), поэтому я сомневаюсь, что это проблема утечки памяти, особенно потому, что теперь этот процессор растет довольно быстро ( Я должен перезапускать каждого работника примерно 10-12 раз в день!). Объем оперативной памяти растет, если честно, но очень медленно, 1 гиг каждые 2-3 дня использования, и странно то, что он не выпускается, даже когда я полностью перезагружаю все приложение. Выпускается только если я перезагружаю сервер! это я не могу понять ...

Теперь я обнаружил удивительную нодли , поэтому теперь я могу наконец увидеть, что происходит на моем производственном сервере, и я собираю данные уже пару дней. Если кто-то захочет увидеть графики, я могу дать вам доступ, но в основном я вижу, что у меня от 80 до 200 одновременных подключений! Я ожидал, что node.js обработает тысячи, а не сотни запросов. Также среднее время отклика для http-трафика колеблется между 500 и 1500 миллисекундами, что, на мой взгляд, очень много. Кроме того, в тот самый момент, когда в сети 1300 пользователей, это вывод "ss -s":

Total: 5013 (kernel 5533)
TCP:   8047 (estab 4788, closed 3097, orphaned 139, synrecv 0, timewait 3097/0), ports 0

Transport Total     IP        IPv6
*         5533      -         -
RAW       0         0         0
UDP       0         0         0
TCP       4950      4948      2
INET      4950      4948      2
FRAG      0         0         0

который показывает, что у меня есть много закрытых соединений в ожидании времени. Я увеличил максимальное количество открытых файлов до 999999, вот вывод ulimit -a:

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 63724
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 999999
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 63724
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

Поэтому я подумал, что проблема может быть в http-трафике, который по некоторым причинам насыщает доступные порты / сокеты (?), Но для меня не имеет смысла одно: почему, когда я перезагружаю работников, и все клиенты повторно соединяются в течение нескольких секунд, нагрузка на процессор работника снижается до 1% и способна правильно обслуживать запросы, пока не будет насыщена примерно через 1 час (в пиковое время)?

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

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

Franjanko
источник
Есть ли способ получить что-то вроде дампа потока из node.js? Вероятно, есть несколько потоков в бесконечном цикле. Кроме того, что на самом деле использует процессор? Что вы видите, topкогда использование процессора близко к 100%?
rvs
CPU полностью используется nodejs, когда я запускаю top, я вижу, как процессы узла принимают весь процессор. Не уверен, как я могу вывести дамп потока из узла, чтобы быть честным ...
Franjanko
Еще одна вещь, на которую следует обратить внимание, это то, что большая часть процессорного времени уходит,
скорее всего,
Кто-нибудь знает, по крайней мере, сколько одновременных подключений я могу обработать с серверами, которые у меня есть? на данный момент я поддерживаю 200 одновременных подключений макс. Это поможет мне оценить, насколько далеко я от оптимальной конфигурации ... спасибо.
Franjanko

Ответы:

10

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

Проблема заключается в соединениях pub / sub, которые я использовал с socket.io, и, в частности, в RedisStore, который используется socket.io для обработки межпроцессного взаимодействия экземпляров сокетов.

Поняв, что я могу легко реализовать свою собственную версию pub / sub, используя redis, я решил попробовать и удалил redisStore из socket.io, оставив его с хранилищем памяти по умолчанию (мне не нужно передавать на все подключенные клиенты, но только между двумя разными пользователями, подключенными возможно в разных процессах)

Первоначально я объявил только 2 глобальных подключения redis x процесс для обработки pub / sub на каждом подключенном клиенте, и приложение использовало меньше ресурсов, но на меня все еще влиял постоянный рост использования ЦП, поэтому мало что изменилось. Но затем я решил попытаться создать 2 новых подключения к redis для каждого клиента, чтобы обрабатывать их pub / sub только в своих сеансах, а затем закрыть подключения, как только пользователь отключился. Затем, после одного дня использования в производстве, процессоры все еще были на 0-5% ... бинго! ни процесс, ни перезапуск, ни ошибок, с ожидаемой производительностью. Теперь я могу сказать, что node.js рушится и рад, что выбрал его для создания этого приложения.

К счастью, redis был разработан для обработки множества одновременных подключений (по-разному для mongo), и по умолчанию он установлен на 10k, что оставляет место для примерно 5k одновременных пользователей на одном экземпляре redis, чего на данный момент мне достаточно, но я ' Я читал, что он может поддерживать до 64 тыс. одновременных подключений, поэтому я считаю, что эта архитектура должна быть достаточно надежной.

В этот момент я думал о реализации какого-либо пула соединений для redis, чтобы немного оптимизировать его, но я не уверен, не вызовет ли это снова события pub / sub для создания соединений, если только не каждое из них уничтожается и воссоздается каждый раз, чтобы очистить их.

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

Приветствия.

Franjanko
источник
2
У меня возникла та же проблема, что и в моем производственном приложении, также новая для роли администратора сервера. Я следую тому, что вы делали в концепции, но у меня есть несколько вопросов о том, как это сделать - возможно, вы могли бы предоставить ссылку на какой-то ресурс в вашем принятом ответе? Или просто предоставить больше информации? В частности, о «Но тогда я решил попробовать создать 2 новых подключения к redis для каждого клиента, чтобы обрабатывать их pub / sub только на своих сеансах, а затем закрыть подключения после отключения пользователя».
Toblerpwn
2

У вас есть исходный код для дампа? Может быть, соединения с базой данных не закрыты? Процессы, ожидающие соединения HTTP, которые никогда не закрываются.

Можете ли вы опубликовать несколько журналов?

Сделайте ps -ef и убедитесь, что ничего не запущено. Я видел, как веб-процессы оставляют зомби, которые не умрут, пока вы не убьете -9. Иногда завершение работы не работает или не работает полностью, и эти потоки или процессы будут содержать ОЗУ, а иногда и ЦП.

Это может быть бесконечный цикл где-то в коде или сбойный процесс, удерживающий соединение с БД.

Какие модули NPM используются? Они все последние?

Вы ловите исключения? См .: http://geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ См .: /programming/10122245/capture-node-js-crash-reason

Общие советы:

http://clock.co.uk/tech-blogs/preventing-http-raise-hangup-error-on-destroyed-socket-write-from-crashing-your-nodejs-server

http://blog.nodejitsu.com/keep-a-nodejs-server-up-with-forever

http://hectorcorrea.com/blog/running-a-node-js-web-site-in-production-a-beginners-guide

/programming/1911015/how-to-debug-node-js-applications

https://github.com/dannycoates/node-inspector

http://elegantcode.com/2011/01/14/taking-baby-steps-with-node-js-debugging-with-node-inspector/

Тим Спанн
источник
1

Сам по себе это не ответ, так как ваш вопрос скорее сказка, чем вопрос с одним ответом.

Просто чтобы сказать, что я успешно построил сервер node.js с socket.io, который обрабатывает более 1 миллиона постоянных соединений со средней полезной нагрузкой сообщения в 700 байт.

Плата сетевого интерфейса на скорости 1 Гбит / с вначале насыщалась, и я видел ОЖИДАНИЕ ожидания ввода-вывода от публикации событий для всех клиентов.

Удаление nginx из роли прокси также вернуло драгоценную память, потому что для достижения миллиона постоянных соединений только с ОДНЫМ сервером требуется непростая настройка конфигов, приложений и параметров настройки ОС. Имейте в виду, что это возможно только с большим количеством оперативной памяти (около 1M подключений к веб-сокетам потребляет около 16 ГБ оперативной памяти, при использовании node.js, я думаю, что использование sock.js было бы идеальным для низкого потребления памяти, но пока, socket.io так много потребляет).

Эта ссылка была моей отправной точкой для достижения этого объема соединений с узлом. Помимо того, что это приложение Erlang, все настройки ОС в значительной степени не зависят от приложения и должны быть полезны всем, кто стремится к множеству постоянных соединений (веб-сокеты или длительный опрос).

НТН,

завивать волосы щипцами
источник