Как следует из названия вопроса, мне трудно понять, что можно улучшить в моем приложении (или настроить в ОС, 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://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,