Тактика использования PHP на сайтах с высокой нагрузкой - PullRequest
239 голосов
/ 24 августа 2008

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


Я разрабатываю инструмент на PHP , который мог бы привлечь довольно много пользователей, если бы он работал правильно. Однако, хотя я полностью способен разрабатывать программу, я почти ничего не понимаю, когда дело доходит до создания чего-то, что может иметь дело с огромным трафиком. Вот несколько вопросов по этому вопросу (не стесняйтесь также превратить этот вопрос в ветку ресурсов).

Базы данных

В настоящее время я планирую использовать функции MySQLi в PHP5. Однако как мне настроить базы данных по отношению к пользователям и контенту? Нужно ли мне несколько баз данных? На данный момент все перемешано в одной базе данных - хотя я рассматривал возможность распространения пользовательских данных в одну, фактического контента в другую и, наконец, основного контента сайта (мастеров шаблонов и т. Д.) В другую. Я считаю, что отправка запросов в разные базы данных облегчит их загрузку, поскольку одна база данных = 3 источника загрузки. Также будет ли это эффективно, если они все будут на одном сервере?

Кэширование

У меня есть система шаблонов, которая используется для создания страниц и замены переменных. Основные шаблоны хранятся в базе данных, и каждый раз, когда вызывается шаблон, вызывается его кэшированная копия (HTML-документ). На данный момент у меня есть два типа переменных в этих шаблонах - статическая переменная и динамическая переменная. Статические переменные - это обычно такие вещи, как имена страниц, названия сайтов - вещи, которые не часто меняются; динамические переменные - это то, что меняется при каждой загрузке страницы.

Мой вопрос по этому вопросу:

Скажите, что у меня есть комментарии к различным статьям. Что является лучшим решением: сохраняйте простой шаблон комментариев и визуализируйте комментарии (из вызова БД) при каждой загрузке страницы или сохраняйте кэшированную копию страницы комментариев в виде html-страницы - каждый раз, когда комментарий добавляется / редактируется / удаляется страница перечитана.

Наконец

У кого-нибудь есть какие-либо советы / указатели для запуска сайта с высокой нагрузкой на PHP. Я почти уверен, что это работоспособный язык - Facebook и Yahoo! дать ему большое преимущество - но есть ли какие-то события, которые я должен остерегаться?

Ответы [ 23 ]

88 голосов
/ 24 августа 2008

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

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

И не забывайте, что вы никогда не закончили масштабирование. Сайт, который обрабатывает 10req / s, потребует изменений для поддержки 1000req / s. И если вам повезет с необходимостью поддержки 10 000 запросов в секунду, ваша архитектура, вероятно, также будет выглядеть совершенно иначе.

Базы данных

  • Не используйте MySQLi - PDO - это «современный» уровень доступа к базе данных OO. Самая важная функция - заполнители в ваших запросах. Он достаточно умен, чтобы использовать подготовку на стороне сервера и другие оптимизации для вас.
  • Вы, вероятно, не хотите разбивать вашу базу данных на этом этапе. Если вы обнаружите, что одна база данных не обрезается, есть несколько способов масштабирования, в зависимости от вашего приложения. Репликация на дополнительные серверы обычно работает хорошо, если у вас больше операций чтения, чем записи. Sharding - это метод разделения ваших данных на множество машин.

Кэширование

  • Вы, вероятно, не хотите кэшировать в своей базе данных. База данных, как правило, является вашим узким местом, поэтому добавление к ней большего количества операций ввода-вывода, как правило, плохо. Существует несколько кешей PHP, которые выполняют похожие функции, такие как APC и Zend.
  • Измерьте вашу систему с включенным и выключенным кэшированием. Бьюсь об заклад, ваш кеш тяжелее, чем обслуживать страницы прямо.
  • Если сборка ваших комментариев и статей из базы данных занимает много времени, интегрируйте memcache в вашу систему. Вы можете кэшировать результаты запроса и сохранять их в экземпляре memcached. Важно помнить, что извлечение данных из memcache должно быть быстрее, чем сборка данных из базы данных, чтобы увидеть какую-либо выгоду.
  • Если ваши статьи не являются динамическими, или у вас есть простые динамические изменения после того, как они сгенерированы, рассмотрите возможность записи html или php на диск. У вас может быть страница index.php, которая ищет статью на диске, если она там, она передает ее клиенту. Если это не так, он генерирует статью, записывает ее на диск и отправляет клиенту. Удаление файлов с диска приведет к перезаписи страниц. Если к статье добавлен комментарий, удалите кэшированную копию - она ​​будет восстановлена.
59 голосов
/ 20 января 2009

Я ведущий разработчик сайта с более чем 15 миллионами пользователей. У нас было очень мало проблем с масштабированием, потому что мы планировали это РАНЬШЕ и масштабировали вдумчиво. Вот некоторые из стратегий, которые я могу предложить из своего опыта.

SCHEMA Во-первых, денормализуйте свои схемы. Это означает, что вместо нескольких реляционных таблиц вы должны выбрать одну большую таблицу. В общем, объединения - это пустая трата драгоценных ресурсов БД, потому что многократная подготовка и сопоставление записывают дисковые операции ввода-вывода. Избегайте их, когда можете.

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

INDEXING Убедитесь, что в ваших запросах используется хотя бы один индекс. Но будьте осторожны, эти индексы будут стоить вам, если вы будете часто писать или обновлять. Есть несколько экспериментальных приемов, чтобы избежать этого.

Вы можете попробовать добавить дополнительные столбцы, которые не проиндексированы, и которые идут параллельно индексированным столбцам. Затем вы можете иметь автономный процесс, который записывает неиндексированные столбцы по индексированным столбцам в пакетном режиме. Таким образом, вы сможете лучше контролировать, когда mySQL потребуется пересчитать индекс.

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

CACHING Я очень рекомендую Memcached. Это было доказано крупнейшими игроками в стеке PHP (Facebook) и является очень гибким. Для этого есть два способа: один - кэширование на уровне вашей БД, другой - кэширование на уровне вашей бизнес-логики.

Параметр уровня БД потребует кэширования результатов запросов, извлеченных из БД. Вы можете хэшировать ваш SQL-запрос с помощью md5 () и использовать его в качестве ключа поиска перед переходом в базу данных. Плюс в том, что это довольно легко реализовать. Недостатком (в зависимости от реализации) является то, что вы теряете гибкость, потому что вы относитесь ко всему кэшированию одинаково в отношении срока действия кэша.

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

ОХРАНА ДАННЫХ Репликация только дает вам так далеко. Рано, чем вы ожидаете, ваши записи станут узким местом. Чтобы компенсировать это, необходимо как можно раньше поддерживать разделение данных. Вы, вероятно, захотите застрелиться позже, если вы этого не сделаете.

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

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

ОФФЛАЙН ОБРАБОТКА Не заставляйте пользователя ждать вашего бэкэнда, если ему это не нужно. Создайте очередь заданий и переместите любую обработку, которую вы можете выполнять в автономном режиме, делая это отдельно от запроса пользователя.

41 голосов
/ 24 августа 2008

Я работал над несколькими сайтами, которые получают миллионы / хитов в месяц с поддержкой PHP и MySQL. Вот некоторые основы:

  1. Кеш, кеш, кеш. Кэширование - это один из самых простых и эффективных способов снизить нагрузку на ваш веб-сервер и базу данных. Кэшируйте содержимое страницы, запросы, дорогостоящие вычисления, все, что связано с вводом / выводом. Memcache очень прост и эффективен.
  2. Используйте несколько серверов, когда вы исчерпаны. Вы можете иметь несколько веб-серверов и несколько серверов баз данных (с репликацией).
  3. Уменьшите общее количество запросов к вашим веб-серверам. Это влечет за собой кэширование JS, CSS и изображений с использованием заголовков expires. Вы также можете переместить статический контент в CDN, что ускорит работу вашего пользователя.
  4. Измерение и тест. Запустите Nagios на своих производственных машинах и загрузите тестирование на своем сервере dev / qa. Вам нужно знать, когда ваш сервер загорится, чтобы вы могли предотвратить это.

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

Ознакомьтесь также с моим блогом о масштабируемости, там много ссылок на презентации о масштабировании с использованием нескольких языков и платформ: http://www.ryandoherty.net/2008/07/13/unicorns-and-scalability/

39 голосов
/ 24 августа 2008

Re: PDO / MySQLi / MySQLND

@ * 1006 Гэри *

Вы не можете просто сказать «не используйте MySQLi», поскольку у них разные цели. PDO почти как уровень абстракции (хотя на самом деле это не так) и предназначен для упрощения использования нескольких продуктов баз данных, тогда как MySQLi специфичен для соединений MySQL. Неверно утверждать, что PDO является современным уровнем доступа в контексте его сравнения с MySQLi, потому что ваше утверждение подразумевает, что прогрессия была mysql -> mysqli -> PDO, что не соответствует действительности.

Выбор между MySQLi и PDO прост - если вам нужно поддерживать несколько продуктов баз данных, вы используете PDO. Если вы просто используете MySQL, вы можете выбрать между PDO и MySQLi.

Так почему бы вы выбрали MySQLi вместо PDO? Смотри ниже ...

@ росс

Вы правы в отношении MySQLnd, который является новейшей библиотекой уровня языка ядра MySQL, однако он не является заменой MySQLi. MySQLi (как и в случае с PDO) остается тем же способом, которым вы будете взаимодействовать с MySQL через ваш PHP-код. Оба они используют libmysql в качестве клиента C за кодом PHP. Проблема заключается в том, что libmysql находится за пределами основного движка PHP, и именно здесь mysqlnd входит, т. Е. Это собственный драйвер, который использует базовые компоненты PHP для максимизации эффективности, особенно в том, что касается использования памяти.

MySQLnd разрабатывается самими MySQL и недавно попал в ветку PHP 5.3, которая находится на тестировании RC, готовая к выпуску в конце этого года. После этого вы сможете использовать MySQL и MySQLi ... но не PDO. Это даст MySQLi повышение производительности во многих областях (не во всех) и сделает его лучшим выбором для взаимодействия с MySQL, если вам не нужна абстракция, такая как возможности PDO.

Тем не менее, MySQLnd теперь доступен в PHP 5.3 для PDO, и поэтому вы можете получить преимущества от повышения производительности от ND до PDO, однако PDO по-прежнему является универсальным уровнем базы данных, и поэтому будет вряд ли сможет извлечь выгоду из улучшений ND так же, как MySQLi .

Некоторые полезные тесты можно найти здесь , хотя они с 2006 года. Вам также необходимо знать о таких вещах, как эта опция .

При выборе между MySQLi и PDO необходимо учитывать множество факторов. В действительности это не будет иметь значения, пока вы не доберетесь до чрезмерно высоких номеров запросов, и в этом случае имеет больше смысла использовать расширение, специально разработанное для MySQL, а не расширение, которое абстрагирует вещи и предоставляет драйвер MySQL. ,

Это не просто вопрос, который лучше, потому что у каждого есть свои преимущества и недостатки. Вам нужно прочитать ссылки, которые я предоставил, и придумать свое собственное решение, затем проверить его и выяснить. Я использовал PDO в прошлых проектах, и это хорошее расширение, но я выбрал бы чистую производительность MySQLi с скомпилированной новой опцией MySQLND (когда выйдет PHP 5.3).

23 голосов
/ 29 сентября 2008

Общее

  • Не пытайтесь оптимизировать, пока не начнете видеть реальную нагрузку. Вы можете догадаться правильно, но если вы этого не сделаете, вы потратили впустую свое время.
  • Используйте jmeter , xdebug или другой инструмент для сравнения сайта.
  • Если загрузка начинает вызывать проблемы, вероятно, будет задействовано кэширование объекта или данных, поэтому обычно читайте о параметрах кэширования (memcached, MySQL options)

код

  • Профилируйте свой код, чтобы вы знали, где находится узкое место, и находится ли он в коде или в базе данных

Базы данных

  • Используйте MYSQLi , если переносимость на другие базы данных не важна, PDO , иначе
  • Если тесты показывают, что проблема в базе данных, проверьте запросы, прежде чем начать кэширование. Используйте EXPLAIN , чтобы увидеть, где замедляются ваши запросы.
  • После того, как запросы оптимизированы и база данных каким-то образом кэширована, вы можете использовать несколько баз данных. Может потребоваться репликация на несколько серверов или разделение (разделение данных на несколько баз данных / серверов) в зависимости от данных, запросов и типа поведения чтения / записи.

Кэширование

  • Много написано о кешировании кода, объектов и данных. Посмотрите статьи на APC , Zend Optimizer , memcached , QuickCache , JPCache . Сделайте это до того, как вам действительно понадобится, и вы будете меньше беспокоиться о том, чтобы начать неоптимизированный.
  • APC и Zend Optimizer являются кэшами кода операции, они ускоряют код PHP, избегая повторного анализа и повторной компиляции кода. Как правило, прост в установке, стоит сделать рано.
  • Memcached - это общий кеш, который вы можете использовать для кеширования запросов, функций или объектов PHP или целых страниц. Код должен быть специально написан для его использования, что может быть сложным процессом, если нет центральных точек для обработки создания, обновления и удаления кэшированных объектов.
  • QuickCache и JPCache являются файловыми кешами, в остальном аналогичны Memcached. Основная концепция проста, но также требует кода и проще с центральными точками создания, обновления и удаления.

Разное

  • Рассмотрим альтернативные веб-серверы для высокой нагрузки. Такие серверы, как lighthttp и nginx могут обрабатывать большие объемы трафика в гораздо меньшем объеме памяти, чем Apache , если вы можете пожертвовать мощью и гибкостью Apache (или если вы просто не не нужны те вещи, которые часто вам не нужны).
  • Помните, что в наши дни аппаратное обеспечение на удивление дешевое, поэтому обязательно потратьте усилия на оптимизацию большого блока кода по сравнению с «давайте купим сервер-монстр».
  • Попробуйте добавить в этот вопрос теги "MySQL" и "scaling"
9 голосов
/ 24 августа 2008

Во-первых, как я думаю, Кнут сказал: «Преждевременная оптимизация - корень всего зла». Если вам не нужно решать эти проблемы прямо сейчас, тогда не сосредотачивайтесь на том, чтобы вначале работать правильно. При этом, если оптимизация не может ждать.

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

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

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

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

9 голосов
/ 24 августа 2008

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

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

6 голосов
/ 28 августа 2008

Для чего бы то ни было, кэширование DIRT ПРОСТО в PHP даже без пакета расширения / помощника, такого как memcached.

Все, что вам нужно сделать, это создать выходной буфер, используя ob_start().

Создать глобальную функцию кэша. Вызовите ob_start, передайте функцию как обратный вызов. В функции найдите кешированную версию страницы. Если существует, обслужи и кончи.

Если он не существует, скрипт продолжит обработку. Когда он достигает соответствующего ob_end (), он вызовет указанную вами функцию. В это время вы просто получаете содержимое буфера вывода, помещаете его в файл, сохраняете файл и завершаете работу.

Добавить в некоторые экспирацию / сборщик мусора.

И многие люди не понимают, что вы можете вкладывать ob_start() / ob_end() звонки. Поэтому, если вы уже используете выходной буфер, скажем, для разбора рекламных объявлений, подсветки синтаксиса или чего-то еще, вы можете просто вставить еще один вызов ob_start/ob_end.

6 голосов
/ 24 августа 2008

Профилирование вашего приложения с помощью чего-то вроде Xdebug (как рекомендовано tj9991) определенно будет обязательным. Не имеет большого смысла просто вслепую оптимизировать вещи. Xdebug поможет вам найти реальные узкие места в вашем коде, чтобы вы могли разумно потратить время на оптимизацию и исправить куски кода, которые действительно вызывают замедление.

Если вы используете Apache, еще одна утилита, которая может помочь в тестировании, - Siege . Это поможет вам предвидеть, как ваш сервер и приложение отреагируют на высокие нагрузки, действительно справившись с этим.

Любой вид кэш-кода для PHP (например, APC или один из множества других) также очень поможет.

6 голосов
/ 26 августа 2008

Я управляю веб-сайтом с 7-8 миллионами просмотров страниц в месяц. Не очень много, но достаточно, чтобы наш сервер чувствовал нагрузку. Решение, которое мы выбрали, было простым: Memcache на уровне базы данных. Это решение хорошо работает, если загрузка базы данных является вашей основной проблемой.

Мы начали использовать Memcache для кэширования целых объектов и результатов базы данных, которые наиболее часто использовались. Это сработало, но в нем также были ошибки (мы могли бы избежать некоторых из них, если бы были более осторожны).

Итак, мы изменили наш подход. Мы создали оболочку базы данных (с теми же методами, что и в нашей старой базе данных, поэтому ее было легко переключать), а затем мы создали ее подклассы, чтобы обеспечить доступ к базе данных memcached.

Теперь все, что вам нужно сделать, это решить, может ли запрос использовать кэшированные (и, возможно, устаревшие) результаты или нет. Большинство запросов, выполняемых пользователями, теперь выбираются непосредственно из Memcache. Исключением являются обновления и вставки, которые для основного сайта происходят только из-за регистрации. Эта довольно простая мера снизила нагрузку на наш сервер примерно на 80%.

...