2013-12-09 5 views
2

В настоящее время я работаю над большим проектом, который требует реализации событий, отправленных сервером. Я решил использовать для него транспорт событий-событий и начал с простого чата. В настоящее время клиентская сторона слушает только новое событие сообщения чата, но в будущем проект будет иметь гораздо больше событий. Во-первых, я действительно обеспокоен сценарием на сервере и его циклом, и во-вторых, я не уверен, что использование базы данных mySQL в качестве хранилища (в данном случае для сообщений чата) на самом деле является хорошей практикой. токовая петля нарушает новые сообщения, как они появляются в базе данных:Выполнение события-источника

$statement = $connect->prepare("SELECT id, event, user, message FROM chat WHERE id > :last_event_id"); 
while(TRUE) { 
    try { 
     $statement->execute(array(':last_event_id' => $lastEventId)); 
     $result = $statement->fetchAll(); 
     foreach($result as $row) { 
      echo "id: " . $row['id'] . "\n"; 
      echo "event: " . $row['event'] . "\n"; 
      echo "data: |" . $row['user'] . "| >>> \n"; 
      echo "data: " . $row['message'] . "\n\n"; 
      $lastEventId++; 
     } 
    } catch(PDOException $PDOEX) { 
     echo $PDOEX->getMessage(); 
    } 
    ob_flush(); 
    flush(); 
    usleep(10000); 
} 

Из того, что я прочитал такую ​​петлю неизбежно, и моя задача состоит в том, чтобы оптимизировать его производительность. В настоящее время я использую подготовленный отчет за пределами while() и разумный (?) usleep().

Итак, вопросы к тем, кто получил опыт в стороне сервера событий:

  1. ли такой метод целесообразно использовать в умеренно нагруженных веб-сайтов (1000-5000 пользователей он-лайн)?
  2. Если да, есть ли способ повысить производительность?
  3. Может ли база данных быть узким местом в этом случае?

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

ответ

3

Будут ли одновременно подключены более 1000 пользователей? И используете ли вы Apache с PHP? Если это так, я думаю, что на самом деле вы должны быть обеспокоены памятью: каждый пользователь держит открытый сокет, процесс Apache и экземпляр PHP. Вам нужно будет измерить себя, для своей собственной настройки, но если мы скажем 20 МБ каждый, то это 20 ГБ памяти для 1000 пользователей. Если вы затягиваете вещи, поэтому каждый процесс составляет 12 МБ, что по-прежнему составляет 12 ГБ на 1000 пользователей. (A m2.xlarge EC2-экземпляр имеет 17 ГБ памяти, поэтому, если вы планируете бюджет одного из 500-1000 пользователей, я думаю, что с вами все будет в порядке.)

В отличие от вашего 10-секундного времени опроса, использование ЦП очень низкое. По той же причине, я бы не предполагал, что опрос БД MySQL будет узким местом, но на этом уровне использования я бы подумал о том, чтобы каждая запись в БД также записывала в memcached. В принципе, если вы не возражаете бросать на него немного аппаратного обеспечения, ваш подход выглядит выполнимым. Это не самое эффективное использование памяти, но если вы знакомы с PHP, это, вероятно, будет наиболее эффективным использованием времени программиста.


UPDATE: Только видел комментарий OP и понял, что это usleep(10000) является 0,01 с, а не 10 секунд. К сожалению! Это меняет все:

  • Ваше использование в настоящее время высоко!
  • В верхней части вашего скрипта вам нужно set_time_limit(0): вы будете очень быстро использовать использование 30-секундного CPU по умолчанию с этим ограниченным лимитом.
  • Вместо опроса БД вы должны использовать службу очереди уведомлений.

Я использовал бы службу очереди вместо memcached, и вы могли бы либо найти что-то с полки, либо написать что-то обычай на PHP довольно легко. Вы все равно можете хранить MySQL в качестве основной БД и иметь свой опрос службы очереди MySQL; разница в том, что у вас есть только один процесс, опросив его интенсивно, а не тысячу. Служба очереди - это простой сервер сокетов, который принимает соединение с каждого из ваших PHP-скриптов на передней панели. Каждый раз, когда его опрос находит новое сообщение, он передает это всем клиентам, которые подключены к нему. (Есть разные способы его создания, но я надеюсь, что это даст вам общую идею.)

На первом скрипте PHP вы используете вызов socket_select() с 15-секундным таймаутом. Он только просыпается, когда нет данных, поэтому используется нулевой процессор в остальное время. (15-второй тайм-аут, так что вы можете отправить SSE Keep-alives.)


(Source for the 20MB and 12MB figures)

+0

Спасибо за ответ. Как предложил ** Дэйв **, в настоящее время я пытаюсь сделать memcache для своих целей, и он служит в качестве временного хранилища для этого входящего сообщения чата. «Время опроса» находится в микросекундах, но это всего лишь задержка, поэтому цикл не будет совершать слишком много итераций. И event-source открывает новое соединение каждые 30 секунд - когда php-script достигает max_execution_time, я полагаю. Я думал, что функция event-source - устанавливает соединение keep-alive и сбрасывает все, что сервер перекликается с этим, или я ошибаюсь? Сеть показывает запрос каждые 30 секунд. – Nevertheless

+0

@ grimv01k См. Мое обновление к моему ответу. –

+1

Ваш ответ был очень ... просвещен, так сказать, и действительно дал мне представление. В настоящее время я пытаюсь настроить односвязный сокет, который прослушивает несколько столбцов и таблицу опроса ** mySQL ** с таблицей типов «MEMORY», и все, что должно быть доставлено клиенту через «event-source». Это в настоящее время ответ на меня. Спасибо! :) – Nevertheless

2
  • такой метод разумно использовать в умеренно загруженных веб-сайтах (1000-5000 пользователей он-лайн)?

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

  • если да, то есть ли способ, чтобы увеличить представление?

Memcached в качестве хранилища темп затем задний конец процесса совершить архив ежечасно/поминутно независимо от БД MySQL

  • может база данных MySql быть узким местом в этом случае?

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

Надежда, которая помогает

Смежные вопросы