Сайт, способный выдержать высокую нагрузку (?)

Опыта в веб-разработке, как оказывается, у меня нет. Сверстать HTML+CSS сайт и настроить/запустить nginx это не опыт…
По мотивам своей статьи и оставленным комментариям возникает вопрос, — так как же тогда сделать сайт, способный выдержать высокую нагрузку?

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

Казалось бы, что может быть проще и легковеснее, чем отдавать статичные .html файлы…

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

Разве можно сделать еще быстрее?

PHP скрипт вызывается всего единожды для генерации страницы, — стоит ли тогда заморачиваться с выбором базы данных? Или может все хранить в тех же файлах?

Где лучше хранить кэш с .html документами? Предположим, что через N лет их все-таки станет очень много.

Хочу сразу все сделать правильно, и не имея своего опыта, — надеюсь на ваши советы.
  • Вопрос задан
  • 13849 просмотров
Пригласить эксперта
Ответы на вопрос 9
@edogs
Не парьтесь. Это основной совет.
Хорошую посещаемость (сервер за 50 евро держит вордпресс с воблой и 200к хитами в сутки без проблем) Вы наберете не скоро, а задумываться об N годах точно не стоит (за это время уже и хтмл-то может умрет, а Вы его хранить).
Так что берите любой распространенный движок (пхпбб/ВП) и допиливайте его до нужной Вам кондиции. Если нравится делать скорость — в этих движках навалом бутылочных горлышек, устранением которых можно долго и с удовольствием заниматься даже новичку:)
Свой велосипед хорошо, но сначала лучше разобрать пару чужих.
Ответ написан
@zuborg
Хочу сразу все сделать правильно
Все хотят, да вот ни у кого не получается ;)

стоит ли тогда заморачиваться с выбором базы данных?
Разумеется, хранить надо в отдельной базе данных, можно и файловой. А то когда захочется шаблон html-ки поменять, будет не смешно.

Казалось бы, что может быть проще и легковеснее, чем отдавать статичные .html файлы
Собственно, ничего, поэтому для незалогиненых пользователей, которые генерируют 90% трафика, стоит использовать именно статичные .html файлы. Запросы пользователей, которым надо генерить индивидуальные странички, надо направлять на движок в обход кеша (например, по факту наличия соотв сесионной куки).

Где лучше хранить кэш с .html документами?
в соотв. documentroot, чтобы nginx мог их легко найти и отдать, прямо по запрашиваемому урлу. Крайне желательно поддерживать некоторую вложенность папок, чтобы в каждой папке было максимум несколько тысяч файлов или других папок.

Или может все хранить в тех же файлах?
Все нельзя. Только то что редко обновляется и долго остается валидным. Для короткоживущих данных лучше использовать все-таки memcached, во избежание лишней нагрузки на диск. Либо FS в памяти, если уж хочется работы с файлами. Для короткоживущих данных в php есть замечательное средство кеширования — pecl модуль APC (основное его предназначение opcode cacher, но данные он тоже может кешировать)

У работы с файловым кешем свои тонкости. Например, данные в нем менять надо атомарно, т.е. через временный файл и последующий rename(). Также желательно использовать блокировки чтобы избежать ситуации, когда несколько запросов паралельно начинают генерировать один и тот же элемент кеша. Часто нет необходимости немедленно перегенерировать элемент кеша при обновлении данных, достаточно его удалить, а генерация произойдет при запросе.
Ответ написан
TheHorse
@TheHorse
Ответ теоретический, вне контекста php:

1. В общем случае, хранить все в .html — не быстрее.

1. 1 Если их мало и можно все хранить в ОП, то нет необходимости хранить кучи мелких файлов. Но сериализация нужна (на случай перезагрузки).

1. 2. Если файлов намного больше, чем можно впихнуть в ОП, то хранение всего в файлах, будет менее эффективно, чем другие методы. Дело в том, что таким файлам свойственно иметь большой процент общей информации. По сути в каждом файле .html может быть от 0% до 100% уникальной информации, для упрощения выкладки, припустим что это значение равно 50%. Тогда, вами используемые средства, делают на 50% больше операций чтения/записи на файловой системе, которая, кстати, является самым слабым звеном производительности, в большинстве случаев.

Если вы храните 50% общей информации (html-шаблоны) в ОП (что в большинстве случаев возможно), то вы на 50% снижаете нагрузку с файловой системы. Если быть точным, то не 50%, а вроде чуть больше, но это уже другой вопрос с «глубоким углублением».

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

Операция записи в вашем случае, в среднем будет иметь более 95% избыточности, в случае полной перезаписи. Этого можно избежать если в файле перезаписывать только то, что изменилось, но в общем случае, с учетом устройства файловых систем, это очень сложно с точки зрения системного и алгоритмического программирования.

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

2. Рекомендую использовать БД. Каждая современная СУБД, крайне не эффективна, и делает то, что вам не нужно (и не один раз). Но чтобы сделать что-то лучше, конкретно для своего проекта, потребуется очень много времени.

3. Если стоит задача сделать безопасный, быстрый, надежный сайт то, я думаю, php, asp.net, python, ruby, node.js никоим образом не сравнятся с системным программированием на С/С++/Delphi (внезапно да, даже Делфи).

4. То, что вы предлагаете — светлая инженерная мысль, удачи вам.
Ответ написан
alekciy
@alekciy
Вёбных дел мастер
>Хочу сразу все сделать правильно, и не имея своего опыта
Взаимоисключающе. «Правильно» можно сделать только опираясь на опыт исходя из конкретной задачи. По крайне мере я пока других вариантов не видел.
Ответ написан
@mithraen
Все зависит от постановки задачи. Если вам нужно для бизнеса, то возьмите wordpress, в интернете масса советов по его ускорению и доточке. Прямо вот завтра у вас тысячи хитов в секунду не будет, а к тому времени, когда будет, вы доточите его до устраивающей вас производительности.

Если же just for fun, вам хочется сделать очень быстрый движок, и именно это является основной целью — только тогда есть смысл браться и писать его.

1. Используйте аналог SSI от nginx для сборки страницы из нескольких кусков. Это позволит сэкономить на записи (большая часть контента будет статична, и часто обновляться будут в основном навигационные элементы).

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

3. Следовательно, чтобы исключить влияние дисковой подсистемы — используйте сервер с SSD (они уже доступны), также часть, или даже весь контент можно дублировать в tmpfs.

4. Часто изменяемые данные (например список новых материалов на форуме, и т.д.) есть смысл держать в memcached. Благо nginx умеет раздавать прямо из memcached.

5. Выбор языка для разработки тут не существенен, на самом деле. А задача объемная. При этом раз вы завязываетесь на nginx со специфическими настройками — все равно «обычный хостинг» уже не подходит. А следовательно вы можете выбирать любой язык разработки, исходя из того на чем такое решение писать будет лучше. Ограничиваться PHP не обязательно.

6. Для подобных проектов главное — быстро выкатить концепт. После осознания результатов вы все равно будете вынуждены переписать 90% кода. Так что если вы знаете PHP — пишите на нем. Совмещать изучение совершенно нового языка, с продумыванием необычной архитектуры нового сервиса — тяжкая задача.
Ответ написан
Anonym
@Anonym
Программирую немного )
Преждевременная оптимизация приносит больше вреда, чем пользы.
Ответ написан
@egorinsk
Начнем с того, что вам это вряд ли нужно для практических целей. В сутках 86400 секунд. Средний нормально написанный сайт (не друпал, не phpBB и прочий кривокод. Не Zend и не симфони) на PHP с использованием MySQL на среднем сферическом VPS в вакууме (с объемом памяти в 256 Мб) выдерживает 40-50 rps. Иногда даже он упирается не в процессор, а в ширину канала.

40-50 rps * 86 400 = примерно 1-2 млн хитов в сутки (так как нагрузка неравномерна по времени суток). Это примерно 100-200 тыс. среднеактивных посетителей (или 20-50 тыс., если речь не о блоге а о соцсети). Вряд ли у вас столько будет.

От идеи генерировать статический HTML давайте откажемся сразу: любой функционал чуть сложнее набора неизменных страниц так не сгенерируешь. Сложность кода и число зависимостей кешей будет расти в геометрических прогрессиях. Идея вставлять динамические фрагменты страниц через SSI/AJAX бесперспективна — они все равно будут вызывать запуск PHP, возможно даже увеличивая нагрузку. Лучше написать масштабируемое приложение с хорошим кешированием данных.

Хорошей идеей мог бы быть отказ от PHP в пользу Java/C++/.NET/D. Но это усложнит разработку: на этих языках все сложнее и дольше пишется.

Даже если на ваш блог ринутся все читатели Хабра, tema и еще нескольких блогов. Имея грубо написанный самопис на кривоPHP, у нас есть возможность масштабироваться раз в 10 с ростом нагрузки: ставим более мощное железо, расширяем память с 256 Мб до 64 Гб, ставим нормальный 8-ядерный процессор, нормальные диски. Тюним объем кешей MySQL, добавляем APC, начинаем понемного кешировать страницы в мемкеш. Далее, если нагрузка все равно растет, разносим код на несколько фронтендов, и, возможно, делаем мастер-слейв на MySQL. Можно скомпилировать PHP через hiphop.

Многим проектам этого хватает.

Но это тупой подход. Сделать репликацию, поставить балансировщик и нарастить память — ума много не надо. Даже обезьяна с этим справится. Гораздо лучше (и интереснее) изначально делать приложение с учетом возможности масштабироваться (что уж там стесняться) неограниченно. И куда как приятнее осознавать, что твое приложение может расти не хуже вконтакта с его отличниками и победителями математических олимпиад.

Представим, что у нас растет нагрузка и нам надо увеличиться до 1000 нод. Что касается фронтендов (в вашем случае на PHP), если не хватает мощности одного сервера, их (серверов) мы легко можем поставить хоть 1000, хоть 10000 (единственное, надо отказаться от сохранения сессий в локальных файлах, иначе никто не сможет залогиниться. Возможно, стоит перейти на REST и вообще отказаться от сессий). Перед ними ставим N балансировщиков на nginx, настраеваем round-robin в DNS (чтобы запросы валились на них поочередно).

Как работает round-robin в DNS вы можете увидеть, набрав nslookup vk.com несколько раз.

Мемкеш также (вы должны использовать мемкеш в приложении) легко масштабируется на N серверов. Лишь бы памяти было много и минимум гигабитная локальная сеть.

Раздача статики (картинки, CSS, скрипты) тоже банальна — ставим nginx на N серверов и забываем об этой проблеме. Единственная сложность — это раздача видео. Погуглите, на Хабре есть статьи про организацию CDN для видео и сопутствующие проблемы.

А вот с БД мы получаем затык. Даже если мы настроим мастер-слейв с несколькими слейвами, объем данных на запись на мастер от 1000 PHP-ных фронтендов положит любой сервер. Несмотря на то, что MySQL в сферической конигрурации на среднем сервере в вакууме легко делает 1-5 тысяч выборок по PKEY в секунду, на запись она работает гораздо хуже. Потому, раз уж мы делаем хайлоад сервис, то база тоже должна масштабироваться. Во-первых, можно разнести разные таблицы на разные сервера. Это мало. во-вторых, можно порезать таблицы на куски и разнести на разные сервера. Это то, что надо. То есть, допустим, в соцсети юзеры с ид 1-10000 хранятся на первом сервере в таблице users_1, юзеры 10000-20000 на втором сервере в таблице user_2, и так далее. Распределение записей и таблиц по серверам должно быть не намертво вбитое, а конфигурируемое, чтобы можно было переносить пачки записей с одного сервера на другой, уравновешивая нагрузку. Для этого придется написать небольшое приложение, показывающее распределение нагрузки и позволяющее переконфигурировать шарды.

Из такой схемы построения БД вытекают очевидные правила: запросы к БД не должны использовать JOIN (так как это невозможно при разнесенных таблицах, и дждойны плохо работают), должны использовать выборку только по индексам, лучше всего по PKEY (так как без индексов слишком медленно) и должны быть как можно проще. Они должны иметь небольшой LIMIT. Также, стоит пользоваться денормализацией данных: например, чтобы получить список фотографий пользователя, мы берем сериализованный список id этих фото, затем выбираем фото по id, а НЕ используем выборку по полю user_id в таблице photos (так как такая выборка не шардится и не масштабируется).

В общем, запросы должны быть тупыми как пробка и сводиться к SELECT… WHERE id IN (1, 2, 3). Кстати, как дополнительный плюс, такие запросы легко кешировать и очищать такой кеш.

Для сервисов типа поиска пользователей (как вконтакте) при такой схеме придется писать отдельные приложения на C++, которые будут индексировать БД и хранить данные в памяти. Увы, PHP тут не справится.

Вы можете почитать про архитектуру высоконагруженных проектов тут: www.insight-it.ru/highload/

А да, все. что написано выше, лишь теоретические рассуждения. Подумайте 10 раз, прежде чем применять это на практике.
Ответ написан
CKOPOBAPKuH
@CKOPOBAPKuH
> так как же тогда сделать сайт, способный выдержать высокую нагрузку?

1. делаете просто нужный функционал
2. оптимизируете
3. всё переделываете

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

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы