Я думаю, что ваша главная проблема здесь - параллелизм. Apache и PHP не преуспевают в таких задачах, когда 100+ пользователей имеют открытый HTTP-запрос.
Если в вашем while (true) вы тратите 0,1 секунды на рабочую нагрузку, связанную с ЦП (проверка состояния изменений или другие полезные вещи) и 1 секунду на режим сна, это приведет к загрузке ЦП на 100%, как только вы 10 пользователей онлайн в чате. Таким образом, чтобы обслуживать большее количество пользователей с ЭТОЙ моделью чата, вам необходимо оптимизировать рабочую нагрузку в вашем цикле while (true) и / или увеличить интервал ожидания от 1 секунды до 3 или выше.
У меня была та же проблема в системе чатов на основе http, которую я написал много лет назад, когда в какой-то момент слишком много параллельных mysql-select, где замедлялся чат, создавая тяжелую нагрузку на систему.
Что я сделал, так это реализовал быстрый «кольцевой буфер» для сообщений и информации о состоянии в общей памяти (sysv в тот день - сегодня я бы, вероятно, использовал APC или memcached). Все операции записи и чтения в буфере, а сам буфер периодически «сбрасывается» в базу данных, чтобы сохранить его (но гораздо реже, чем один раз в секунду на пользователя). Если упорство не требуется, вы можете опустить бэкэнд, конечно.
Таким образом, я смог увеличить количество пользователей, которым могу служить, примерно на 500%.
НО, как только вы решите эту проблему, вы столкнетесь с другой: доступной системной памятью (100+ apache обрабатывает ~ 5 МБ каждый - весело) и издержками переключения контекста. Чем больше у вас активных процессов, тем больше ваша операционная система потратит на накладные расходы, связанные с назначением «достаточно справедливых» слотов CPU AFAIK.
Вы увидите, что очень сложно эффективно масштабировать с использованием только apache и PHP для вашего варианта использования. Есть инструменты с открытым исходным кодом, клиент и сервер, чтобы помочь, хотя. Один из них, который я помню, помещает сервер перед Apache и помещает в очередь сообщения внутри, имея при этом очень эффективную многосокетную связь с клиентами javascript, делающими возможными реальные события «push». К сожалению, я не помню ни одного имени, поэтому вам придется исследовать или надеяться, что сообщество stackoverflow внесет то, что мой мозг уже отбросил;)
Edit:
Привет Нуно,
поле комментария содержит слишком мало символов, поэтому я отвечаю здесь.
Давайте снова получим 10 пользователей параллельно:
Время ЦП 10 * 0,1 секунды за цикл (предположительно) составляет примерно 1 с времени ЦП за период 1,1 секунды (1 секунда ожидания + 0,1 секунды выполнения). Это 1 / 1.1, который я бы смело округлил до 100% загрузки ЦП, хотя это "всего лишь"% 90.9
Если процессорное время 10 * 0,1 с «растягивается» в течение не 1,1 секунды, а 3,1 (3 секунды ожидания + 0,1 секунды выполнения), вычисление составляет 1 / 3,1 =% 32
И это логично. Если ваш цикл проверки запрашивает ваш бэкэнд в три раза медленнее, у вас есть только треть нагрузки в вашей системе.
Относительно разделяемой памяти: имя может подразумевать это, но если вы используете хорошие идентификаторы для своих областей кэша, например, один идентификатор для разговора или пользователя, у вас будут частные области в общей памяти. Таблицы базы данных также полагаются на то, что вы предоставляете хорошие идентификаторы для отделения личных данных от общедоступной информации, поэтому их следует уже готовить:)
Я бы тоже больше не "раскололся". Чем меньше PHP-процессов нужно «жонглировать» параллельно, тем проще для ваших систем и для вас. Если вы не видите, это имеет абсолютный смысл, потому что один тип уведомлений требует больше запрашивающих ресурсов, чем другой, и вы хотите иметь другое время обновления или что-то в этом роде. Но даже это можно решить во время цикла. пользователь "вдали" -статус может проверяться каждые 30 секунд, в то время как написанные им сообщения могут проверяться каждые 3. Нет причин создавать больше циклов. Просто разные переменные счетчика или использование правого делителя в операции по модулю.
Изобретатель PHP сказал, что он считает, что человек слишком ограничен для управления параллельными процессами:)
Редактировать 2
хорошо, давайте построим формулу.У нас есть эти переменные:
продолжительность выполнения (e) продолжительность сна (с) продолжительность одного цикла (C) число одновременных пользователей (u) загрузка процессора (l)
c =e + sl = u e / c # выражает "как часто" доступный временной интервал c соответствует нагрузке на ЦП, генерируемой 30 пользователями CONCURRENT.l = u e / (e + s)
для 30 пользователей, при условии, что у вас есть время выполнения 0,1 с и 1 секунда сна l = 30 * 0,1 / (0,1 + 1) l = 2,73 l =% 273 Загрузка ЦП (иначе вам нужно 3 ядра: P)
, превышающих capab.из вашего процессора, что циклы будут работать дольше, чем вы планируете.общее время отклика увеличится (и процессор разогреется)