Назад | Перейти на главную страницу

node.js, mongodb, redis, об ухудшении производительности ubuntu в продакшене, оперативная память свободна, процессор 100%

Как следует из названия вопроса, мне трудно понять, что можно улучшить в моем приложении (или настроить в ОС, 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 тысяч пользователей в день. Это всегда работало очень хорошо, если не считать одной главной проблемы: снижения производительности. По мере использования количество процессоров, используемых каждым процессом, увеличивается до тех пор, пока не будет установлен рабочий процесс (который больше не будет обслуживать запросы). Я временно решил, что он проверяет процессор, используемый каждым рабочим каждую минуту, и перезапускает его, если он достигает 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

что показывает, что у меня много закрытых соединений в timewait. Я увеличил максимальное количество открытых файлов до 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, а не системный администратор, поэтому я не знаю, какую нагрузку мне следует ожидать от моих серверов, но, конечно, он не работает должным образом. В остальном приложение стабильно, и эта последняя проблема не позволяет мне отгрузить готовые мобильные версии приложения, так как очевидно, что они принесут больше нагрузки и, в конечном итоге, выйдут из строя!

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

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

Проблема заключается в соединениях 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, что на данный момент достаточно для меня, но я ' Я читал, что он может быть увеличен до 64k одновременных подключений, поэтому я считаю, что эта архитектура должна быть достаточно прочной.

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

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

Ура.

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

Можете выложить журналы?

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

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

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

Вы ловите исключения? Видеть: http://geoff.greer.fm/2012/06/10/nodejs-dealing-with-errors/ Видеть: https://stackoverflow.com/questions/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

https://stackoverflow.com/questions/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/

Не ответ как таковой, поскольку ваш вопрос - это больше сказка, чем вопрос с одним ответом.

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

Карта сетевого интерфейса со скоростью 1 Гбит / с вначале была насыщенной, и я наблюдал МНОГО ожидания ввода-вывода от событий публикации для всех клиентов.

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

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

HTH,