Горизонтальное масштабирование PHP-приложений


Оглавление (нажмите, чтобы открыть):

MySql Горизонтальное масштабирование с PHP

Я разрабатываю веб-приложение, и для подключения PHP к БД MySql я использую следующий код:

Я хочу подготовить свое приложение для масштабирования серверов БД, я имею в виду, например, главный хост и ведомый хост. Как я мог добиться в PHP, чтобы сделать SELECT запросы к рабу и тому INSERT мастеру?

1 ответ

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

Делать это вручную, с нуля будет довольно сложно. Чтобы надежно отделить запросы модификаторов от выбранных, вы хотите построить построитель запросов. Вы, вероятно, хотите использовать среду, которая предоставляет такую ​​возможность, как Drupal 7.

Вертикальное и горизонтальное масштабирование, scaling для web. Горизонтальное масштабирование PHP-приложений

С ростом популярности web-приложения его поддержка неизбежно начинает требовать всё больших и больших ресурсов. Первое время с нагрузкой можно (и, несомненно, нужно) бороться путём оптимизации алгоритмов и/или архитектуры самого приложения. Однако, что делать, если всё, что можно было оптимизировать, уже оптимизировано, а приложение всё равно не справляется с нагрузкой?

Оптимизация

Масштабирование

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

Архитектура приложения

Каждый их этих слоёв может быть масштабирован. Поэтому если в вашей системе приложение и БД живут на одном хосте – первым шагом, несомненно, должно стать разнесение их по разным хостам.

Узкое место

Обычно всё зависит от архитектуры приложения, но наиболее вероятными кандидатами на «узкое место» в общем случае являются БД и код. Если ваше приложение работает с большим объёмом пользовательских данных, то «узким местом», соответственно, скорее всего будет хранение статики.

Масштабирование БД

Снизить нагрузку на БД можно разнеся её на несколько хостов. При этом остро встаёт проблема синхронизации между ними, решить которую можно путём реализации схемы master/slave с синхронной или асинхронной репликацией. В случае с PostgreSQL реализовать синхронную репликацию можно с помощью Slony-I , асинхронную – PgPool-II или WAL (9.0). Решить проблему разделения запросов чтения и записи, а так же балансировки нагрузку между имеющимися slave’ами, можно с помощью настройки специального слоя доступа к БД (PgPool-II).

Проблему хранения большого объёма данных в случае использования реляционных СУБД можно решить с помощью механизма партицирования (“partitioning” в PostgreSQL), либо разворачивая БД на распределённых ФС типа Hadoop DFS .

Однако, для хранения больших объёмов данных лучшим решением будет «шардинг » (sharding) данных, который является встроенным преимуществом большинства NoSQL БД (например, MongoDB).

Кроме того, NoSQL БД в общем работают быстрее своих SQL-братьев за счёт отсутствия overhead’а на разбор/оптимизацию запроса, проверки целостности структуры данных и т.д. Тема сравнения реляционных и NoSQL БД так же довольно обширна и заслуживает отдельной статьи .

Отдельно стоит отметить опыт Facebook, который используют MySQL без JOIN-выборок. Такая стратегия позволяет им значительно легче масштабировать БД, перенося при этом нагрузку с БД на код, который, как будет описано ниже, масштабируется проще БД.

Масштабирование кода

Далее необходимо настроить балансировку нагрузки/запросов между этими хостами. Сделать это можно как на уровне TCP (haproxy), так и на HTTP (nginx) или DNS .

Следующим шагом нужно сделать так, что бы файлы статики, cache и сессии web-приложения были доступны на каждом хосте. Для сессий можно использовать сервер, работающий по сети (например, memcached). В качестве сервера кеша вполне разумно использовать тот же memcached, но, естественно, на другом хосте.

Файлы статики можно смонтировать с некого общего файлового хранилища по NFS /CIFS или использовать распределённую ФС (HDFS , GlusterFS , Ceph).

Так же можно хранить файлы в БД (например, Mongo GridFS), решая тем самым проблемы доступности и масштабируемости (с учётом того, что для NoSQL БД проблема масштабируемости решена за счёт шардинга).

Отдельно стоит отметить проблему деплоймента на несколько хостов. Как сделать так, что бы пользователь, нажимая «Обновить», не видел разные версии приложения? Самым простым решением, на мой взгляд, будет исключение из конфига балансировщика нагрузки (web-сервера) не обновлённых хостов, и последовательного их включения по мере обновления. Так же можно привязать пользователей к конкретным хостам по cookie или IP. Если же обновление требует значимых изменений в БД, проще всего, вообще временно закрыть проект.

Масштабирование ФС

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

Мониторинг

Заключение

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

Но в какой-то момент, траффик начинает расти очень медленно, кто-то опубликовал ссылку на ваше приложение в Reddit или Hacker News , что-то случилось с исходниками проекта на GitHub и вообще, все стало как будто против вас.

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

Все ваши усилия по возобновлению работы безрезультатны – даже после перезагрузки, сервер не может справиться с потоком посетителей. Вы теряете трафик!

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

Как же тогда избежать всех этих проблем? Для этого нужно решить два вопроса: оптимизация и масштабирование .

Оптимизация

Первым делом, стоит провести обновление до последней версии PHP (текущая версия 5.5, использует OpCache ), проиндексировать базу данных и закэшировать статический контент (редко изменяющиеся страницы вроде About , FAQ и так далее).

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

Идея заключается в следующем: вы помещаете Nginx перед вашим Apache-сервером (Ngiz будет frontend -сервером, а Apache — backend ), и поручаете ему, перехват запросов на статические ресурсы (т.е. *.jpg , *.png , *.mp4 , *.html …) и их обслуживание БЕЗ ОТПРАВЛЕНИЯ запроса на Apache.

Такая схема называется reverse proxy (её часто упоминают вместе с техникой балансировки нагрузки, о которой рассказано ниже).

Масштабирование

Существует два типа масштабирования – горизонтальное и вертикальное .

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

Вертикальное масштабирование

Представьте, что у вас имеется веб-сервер, обслуживающий веб-приложение. Этот сервер имеет следующие характеристики 4GB RAM , i5 CPU и 1TB HDD .

Он хорошо выполняет возложенные на него задачи, но чтобы лучше справляться с нарастающим трафиком, вы решаете заменить 4GB RAM на 16GB, устанавливаете новый i7 CPU и добавляете гибридный носитель PCIe SSD/HDD .

Сервер теперь стал более мощным и может выдерживать увеличенные нагрузки. Именно это и называется вертикальным масштабированием или « масштабированием вглубь » – вы улучшаете характеристики машины, чтобы сделать её более мощной.

Это хорошо проиллюстрировано на изображении ниже:

Горизонтальное масштабирование

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

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

Если количества ядер процессора недостаточно для выполнения имеющихся потоков, то не имеет значения, насколько мощный установлен CPU – сервер все равно будет работать медленно, и заставит посетителей ждать.

Горизонтальное масштабирование подразумевает построение кластеров из машин (часто достаточно маломощных), связанных вместе для обслуживания веб-сайта.

В данном случае, используется балансировщик нагрузки (load balancer ) – машина или программа, которая занимается тем, что определяет, какому кластеру следует отправить очередной поступивший запрос.

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

Есть два типа балансировщиков нагрузки – аппаратные и программные . Программный балансировщик устанавливается на обычную машину и принимает весь входящий трафик, перенаправляя его в соответствующий обработчик. В качестве программного балансировщика нагрузки, может выступить, например, Nginx .

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

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

При горизонтальном масштабировании происходит следующее:

Заметьте, что два описанных способа масштабирования не являются взаимоисключающими – вы можете улучшать аппаратные характеристики машин (также называемых нодами — node ), используемых в масштабированной вширь кластерной системе.

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

Сложности с разделением данных

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

Также, проблемы возникают с управлением данными сессий, так как залогинившись на одной машине, вы окажетесь неавторизованным, если балансировщик при следующем вашем запросе перебросит вас на другой компьютер. Есть несколько способов решения данной проблемы – можно передавать локальные данные между машинами, либо использовать постоянный балансировщик нагрузки.

Постоянный балансировщик нагрузки

Постоянный балансировщик нагрузки запоминает, где обрабатывался предыдущий запрос того или иного клиента и, при следующем запросе, отправляет запрос туда же.

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

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

Это становится еще одним узким местом. А что, если единственный балансировщик нагрузки сам выйдет из строя и вся информации о расположении клиентов на серверах будет утеряна? Кто будет управлять балансировкой? Замысловатая ситуация, не правда ли?

Разделение локальных данных

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

Известно, что данные сессии хранятся в суперглобальном PHP-массиве $_SESSION . Также, ни для кого не секрет, что этот массив $_SESSION хранится на жестком диске.

Соответственно, так как диск принадлежит той или иной машине, то другие к нему доступа не имеют. Тогда как же организовать к нему общий доступ для нескольких компьютеров?

Замечу, что обработчики сессий в PHP могут быть переопределены – вы можете определить свой собственный класс/функцию для управления сессиями.

Использование базы данных

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

Хотя данный подход работает достаточно хорошо, в случае большого трафика, база данных становится не просто уязвимым местом (потеряв её, вы потеряете все), к ней будет много обращений из-за необходимости записывать и считывать данные сессий.

Это становится очередным узким местом в нашей системе. В этом случае, можно применить масштабирование вширь, что проблематично при использовании традиционных баз данных типа MySQL , Postgre и тому подобных (эта проблема будет раскрыта во второй части цикла).

Использование общей файловой системы

Можно настроить сетевую файловую систему, к которой будут обращаться все серверы, и работать с данными сессий. Так делать не стоит. Это совершенно неэффективный подход, при котором велика вероятность потери данных, к тому же, все это работает очень медленно.

Это еще одна потенциальная опасность, даже более опасная, чем в случае с базой данных, описанном выше. Активация общей файловой системы очень проста: смените значение session.save_path в файле php.ini , но категорически рекомендуется использовать другой способ.

Если вы все-таки хотите реализовать вариант с общей файловой системой, то есть гораздо более лучшее решение — GlusterFS .

Memcached

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

Какое-либо постоянство отсутствует – данные о входе будут храниться до тех пор, пока memcached -сервер запущен и имеется свободное пространство для хранения этих данных.

Вы можете быть удивлены – разве оперативная память не отдельна для каждой машины? Как применить данный способ к кластеру? Memcached имеет возможность виртуально объединять всю доступную RAM нескольких машин в единое хранилище:

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

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

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

Использовать этот способ в PHP-приложениях очень легко: нужно изменить значение в файле php.ini :

session.save_handler = memcache session.save_path = «tcp://path.to.memcached.server:port»

Redis Cluster

Redis это не SQL хранилище данных, расположенное в оперативной памяти, подобно Memcached , однако оно имеет постоянство и поддерживает более сложные типы данных, чем просто строки PHP-массива в форме пар «key => value ».

Это решение не имеет поддержки кластеров, поэтому реализация его в горизонтальной системе масштабирования не так проста, как может показаться на первый взгляд, но вполне выполняема. На самом деле, альфа-версия кластерной версии уже вышла и можно её использовать.

Если сравнивать Redis с решениями вроде Memcached , то он представляет собой нечто среднее между обычной базой данных и Memcached .

Итак вы сделали сайт. Всегда интересно и волнительно наблюдать как счетчик посещений медленно, но верно ползет вверх, с каждым днем показывая все лучшие результаты. Но однажды, когда вы этого не ждете, кто-то запостит ссылку на ваш ресурс на каком-нибудь Reddit или Hacker News (или на Хабре — прим. пер.), и ваш сервер ляжет.

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

Немного про оптимизацию

Основные советы всем известны: обновитесь до последней версии PHP (в 5.5 теперь встроен OpCache), разберитесь с индексами в базе данных, кэшируйте статику (редко изменяемые страницы, такие как “О нас”, “FAQ” и т.д.).

Также стоит упомянуть об одном особом аспекте оптимизации — обслуживании статического контента не-Apache сервером, таким как, например, Nginx, Настройте Nginx на обработку всего статического контента (*.jpg, *.png, *.mp4, *.html…), а файлы требующие серверной обработки пусть отсылает тяжелому Apache. Это называется reverse proxy .

Масштабирование

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

Вертикальное масштабирование.

Представьте себе сервер, обслуживающий веб-приложение. У него 4ГБ RAM, i5 процессор и 1ТБ HDD. Он отлично выполняет свои функции, но, что бы лучше справляться с более высоким трафиком, вы решаете увеличить RAM до 16ГБ, поставить процессор i7, и раскошелиться на SSD диск. Теперь сервер гораздо мощнее, и справляется с высокими нагрузками. Это и есть вертикальное масштабирование.

Горизонтальное масштабирование.

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

Есть два типа балансировщиков — аппаратные и программные. Программный — устанавливается на обычный сервер и принимает весь трафик, передавая его соответствующим обработчикам. Таким балансировщиком может быть, например, Nginx. В разделе “Оптимизация” он перехватывал все запросы на статические файлы, и обслуживал эти запросы сам, не обременяя Apache. Другое популярное ПО для реализации балансировки нагрузки — Squid . Лично я всегда использую именно его, т.к. он предоставляет отличный дружественный интерфейс, для контроля за самыми глубокими аспектами балансировки.

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

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

Постоянное соединение

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

Обмен локальными данными.


Разделить данные сессии пользователей между всеми нодами кластера — кажется неплохой идеей. И несмотря на то, что этот подход требует некоторых изменений в архитектуре вашего приложения, оно того стоит — разгружается балансировщик, и весь кластер становится более отказоустойчивым. Смерть одного из серверов совершенно не отражается на работе всей системы.
Как мы знаем, данные сессии хранятся в суперглобальном массиве $_SESSION , который пишет и берет данные с файла на диске. Если этот диск находится на одном сервере, очевидно, что другие сервера не имеют к нему доступа. Как же нам сделать его доступным на нескольких машинах?
Во первых, обратите внимание, что обработчик сессий в PHP можно переопределить . Вы можете реализовать свой собственный класс для работы с сессиями .

Использование БД для хранения сессий

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

Распределенная файловая система

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

Memcached

Вы также можете использовать memcached для хранения данных сессий в RAM. Однако это не безопасно, ибо данные в memcached перезаписываются, если заканчивается свободное место. Вы, наверное, задаетесь вопросом, разве RAM не разделен по машинам? Как он применяется на весь кластер? Memcached имеет возможность объединять доступную на разных машинах RAM в один пул .

Чем больше у вас машин, тем больше вы можете отвести в этот пул памяти. Вам не обязательно объединять всю память машин в пул, но вы можете, и вы можете пожертвовать в пул произвольное количество памяти с каждой машины. Так что, есть возможность оставить бо льшую часть памяти для обычного использования, и выделить кусок для кэша, что позволит кэшировать не только сессии, но другую подходящую информацию. Memcached — отличное и широко распространенное решение .

Для использования этого подхода, нужно немного подредактировать php.ini

Session.save_handler = memcache session.save_path = «tcp://path.to.memcached.server:port»

Redis кластер

Redis — NoSQL хранилище данных. Хранит базу в оперативной памяти. В отличие от memcached поддерживает постоянное хранение данных, и более сложные типы данных. Redis не поддерживает кластеризацию , так что использовать его для горизонтального масштабирования несколько затруднительно, однако, это временно, и уже вышла альфа версия кластерного решения .

Другие решения

Итого

Как видите, горизонтальное масштабирование PHP приложений не такое уж простое дело. Существует много трудностей, большинство решений не взаимозаменяемые, так что приходится выбирать одно, и придерживаться его до конца, ведь когда трафик зашкаливает — уже нет возможности плавно перейти на что-то другое.

Надеюсь этот небольшой гайд поможет вам выбрать подход к масштабированию для вашего проекта.

Во второй части статьи мы поговорим о масштабировании базы данных .

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

Однако это поправимо. И если сейчас вы подумали о масштабировании – вы на правильном пути.

В двух словах, масштабируемость – это способность системы обрабатывать большой объем трафика и приспособляться к его росту, сохраняя при этом необходимый UX. Существует два метода масштабирования:

  • Вертикальное (также называется scaling up): увеличение системных ресурсов, например, добавление памяти и вычислительной мощности. Этот метод позволяет быстро устранить проблемы с обработкой трафика, но его ресурсы могут быстро себя исчерпать.
  • Горизонтальное (или scaling out): добавление серверов в кластер. Рассмотрим этот метод подробнее.

Что такое горизонтальное масштабирование?

Проще говоря, кластер – это группа серверов. Балансировщик нагрузки – это сервер, распределяющий рабочую нагрузку между серверами в кластере. В любой момент в существующий кластер можно добавить веб-сервер для обработки большего объёма трафика. В этом и есть суть горизонтального масштабирования.

Балансировщик нагрузки отвечает только за то, какой сервер из кластера будет обрабатывать полученный запрос. в основном, он работает как обратный прокси-сервер.

Горизонтальное масштабирование – несомненно, более надёжный метод увеличения производительности приложения, однако оно сложнее в настройке, чем вертикальное масштабирование. Главная и самая сложная задача в этом случае – постоянно поддерживать все ноды приложения обновленными и синхронизированными. Предположим, пользователь А отправляет запрос сайту mydomain.com, после чего балансировщик передаёт запрос на сервер 1. Тогда запрос пользователя Б будет обрабатываться сервером 2.

Что произойдёт, если пользователь А внесёт изменения в приложение (например, выгрузит какой-нибудь файл или обновит содержимое БД)? Как передать это изменение остальным серверам кластера?

Ответ на эти и другие вопросы можно найти в этой статье.

Разделение серверов

Подготовка системы к масштабированию требует разделения серверов; при этом очень важно, чтобы серверы с меньшим объёмом ресурсов имели меньше обязанностей, чем более объёмные серверы. Кроме того, разделение приложения на такие «части» позволит быстро определить его критические элементы.

Предположим, у вас есть PHP-приложение, позволяющее проходить аутентификацию и выкладывать фотографии. Приложение основано на стеке LAMP. Фотографии сохраняются на диске, а ссылки на них – в базе данных. Задача здесь заключается в поддержке синхронизации между несколькими серверами приложений, которые совместно используют эти данные (загруженные файлы и сессии пользователя).

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

В дальнейшем можно настроить балансировку нагрузки; об этом можно прочесть в руководстве « »

Сессионная согласованность

Разделив веб-сервер и базу данных, нужно сосредоточиться на обработке пользовательских сессий.

Реляционные базы данных и сетевые файловые системы

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

Однако это решение не самое надёжное, потому что в таком случае увеличивается нагрузка. Сервер должен вносить в БД каждую операцию чтения и записи для каждого отдельного запроса, и в случае резкого увеличения трафика база данных, как правило, отказывает раньше других компонентов.

Сетевые файловые системы – ещё один простой способ хранения данных; при этом не требуется вносить изменения в базу исходных текстов, однако сетевые системы очень медленно обрабатывают I/O операции, а это может оказать негативное влияние на производительность приложения.

Липкие сессии

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

Однако это решение тоже имеет один серьёзный недостаток. Теперь балансировщик не только распределяет нагрузку, у него появляется дополнительная задача. Это может повлиять на его производительность и привести к сбою.

Серверы Memcached и Redis

Также можно настроить один или несколько дополнительных серверов для обработки сессий. Это самый надёжный способ решения проблем, связанных с обработкой сессий.

Заключительные действия

Горизонтальное масштабирование приложения сначала кажется очень сложным и запутанным решением, однако оно помогает устранить серьёзные проблемы с трафиком. Главное – научиться работать с балансировщиком нагрузки, чтобы понимать, какие из компонентов требуют дополнительной настройки.

Масштабирование и производительность приложения очень тесно связаны между собой. Конечно, масштабирование нужно далеко не всем приложениям и сайтам. Однако лучше подумать об этом заранее, желательно ещё на стадии разработки приложения.

Возможность масштабирования информационной системы – как горизонтальное, так и вертикальное – является одним из самых важных факторов, на которые стоит обращать при выборе средства автоматизации деятельности любой организации. Если выбранное решение невозможно будет масштабировать, или каждая стадия роста бизнеса будет приводить к сложностям с сопровождением и развитием такого программного продукта, то не следует даже начинать его использовать. Мы разрабатывали СЭД ЛЕТОГРАФ с учетом высоких требований к масштабированию.

Необходимость в горизонтальном или вертикальном масштабировании возникает в связи с созданием корпоративных высоконагруженных ИТ-систем, в которых работают тысячи или даже десятки тысяч пользователей. Однако поддерживать одновременную работу большого числа пользователей могут далеко не все СЭД. Только если в СЭД на уровне архитектуры заложены возможности по наращиванию количества пользователей без потери производительности – только в этом случае масштабирование будет успешным. Созданная нами система ЛЕТОГРАФ была разработана таким образом, чтобы идеально масштабироваться как горизонтально, так и вертикально. Это достигается как за счет архитектуры самой системы и того прикладного кода, который мы разработали, так и за счет функционала СУБД InterSystems Caché, на которой наша СЭД построена.

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

СУБД Caché сохраняет высокую производительность даже при работе с огромными массивами данных и большим числом серверов в распределенных системах. При этом доступ к данным осуществляется через объекты, высокопроизводительные SQL-запросы и путем прямой обработки многомерных структур данных.

Вертикальное масштабирование предполагает наращивание мощности сервера и его возможностей, связанных с дисковой подсистемой. ЛЕТОГРАФ поддерживает современную процессорную архитектуру, что позволяет обрабатывать большие объемы данных в несколько потоков. При этом сами данные в СЭД организованы таким образом, чтобы их можно было легко разносить по СХД на разные диски. Такой подход позволяет равномерно распределить нагрузку на хранилища данных и минимизировать ее при чтении данных непосредственно из базы, а значит и падения производительности системы удастся избежать даже при одновременной работе большого количества пользователей.

Еще на этапе разработки платформы мы понимали, что вертикальное масштабирование – одна из ключевых возможностей системы, потребность в которой со временем будет только увеличиваться. Мы разработали систему таким образом, чтобы процессы работы каждого пользователя были выделены в отдельные системные процессы, которые между собой не пересекаются благодаря тому, что базы данных эффективно делят доступ к информации. При этом количество блокировок данных в СЭД ЛЕТОГРАФ минимизировано и нет «узкого горла» ни при чтении данных, ни при их записи.

Архитектура СЭД ЛЕТОГРАФ позволяет распределять данные на несколько физических или виртуальных серверов. Благодаря такому распределению каждый из пользователей работает в изолированном процессе, а требуемые данные эффективно кэшируются с использованием технологий СУБД Caché. Время блокировки данных минимизировано: все транзакции выстроены таким образом, чтобы переводить данные в эксклюзивный режим доступа лишь на очень короткое время. При этом даже такие высоконагруженные с точки зрения количества обращений к диску данные, как журналы, индексы, данные объектов, потоки, логи действий пользователей, распределены таким образом, что средняя нагрузка на подсистему остается равномерной и не приводит к задержкам. Такой подход позволяет эффективно вертикально масштабировать систему, распределяя нагрузку между серверами или виртуальными дисками.

Горизонтальное масштабирование – это распределение сессий пользователей по разным серверам (равномерная загрузка серверов приложений и возможность подключать дополнительные сервера приложений), а также распределение данных по разным серверам БД, что обеспечивает высокую производительность системы, при этом не приводя к снижению отказоустойчивости. Для горизонтального масштабирования в системе ЛЕТОГРАФ предусмотрен целый ряд возможностей.

Прежде всего, это масштабирование нагрузки благодаря Enterprise Cache Protocol (ECP, протокол распределенного кэша), протоколу, используемому в СУБД InterSystems Caché. Преимущество ECP заключается в инновационном подходе к кэшированию данных. В рамках данного протокола пользовательские процессы, которые работают на серверах приложений (или ECP-клиентах) СУБД и обслуживают запросы, получают доступ к локальному кэшу недавно использованных данных. И только если этих данных недостаточно, ECP-клиент обращается к базе данных. С помощью протокола ECP выполняется автоматическое управление кэшем: наиболее часто используемые данные сохраняются в кэше, часто обновляемые данные периодически реплицируются, обеспечивая постоянное целостность и корректность данных на всех ECP-клиентах. При этом внутренний алгоритм InterSystems Caché предполагает, что базы данных синхронизируются между ECP-клиентом и ECP-сервером.

Фактически использование технологий СУБД Caché позволяет легко и быстро масштабировать нагрузку по серверам приложений, обеспечив таким образом подключение большого числа пользователей к одному серверу базы данных благодаря использованию ECP-протокола.

Так как информация, которую затребовал тот или иной пользователь, может быть задействована на нескольких ECP-клиентах, необходимо блокировать данные на короткий период времени, быстро выполнять транзакции, не выполняя внутренних вычислений. И мы успешно это реализовали. Данная технология позволяет нам эффективно масштабировать систему в ситуации, когда используются один сервер базы данных и несколько серверов, на которых работают пользовательские процессы. Технологическая особенность СУБД Caché заключается в том, что она поддерживает корректность транзакций в рамках одного ECP-сервера вне зависимости от количества ECP-клиентов, которые к ней подключены. В случае, когда у нас один ECP-сервер и множество ECP-клиентов, эта задача великолепно решается, потому что все транзакции идут на одном сервере базы данных.

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

В СЭД ЛЕТОГРАФ реализован механизм шардинга, благодаря которому мы на уровне настроек системы (без применения программирования), даем возможность описать правила и принципы разнесения самих данных по разным серверам БД. Несмотря на то, что с точки зрения структуры баз данных информация, хранящаяся на каждом сервере одинакова, сама информация отличается принципиально в зависимости от организации или каких-либо других признаков, которые являются значимыми для конкретной задачи. Используя технологию шардинга можно добиться, что в 95-99 % случаев пользователи будут работать только со своей «порцией данных», и не потребуется в рамках сессии обращаться к разным серверам БД.

На возможности масштабирования СЭД ЛЕТОГРАФ влияет и то, данные могут по разному обрабатываться. Например, в документы (даже созданные несколько лет назад) могут вноситься изменения, а в журнал действий пользователей записи только добавляются (ни одна запись не может быть ни удалена, ни изменена). Механизмы, которые используются в СЭД ЛЕТОГРАФ, позволяют дополнительно повысить производительность системы и улучшить масштабирование за счет ведения таких журналов на отдельных серверах БД – причем, как в случае односерверной, так и многосерверной конфигурации. Такой подход ориентирован на снижение нагрузки на основные сервера БД.

Аналогичная ситуация возникает и контентом (“информационным содержанием” СЭД). Так как система ЛЕТОГРАФ работает с большим объемом контента – это терабайты данных, миллионы файлов и документов – разумно предположить, что контент, который попадает в систему, ни при каких условиях не должен пострадать. Поэтому мы также выносим хранение файлов на отдельные сервера баз данных и обеспечиваем таким образом дополнительно горизонтальное масштабирование.

Программное обеспечение фронт-энда

В качестве фронт-энда в СЭД ЛЕТОГРАФ используются Apache и HAProxy. HAProxy отвечает за балансировку нагрузки между веб-серверами Apache. HAProxy, как показал опыт работы системы, зарекомендовал себя как наиболее эффективное решение, способное обеспечить поддержку работы большого числа пользователей и необходимый контроль за отказоустойчивостью.

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

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

Пример реализации проекта

Архитектура ЛЕТОГРАФ позволяет добиться существенных результатов в сокращении времени отклика и повышении производительности системы. В рамках одного из наших проектов в СЭД хранится 23,5 Тбайт данных. Из них 14,7 Тбайт (63%) приходится на потоки (“прикрепленные к карточкам файлы”), 3,5 Тбайт (15%) – на отчетные формы, такие как таблицы отчетов, которые формируются в асинхронном режиме, могут запускаться как по расписанию, так и по требованию пользователя и представляют собой сводную таблицу, любые данные в которой можно детализировать до объекта. Еще 1,6 Тбайт (7%) – это протокол пользовательских операций, а все остальное (16%) – данные карточек и индексы.

В данной системе работает более 11 тыс. пользователей, 2 тыс. из них работают одновременно, а в дни пиковой нагрузки число одновременно работающих в СЭД сотрудников превышает 3 тыс. Количество записей в журнале уже превысило 5,5 млрд, а учетных карточек – почти достигло полумиллиарда.

В качестве сервера базы данных в данном проекте установлен отказоустойчивый кластер из двух физических серверов с тремя инсталляциями СУБД, а также резервный сервер. Десять серверов приложений (и один резервный) обрабатывают пользовательские сессии и обеспечивают формирование асинхронных отчетов. 2 сервера HAProxy выполняют функции балансировщиков. В случае проблем с одним из серверов, выполняется автоматическая передача его IP-адреса на другой сервер. Также предусмотрены сервер индексации файлов и сервер распознавания (обеспечивающий распознавание текста отсканированных бумажных документов при размещении электронных образов в систему).

В СЭД ЛЕТОГРАФ предусмотрено большое количество разнообразных механизмов масштабирования. Мы предлагаем своеобразный пирог, в основе которого лежит сервер (физический или виртуальный), на который устанавливается операционная система. Поверх нее стоит СУБД InterSystems Caché, внутри которой располагается код платформы. А уже над ним – настройки системы ЛЕТОГРАФ, благодаря которым СЭД полностью конфигурируется. И такой пирог размещен на каждом сервере. Сервера между собой связаны определенным образом за счет выбранных конфигураций. И последний слой – это HAProxy, распределяющий между серверами запросы пользователей. Такая архитектура позволяет нам поддерживать масштабирование и обеспечивать все необходимые механизмы мониторинга. В результате конечные пользователи получают быстро работающую СЭД, а ИТ-специалисты – простую в управлении и обслуживании, унифицированную систему, без огромного числа составляющих, которые в случае высоконагруженных приложений приходится постоянно контролировать и администрировать. Кроме того, в зависимости от изменения потребностей организации СЭД ЛЕТОГРАФ легко переконфигурировать, добавив новые серверы или дисковые возможности.

Горизонтальное и вертикальное масштабирование сети. Горизонтальное масштабирование PHP-приложений

Масштабируемость — такое свойство вычислительной системы, которое обеспечивает предсказуемый рост системных характеристик, например, числа поддерживаемых пользователей, быстроты реакции, общей производительности и пр., при добавлении к ней вычислительных ресурсов. В случае сервера СУБД можно рассматривать два способа масштабирования — вертикальный и горизонтальный (рис. 2).

При горизонтальном масштабировании увеличивается число серверов СУБД, возможно, взаимодействующих друг с другом в прозрачном режиме, разделяя таким образом общую загрузку системы. Такое решение, видимо, будет все более популярным с ростом поддержки слабосвязанных архитектур и распределенных баз данных, однако обычно оно характеризуется сложным администрированием.

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

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

  • поддержка многопроцессорной обработки;
  • гибкость архитектуры.

Многопроцессорные системы

Для вертикального масштабирования все чаще используются симметричные многопроцессорные системы (SMP), поскольку в этом случае не требуется смены платформы, т.е. операционной системы, аппаратного обеспечения, а также навыков администрирования. С этой целью возможно также применение систем с массовым параллелизмом (MPP), но пока их использование ограничивается специальными задачами, например, расчетными. При оценке сервера СУБД с параллельной архитектурой целесообразно обратить внимание на две основные характеристики расширяемости архитектуры: адекватности и прозрачности.

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

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

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

Гибкость архитектуры

Независимо от степени мобильности, поддержки стандартов, параллелизма и других полезных качеств, производительность СУБД, имеющей ощутимые встроенные архитектурные ограничения, не может наращиваться свободно. Наличие документированных или практических ограничений на число и размеры объектов базы данных и буферов памяти, количество одновременных подключений, на глубину рекурсии вызова процедур и подчиненных запросов (subqueries) или срабатывания триггеров базы данных является таким же ограничением применимости СУБД как, например, невозможность переноса на несколько вычислительных платформ. Параметры, ограничивающие сложность запросов к базе данных, в особенности размеры динамических буферов и стека для рекурсивных вызовов, должны настраиваться в динамике и не требовать остановки системы для реконфигурации. Нет смысла покупать новый мощный сервер, если ожидания не могут быть удовлетворены из-за внутренних ограничений СУБД.

Обычно узким местом является невозможность динамической подстройки характеристик программ сервера баз данных. Способность на ходу определять такие параметры, как объем потребляемой памяти, число занятых процессоров, количество параллельных потоков выполнения заданий (будь то настоящие потоки (threads), процессы операционной системы или виртуальные процессоры) и количество фрагментов таблиц и индексов баз данных, а также их распределение по физическим дискам БЕЗ останова и перезапуска системы является требованием, вытекающим из сути современных приложений. В идеальном варианте каждый из этих параметров можно было бы изменить динамически в заданных для конкретного пользователя пределах.

) Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «Yii» — я один из его разработчиков. У меня также есть full-time работа — и это уже не стартап — Stay.com, который занимается путешествиями.

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

Что такое масштабирование, вообще? Это возможность увеличить производительность проекта за минимальное время путем добавления ресурсов.

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

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

Самый классный вопрос, который задают, — а зачем оно надо, если у меня все и на одном сервере прекрасно работает? На самом-то деле, надо проверить, что будет. Т.е., сейчас оно работает, но что будет потом? Есть две замечательные утилиты — ab и siege, которые как бы нагоняют тучу пользователей конкурента, которые начинают долбить сервер, пытаются запросить странички, послать какие-то запросы. Вы должны указать, что им делать, а утилиты формируют такие вот отчеты:

Главные два параметра: n — количество запросов, которые надо сделать, с — количество одновременных запросов. Таким образом они проверяют конкурентность.

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

Есть еще один параметр — Response time — время ответа, за которое в среднем сервер отдал страничку. Оно бывает разное, но известно, что около 300 мс — это норма, а что выше — уже не очень хорошо, потому что эти 300 мс отрабатывает сервер, к этому прибавляются еще 300-600 мс, которые отрабатывает клиент, т.е. пока все загрузится — стили, картинки и остальное — тоже проходит время.

Бывает, что на самом деле пока и не надо заботиться о масштабировании — идем на сервер, обновляем PHP, получаем 40% прироста производительности и все круто. Далее настраиваем Opcache, тюним его. Opcache, кстати, тюнится так же, как и APC, скриптом, который можно найти в репозитории у Расмуса Лердорфа и который показывает хиты и мисы, где хиты — это сколько раз PHP пошел в кэш, а мисы — сколько раз он пошел в файловую систему доставать файлики. Если прогнать весь сайт, либо запустить туда какой-то краулер по ссылкам, либо вручную потыкать, то у нас будет статистика по этим хитам и мисам. Если хитов 100%, а мисов — 0%, значит, все нормально, а если есть мисы, то надо выделить больше памяти, чтобы весь наш код влез в Opcache. Это частая ошибка, которую допускают — вроде Opcache есть, но что-то не работает…

Еще часто начинают масштабировать, но не смотрят, вообще, из-за чего все работает медленно. Чаще всего лезем в базу, смотрим — индексов нет, ставим индексы — все сразу залетало, еще на 2 года хватит, красота!

Ну, еще надо включить кэш, заменить apache на nginx и php-fpm, чтобы сэкономить память. Будет все классно.

Все перечисленное достаточно просто и дает вам время. Время на то, что когда-то этого станет мало, и к этому уже сейчас надо готовиться.

Как, вообще, понять, в чем проблема? Либо у вас уже настал highload, а это не обязательно какое-то бешеное число запросов и т.д., это, когда у вас проект не справляется с нагрузкой, и тривиальными способами это уже не решается. Надо расти либо вширь, либо вверх. Надо что-то делать и, скорее всего, на это мало времени, что-то надо придумывать.

Первое правило — никогда ничего нельзя делать вслепую, т.е. нам нужен отличный мониторинг. Сначала мы выигрываем время на какой-то очевидной оптимизации типа включения кэша или кэширования Главной и т.п. Потом настраиваем мониторинг, он нам показывает, чего не хватает. И все это повторяется многократно – останавливать мониторинг и доработку никогда нельзя.

Что может показать мониторинг? Мы можем упереться в диск, т.е. в файловую систему, в память, в процессор, в сеть… И может быть такое, что, вроде бы, все более-менее, но какие-то ошибки валятся. Все это разрешается по-разному. Можно проблему, допустим, с диском решить добавлением нового диска в тот же сервер, а можно поставить второй сервер, который будет заниматься только файлами.

На что нужно обращать внимание прямо сейчас при мониторинге? Это:

  1. доступность, т.е. жив сервер, вообще, или нет;
  2. нехватка ресурсов диска, процессора и т.д.;
  3. ошибки.

Как это все мониторить?

Вот список замечательных инструментов, которые позволяют мониторить ресурсы и показывать результаты в очень удобном виде:

Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем за 2015 год.

Старьё! — скажите вы.
— Вечные ценности! — ответим мы. Добавить метки

Вертикальное масштабирование — scaling up — увеличение количества доступных для ПО ресурсов за счет увеличения мощности применяемых с серверов.

— scaling out — увеличение количества нод, объединенных в кластер серверов при нехватке CPU, памяти или дискового пространства.

И то и другое является инфраструктурными решениями, которые в разных ситуациях требуются когда веб проект растет.

Вертикальное и горизонтальное масштабирование, scaling для web

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

Возможности для масштабирования для серверов баз данных определяются применяемыми программными решениями: чаще всего это реляционные базы данных (MySQL, Postgresql) или NoSQL ( , Cassandra и др).


Горизонтальное масштабирование для серверов баз данных при больших нагрузках значительно дешевле

Веб-проект обычно начинают на одном сервере, ресурсы которого при росте заканчиваются. В такой ситуации возможны 2 варианта:

  • перенести сайт на более мощный сервер
  • добавить еще один сервер небольшой мощности с объединить машины в кластер

MySQL является самой популярной RDBMS и, как и любая из них, требует для работы под нагрузкой много серверных ресурсов. Масштабирование возможно, в основном, вверх. Есть шардинг (для его настройки требуется вносить изменения в код) и , которая может быть сложной в поддержке.

NoSQL масштабируется легко и второй вариант с, например, MongoDB будет значительно выгоднее материально, при этом не потребует трудозатратных настроек и поддержки получившегося решения. Шардинг осуществляется автоматически.

Таким образом с MySQL нужен будет сервер с большим количеством CPU и оперативной памяти, такие сервера имеют значительную стоимость.

Горизонтальное масштабирование
С MongoDB можно добавить еще один средний сервер и полученное решение будет стабильно работать давая дополнительно отказоустойчивость.

Scale-out или является закономерным этапом развития инфраструктуры. Любой сервер имеет ограничения и когда они достигнуты или когда стоимость более мощного сервера оказывается неоправданно высокой добавляются новые машины. Нагрузка распределяется между ними. Также это дает отказоустойчивость.

Добавлять средние сервера и настраивать кластеры нужно начинать когда возможности для увеличения ресурсов одной машины исчерпаны или когда приобретение сервера мощнее оказывается невыгодно

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

Читайте про и балансер

Модель доверенная подсистема (или доверенный сервер)

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

Модель с применением множества доверенных удостоверений сервиса

Вертикальное и горизонтальное масштабирование

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

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

горизонтальное (больше блоков).

При вертикальном масштабировании поддержка повышенной нагрузки обеспечивается через введение в существующие серверы дополнительного оборудования, такого как процессоры, оперативная память и сетевые интерфейсные платы (network interface cards, NIC). Такой простой вариант не добавляет затрат на обслуживание и поддержку, но может быть экономически выгодным лишь до определенного момента. Однако всегда сохраняется вероятность сбоя, что является риском. Кроме того, введение дополнительного оборудования в существующие серверы обеспечивает желаемые результаты не бесконечно, и получение последних 10% расчетной производительности путем наращивания мощностей одного компьютера может быть очень дорогим удовольствием.

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

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

Вопросы вертикального масштабирования

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

Проектирование с поддержкой горизонтального масштабирования

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

Узкие места идентификации и горизонтального масштабирования . Часто узким местом являются совместно используемые плохо масштабируемые в вертикальном направлении ресурсы. Например, имеется единственный экземпляр SQL Server, с которым работают множество серверов приложений. В этом случае разделение данных таким образом, чтобы они могли обслуживаться несколькими экземплярами SQL Server, обеспечит возможность горизонтального масштабирования решения. Если существует вероятность того, что узким местом станет сервер базы данных, предусмотрите секционирование данных при проектировании, это избавит от многих проблем в будущем.

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

Компромиссы и последствия их принятия

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

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

Как правило, выполняется оптимизация цены и производительности в рамках, налагаемых всеми остальными ограничениями. Например, использование четырех 2-процессорных Веб-

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

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

Компоненты без сохранения состояния

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

Секционирование данных и базы данных

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

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

Принимаемые в сценариях развертывания решения о секционировании хранилища данных во многом определяются типом данных. Рассмотрим значимые факторы:

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

тиражирование требует применения механизмов обеспечения синхронизации системы.

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

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

Данные с отложенной синхронизацией . Некоторые используемые в приложениях данные не требуют немедленной синхронизации или синхронизации вообще. Отличный пример – такие данные онлайн-магазинов, как «С товаром Х часто покупают Y и Z». Эти данные извлекаются из основных данных, но не требуют обновления в режиме реального времени. Проектирование стратегий, обеспечивающих перевод данных из основных в секционируемые (динамические) и затем в статические, является ключевым фактором в построении высокомасштабируемых приложений.

Более подробно схемы перемещения и тиражирования данных рассматриваются в статье «Data Movement Patterns » (Шаблоны передачи данных) по адресу https://msdn.microsoft.com/en-us/library/ms998449.aspx .

Масштабирование приложений ASP.NET

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

Далее вы развертываете приложение, вводите его в эксплуатацию и оно работает замечательно в течение нескольких первых недель, но с увеличением количества пользователей увеличивается и количество запросов, которые требуется обработать вашему серверу, и вдруг, ваш сервер начинает захлебываться. Сначала это может проявляться в увеличении времени обработки запросов, затем рабочий процесс начинает использовать все больше памяти и вычислительных ресурсов и в конечном итоге веб сервер просто перестает успевать обрабатывать все запросы и в файлах журналов начинают все чаще появляться сообщения HTTP 500 («Internal Server Error»).

Что случилось? Может быть снова заняться оптимизацией приложения? Однако, с увеличением количества пользователей ситуация повторится. Может быть увеличить объем памяти или добавить процессоры? Однако подобное расширение возможностей единственного компьютера имеет свои пределы. Пришло время признать тот факт, что вам необходимы дополнительные серверы.

Горизонтальное масштабирование (scaling out) веб-приложений — это естественный процесс, начинающийся в определенный момент в жизни веб-приложений. Один сервер может одновременно обслуживать десятки, сотни и даже тысячи пользователей, но он не в состоянии достаточно долго выдерживать пиковые нагрузки. Память начинает заполняться информацией о сеансах, обработка новых запросов приостанавливается из-за отсутствия свободных потоков выполнения, и переключения контекста начинают выполняться слишком часто, что ведет к увеличению задержек и снижению пропускной способности сервера.

Горизонтальное масштабирование

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

Одной из основных проблем горизонтального масштабирования, с которыми сталкиваются разработчики — как реализовать привязку к серверу. Например, когда работает единственный веб-сервер, информация о состоянии сеансов пользователей хранится в памяти. Если добавить еще один сервер, как обеспечить для него доступ к объектам сеансов? Как синхронизировать сеансы между серверами?

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

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

Представьте, что произойдет, когда пользователь пошлет запрос, вызывающий обновление кеша: сервер, получивший запрос, обновит свой кеш в памяти, но другие серверы не будут знать, что это необходимо сделать, и если в их кешах хранится копия того же объекта, это приведет к противоречивости данных в масштабе всего приложения. Один из способов решения этой проблемы — организовать синхронизацию объектов в кеше между серверами. Такое вполне возможно, но это усложнит общую архитектуру веб-приложения, не говоря уже о том, как вырастет объем трафика между серверами.

Механизмы масштабирования в ASP.NET

Горизонтальное масштабирование требует хранения информации о состоянии за пределами процессов. В ASP.NET имеется два механизма, обеспечивающих такой способ хранения данных:

Служба управления состоянием (State Service)

Служба управления состоянием — это служба Windows, поддерживающая управление состоянием для нескольких компьютеров. Эта служба устанавливается автоматически при установке.NET Framework, но она выключена по умолчанию. Вам достаточно просто выбрать, на каком сервере будет выполняться служба управления состоянием, и настроить все остальные на ее использование. Несмотря на то, что служба управления состоянием позволяет нескольким серверам использовать общее хранилище информации, она не поддерживает возможность долговременного хранения. То есть, если что-то приключится с сервером, где выполняется эта служба, вся информация о сеансах в вашей веб-ферме будет утеряна.

Мастер Йода рекомендует:  JQuery Ajax загрузка изображений с анимированным индикатором выполнения Javascript

ASP.NET поддерживает возможность хранения информации о состоянии в базе данных SQL Server. Этот механизм не только поддерживает те же возможности, что и служба управления состоянием, но также обеспечивает долговременное хранение данных, поэтому, даже если на веб-серверах и на сервере с базой данных SQL Server случится аварийная ситуация, информация о состоянии сохранится.

Для нужд кеширования в большинстве случаев можно с успехом использовать один из механизмов распределенного кеширования, таких как Microsoft AppFabric Cache , NCache или Memcached , последний из которых является открытой реализацией распределенного кеша.

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

Некоторые распределенные кеши, такие как AppFabric Cache и Memcached, также имеют собственные реализации службы управления состоянием и провайдеров кеша для ASP.NET.

Ловушки горизонтального масштабирования

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

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

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

Управлять генерацией этих ключей в ASP.NET можно путем настройки параметров в разделе machineKey, в файле web.config. Когда веб-приложение выполняется на нескольких серверах, вам необходимо настроить все серверы так, чтобы они использовали один и тот же предварительно сгенерированный ключ.

Другой проблемой, связанной с горизонтальным масштабированием и уникальными ключами, является возможность шифрования разделов в файлах web.config. Закрытая информация в файлах web.config часто шифруется, когда приложение развертывается на серверах. Например, раздел connectionString можно зашифровать, чтобы предотвратить утечку имени пользователя и пароля к базе данных. Вместо того, чтобы шифровать файл web.config на каждом сервере отдельно, усложняя процесс развертывания, можно сгенерировать один зашифрованный файл web.config и развернуть его на всех серверах. Для этого следует создать RSA-контейнер ключей и импортировать его на все веб-серверы.

Более полную информацию о создании уникальных ключей и включения их в настройки приложений можно получить в базе знаний Microsoft Knowledge Base . За дополнительной информацией о создании RSA-контейнера ключей обращайтесь к статье «Импорт и экспорт защищенных контейнеров ключей RSA для конфигурации» на сайте MSDN.

Приложение называется масштабируемым если. Горизонтальное масштабирование PHP-приложений

Масштабируемость — способность устройства увеличивать свои
возможности
путем наращивания числа функциональных блоков,
выполняющих одни и
те же задачи.
Глоссарий.ru

Обычно о масштабировании начинают думать тогда, когда один
сервер не справляется с возложенной на него работой. С чем именно он не
справляется? Работа любого web-сервера по большому счету сводится к основному
занятию компьютеров — обработке данных. Ответ на HTTP (или любой другой) запрос
подразумевает проведение некоторых операций над некими данными. Соответственно,
у нас есть две основные сущности — это данные (характеризуемые своим объемом) и
вычисления (характеризуемые сложностью). Сервер может не справляться со своей
работой по причине большого объема данных (они могут физически не помещаться на
сервере), либо по причине большой вычислительной нагрузки. Речь здесь идет,
конечно, о суммарной нагрузке — сложность обработки одного запроса может быть
невелика, но большое их количество может «завалить» сервер.

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

Типичная архитектура сайта

Жизнь типичного сайта начинается с очень простой архитектуры
— это один web-сервер (обычно в его роли выступает Apache),
который занимается всей работой по обслуживанию HTTP-запросов,
поступающих от посетителей. Он отдает клиентам так называемую «статику», то
есть файлы, лежащие на диске сервера и не требующие обработки: картинки (gif,
jpg, png), листы стилей (css), клиентские скрипты (js, swf). Тот же сервер
отвечает на запросы, требующие вычислений — обычно это формирование
html-страниц, хотя иногда «на лету» создаются и изображения и другие документы.
Чаще всего ответы на такие запросы формируются скриптами, написанными на php,
perl или других языках.

Минус такой простой схемы работы в том, что разные по
характеру запросы (отдача файлов с диска и вычислительная работа скриптов)
обрабатываются одним и тем же web-сервером. Вычислительные запросы требуют
держать в памяти сервера много информации (интерпретатор скриптового языка,
сами скрипты, данные, с которыми они работают) и могут занимать много
вычислительных ресурсов. Выдача статики, наоборот, требует мало ресурсов
процессора, но может занимать продолжительное время, если у клиента низкая
скорость связи. Внутреннее устройство сервера Apache предполагает, что каждое
соединение обрабатывается отдельным процессом. Это удобно для работы скриптов,
однако неоптимально для обработки простых запросов. Получается, что тяжелые (от
скриптов и прочих данных) процессы Apache много времени проводят в ожидании (сначала при получении
запроса, затем при отправке ответа), впустую занимая память сервера.

Решение этой проблемы — распределение работы по обработке
запросов между двумя разными программами — т.е. разделение на frontend и
backend. Легкий frontend-сервер выполняет задачи по отдаче статики, а остальные
запросы перенаправляет (проксирует) на backend, где выполняется формирование
страниц. Ожидание медленных клиентов также берет на себя frontend, и если он использует
мультиплексирование (когда один процесс обслуживает нескольких клиентов — так
работают, например, nginx или lighttpd), то ожидание практически ничего не
стоит.

Из других компонент сайта следует отметить базу данных, в
которой обычно хранятся основные данные системы — тут наиболее популярны
бесплатные СУБД MySQL и PostgreSQL. Часто отдельно выделяется хранилище
бинарных файлов, где содержатся картинки (например, иллюстрации к статьям
сайта, аватары и фотографии пользователей) или другие файлы.

Таким образом, мы получили схему архитектуры, состоящую из
нескольких компонент.

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

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

Распределение вычислений

Типичная ситуация для растущего сайта — база данных уже
вынесена на отдельную машину, разделение на frontend и backend выполнено,
однако посещаемость продолжает увеличиваться и backend не успевает обрабатывать
запросы. Это значит, что нам необходимо распределить вычисления на несколько
серверов. Сделать это просто — достаточно купить второй сервер и поставить на
него программы и скрипты, необходимые для работы backend.
После этого надо сделать так, чтобы запросы пользователей распределялись
(балансировались) между полученными серверами. О разных способах балансировки
будет сказано ниже, пока же отметим, что обычно этим занимается frontend,
который настраивают так, чтобы он равномерно распределял запросы между
серверами.

Важно, чтобы все backend-серверы были способны правильно
отвечать на запросы. Обычно для этого необходимо, чтобы каждый из них работал с
одним и тем же актуальным набором данных. Если мы храним всю информацию в единой
базе данных, то СУБД сама обеспечит совместный доступ и согласованность данных.
Если же некоторые данные хранятся локально на сервере (например, php-сессии
клиента), то стоит подумать о переносе их в общее хранилище, либо о более
сложном алгоритме распределения запросов.

Распределить по нескольким серверам можно не только работу
скриптов, но и вычисления, производимые базой данных. Если СУБД выполняет много
сложных запросов, занимая процессорное время сервера, можно создать несколько
копий базы данных на разных серверах. При этом возникает вопрос синхронизации
данных при изменениях, и здесь применимы несколько подходов.

  • Синхронизация на уровне приложения . В этом случае наши
    скрипты самостоятельно записывают изменения на все копии базы данных (и сами несут
    ответственность за правильность данных). Это не лучший вариант, поскольку он
    требует осторожности при реализации и весьма неустойчив к ошибкам.
  • Репликация — то есть автоматическое тиражирование
    изменений, сделанных на одном сервере, на все остальные сервера. Обычно при
    использовании репликации изменения записываются всегда на один и тот же сервер — его называют master, а остальные копии — slave. В большинстве СУБД есть
    встроенные или внешние средства для организации репликации. Различают
    синхронную репликацию — в этом случае запрос на изменение данных будет ожидать,
    пока данные будут скопированы на все сервера, и лишь потом завершится успешно — и асинхронную — в этом случае изменения копируются на slave-сервера с
    задержкой, зато запрос на запись завершается быстрее.
  • Multi-master репликация. Этот подход аналогичен
    предыдущему, однако тут мы можем производить изменение данных, обращаясь не к
    одному определенному серверу, а к любой копии базы. При этом изменения
    синхронно или асинхронно попадут на другие копии. Иногда такую схему называют
    термином «кластер базы данных».

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

Методы балансировки

Пусть мы создали несколько серверов (любого назначения — http, база данных и т.п.), каждый из которых может обрабатывать запросы. Перед
нами встает задача — как распределить между ними работу, как узнать, на какой
сервер отправлять запрос? Возможны два основных способа распределения запросов.

    Балансирующий узел . В этом случае клиент шлет запрос на один
    фиксированный, известный ему сервер, а тот уже перенаправляет запрос на один из
    рабочих серверов. Типичный пример — сайт с одним frontend и несколькими
    backend-серверами, на которые проксируются запросы. Однако «клиент» может
    находиться и внутри нашей системы — например, скрипт может слать запрос к
    прокси-серверу базы данных, который передаст запрос одному из серверов СУБД.
    Сам балансирующий узел может работать как на отдельном сервере, так и на одном
    из рабочих серверов.

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

  • Балансировка на стороне клиента . Если мы хотим избежать
    единой точки отказа, существует альтернативный вариант — поручить выбор сервера
    самому клиенту. В этом случае клиент должен знать о внутреннем устройстве нашей
    системы, чтобы уметь правильно выбирать, к какому серверу обращаться.
    Несомненным плюсом является отсутствие точки отказа — при отказе одного из
    серверов клиент сможет обратиться к другим. Однако платой за это является
    усложнение логики клиента и меньшая гибкость балансировки.
  • Разумеется, существуют и комбинации этих подходов. Например,
    такой известный способ распределения нагрузки, как DNS-балансировка, основан на
    том, что при определении IP-адреса сайта клиенту выдается
    адрес одного из нескольких одинаковых серверов. Таким образом, DNS выступает в
    роли балансирующего узла, от которого клиент получает «распределение». Однако
    сама структура DNS-серверов предполагает отсутствие точки отказа за счет
    дублирования — то есть сочетаются достоинства двух подходов. Конечно, у такого
    способа балансировки есть и минусы — например, такую систему сложно динамически
    перестраивать.

    Работа с сайтом обычно не ограничивается одним запросом.
    Поэтому при проектировании важно понять, могут ли последовательные запросы
    клиента быть корректно обработаны разными серверами, или клиент должен быть
    привязан к одному серверу на время работы с сайтом. Это особенно важно, если на
    сайте сохраняется временная информация о сессии работы пользователя (в этом
    случае тоже возможно свободное распределение — однако тогда необходимо хранить
    сессии в общем для всех серверов хранилище). «Привязать» посетителя к
    конкретному серверу можно по его IP-адресу (который, однако, может меняться),
    или по cookie (в которую заранее записан идентификатор сервера), или даже
    просто перенаправив его на нужный домен.

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

    Распределение данных

    Мы научились распределять вычисления, поэтому большая
    посещаемость для нас не проблема. Однако объемы данных продолжают расти,
    хранить и обрабатывать их становится все сложнее — а значит, пора строить
    распределенное хранилище данных. В этом случае у нас уже не будет одного или
    нескольких серверов, содержащих полную копию базы данных. Вместо этого, данные
    будут распределены по разным серверам. Какие возможны схемы распределения?

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

    Более сложный случай
    вертикального распределения базы — это декомпозиция одной таблицы, когда часть
    ее столбцов оказывается на одном сервере, а часть — на другом. Такой прием
    встречается реже, но он может использоваться, например, для отделения маленьких
    и часто обновляемых данных от большого объема редко используемых.

    Горизонтальное распределение (horizontal partitioning) — заключается в
    распределении данных одной таблицы по нескольким серверам. Фактически, на
    каждом сервере создается таблица такой же структуры, и в ней хранится
    определенная порция данных. Распределять данные по серверам можно по разным
    критериям: по диапазону (записи с id

    Горизонтальное масштабирование PHP-приложений. Вертикальное и горизонтальное масштабирование систем

    ) Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «Yii» — я один из его разработчиков. У меня также есть full-time работа — и это уже не стартап — Stay.com, который занимается путешествиями.

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

    Что такое масштабирование, вообще? Это возможность увеличить производительность проекта за минимальное время путем добавления ресурсов.

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

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


    Самый классный вопрос, который задают, — а зачем оно надо, если у меня все и на одном сервере прекрасно работает? На самом-то деле, надо проверить, что будет. Т.е., сейчас оно работает, но что будет потом? Есть две замечательные утилиты — ab и siege, которые как бы нагоняют тучу пользователей конкурента, которые начинают долбить сервер, пытаются запросить странички, послать какие-то запросы. Вы должны указать, что им делать, а утилиты формируют такие вот отчеты:

    Главные два параметра: n — количество запросов, которые надо сделать, с — количество одновременных запросов. Таким образом они проверяют конкурентность.

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

    Есть еще один параметр — Response time — время ответа, за которое в среднем сервер отдал страничку. Оно бывает разное, но известно, что около 300 мс — это норма, а что выше — уже не очень хорошо, потому что эти 300 мс отрабатывает сервер, к этому прибавляются еще 300-600 мс, которые отрабатывает клиент, т.е. пока все загрузится — стили, картинки и остальное — тоже проходит время.

    Бывает, что на самом деле пока и не надо заботиться о масштабировании — идем на сервер, обновляем PHP, получаем 40% прироста производительности и все круто. Далее настраиваем Opcache, тюним его. Opcache, кстати, тюнится так же, как и APC, скриптом, который можно найти в репозитории у Расмуса Лердорфа и который показывает хиты и мисы, где хиты — это сколько раз PHP пошел в кэш, а мисы — сколько раз он пошел в файловую систему доставать файлики. Если прогнать весь сайт, либо запустить туда какой-то краулер по ссылкам, либо вручную потыкать, то у нас будет статистика по этим хитам и мисам. Если хитов 100%, а мисов — 0%, значит, все нормально, а если есть мисы, то надо выделить больше памяти, чтобы весь наш код влез в Opcache. Это частая ошибка, которую допускают — вроде Opcache есть, но что-то не работает…

    Еще часто начинают масштабировать, но не смотрят, вообще, из-за чего все работает медленно. Чаще всего лезем в базу, смотрим — индексов нет, ставим индексы — все сразу залетало, еще на 2 года хватит, красота!

    Ну, еще надо включить кэш, заменить apache на nginx и php-fpm, чтобы сэкономить память. Будет все классно.

    Все перечисленное достаточно просто и дает вам время. Время на то, что когда-то этого станет мало, и к этому уже сейчас надо готовиться.

    Как, вообще, понять, в чем проблема? Либо у вас уже настал highload, а это не обязательно какое-то бешеное число запросов и т.д., это, когда у вас проект не справляется с нагрузкой, и тривиальными способами это уже не решается. Надо расти либо вширь, либо вверх. Надо что-то делать и, скорее всего, на это мало времени, что-то надо придумывать.

    Первое правило — никогда ничего нельзя делать вслепую, т.е. нам нужен отличный мониторинг. Сначала мы выигрываем время на какой-то очевидной оптимизации типа включения кэша или кэширования Главной и т.п. Потом настраиваем мониторинг, он нам показывает, чего не хватает. И все это повторяется многократно – останавливать мониторинг и доработку никогда нельзя.

    Что может показать мониторинг? Мы можем упереться в диск, т.е. в файловую систему, в память, в процессор, в сеть… И может быть такое, что, вроде бы, все более-менее, но какие-то ошибки валятся. Все это разрешается по-разному. Можно проблему, допустим, с диском решить добавлением нового диска в тот же сервер, а можно поставить второй сервер, который будет заниматься только файлами.

    На что нужно обращать внимание прямо сейчас при мониторинге? Это:

    1. доступность, т.е. жив сервер, вообще, или нет;
    2. нехватка ресурсов диска, процессора и т.д.;
    3. ошибки.

    Как это все мониторить?

    Вот список замечательных инструментов, которые позволяют мониторить ресурсы и показывать результаты в очень удобном виде:

    Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем за 2015 год.

    Старьё! — скажите вы.
    — Вечные ценности! — ответим мы.

    highload junior Добавить метки

    Масштабируемость — такое свойство вычислительной системы, которое обеспечивает предсказуемый рост системных характеристик, например, числа поддерживаемых пользователей, быстроты реакции, общей производительности и пр., при добавлении к ней вычислительных ресурсов. В случае сервера СУБД можно рассматривать два способа масштабирования — вертикальный и горизонтальный (рис. 2).

    При горизонтальном масштабировании увеличивается число серверов СУБД, возможно, взаимодействующих друг с другом в прозрачном режиме, разделяя таким образом общую загрузку системы. Такое решение, видимо, будет все более популярным с ростом поддержки слабосвязанных архитектур и распределенных баз данных, однако обычно оно характеризуется сложным администрированием.

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

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

    • поддержка многопроцессорной обработки;
    • гибкость архитектуры.

    Многопроцессорные системы

    Для вертикального масштабирования все чаще используются симметричные многопроцессорные системы (SMP), поскольку в этом случае не требуется смены платформы, т.е. операционной системы, аппаратного обеспечения, а также навыков администрирования. С этой целью возможно также применение систем с массовым параллелизмом (MPP), но пока их использование ограничивается специальными задачами, например, расчетными. При оценке сервера СУБД с параллельной архитектурой целесообразно обратить внимание на две основные характеристики расширяемости архитектуры: адекватности и прозрачности.

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

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

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

    Гибкость архитектуры

    Независимо от степени мобильности, поддержки стандартов, параллелизма и других полезных качеств, производительность СУБД, имеющей ощутимые встроенные архитектурные ограничения, не может наращиваться свободно. Наличие документированных или практических ограничений на число и размеры объектов базы данных и буферов памяти, количество одновременных подключений, на глубину рекурсии вызова процедур и подчиненных запросов (subqueries) или срабатывания триггеров базы данных является таким же ограничением применимости СУБД как, например, невозможность переноса на несколько вычислительных платформ. Параметры, ограничивающие сложность запросов к базе данных, в особенности размеры динамических буферов и стека для рекурсивных вызовов, должны настраиваться в динамике и не требовать остановки системы для реконфигурации. Нет смысла покупать новый мощный сервер, если ожидания не могут быть удовлетворены из-за внутренних ограничений СУБД.

    Обычно узким местом является невозможность динамической подстройки характеристик программ сервера баз данных. Способность на ходу определять такие параметры, как объем потребляемой памяти, число занятых процессоров, количество параллельных потоков выполнения заданий (будь то настоящие потоки (threads), процессы операционной системы или виртуальные процессоры) и количество фрагментов таблиц и индексов баз данных, а также их распределение по физическим дискам БЕЗ останова и перезапуска системы является требованием, вытекающим из сути современных приложений. В идеальном варианте каждый из этих параметров можно было бы изменить динамически в заданных для конкретного пользователя пределах.

    Модель доверенная подсистема (или доверенный сервер)

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

    Модель с применением множества доверенных удостоверений сервиса

    Вертикальное и горизонтальное масштабирование

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

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

    горизонтальное (больше блоков).

    При вертикальном масштабировании поддержка повышенной нагрузки обеспечивается через введение в существующие серверы дополнительного оборудования, такого как процессоры, оперативная память и сетевые интерфейсные платы (network interface cards, NIC). Такой простой вариант не добавляет затрат на обслуживание и поддержку, но может быть экономически выгодным лишь до определенного момента. Однако всегда сохраняется вероятность сбоя, что является риском. Кроме того, введение дополнительного оборудования в существующие серверы обеспечивает желаемые результаты не бесконечно, и получение последних 10% расчетной производительности путем наращивания мощностей одного компьютера может быть очень дорогим удовольствием.

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

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

    Вопросы вертикального масштабирования

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

    Проектирование с поддержкой горизонтального масштабирования

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

    Узкие места идентификации и горизонтального масштабирования . Часто узким местом являются совместно используемые плохо масштабируемые в вертикальном направлении ресурсы. Например, имеется единственный экземпляр SQL Server, с которым работают множество серверов приложений. В этом случае разделение данных таким образом, чтобы они могли обслуживаться несколькими экземплярами SQL Server, обеспечит возможность горизонтального масштабирования решения. Если существует вероятность того, что узким местом станет сервер базы данных, предусмотрите секционирование данных при проектировании, это избавит от многих проблем в будущем.

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

    Компромиссы и последствия их принятия

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

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

    Как правило, выполняется оптимизация цены и производительности в рамках, налагаемых всеми остальными ограничениями. Например, использование четырех 2-процессорных Веб-

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

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

    Компоненты без сохранения состояния

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

    Секционирование данных и базы данных

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

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

    Принимаемые в сценариях развертывания решения о секционировании хранилища данных во многом определяются типом данных. Рассмотрим значимые факторы:

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

    тиражирование требует применения механизмов обеспечения синхронизации системы.

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

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

    Данные с отложенной синхронизацией . Некоторые используемые в приложениях данные не требуют немедленной синхронизации или синхронизации вообще. Отличный пример – такие данные онлайн-магазинов, как «С товаром Х часто покупают Y и Z». Эти данные извлекаются из основных данных, но не требуют обновления в режиме реального времени. Проектирование стратегий, обеспечивающих перевод данных из основных в секционируемые (динамические) и затем в статические, является ключевым фактором в построении высокомасштабируемых приложений.

    Более подробно схемы перемещения и тиражирования данных рассматриваются в статье «Data Movement Patterns » (Шаблоны передачи данных) по адресу https://msdn.microsoft.com/en-us/library/ms998449.aspx .

    В последнее время нередки утверждения, что серверы среднего и старшего класса активно заменяются на группы серверов начального уровня, объединенные в стойки или кластеры. Однако некоторые эксперты с этим не согласны. Так, по данным Dataquest, доля моделей ценой от 500 тыс. долл. и выше (к ним относятся средние и старшие серверы SMP) в общем объеме продаж серверов с 2000 до 2002 г. выросла с 38 до 52%.

    Другие данные, полученные компанией IDC, свидетельствуют о росте (по крайней мере, по числу машин) в секторе младших моделей серверов — с двумя процессорами. IDC также предсказывает, что в 2005 г. самой распространенной операционной системой для серверов стоимостью от 50 тыс. до 3 млн долл. будет Unix. Из сравнения этих данных видно, что Unix-серверы среднего и старшего класса останутся преобладающей платформой для центров обработки данных, но будут дополняться все растущим числом небольших (обычно двухпроцессорных) серверов.

    Эта тенденция сложилась в результате выделения в центрах обработки данных разных уровней вычислений (рис. 1). Уровень 1, или фронтальный уровень, постепенно переходит на модель горизонтального масштабирования небольших серверов, а на уровне 3 (уровне баз данных) преобладают серверы с вертикальным масштабированием. Уровень 2 (уровень приложений) становится областью, где сосуществуют вертикальная и горизонтальная архитектуры.

    Вертикальная и горизонтальная архитектуры

    Рассмотрим основные различия между вертикальной и горизонтальной архитектурами. Серверы с вертикальным масштабированием — это большие SMP-системы (с симметричной многопроцессорной обработкой или совместно используемой памятью), насчитывающие свыше четырех центральных процессоров. В них используется только одна копия ОС, управляющая работой всех процессоров, памяти и компонентов ввода-вывода. Обычно все эти ресурсы размещены в одной стойке или шкафу. Межсоединения у таких серверов осуществляются по высокоскоростной центральной или объединительной панели с небольшим временем запаздывания и согласованным доступом к кэш-памяти. Добавить ресурсы можно путем установки внутрь шкафа дополнительных системных плат. В системах с вертикальной архитектурой (или SMP-системах) память используется совместно, т. е. все процессоры и компоненты ввода-вывода получают доступ ко всей памяти. Пользователь «видит» память как единый большой объект.

    При альтернативном, горизонтальном масштабировании системы соединяются через сеть или объединяются в кластер. Для межсоединений обычно используются стандартные сетевые технологии, такие, как Fast Ethernet, Gigabit Ethernet (GBE) и Scalable Coherent Interconnect (SCI), дающие меньшую пропускную способность и большее запаздывание по сравнению с вертикальными системами. Ресурсы в этом случае распределяются между узлами, обычно содержащими от одного до четырех процессоров; каждый узел имеет собственный процессор и память и может иметь собственную подсистему ввода-вывода или использовать ее совместно с другими узлами. На каждом узле работает отдельная копия ОС. Ресурсы расширяются за счет добавления узлов, но не добавления ресурсов в узел. Память в горизонтальных системах распределена, т. е. у каждого узла есть собственная память, к которой напрямую обращаются его процессоры и подсистема ввода-вывода. Доступ к этим ресурсам с другого узла происходит намного медленнее, чем с узла, где они расположены. Кроме того, при горизонтальной архитектуре отсутствует согласованный доступ узлов к памяти, а используемые приложения потребляют относительно немного ресурсов, поэтому они «умещаются» на одном узле и им не нужен согласованный доступ. Если же приложению потребуется несколько узлов, то оно само должно обеспечить согласованный доступ к памяти.

    Если горизонтальная система удовлетворяет требованиям приложений, то такая архитектура предпочтительна, поскольку расходы на ее приобретение меньше. Обычно стоимость приобретения в расчете на один процессор у горизонтальных систем ниже, чем у вертикальных. Разница в цене объясняется тем, что в вертикальных системах применяются более мощные функции надежности, доступности и обслуживаемости — RAS (reliability, availability, serviceability), а также высокопроизводительные межсоединения. Однако есть ряд ограничений на применение систем с горизонтальной архитектурой. Ниже мы обсудим, в каких условиях возможно применение горизонтальных систем и когда обязательно вертикальное масштабирование.

    Помимо одного большого SMP-сервера, к вертикальной архитектуре относятся также кластеры больших SMP-серверов, используемые для одного крупномасштабного приложения.

    Недавно появившиеся на рынке модульные, или blade-серверы, обычно оборудуемые одним-двумя процессорами, — пример горизонтальных серверов. Здесь кластер состоит из небольших узлов, в каждом из которых установлен SMP-сервер начального уровня с числом центральных процессоров от 1 до 4.

    Другой способ горизонтального масштабирования — это большие вычислительные системы с массовым параллелизмом (MPP), состоящие из множества установленных в одном шкафу небольших процессоров, каждый из которых имеет собственную копию ОС или копию микроядра ОС. В настоящее время выпускаются всего несколько систем MPP, которые чаще всего представляют специализированные решения. Это, например, системы Terradata производства компании NCR, IBM RS/6000SP (SP-2) и HP Tandem non-stop.

    Таблица 1. Особенности вертикальной и горизонтальной архитектур

    Параметр Вертикальные системы Горизонтальные системы
    Память Большая совместно используемая Небольшая выделенная
    Потоки Много взаимозависимых потоков Много независимых потоков
    Межсоединения Сильносвязанные внутренние Слабосвязанные внешние
    RAS Мощные RAS одиночной системы Мощные RAS с использованием репликации
    Центральные процессоры Много стандартных Много стандартных
    ОС Одна копия ОС на множество центральных процессоров Несколько копий ОС (по одной копии на 1-4 процессора)
    Компоновка В одном шкафу Размещение большого числа серверов в стойке
    Плотность размещения Высокая плотность размещения процессоров на единицу площади пола
    Оборудование Стандартное и специально разработанное Стандартное
    Масштабирование В пределах корпуса одного сервера В масштабе нескольких серверов
    Расширение Путем установки в сервер дополнительных компонентов Путем добавления новых узлов
    Архитектура 64-разрядная 32- и 64-разрядная

    Табл. 1 позволяет провести сравнительный анализ вертикальной и горизонтальной архитектур.

    • В вертикальных системах память используется совместно и обеспечивается согласованный доступ к кэш-памяти.
    • Вертикальные системы идеальны для потоков выполнения задач, которые должны обмениваться данными между собой.
    • Вертикальные системы характеризуются мощными функциями RAS, а в горизонтальных системах доступность реализуется с помощью массивной репликации (в кластер соединяются несколько узлов, поэтому отказ одного из них мало влияет на работу всей системы).
    • В вертикальных системах одна копия ОС охватывает все ресурсы. Некоторые вертикальные системы, например, мидфреймы и серверы класса high-end Sun Microsystems (от Sun Fire 4800 до Sun Fire 15K), можно разделить на меньшие вертикальные серверы.
    • В вертикальных системах используется максимально возможное число стандартных компонентов, но некоторые основные составляющие (например, межсоединения) специально разрабатываются.
    • Вертикальные системы можно расширять, устанавливая в существующий каркас дополнительные компоненты (более мощные процессоры, добавочную память, дополнительные и более производительные соединения ввода-вывода и т. п.). Горизонтальные системы расширяются за счет добавления узла или замены старых узлов на новые.
    • Практически все вертикальные системы 64-разрядные, а горизонтальные могут быть как 32-разрядными, так и 64-разрядными.

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

    Таблица 2. Типы приложений для вертикальной и горизонтальной архитектур

    Для небольших и модульных серверов хорошо подходят приложения, которые не используют информацию о состоянии, невелики по масштабу и легко реплицируются. А для приложений, использующих информацию о состоянии и большие объемы данных, требующих интенсивной передачи данных внутри системы, идеальным решением будут вертикальные серверы. На рынке высокопроизводительных технических вычислений (HPTC) имеется множество приложений, в которых потоки зависят друг от друга и обмениваются данными между собой. Существуют также приложения, которым нужны большие объемы совместно используемой памяти. Для этих двух типов приложений лучше всего подходят большие SMP-серверы. Однако имеются и такие приложения HPTC, в которых потоки исполнения независимы и им не требуется совместно используемая память большого объема. Такие приложения можно разбивать на разделы, и потому для их выполнения идеальны кластеры небольших серверов. Аналогичным образом некоторые коммерческие приложения поддерживают разделы, и для них оптимальны горизонтальные серверы, а другие нельзя разбить на разделы, поэтому для них лучшая платформа — это вертикальные серверы.

    Факторы, влияющие на производительность

    Все крупные центры обработки данных представляют собой параллельные компьютеры. Здесь даже кластеры можно рассматривать как особый тип параллельных систем. Для получения высокой производительности требуется сбалансированная система с мощными процессорами, работающими на высокой скорости межсоединениями и подсистемой ввода-вывода, масштабируемой ОС, оптимизированными приложениями и совершенными функциями RAS.

    Процессоры и системные межсоединения

    Процессоры, безусловно, существенный компонент, но они только отчасти определяют общую производительность системы. Более важно обеспечить работу процессоров с максимальной загрузкой. У мощного процессора, загруженного лишь на 50%, производительность будет хуже, чем у более медленного процессора, который загружен на 80%.

    Кроме того, по мере роста числа процессоров в параллельной системе на первый план выходит не их мощность, а системные межсоединения. Именно они отвечают за перемещение данных с диска, из памяти и из сети к процессору. В кластере в качестве межсоединения выступает сетевое соединение, например, Fast Ethernet или Gigabit Ethernet. Кластерные межсоединения перемещают данные между узлами, а системные — внутри отдельной системы. Если межсоединение работает слишком медленно, то процессор в ожидании данных будет простаивать.

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

    Основное техническое различие между горизонтальными и вертикальными системами — это пропускная способность и запаздывание их межсоединений. У межсоединений кластеров пропускная способность может составлять от 125 Мбайт/с для Fast Ethernet до 200 Мбайт/с для SCI, а запаздывание — от 100 тыс. нс для GBE и до 10 тыс. нс для SCI. С помощью интерфейса InfiniBand возможно реализовать более быстрые межсоединения с пиковой скоростью от примерно 250 Мбайт/с для первой версии и до 3 Гбайт/с для последующих.

    Ввод и вывод

    Быстрый ввод-вывод необходим для того, чтобы межсоединение могло быстро получить данные с диска и из сети и передать их процессорам. Узкое место в подсистеме ввода-вывода может отрицательно сказаться на работе даже самых быстрых межсоединений и процессоров.

    Операционная система

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

    Доступность системы

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

    Оптимизированные приложения

    Приложения необходимо оптимизировать для архитектуры вычислительной системы. Легче всего писать и оптимизировать приложения для SMP-систем. Основные коммерческие приложения оптимизированы именно для SMP-систем и даже разрабатывались на них, поэтому SMP доминируют на рынке систем среднего класса и high-end последние десять лет.

    Размер приложений

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

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

    Конфигурация большой системы SMP может включать, например, до 100 процессоров, 576 Гбайт совместно используемой памяти и высокоскоростные межсоединения. Такая система может обрабатывать все типы нагрузок, поскольку в ней отсутствует обмен данными между узлами и эффективно осуществляется обмен данными между процессами. Все центральные процессоры могут одновременно получить доступ ко всем дискам, всей памяти и сетевым соединениям — это ключевая особенность SMP-систем (или вертикальных систем).

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

    Производительность на уровне базы данных

    Основной вопрос здесь — сравнение производительности одиночных средних и больших SMP-серверов с кластером небольших серверов (не более четырех процессоров).

    При обсуждении масштабируемости фирмы-производители используют ряд специальных терминов. Так, рост производительности (Speedup) для SMP определяется как отношение скоростей выполнения приложения на нескольких процессорах и на одном. Линейный рост производительности (Linear speedup) означает, например, что на 40 процессорах приложение работает в 40 раз (40x) быстрее, чем на одном. Рост производительности не зависит от числа процессоров, т. е. для конфигурации из 24 процессоров он будет таким же, как для 48 процессоров. Рост производительности кластера (Cluster speedup) отличается только тем, что при его расчете берется число узлов, а не процессоров. Как и рост производительности SMP, рост производительности кластера остается постоянным для разного числа узлов.

    Эффективность масштабирования (Scaling efficiency) характеризует способность приложений, особенно кластерных, масштабироваться на большое число узлов. Обычно считается, что эффективность масштабирования зависит от числа узлов, участвующих в измерении. Эффективность масштабирования SMP (SMP scaling efficiency) — это рост производительности, деленный на число процессоров, а эффективность кластера (Cluster efficiency) — это рост производительности кластера, деленный на число узлов в нем. Нужно понимать, в чем смысл этих параметров, чтобы не складывалась неправильная картина, поскольку эффективность масштабирования 90% на двух узлах — это не то же самое, что эффективность масштабирования 90% на четырех узлах.

    На рис. 2 приведены три графика: идеальная линейная масштабируемость, масштабируемость 24-процессорного SMP-сервера в 95% и масштабируемость кластера из двух 4-процессорных серверов в 90%. Видно, что существуют определенные ограничения на масштабируемость баз данных в кластерах (при горизонтальном масштабировании). Соединяя вместе много маленьких серверов, не удается получить масштабируемость, необходимую для средних и крупных приложений. Причина этого — ограничения пропускной способности внутрикластерных межсоединений, дополнительная нагрузка на ПО баз данных, связанная с управлением кластером, и трудности написания приложений для кластерных сред с распределенной памятью.

    Опубликованные результаты эталонных тестов показывают, например, что у Oracle9i RAC (Real Application Cluster) рост производительности составляет 1,8 и эффективность масштабирования равна 90%. Такая эффективность масштабируемости может показаться достаточно высокой, но на самом деле масштабируемость 90% для четырех узлов оказывается неэффективной, если сравнить ее с результатами больших SMP-серверов.

    Производительность на уровне приложений

    Уровень приложений в трехуровневом центре обработки данных сильно отличается от уровня базы данных. Обычно приложения этого уровня работают без запоминания состояния — иными словами, на самом сервере данные не хранятся или хранится только их небольшая часть. Этот уровень содержит бизнес-правила для сервисов приложений. Транзакции приходят на уровень приложений и им же обрабатываются. Когда данные нужно записать или считать, транзакции передаются на уровень базы данных. Серверы приложений стремятся консолидировать соединения с базой данных, поскольку большое число соединений отрицательно влияет на производительность.

    В большинстве случаев уровню сервера приложений требуется намного больше процессоров, чем уровню базы данных в расчете на отдельный прикладной сервис. Например, в случае SAP R/3 это соотношение составляет примерно 10 процессоров на каждый процессор базы данных, т. е. если SAP R/3 требуется 20 процессоров для уровня базы данных, то на уровне приложений должно быть примерно 200 процессоров. Вопрос заключается в том, что выгоднее развернуть — 100 двухпроцессорных серверов или десять 20-процессорных. Аналогичным образом в Oracle соотношение процессоров приложений к процессорам баз данных равно примерно 5 к 1.


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

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

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

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

    Влияние архитектуры на доступность

    Доступность крайне важна для современных центров обработки данных — сервисы приложений должны быть доступны в режиме 24x7x365 (24 часа в сутки, 7 дней в неделю, 365 дней в году). В зависимости от потребностей конкретного центра обработки данных используются разные схемы обеспечения высокой доступности. Для выбора конкретного решения необходимо определить допустимое время простоев (запланированных и незапланированных). На рис. 3 показано, как процент доступности отражается на продолжительности простоев.

    По мере роста требований к доступности растет и стоимость решения. Менеджеры центров обработки данных должны определить, какое сочетание стоимости, сложности и доступности наилучшим образом соответствует требованиям к уровню сервиса. Центры обработки данных, которым нужна доступность примерно 99,95%, могут развернуть одиночный SMP-сервер с такими функциями RAS, как полное резервирование аппаратуры и обслуживание в онлайновом режиме.

    Однако для достижения доступности выше 99,95% потребуется кластер. ПО Sun Cluster с переключением при отказе HA (High Availability — высокой доступности) обеспечивает доступность 99,975%. Переключение при отказе HA использует основной сервер и находящийся в горячем резерве; при отказе основного сервера резервный берет на себя его нагрузку. Время перезапуска сервиса зависит от приложений и может занять несколько минут, особенно в случае приложений баз данных, которым для восстановления транзакций требуется откат с обработкой большого объема данных.

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

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

    Для трехуровневой архитектуры хорошим примером горизонтальной высокой доступности служит развертывание Web-серверов. Можно развернуть много небольших серверов, на каждом из которых будет установлена отдельная копия ПО Web-сервера. Если один Web-сервер выйдет из строя, его транзакции перераспределяются между остальными работоспособными серверами. В случае серверов приложений они могут размещаться как на горизонтальных, так и на вертикальных серверах, и высокая доступность реализуется с помощью дублирования. Независимо от того, развертывается ли несколько крупных SMP-серверов или много небольших, дублирование остается основным способом обеспечения высокого RAS на уровне приложений.

    Однако для уровня баз данных ситуация меняется. Базы данных сохраняют состояние и по своей природе требуют в большинстве случаев разделения данных и возможности доступа к ним со всех процессоров/узлов. Это означает, что для высокой доступности с помощью дублирования нужно использовать такое ПО кластеризации, как Sun Cluster или Oracle9i RAC (для очень высокой доступности).

    Выводы

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

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

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

    Эта статья также доступна на следующих языках: Тайский

    NexxDigital — компьютеры и операционные системы

    Масштабируемая система. Горизонтальное и вертикальное масштабирование в летограф. Распределенная файловая система

    Итак вы сделали сайт. Всегда интересно и волнительно наблюдать как счетчик посещений медленно, но верно ползет вверх, с каждым днем показывая все лучшие результаты. Но однажды, когда вы этого не ждете, кто-то запостит ссылку на ваш ресурс на каком-нибудь Reddit или Hacker News (или на Хабре — прим. пер.), и ваш сервер ляжет.

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

    Немного про оптимизацию

    Основные советы всем известны: обновитесь до последней версии PHP (в 5.5 теперь встроен OpCache), разберитесь с индексами в базе данных, кэшируйте статику (редко изменяемые страницы, такие как “О нас”, “FAQ” и т.д.).

    Также стоит упомянуть об одном особом аспекте оптимизации — обслуживании статического контента не-Apache сервером, таким как, например, Nginx, Настройте Nginx на обработку всего статического контента (*.jpg, *.png, *.mp4, *.html…), а файлы требующие серверной обработки пусть отсылает тяжелому Apache. Это называется reverse proxy .

    Масштабирование

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

    Вертикальное масштабирование.

    Представьте себе сервер, обслуживающий веб-приложение. У него 4ГБ RAM, i5 процессор и 1ТБ HDD. Он отлично выполняет свои функции, но, что бы лучше справляться с более высоким трафиком, вы решаете увеличить RAM до 16ГБ, поставить процессор i7, и раскошелиться на SSD диск. Теперь сервер гораздо мощнее, и справляется с высокими нагрузками. Это и есть вертикальное масштабирование.

    Горизонтальное масштабирование.

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

    Есть два типа балансировщиков — аппаратные и программные. Программный — устанавливается на обычный сервер и принимает весь трафик, передавая его соответствующим обработчикам. Таким балансировщиком может быть, например, Nginx. В разделе “Оптимизация” он перехватывал все запросы на статические файлы, и обслуживал эти запросы сам, не обременяя Apache. Другое популярное ПО для реализации балансировки нагрузки — Squid . Лично я всегда использую именно его, т.к. он предоставляет отличный дружественный интерфейс, для контроля за самыми глубокими аспектами балансировки.

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

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

    Постоянное соединение

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

    Обмен локальными данными.

    Разделить данные сессии пользователей между всеми нодами кластера — кажется неплохой идеей. И несмотря на то, что этот подход требует некоторых изменений в архитектуре вашего приложения, оно того стоит — разгружается балансировщик, и весь кластер становится более отказоустойчивым. Смерть одного из серверов совершенно не отражается на работе всей системы.
    Как мы знаем, данные сессии хранятся в суперглобальном массиве $_SESSION , который пишет и берет данные с файла на диске. Если этот диск находится на одном сервере, очевидно, что другие сервера не имеют к нему доступа. Как же нам сделать его доступным на нескольких машинах?
    Во первых, обратите внимание, что обработчик сессий в PHP можно переопределить . Вы можете реализовать свой собственный класс для работы с сессиями .

    Использование БД для хранения сессий

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

    Распределенная файловая система

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

    Memcached

    Вы также можете использовать memcached для хранения данных сессий в RAM. Однако это не безопасно, ибо данные в memcached перезаписываются, если заканчивается свободное место. Вы, наверное, задаетесь вопросом, разве RAM не разделен по машинам? Как он применяется на весь кластер? Memcached имеет возможность объединять доступную на разных машинах RAM в один пул .

    Чем больше у вас машин, тем больше вы можете отвести в этот пул памяти. Вам не обязательно объединять всю память машин в пул, но вы можете, и вы можете пожертвовать в пул произвольное количество памяти с каждой машины. Так что, есть возможность оставить бо льшую часть памяти для обычного использования, и выделить кусок для кэша, что позволит кэшировать не только сессии, но другую подходящую информацию. Memcached — отличное и широко распространенное решение .

    Для использования этого подхода, нужно немного подредактировать php.ini

    Session.save_handler = memcache session.save_path = «tcp://path.to.memcached.server:port»

    Redis кластер

    Redis — NoSQL хранилище данных. Хранит базу в оперативной памяти. В отличие от memcached поддерживает постоянное хранение данных, и более сложные типы данных. Redis не поддерживает кластеризацию , так что использовать его для горизонтального масштабирования несколько затруднительно, однако, это временно, и уже вышла альфа версия кластерного решения .

    Другие решения

    Итого

    Как видите, горизонтальное масштабирование PHP приложений не такое уж простое дело. Существует много трудностей, большинство решений не взаимозаменяемые, так что приходится выбирать одно, и придерживаться его до конца, ведь когда трафик зашкаливает — уже нет возможности плавно перейти на что-то другое.

    Надеюсь этот небольшой гайд поможет вам выбрать подход к масштабированию для вашего проекта.

    Во второй части статьи мы поговорим о масштабировании базы данных .

    Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «Yii» — я один из его разработчиков. У меня также есть full-time работа — и это уже не стартап — Stay.com, который занимается путешествиями.

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

    Что такое масштабирование, вообще? Это возможность увеличить производительность проекта за минимальное время путем добавления ресурсов.

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

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

    Самый классный вопрос, который задают, — а зачем оно надо, если у меня все и на одном сервере прекрасно работает? На самом-то деле, надо проверить, что будет. Т.е., сейчас оно работает, но что будет потом? Есть две замечательные утилиты — ab и siege, которые как бы нагоняют тучу пользователей конкурента, которые начинают долбить сервер, пытаются запросить странички, послать какие-то запросы. Вы должны указать, что им делать, а утилиты формируют такие вот отчеты:

    Главные два параметра: n — количество запросов, которые надо сделать, с — количество одновременных запросов. Таким образом они проверяют конкурентность.

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

    Есть еще один параметр — Responce time — время ответа, за которое в среднем сервер отдал страничку. Оно бывает разное, но известно, что около 300 мс — это норма, а что выше — уже не очень хорошо, потому что эти 300 мс отрабатывает сервер, к этому прибавляются еще 300-600 мс, которые отрабатывает клиент, т.е. пока все загрузится — стили, картинки и остальное — тоже проходит время.

    Бывает, что на самом деле пока и не надо заботиться о масштабировании — идем на сервер, обновляем PHP, получаем 40% прироста производительности и все круто. Далее настраиваем Opcache, тюним его. Opcache, кстати, тюнится так же, как и APC, скриптом, который можно найти в репозитории у Расмуса Лердорфа и который показывает хиты и мисы, где хиты — это сколько раз PHP пошел в кэш, а мисы — сколько раз он пошел в файловую систему доставать файлики. Если прогнать весь сайт, либо запустить туда какой-то краулер по ссылкам, либо вручную потыкать, то у нас будет статистика по этим хитам и мисам. Если хитов 100%, а мисов — 0%, значит, все нормально, а если есть мисы, то надо выделить больше памяти, чтобы весь наш код влез в Opcache. Это частая ошибка, которую допускают — вроде Opcache есть, но что-то не работает…

    Еще часто начинают масштабировать, но не смотрят, вообще, из-за чего все работает медленно. Чаще всего лезем в базу, смотрим — индексов нет, ставим индексы — все сразу залетало, еще на 2 года хватит, красота!

    Ну, еще надо включить кэш, заменить apache на nginx и php-fpm, чтобы сэкономить память. Будет все классно.

    Все перечисленное достаточно просто и дает вам время. Время на то, что когда-то этого станет мало, и к этому уже сейчас надо готовиться.

    Как, вообще, понять, в чем проблема? Либо у вас уже настал highload, а это не обязательно какое-то бешеное число запросов и т.д., это, когда у вас проект не справляется с нагрузкой, и тривиальными способами это уже не решается. Надо расти либо вширь, либо вверх. Надо что-то делать и, скорее всего, на это мало времени, что-то надо придумывать.

    Первое правило — никогда ничего нельзя делать вслепую, т.е. нам нужен отличный мониторинг. Сначала мы выигрываем время на какой-то очевидной оптимизации типа включения кэша или кэширования Главной и т.п. Потом настраиваем мониторинг, он нам показывает, чего не хватает. И все это повторяется многократно – останавливать мониторинг и доработку никогда нельзя.

    Что может показать мониторинг? Мы можем упереться в диск, т.е. в файловую систему, в память, в процессор, в сеть… И может быть такое, что, вроде бы, все более-менее, но какие-то ошибки валятся. Все это разрешается по-разному. Можно проблему, допустим, с диском решить добавлением нового диска в тот же сервер, а можно поставить второй сервер, который будет заниматься только файлами.

    На что нужно обращать внимание прямо сейчас при мониторинге? Это:

    1. доступность, т.е. жив сервер, вообще, или нет;
    2. нехватка ресурсов диска, процессора и т.д.;
    3. ошибки.

    Как это все мониторить?

    Вот список замечательных инструментов, которые позволяют мониторить ресурсы и показывать результаты в очень удобном виде:

    Первые 4 инструмента можно поставить на сервер, они мощные, классные. А ServerDensity хостится у кого-то, т.е. мы за нее платим деньги, и она может собирать с серверов все данные и отображать их для анализа.

    Для мониторинга ошибок есть два хороших сервиса:

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

    Sentry можно поставить к себе на сервер, есть исходник, а Rollbar — нет, но Rollbar лучше, потому что он берет деньги за количество ошибок, т.е. стимулирует их исправлять.

    Про нотификации повторю, что спамить не стоит, теряется внимание.

    Что, вообще, надо анализировать?

    RPS и Responce time — если у нас начинает время ответа падать, то надо что-то делать.

    Количество процессов, потоков и размеры очередей — если это все начинает плодиться, забиваться и т.д., то что-то здесь опять не так, надо анализировать более детально и как-то менять инфраструктуру.

    Также стоит смотреть на бизнес-анализ. Google Analytics для сайтовых типов отлично подходит, а mixpanel — для логирования ивентов, он работает на десктопных приложениях, на мобильных, на веб. Можно и на основе каких-то своих данных писать, но я бы советовал готовые сервисы. Смысл в том, что наш мониторинг может показывать, что сервис жив, что все работает, что общий Responce time нормальный, но когда мы, допустим, регистрацию в mixpanel»е начинаем трекать, он показывает, что их как-то маловато. В этом случае надо смотреть, насколько быстро отрабатывают определенные ивенты, страницы, и в чем состоят проблемы. Проект всегда должен быть «обвешан» анализом, чтобы всегда знать, что происходит, а не работать вслепую.

    Нагрузка, вообще, возникает или запланировано, или нет, может возникать постепенно, может не постепенно:

    Как бороться с нагрузкой? Решает все бизнес, и важна только цена вопроса. Важно:

    1. чтобы сервис работал,
    2. чтобы это было не сильно дорого, не разорило компанию.

    Остальное не очень важно.

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

    На рисунке синяя штука — это Интернет, из которого идут запросы. Ставится балансировщик, единственная задача которого — распределить запросы на отдельные фронтенды-сервера, принять от них ответы и отдать клиенту. Смысл тут в том, что 3 сервера могут обработать (в идеале) в 3 раза больше запросов, исключая какие-то накладные расходы на сеть и на саму работу балансировщика.

    Что это нам дает? Указанную выше возможность обработать больше запросов, а еще надежность. Если в традиционной схеме валится nginx или приложение, или в диск уперлись и т.п., то все встало. Здесь же, если у нас один фронтенд отвалился, то ничего страшного, балансировщик, скорее всего, это поймет и отправит запросы на оставшиеся 2 сервера. Может, будет чуть помедленнее, но это не страшно.

    Вообще, PHP — штука отличная для масштабирования, потому что он следует принципу Share nothing по умолчанию. Это означает, что если мы возьмем, допустим, Java для веба, то там приложение запускается, читает весь код, записывает по максимуму данных в память программы, все там крутится, работает, на request уходит очень мало времени, очень мало дополнительных ресурсов. Однако есть засада — т.к. приложение написано так, что оно должно на одном инстансе работать, кэшироваться, читать из своей же памяти, то ничего хорошего у нас при масштабировании не получится. А в PHP по умолчанию ничего общего нет, и это хорошо. Все, что мы хотим сделать общим, мы это помещаем в memcaсhed, а memcaсhed можно читать с нескольких серверов, поэтому все замечательно. Т.е. достигается слабая связанность для слоя серверов приложений. Это прекрасно.

    Чем, вообще, балансировать нагрузку?

    Чаще всего это делали Squid»ом или HAProxy, но это раньше. Сейчас же автор nginx взял и партировал из nginx+ балансировщик в nginx, так что теперь он может делать все то, что раньше делали Squid»ом или HAProxy. Если оно начинает не выдерживать, можно поставить какой-нибудь крутой дорогой аппаратный балансировщик.

    Проблемы, которые решает балансировщик — это как выбрать сервер и как хранить сессии? Вторая проблема — чисто PHP»шная, а сервер может выбираться либо по очереди из списка, либо по географии каких-то IP»шников, либо по какой-то статистике (nginx поддерживает least-connected, т.е. к какому серверу меньше коннектов, на него он и будет перекидывать). Можем написать для балансировщика какой-то код, который будет выбирать, как ему работать.

    Что, если мы упремся в балансировщик?

    Есть такая штука как DNS Round robin — это замечательный трюк, который позволяет нам не тратиться на аппаратный балансировщик. Что мы делаем? Берем DNS-сервер (обычно DNS-сервера у себя никто не хостит, это дорого, несильно надежно, если он выйдет из строя, то ничего хорошего не получится, все пользуются какими-то компаниями), в А-записи прописываем не один сервер, а несколько. Это будут А-записи разных балансировщиков. Когда браузер туда идет (гарантий, на самом деле, нет, но все современные браузеры так действуют), он выбирает по очереди какой-нибудь IP-адрес из А-записей и попадает либо на один балансировщик, либо на второй. Нагрузка, конечно, может размазываться не равномерно, но, по крайней мере, она размазывается, и балансировщик может выдержать немного больше.

    Что делать с сессиями?

    Сессии у нас по умолчанию в файлах. Это не дело, потому что каждый из серверов-фронтендов у нас будет держать сессии в своей файловой системе, а пользователь может попадать то на один, то на второй, то на третий, т.е. сессии он будет каждый раз терять.

    Возникает очевидное желание сделать общую файловую систему, подключить NFS. Но делать так не надо — она до жути медленная.

    Можно записать в БД, но тоже не стоит, т.к. БД не оптимальна для этой работы, но если у вас нет другого выхода, то, в принципе, сойдет.

    Можно писать в memcached, но очень-очень осторожно, потому что memcached — это, все-таки, кэш и он имеет свойство вытираться, как только у него мало ресурсов, или некуда писать новые ключи — тогда он начинает терять старые без предупреждения, сессии начинают теряться. За этим надо либо следить, либо выбрать тот же Redis.

    Redis — нормальное решение. Смысл в том, что Redis у нас на отдельном сервере, и все наши фронтенды ломятся туда и начинают с Redis»а свои сессии считывать. Но Redis однопоточный и рано или поздно можем хорошенько упереться. Тогда делают sticky-сессии. Ставится тот же nginx и сообщается ему, что нужно сделать сессии так, чтобы юзер, когда он пришел на сервер и ему выдалась сессионная coockies, чтобы он впоследствии попадал только на этот сервер. Чаще всего это делают по IP-хэшу. Получается, что если Redis на каждом инстансе, соответственно, сессии там свои, и пропускная способность чтения-записи будет гораздо лучше.

    Как насчет coockies? Можно писать в coockies, никаких хранилищ не будет, все хорошо, но, во-первых, у нас все еще куда-то надо девать данные о сессии, а если мы начнем писать в coockies, она может разрастись и не влезть в хранилище, а, во-вторых, можно хранить в coockies только ID, и нам все равно придется обращаться к БД за какими-то сессионными данными. В принципе, это нормально, решает проблему.

    Есть классная штука — прокси для memcached и Redis:

    Они, вроде как, поддерживают распараллеливание из коробки, но делается это, я не сказал бы, что очень оптимально. А вот эта штука — twemproxy — она работает примерно как nginx с PHP, т.е. как только ответ получен, он сразу отправляет данные и в фоне закрывает соединение, получается быстрее, меньше ресурсов потребляет. Очень хорошая штука.

    Очень часто возникает такая ошибка «велосипедирования», когда начинают писать, типа «мне сессии не нужны! я сейчас сделаю замечательный токен, который будет туда-сюда передаваться»… Но, если подумать, то это опять же сессия.

    В PHP есть такой механизм как session handler, т.е. мы можем поставить свой handler и писать в coockies, в БД, в Redis — куда угодно, и все это будет работать со стандартными session start и т.д.

    Сессии надо закрывать вот этим замечательным методом.

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

    Что делать с файлами?

    С ними можно справляться двумя способами:

    1. какое-то специализированное решение, которое дает абстракцию, и мы работаем с файлами как с файловой системой. Это что-то вроде NFS, но NFS не надо.
    2. «шардирование» средствами PHP.


    Специализированные решения из того, что действительно работает, — это GlusterFS. Это то, что можно поставить себе. Оно работает, оно быстрое, дает тот же интерфейс, что NFS, только работает с нормальной терпимой скоростью.

    И Amazon S3 — это, если вы в облаке Amazon»а, — тоже хорошая файловая система.

    Если вы реализуете со стороны PHP, есть замечательная библиотека Flysystem, покрытая отличными тестами, ее можно использовать для работы со всякими файловыми системами, что очень удобно. Если вы сразу напишете всю работу с файлами с этой библиотекой, то потом перенести с локальной файловой системы на Amazon S3 или др. будет просто — в конфиге строчку переписать.

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

    Лучше всего раздавать файлы nginx»ом или Varnish»ем, но лучше все делать nginx»ом, т.к. мы все его любим и используем — он справится, он хороший.

    Что у нас происходит с базой данных?

    Если у вас все уперлось в код PHP, мы делаем кучу фронтендов и все еще обращаемся к одной БД — она справится достаточно долгое время. Если нагрузка не страшная, то БД живет хорошо. Например, мы делали JOIN»ы по 160 млн. строк в таблице, и все было замечательно, все бегало хорошо, но там, правда, оперативки надо больше выделить на буферы, на кэш…

    Что делать с БД, если мы уперлись в нее? Есть такие техники как репликация. Обычно делается репликация мастер-слэйв, есть репликация мастер-мастер. Можно делать репликацию вручную, можно делать шардирование и можно делать партицирование.

    Что такое мастер-слэйв?

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

    В случае типичного проекта большое количество слэйвов позволяет разгрузить как мастер, так и, вообще, увеличить скорость чтения.

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

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

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

    Есть такая штука как read/write split.Делается 2 пула серверов — мастер, слэйв, соединение по требованию, и логика выбора соединения варьируется. Смысл в том, что если мы будем всегда читать со слэйвов, а писать всегда в мастер, то будет небольшая засада:

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

    Есть два типа выборок:

    1. для чтения или для вывода;
    2. для записи, т.е., когда мы что-то выбрали и потом это что-то надо изменить и записать обратно.

    Если выборка для записи, то мы можем либо всегда читать с мастера и писать на мастер, либо мы можем выполнить «SHOW SLAVE STATUS» и посмотреть там Seconds_Behind_Master (для PostgreSQL тоже супер-запрос есть на картинке) — он покажет нам число. Если это 0 (нуль), значит, все у нас уже реплицировалось, можно смело читать со слэйва. Если число больше нуля, то надо смотреть значение — либо нам стоит подождать немного и тогда прочитать со слэйва, либо сразу читать с мастера. Если у нас NULL, значит еще не реплицировали, что-то застряло, и надо смотреть логи.

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

    Что такое мастер-мастер?

    Это ситуация, когда стоит несколько серверов, и везде и пишется, и читается. Плюс в том, что оно может быть быстрее, оно отказоустойчивое. В принципе, все то же, что и у слэйвов, но логика, вообще, простая — мы просто выбираем рандомное соединение и с ним работаем. Минусы: лаг репликации выше, есть шанс получить какие-то неконсистентные данные, и, если произошла какая-нибудь поломка, то она начинает раскидываться по всем мастерам, и никому уже неизвестно, какой мастер нормальный, какой поломался… Это все дело начинает реплицироваться по кругу, т.е. очень неслабо забивает сеть. Вообще, если пришлось делать мастер-мастер, надо 100 раз подумать. Скорее всего, можно обойтись мастер-слэйвом.

    Можно делать репликацию всегда руками, т.е. организовать пару соединений и писать сразу в 2, в 3, либо что-то делать в фоне.

    Что такое шардирование?

    Фактически это размазывание данных по нескольким серверам. Шардировать можно отдельные таблицы. Берем, допустим, таблицу фото, таблицу юзеров и др., растаскиваем их на отдельные сервера. Если таблицы были большие, то все становится меньше, памяти ест меньше, все хорошо, только нельзя JOIN»ить и приходится делать запросы типа WHERE IN, т.е. сначала выбираем кучу ID»шников, потом все эти ID»шники подставляем запросу, но уже к другому коннекту, к другому серверу.

    Можно шардировать часть одних и тех же данных, т.е., например, мы берем и делаем несколько БД с юзерами.

    Можно достаточно просто выбрать сервер — остаток от деления на количество серверов. Альтернатива — завести карту, т.е. для каждой записи держать в каком-нибудь Redis»е или т.п. ключ значения, т.е. где какая запись лежит.

    Есть вариант проще:

    Сложнее — это когда не удается сгруппировать данные. Надо знать ID данных, чтобы их достать. Никаких JOIN, ORDER и т.д. Фактически мы сводим наш MySQL или PostgreSQL к key-valuе хранилищу, потому что мы с ними ничего делать не можем.

    Обычные задачи становятся необычными:

    • Выбрать TOP 10.
    • Постраничная разбивка.
    • Выбрать с наименьшей стоимостью.
    • Выбрать посты юзера X.

    Если мы зашардировали так, что все разлетелось по всем серверам, это уже начинает решаться очень нетривиально. В этой ситуации возникает вопрос — а зачем нам, вообще SQL? Не писать ли нам в Redis сразу? А правильно ли мы выбрали хранилище?

    Из коробки шардинг поддерживается такими штуками как:

    • memcache;
    • Redis;
    • Cassandra (но она, говорят, с какого-то момента не справляется и начинает падать).

    Как быть со статистикой?

    Часто статистику любят считать с основного сервера — с единственного сервера БД. Это прекрасно, но запросы в статистике обычно жуткие, многостраничные и т.д., поэтому считать статистику по основным данным — это большая ошибка. Для статистики в большинстве случаев realtime не нужен, так что мы можем настроить мастер-слэйв репликацию и на слэйве эту статистику уже посчитать. Или мы можем взять что-нибудь готовое — Mixpanel, Google Analytics или подобное.

    Это основная идея, которая помогает раскидывать все по разным серверам и масштабировать. Во-первых, от этого сразу виден профит — даже если у вас один сервер и вы начинаете в фоне что-то выполнять, юзер получает ответ гораздо быстрее, но и впоследствии размазывать нагрузку, т.е. мы можем перетащить всю эту обработку на другой сервер, можно обрабатывать даже не на PHP. Например, в Stay.com картинки ресайзятся на Go.

    Можно сразу взять Gearman. Это готовая штука для обработки в фоне. Есть под PHP библиотеки, драйвера… А можно использовать очереди, т.е. ActiveMQ, RabbitMQ, но очереди пересылают только сообщения, сами обработчики они не вызывают, не выполняют, и тогда придется что-то придумывать.

    Общий смысл всегда один — есть основное ПО, которое помещает в очереди какие-то данные (обычно это «что сделать?» и данные для этого), и какой-то сервис – он либо достает, либо ему прилетают (если очередь умеет активно себя вести) эти данные, он все обрабатывает в фоне.

    Перейдем к архитектуре.

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

    Связанность бывает в коде. SOLID, GRASP — это принципы, которые позволяют избежать связанности именно в коде. Но связанность в коде на разнос по серверам, конечно, влияет, но не настолько, насколько связанность доменного слоя с нашим окружением. Если мы в контроллере пишем много-много кода, получается, что в другом месте мы это использовать, скорее всего, не сможем. Нам непросто будет все это переносить из веб-контроллера в консоль и, соответственно, сложнее переносить на другие сервера и там обрабатывать по-другому.

    Есть 2 подхода разбиения систем на части:

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

    Это хорошо, но когда эти очереди, изображения и т.п. взаимодействуют в рамках двух доменных областей… Например, в проекте есть область Sales и область Customer — это разные области, с ними работают разные пользователи, но и у тех, и у тех есть разные очереди. Когда все начинает сваливаться в кучу, проект превращается в месиво;

    правильное решение — бить на отдельные логические части, т.е. если в областях Sales и Customer используется модель user, то мы создаем 2 модели user. Они могут читать одни и те же данные, но представляют они их немного по-разному. Если разбить систему таким образом, то все гораздо лучше воспринимается и намного проще все это раскидать.

    Еще важно то, что части всегда должны взаимодействовать через интерфейсы. Так, в нашем примере, если Sales с чем-то взаимодействует, то он не пишет в БД, не использует общую модель, а с другими областями «разговаривает» через определенный контракт.

    Что с доменным слоем?

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

    Есть 2 книги про доменный слой, которые всем советую:

    • «Domain-Driven Design: Tackling Complexity in the Heart of Software» от Eric Evans,
    • «Implementing Domain-Driven Design, Implementing Domain-Driven Design».
    • про BoundedContext — https://martinfowler.com/bliki/BoundedContext.html (то, о чем было выше — если у вас две области вроде как пересекаются, но они
      разные, то стоит некоторые сущности продублировать, такие как модель user);
    • про DDD в общем — — ссылка еще на одну книгу.

    В архитектуре, опять же, стоит придерживаться принципа share nothing, т.е. если вы хотите что-то сделать общим, делайте это всегда сознательно. Логику предпочтительно закидывать на сторону приложения, но и в этом стоит знать меру. Никогда не стоит, допустим, делать хранимые процедуры в СУБД, потому что масштабировать это очень тяжело. Если это перенести на сторону приложения, то становится проще — сделаем несколько серверов и все будет выполняться там.

    Не стоит недооценивать браузерную оптимизацию. Как я уже говорил, из тех 300-600 мс, которые запросы выполняются на сервере, к ним прибавляется 300-600 мс, которые тратятся на клиенте. Клиенту все равно, сервер ли у нас быстрый, или это сайт так быстро отработал, поэтому советую использовать Google PageSpeed и т.д.

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

    Никогда не действуйте вслепую, всегда мониторьте, анализируйте. Вслепую практически все решения по умолчанию неправильные. Думайте! Не верьте, что существует «серебряная пуля», всегда проверяйте.

    Еще немного ссылок полезных:

    Контакты

    Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем за 2015 год.

    Старьё! — скажите вы.
    — Вечные ценности! — ответим мы.

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

    Ну и главная новость — мы начали подготовку весеннего фестиваля «Российские интернет-технологии «, в который входит восемь конференций, включая HighLoad++ Junior .

    Вертикальное масштабирование — scaling up — увеличение количества доступных для ПО ресурсов за счет увеличения мощности применяемых с серверов.

    — scaling out — увеличение количества нод, объединенных в кластер серверов при нехватке CPU, памяти или дискового пространства.

    И то и другое является инфраструктурными решениями, которые в разных ситуациях требуются когда веб проект растет.

    Вертикальное и горизонтальное масштабирование, scaling для web

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

    Возможности для масштабирования для серверов баз данных определяются применяемыми программными решениями: чаще всего это реляционные базы данных (MySQL, Postgresql) или NoSQL ( , Cassandra и др).

    Горизонтальное масштабирование для серверов баз данных при больших нагрузках значительно дешевле

    Веб-проект обычно начинают на одном сервере, ресурсы которого при росте заканчиваются. В такой ситуации возможны 2 варианта:

    • перенести сайт на более мощный сервер
    • добавить еще один сервер небольшой мощности с объединить машины в кластер

    MySQL является самой популярной RDBMS и, как и любая из них, требует для работы под нагрузкой много серверных ресурсов. Масштабирование возможно, в основном, вверх. Есть шардинг (для его настройки требуется вносить изменения в код) и , которая может быть сложной в поддержке.

    NoSQL масштабируется легко и второй вариант с, например, MongoDB будет значительно выгоднее материально, при этом не потребует трудозатратных настроек и поддержки получившегося решения. Шардинг осуществляется автоматически.

    Таким образом с MySQL нужен будет сервер с большим количеством CPU и оперативной памяти, такие сервера имеют значительную стоимость.

    Горизонтальное масштабирование
    С MongoDB можно добавить еще один средний сервер и полученное решение будет стабильно работать давая дополнительно отказоустойчивость.

    Scale-out или является закономерным этапом развития инфраструктуры. Любой сервер имеет ограничения и когда они достигнуты или когда стоимость более мощного сервера оказывается неоправданно высокой добавляются новые машины. Нагрузка распределяется между ними. Также это дает отказоустойчивость.

    Добавлять средние сервера и настраивать кластеры нужно начинать когда возможности для увеличения ресурсов одной машины исчерпаны или когда приобретение сервера мощнее оказывается невыгодно

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

    Читайте про и балансер

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

    Для начала имеет смысл определиться с тем, о чем мы вообще будем говорить. В данном контексте перед веб-приложением ставятся три основные цели:

    • масштабируемость — способность своевременно реагировать на непрерывный рост нагрузки и непредвиденные наплывы пользователей;
    • доступность — предоставление доступа к приложению даже в случае чрезвычайных обстоятельств;
    • производительность — даже малейшая задержка в загрузке страницы может оставить негативное впечатление у пользователя.

    Основной темой разговора будет, как не трудно догадаться, масштабируемость, но и остальные цели не думаю, что останутся в стороне. Сразу хочется сказать пару слов про доступность, чтобы не возвращаться к этому позднее, подразумевая как «само собой разумеется»: любой сайт так или иначе стремится к тому, чтобы функционировать максимально стабильно, то есть быть доступным абсолютно всем своим потенциальным посетителям в абсолютно каждый момент времени, но порой случаются всякие непредвиденные ситуации, которые могут стать причиной временной недоступности. Для минимизации потенциального ущерба доступности приложения необходимо избегать наличия компонентов в системе, потенциальный сбой в которых привел бы к недоступности какой-либо функциональности или данных (или хотябы сайта в целом). Таким образом каждый сервер или любой другой компонент системы должен иметь хотябы одного дублера (не важно в каком режиме они будут работать: параллельно или один «подстраховывает» другой, находясь при этом в пассивном режиме), а данные должны быть реплицированы как минимум в двух экземплярах (причем желательно не на уровне RAID, а на разных физических машинах). Хранение нескольких резервных копий данных где-то отдельно от основной системы (например на специальных сервисах или на отдельном кластере) также поможет избежать многих проблем, если что-то пойдет не так. Не стоит забывать и о финансовой стороне вопроса: подстраховка на случай сбоев требует дополнительных существенных вложений в оборудование, которые имеет смысл стараться минимизировать.

    Масштабируемость принято разделять на два направления:

    Вертикальная масштабируемость Увеличение производительности каждого компонента системы c целью повышения общей производительности. Горизонтальная масштабируемость Разбиение системы на более мелкие структурные компоненты и разнесение их по отдельным физическим машинам (или их группам) и/или увеличение количества серверов параллельно выполняющих одну и ту же функцию.

    Так или иначе, при разработке стратегии роста системы приходится искать компромис между ценой, временем разработки, итоговой производительность, стабильностью и еще массой других критериев. С финансовой точки зрения вертикальная масштабируемость является далеко не самым привлекательным решением, ведь цены на сервера с большим количеством процессоров всегда растут практически экспоненциально относительно количества процессоров. Именно по-этому наиболее интересен горизонтальный подход, так как именно он используется в большинстве случаев. Но и вертикальная масштабируемость порой имеет право на существование, особенно в ситуациях, когда основную роль играет время и скорость решения задачи, а не финансовый вопрос: ведь купить БОЛЬШОЙ сервер существенно быстрее, чем практически заново разрабатывать приложения, адаптируя его к работе на большом количестве параллельно работающих серверов.

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

    Серверы приложений

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

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

    Балансировка нагрузки

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

    Оборудование Сетевое оборудование, позволяющее распределять нагрузку между несколькими серверами, обычно стоит достаточно внушительные суммы, но среди прочих вариантов обычно именно этот подход предлагает наивысшую производительность и стабильность (в основном благодаря качеству, плюс такое оборудование иногда поставляется парами, работающими по принципу ). В этой индустрии достаточно много серьезных брендов, предлагающих свои решения — есть из чего выбрать: Cisco , Foundry , NetScalar и многие другие. Программное обеспечение В этой области еще большее разнообразие возможных вариантов. Получить программно производительность сопоставимую с аппаратными решениями не так-то просто, да и HeartBeat придется обеспечивать программно, но зато оборудование для функционирования такого решения представляет собой обычный сервер (возможно не один). Таких программных продуктов достаточно много, обычно они представляют собой просто HTTP-серверы, перенаправляющие запросы своим коллегам на других серверах вместо отправки напрямую на обработку интерпретатору языка программирования. Для примера можно упомянуть, скажем, с mod_proxy . Помимо этого имеют место более экзотические варианты, основанные на DNS, то есть в процессе определения клиентом IP-адреса сервера с необходимым ему интернет-ресурсов адрес выдается с учетом нагрузки на доступные сервера, а также некоторых географических соображений.

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

    Ресурсоемкие вычисления

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

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

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

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

    Сессии

    Практически все веб-приложения каким-либо образом взаимодействуют со своими посетителями и в подавляющем большинстве случаев в них присутствует необходимость отслеживать перемещения пользователей по страницам сайта. Для решения этой задачи обычно используется механизм сессий , который заключается в присвоении каждому посетителю уникального идентификационного номера, который ему передается для хранения в cookies или, в случае их отсутствия, для постоянного «таскания» за собой через GET. Получив от пользователя некий ID вместе с очередным HTTP-запросом сервер может посмотреть в список уже выданных номеров и однозначно определить кто его отправил. С каждым ID может ассоциироваться некий набор данных, который веб-приложение может использовать по своему усмотрению, эти данные обычно по-умолчанию хранятся в файле во временной директории на сервере.

    Казалось бы все просто, но. но запросы посетителей одного и того же сайта могут обрабатывать сразу несколько серверов, как же тогда определить не был ли выдан полученный ID на другом сервере и где вообще хранятся его данные?

    Наиболее распространенными решениями является централизация или децентрализация сессионных данных. Несколько абсурдная фраза, но, надеюсь, пара примеров сможет прояснить ситуацию:

    Централизованное хранение сессий Идея проста: создать для всех серверов общую «копилку», куда они смогут складывать выданные ими сессии и узнавать о сессиях посетителей других серверов. В роли такой «копилки» теоретически может выступать и просто примонтированная по сети файловая система, но по некоторым причинам более перспективным выглядит использование какой-либо СУБД, так как это избавляет от массы проблем, связанных с хранением сессионных данных в файлах. Но в варианте с общей базой данных не стоит забывать, что нагрузка на него будет неуклонно расти с ростом количества посетителей, а также стоит заранее предусмотреть варианты выхода из проблематичных ситуаций, связанных с потенциальными сбоями в работе сервера с этой СУБД. Децентрализованное хранение сессий Наглядный пример — хранение сессий в , изначально расчитанная на распределенное хранение данных в оперативной памяти система позволит получать всем серверам быстрый доступ к любым сессионным данным, но при этом (в отличии от предыдущего способа) какой-либо единый центр их хранения будет отсутствовать. Это позволит избежать узких мест с точек зрения производительности и стабильности в периоды повышенных нагрузок.


    В качестве альтернативы сессиям иногда используют похожие по предназначению механизмы, построенные на cookies, то есть все необходимые приложению данные о пользователе хранятся на клиентской стороне (вероятно в зашифрованном виде) и запрашиваются по мере необходимости. Но помимо очевидных преимуществ, связанных с отсутствием необходимости хранить лишние данные на сервере, возникает ряд проблем с безопасностью. Данные, хранимые на стороне клиента даже в зашифрованном виде, представляют собой потенциальную угрозу для функционирования многих приложений, так как любой желающий может попытаться модифицировать их в своих интересах или с целью навредить приложению. Такой подход хорош только если есть уверенность, что абсолютно любые манипуляции с хранимые у пользователей данными безопасны. Но можно ли быть уверенными на 100%?

    Статический контент

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

    Если статический контент играет одну из основных ролей в работе приложения, то стоит задуматься о применении распределенной файловой системы для его хранения. Это, пожалуй, один из немногих способов горизонтально масштабировать объем дискового пространства путем добавления дополнительных серверов без каких-либо кардинальных изменений в работе самого приложения. На какой именно кластерной файловой системе остановить свой выбор ничего сейчас советовать не хочу, я уже опубликовал далеко не один обзор конкретных реализаций — попробуйте прочитать их все и сравнить, если этого мало — вся остальная Сеть в Вашем распоряжении.

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

    Альтернативой этим подходам выступает использование так называемых Content Delievery Network — внешних сервисов, обеспечивающих доступность Вашего контента пользователям за определенное материальное вознаграждение сервису. Преимущество очевидно — нет необходимости организовывать собственную инфраструктуру для решения этой задачи, но зато появляется другая дополнительная статья расходов. Список таких сервисов приводить не буду, если кому-нибудь понадобится — найти будет не трудно.

    Кэширование

    Кэширование имеет смысл проводить на всех этапах обработки данных, но в разных типах приложений наиболее эффективными являются лишь некоторые методы кэширования.

    СУБД Практически все современные СУБД предоставляют встроенные механизмы для кэширования результатов определенных запросов. Этот метод достаточно эффективен, если Ваша система регулярно делает одни и те же выборки данных, но также имеет ряд недостатков, основными из которых является инвалидация кэша всей таблицы при малейшем ее изменении, а также локальное расположение кэша, что неэффективно при наличии нескольких серверов в системе хранения данных. Приложение На уровне приложений обычно производится кэширование объектов любого языка программирования. Этот метод позволяет вовсе избежать существенной части запросов к СУБД, сильно снижая нагрузку на нее. Как и сами приложения такой кэш должен быть независим от конкретного запроса и сервера, на котором он выполняется, то есть быть доступным всем серверам приложений одновременно, а еще лучше — быть распределенным по нескольким машинам для более эффективной утилизации оперативной памяти. Лидером в этом аспекте кэширования по праву можно назвать , о котором я в свое время уже успел . HTTP-сервер Многие веб-серверы имеют модули для кэширования как статического контента, так и результатов работы скриптов. Если страница редко обновляется, то использование этого метода позволяет без каких-либо видимых для пользователя изменений избегать генерации страницы в ответ на достаточно большую часть запросов. Reverse proxy Поставив между пользователем и веб-сервером прозрачный прокси-сервер, можно выдавать пользователю данные из кэша прокси (который может быть как в оперативной памяти, так и дисковым), не доводя запросы даже до HTTP-серверов. В большинстве случаев этот подход актуален только для статического контента, в основном разных форм медиа-данных: изображений, видео и тому подобного. Это позволяет веб-серверам сосредоточиться только на работе с самими страницами.

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

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

    Базы данных

    На закуску я оставил самое интересное, ведь этот неотъемлемый компонент любого веб-приложения вызывает больше проблем при росте нагрузок, чем все остальные вместе взятые. Порой даже может показаться, что стоит вообще отказаться от горизонтального масштабирования системы хранения данных в пользу вертикального — просто купить тот самый БОЛЬШОЙ сервер за шести- или семизначную сумму не-рублей и не забивать себе голову лишними проблемами.

    Но для многих проектов такое кардинальное решение (и то, по большому счету, временное) не подходит, а значит перед ними осталась лишь одна дорога — горизонтальное масштабирование. О ней и поговорим.

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

    Следующим шагом обычно бывает master-slave с асинхронной репликацией данных, как работает эта схема уже неоднократно упоминалось в блоге, но, пожалуй, повторюсь: при таком подходе все операции записи выполняются лишь на одном сервере (master), а остальные сервера (slave) получают данные напрямую от «мастера», обрабатывая при этом лишь запросы на чтение данных. Как известно, операции чтения и записи любого веб-проекта всегда растут пропорционально росту нагрузки, при этом сохраняется почти фиксированным соотношение между обоими типами запросов: на каждый запрос на обновление данных обычно приходится в среднем около десятка запросов на чтение. Со временем нагрузка растет, а значит растет и количество операций записи в единицу времени, а сервер-то обрабатывает их всего один, а затем он же еще и обеспечивает создание некоторого количества копий на других серверах. Рано или поздно издержки операций репликации данных станут быть настолько высоки, что этот процесс станет занимать очень большую часть процессорного времени каждого сервера, а каждый slave сможет обрабатывать лишь сравнительно небольшое количество операций чтения, и, как следствие, каждый дополнительный slave-сервер начнет увеличивать суммарную производительность лишь незначительно, тоже занимаясь по большей части лишь поддержанием своих данных в соответствии с «мастером».

    Временным решением этой проблемы, возможно, может стать замена master-сервера на более производительный, но так или иначе не выйдет бесконечно откладывать переход на следующий «уровень» развития системы хранения данных: «sharding» , которому я совсем недавно посвятил . Так что позволю себе остановиться на нем лишь вкратце: идея заключается в том, чтобы разделить все данные на части по какому-либо признаку и хранить каждую часть на отдельном сервере или кластере, такую часть данных в совокупности с системой хранения данных, в которой она находится, и называют сегментом или shard ’ом. Такой подход позволяет избежать издержек, связанных с реплицированием данных (или сократить их во много раз), а значит и существенно увеличить общую производительность системы хранения данных. Но, к сожалению, переход к этой схеме организации данных требует массу издержек другого рода. Так как готового решения для ее реализации не существует, приходится модифицировать логику приложения или добавлять дополнительную «прослойку» между приложением и СУБД, причем все это чаще всего реализуется силами разработчиков проекта. Готовые продукты способны лишь облегчить их работу, предоставив некий каркас для построения основной архитектуры системы хранения данных и ее взаимодействия с остальными компонентами приложения.

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

    Денормализация Запросы, комбинирующие данные из нескольких таблиц, обычно при прочих равных требуют большего процессорного времени для выполнения, чем запрос, затрагивающий лишь одну таблицу. А производительность, как уже упоминалось в начале повествования, чрезвычайно важна на просторах Сети. Логическое разбиение данных Если какая-то часть данных всегда используется отдельно от основной массы, то иногда имеет смысл выделить ее в отдельную независимую систему хранения данных. Низкоуровневая оптимизация запросов Ведя и анализируя логи запросов, можно определить наиболее медленные из них. Замена найденных запросов на более эффективные с той же функциональностью может помочь более рационально использовать вычислительные мощности.

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

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

    Map Основной целью данного этапа является представление произвольных входных данных в виде промежуточных пар ключ-значение, имеющих определенный смысл и формально оформленных. Результаты подвергаются сортировке и группированию по ключу, а после чего передаются на следующий этап. Reduce Полученные после map значения используются для финального вычисления требуемых итоговых данных.

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

    Примером готового каркаса для реализации работы с данными по такому принципу служит opensource проект Apache Foundation под названием , о котором я уже неоднократно рассказывал ранее, да и написал в свое время.

    Вместо заключения

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

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

    Систем, программных комплексов , систем баз данных , маршрутизаторов , сетей и т. п., если для них требуется возможность работать под большой нагрузкой. Система называется масштабируемой , если она способна увеличивать производительность пропорционально дополнительным ресурсам. Масштабируемость можно оценить через отношение прироста производительности системы к приросту используемых ресурсов. Чем ближе это отношение к единице, тем лучше. Также под масштабируемостью понимается возможность наращивания дополнительных ресурсов без структурных изменений центрального узла системы.

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

    Вертикальное масштабирование

    Увеличение производительности каждого компонента системы c целью повышения общей производительности.

    Горизонтальное масштабирование

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

    Горизонтальное масштабирование PHP-приложений. Масштабируемость системы

    Итак вы сделали сайт. Всегда интересно и волнительно наблюдать как счетчик посещений медленно, но верно ползет вверх, с каждым днем показывая все лучшие результаты. Но однажды, когда вы этого не ждете, кто-то запостит ссылку на ваш ресурс на каком-нибудь Reddit или Hacker News (или на Хабре — прим. пер.), и ваш сервер ляжет.

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

    Немного про оптимизацию

    Основные советы всем известны: обновитесь до последней версии PHP (в 5.5 теперь встроен OpCache), разберитесь с индексами в базе данных, кэшируйте статику (редко изменяемые страницы, такие как “О нас”, “FAQ” и т.д.).

    Также стоит упомянуть об одном особом аспекте оптимизации — обслуживании статического контента не-Apache сервером, таким как, например, Nginx, Настройте Nginx на обработку всего статического контента (*.jpg, *.png, *.mp4, *.html…), а файлы требующие серверной обработки пусть отсылает тяжелому Apache. Это называется reverse proxy .

    Масштабирование

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

    Вертикальное масштабирование.

    Представьте себе сервер, обслуживающий веб-приложение. У него 4ГБ RAM, i5 процессор и 1ТБ HDD. Он отлично выполняет свои функции, но, что бы лучше справляться с более высоким трафиком, вы решаете увеличить RAM до 16ГБ, поставить процессор i7, и раскошелиться на SSD диск. Теперь сервер гораздо мощнее, и справляется с высокими нагрузками. Это и есть вертикальное масштабирование.

    Горизонтальное масштабирование.

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

    Есть два типа балансировщиков — аппаратные и программные. Программный — устанавливается на обычный сервер и принимает весь трафик, передавая его соответствующим обработчикам. Таким балансировщиком может быть, например, Nginx. В разделе “Оптимизация” он перехватывал все запросы на статические файлы, и обслуживал эти запросы сам, не обременяя Apache. Другое популярное ПО для реализации балансировки нагрузки — Squid . Лично я всегда использую именно его, т.к. он предоставляет отличный дружественный интерфейс, для контроля за самыми глубокими аспектами балансировки.

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

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

    Постоянное соединение

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

    Обмен локальными данными.

    Разделить данные сессии пользователей между всеми нодами кластера — кажется неплохой идеей. И несмотря на то, что этот подход требует некоторых изменений в архитектуре вашего приложения, оно того стоит — разгружается балансировщик, и весь кластер становится более отказоустойчивым. Смерть одного из серверов совершенно не отражается на работе всей системы.
    Как мы знаем, данные сессии хранятся в суперглобальном массиве $_SESSION , который пишет и берет данные с файла на диске. Если этот диск находится на одном сервере, очевидно, что другие сервера не имеют к нему доступа. Как же нам сделать его доступным на нескольких машинах?
    Во первых, обратите внимание, что обработчик сессий в PHP можно переопределить . Вы можете реализовать свой собственный класс для работы с сессиями .

    Использование БД для хранения сессий

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

    Распределенная файловая система

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

    Memcached

    Вы также можете использовать memcached для хранения данных сессий в RAM. Однако это не безопасно, ибо данные в memcached перезаписываются, если заканчивается свободное место. Вы, наверное, задаетесь вопросом, разве RAM не разделен по машинам? Как он применяется на весь кластер? Memcached имеет возможность объединять доступную на разных машинах RAM в один пул .

    Чем больше у вас машин, тем больше вы можете отвести в этот пул памяти. Вам не обязательно объединять всю память машин в пул, но вы можете, и вы можете пожертвовать в пул произвольное количество памяти с каждой машины. Так что, есть возможность оставить бо льшую часть памяти для обычного использования, и выделить кусок для кэша, что позволит кэшировать не только сессии, но другую подходящую информацию. Memcached — отличное и широко распространенное решение .

    Для использования этого подхода, нужно немного подредактировать php.ini

    Session.save_handler = memcache session.save_path = «tcp://path.to.memcached.server:port»

    Redis кластер

    Redis — NoSQL хранилище данных. Хранит базу в оперативной памяти. В отличие от memcached поддерживает постоянное хранение данных, и более сложные типы данных. Redis не поддерживает кластеризацию , так что использовать его для горизонтального масштабирования несколько затруднительно, однако, это временно, и уже вышла альфа версия кластерного решения .

    Другие решения

    Итого

    Как видите, горизонтальное масштабирование PHP приложений не такое уж простое дело. Существует много трудностей, большинство решений не взаимозаменяемые, так что приходится выбирать одно, и придерживаться его до конца, ведь когда трафик зашкаливает — уже нет возможности плавно перейти на что-то другое.

    Надеюсь этот небольшой гайд поможет вам выбрать подход к масштабированию для вашего проекта.

    Во второй части статьи мы поговорим о масштабировании базы данных .

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

    Для начала имеет смысл определиться с тем, о чем мы вообще будем говорить. В данном контексте перед веб-приложением ставятся три основные цели:

    • масштабируемость — способность своевременно реагировать на непрерывный рост нагрузки и непредвиденные наплывы пользователей;
    • доступность — предоставление доступа к приложению даже в случае чрезвычайных обстоятельств;
    • производительность — даже малейшая задержка в загрузке страницы может оставить негативное впечатление у пользователя.

    Основной темой разговора будет, как не трудно догадаться, масштабируемость, но и остальные цели не думаю, что останутся в стороне. Сразу хочется сказать пару слов про доступность, чтобы не возвращаться к этому позднее, подразумевая как «само собой разумеется»: любой сайт так или иначе стремится к тому, чтобы функционировать максимально стабильно, то есть быть доступным абсолютно всем своим потенциальным посетителям в абсолютно каждый момент времени, но порой случаются всякие непредвиденные ситуации, которые могут стать причиной временной недоступности. Для минимизации потенциального ущерба доступности приложения необходимо избегать наличия компонентов в системе, потенциальный сбой в которых привел бы к недоступности какой-либо функциональности или данных (или хотябы сайта в целом). Таким образом каждый сервер или любой другой компонент системы должен иметь хотябы одного дублера (не важно в каком режиме они будут работать: параллельно или один «подстраховывает» другой, находясь при этом в пассивном режиме), а данные должны быть реплицированы как минимум в двух экземплярах (причем желательно не на уровне RAID, а на разных физических машинах). Хранение нескольких резервных копий данных где-то отдельно от основной системы (например на специальных сервисах или на отдельном кластере) также поможет избежать многих проблем, если что-то пойдет не так. Не стоит забывать и о финансовой стороне вопроса: подстраховка на случай сбоев требует дополнительных существенных вложений в оборудование, которые имеет смысл стараться минимизировать.

    Масштабируемость принято разделять на два направления:

    Вертикальная масштабируемость Увеличение производительности каждого компонента системы c целью повышения общей производительности. Горизонтальная масштабируемость Разбиение системы на более мелкие структурные компоненты и разнесение их по отдельным физическим машинам (или их группам) и/или увеличение количества серверов параллельно выполняющих одну и ту же функцию.

    Так или иначе, при разработке стратегии роста системы приходится искать компромис между ценой, временем разработки, итоговой производительность, стабильностью и еще массой других критериев. С финансовой точки зрения вертикальная масштабируемость является далеко не самым привлекательным решением, ведь цены на сервера с большим количеством процессоров всегда растут практически экспоненциально относительно количества процессоров. Именно по-этому наиболее интересен горизонтальный подход, так как именно он используется в большинстве случаев. Но и вертикальная масштабируемость порой имеет право на существование, особенно в ситуациях, когда основную роль играет время и скорость решения задачи, а не финансовый вопрос: ведь купить БОЛЬШОЙ сервер существенно быстрее, чем практически заново разрабатывать приложения, адаптируя его к работе на большом количестве параллельно работающих серверов.

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

    Серверы приложений

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

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

    Балансировка нагрузки

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

    Оборудование Сетевое оборудование, позволяющее распределять нагрузку между несколькими серверами, обычно стоит достаточно внушительные суммы, но среди прочих вариантов обычно именно этот подход предлагает наивысшую производительность и стабильность (в основном благодаря качеству, плюс такое оборудование иногда поставляется парами, работающими по принципу ). В этой индустрии достаточно много серьезных брендов, предлагающих свои решения — есть из чего выбрать: Cisco , Foundry , NetScalar и многие другие. Программное обеспечение В этой области еще большее разнообразие возможных вариантов. Получить программно производительность сопоставимую с аппаратными решениями не так-то просто, да и HeartBeat придется обеспечивать программно, но зато оборудование для функционирования такого решения представляет собой обычный сервер (возможно не один). Таких программных продуктов достаточно много, обычно они представляют собой просто HTTP-серверы, перенаправляющие запросы своим коллегам на других серверах вместо отправки напрямую на обработку интерпретатору языка программирования. Для примера можно упомянуть, скажем, с mod_proxy . Помимо этого имеют место более экзотические варианты, основанные на DNS, то есть в процессе определения клиентом IP-адреса сервера с необходимым ему интернет-ресурсов адрес выдается с учетом нагрузки на доступные сервера, а также некоторых географических соображений.

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

    Ресурсоемкие вычисления

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

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

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

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

    Сессии

    Практически все веб-приложения каким-либо образом взаимодействуют со своими посетителями и в подавляющем большинстве случаев в них присутствует необходимость отслеживать перемещения пользователей по страницам сайта. Для решения этой задачи обычно используется механизм сессий , который заключается в присвоении каждому посетителю уникального идентификационного номера, который ему передается для хранения в cookies или, в случае их отсутствия, для постоянного «таскания» за собой через GET. Получив от пользователя некий ID вместе с очередным HTTP-запросом сервер может посмотреть в список уже выданных номеров и однозначно определить кто его отправил. С каждым ID может ассоциироваться некий набор данных, который веб-приложение может использовать по своему усмотрению, эти данные обычно по-умолчанию хранятся в файле во временной директории на сервере.

    Казалось бы все просто, но. но запросы посетителей одного и того же сайта могут обрабатывать сразу несколько серверов, как же тогда определить не был ли выдан полученный ID на другом сервере и где вообще хранятся его данные?

    Наиболее распространенными решениями является централизация или децентрализация сессионных данных. Несколько абсурдная фраза, но, надеюсь, пара примеров сможет прояснить ситуацию:

    Централизованное хранение сессий Идея проста: создать для всех серверов общую «копилку», куда они смогут складывать выданные ими сессии и узнавать о сессиях посетителей других серверов. В роли такой «копилки» теоретически может выступать и просто примонтированная по сети файловая система, но по некоторым причинам более перспективным выглядит использование какой-либо СУБД, так как это избавляет от массы проблем, связанных с хранением сессионных данных в файлах. Но в варианте с общей базой данных не стоит забывать, что нагрузка на него будет неуклонно расти с ростом количества посетителей, а также стоит заранее предусмотреть варианты выхода из проблематичных ситуаций, связанных с потенциальными сбоями в работе сервера с этой СУБД. Децентрализованное хранение сессий Наглядный пример — хранение сессий в , изначально расчитанная на распределенное хранение данных в оперативной памяти система позволит получать всем серверам быстрый доступ к любым сессионным данным, но при этом (в отличии от предыдущего способа) какой-либо единый центр их хранения будет отсутствовать. Это позволит избежать узких мест с точек зрения производительности и стабильности в периоды повышенных нагрузок.

    В качестве альтернативы сессиям иногда используют похожие по предназначению механизмы, построенные на cookies, то есть все необходимые приложению данные о пользователе хранятся на клиентской стороне (вероятно в зашифрованном виде) и запрашиваются по мере необходимости. Но помимо очевидных преимуществ, связанных с отсутствием необходимости хранить лишние данные на сервере, возникает ряд проблем с безопасностью. Данные, хранимые на стороне клиента даже в зашифрованном виде, представляют собой потенциальную угрозу для функционирования многих приложений, так как любой желающий может попытаться модифицировать их в своих интересах или с целью навредить приложению. Такой подход хорош только если есть уверенность, что абсолютно любые манипуляции с хранимые у пользователей данными безопасны. Но можно ли быть уверенными на 100%?

    Статический контент

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

    Если статический контент играет одну из основных ролей в работе приложения, то стоит задуматься о применении распределенной файловой системы для его хранения. Это, пожалуй, один из немногих способов горизонтально масштабировать объем дискового пространства путем добавления дополнительных серверов без каких-либо кардинальных изменений в работе самого приложения. На какой именно кластерной файловой системе остановить свой выбор ничего сейчас советовать не хочу, я уже опубликовал далеко не один обзор конкретных реализаций — попробуйте прочитать их все и сравнить, если этого мало — вся остальная Сеть в Вашем распоряжении.

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

    Альтернативой этим подходам выступает использование так называемых Content Delievery Network — внешних сервисов, обеспечивающих доступность Вашего контента пользователям за определенное материальное вознаграждение сервису. Преимущество очевидно — нет необходимости организовывать собственную инфраструктуру для решения этой задачи, но зато появляется другая дополнительная статья расходов. Список таких сервисов приводить не буду, если кому-нибудь понадобится — найти будет не трудно.

    Кэширование

    Кэширование имеет смысл проводить на всех этапах обработки данных, но в разных типах приложений наиболее эффективными являются лишь некоторые методы кэширования.

    СУБД Практически все современные СУБД предоставляют встроенные механизмы для кэширования результатов определенных запросов. Этот метод достаточно эффективен, если Ваша система регулярно делает одни и те же выборки данных, но также имеет ряд недостатков, основными из которых является инвалидация кэша всей таблицы при малейшем ее изменении, а также локальное расположение кэша, что неэффективно при наличии нескольких серверов в системе хранения данных. Приложение На уровне приложений обычно производится кэширование объектов любого языка программирования. Этот метод позволяет вовсе избежать существенной части запросов к СУБД, сильно снижая нагрузку на нее. Как и сами приложения такой кэш должен быть независим от конкретного запроса и сервера, на котором он выполняется, то есть быть доступным всем серверам приложений одновременно, а еще лучше — быть распределенным по нескольким машинам для более эффективной утилизации оперативной памяти. Лидером в этом аспекте кэширования по праву можно назвать , о котором я в свое время уже успел . HTTP-сервер Многие веб-серверы имеют модули для кэширования как статического контента, так и результатов работы скриптов. Если страница редко обновляется, то использование этого метода позволяет без каких-либо видимых для пользователя изменений избегать генерации страницы в ответ на достаточно большую часть запросов. Reverse proxy Поставив между пользователем и веб-сервером прозрачный прокси-сервер, можно выдавать пользователю данные из кэша прокси (который может быть как в оперативной памяти, так и дисковым), не доводя запросы даже до HTTP-серверов. В большинстве случаев этот подход актуален только для статического контента, в основном разных форм медиа-данных: изображений, видео и тому подобного. Это позволяет веб-серверам сосредоточиться только на работе с самими страницами.

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

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

    Базы данных

    На закуску я оставил самое интересное, ведь этот неотъемлемый компонент любого веб-приложения вызывает больше проблем при росте нагрузок, чем все остальные вместе взятые. Порой даже может показаться, что стоит вообще отказаться от горизонтального масштабирования системы хранения данных в пользу вертикального — просто купить тот самый БОЛЬШОЙ сервер за шести- или семизначную сумму не-рублей и не забивать себе голову лишними проблемами.

    Но для многих проектов такое кардинальное решение (и то, по большому счету, временное) не подходит, а значит перед ними осталась лишь одна дорога — горизонтальное масштабирование. О ней и поговорим.

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

    Следующим шагом обычно бывает master-slave с асинхронной репликацией данных, как работает эта схема уже неоднократно упоминалось в блоге, но, пожалуй, повторюсь: при таком подходе все операции записи выполняются лишь на одном сервере (master), а остальные сервера (slave) получают данные напрямую от «мастера», обрабатывая при этом лишь запросы на чтение данных. Как известно, операции чтения и записи любого веб-проекта всегда растут пропорционально росту нагрузки, при этом сохраняется почти фиксированным соотношение между обоими типами запросов: на каждый запрос на обновление данных обычно приходится в среднем около десятка запросов на чтение. Со временем нагрузка растет, а значит растет и количество операций записи в единицу времени, а сервер-то обрабатывает их всего один, а затем он же еще и обеспечивает создание некоторого количества копий на других серверах. Рано или поздно издержки операций репликации данных станут быть настолько высоки, что этот процесс станет занимать очень большую часть процессорного времени каждого сервера, а каждый slave сможет обрабатывать лишь сравнительно небольшое количество операций чтения, и, как следствие, каждый дополнительный slave-сервер начнет увеличивать суммарную производительность лишь незначительно, тоже занимаясь по большей части лишь поддержанием своих данных в соответствии с «мастером».

    Временным решением этой проблемы, возможно, может стать замена master-сервера на более производительный, но так или иначе не выйдет бесконечно откладывать переход на следующий «уровень» развития системы хранения данных: «sharding» , которому я совсем недавно посвятил . Так что позволю себе остановиться на нем лишь вкратце: идея заключается в том, чтобы разделить все данные на части по какому-либо признаку и хранить каждую часть на отдельном сервере или кластере, такую часть данных в совокупности с системой хранения данных, в которой она находится, и называют сегментом или shard ’ом. Такой подход позволяет избежать издержек, связанных с реплицированием данных (или сократить их во много раз), а значит и существенно увеличить общую производительность системы хранения данных. Но, к сожалению, переход к этой схеме организации данных требует массу издержек другого рода. Так как готового решения для ее реализации не существует, приходится модифицировать логику приложения или добавлять дополнительную «прослойку» между приложением и СУБД, причем все это чаще всего реализуется силами разработчиков проекта. Готовые продукты способны лишь облегчить их работу, предоставив некий каркас для построения основной архитектуры системы хранения данных и ее взаимодействия с остальными компонентами приложения.

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

    Денормализация Запросы, комбинирующие данные из нескольких таблиц, обычно при прочих равных требуют большего процессорного времени для выполнения, чем запрос, затрагивающий лишь одну таблицу. А производительность, как уже упоминалось в начале повествования, чрезвычайно важна на просторах Сети. Логическое разбиение данных Если какая-то часть данных всегда используется отдельно от основной массы, то иногда имеет смысл выделить ее в отдельную независимую систему хранения данных. Низкоуровневая оптимизация запросов Ведя и анализируя логи запросов, можно определить наиболее медленные из них. Замена найденных запросов на более эффективные с той же функциональностью может помочь более рационально использовать вычислительные мощности.

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


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

    Map Основной целью данного этапа является представление произвольных входных данных в виде промежуточных пар ключ-значение, имеющих определенный смысл и формально оформленных. Результаты подвергаются сортировке и группированию по ключу, а после чего передаются на следующий этап. Reduce Полученные после map значения используются для финального вычисления требуемых итоговых данных.

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

    Примером готового каркаса для реализации работы с данными по такому принципу служит opensource проект Apache Foundation под названием , о котором я уже неоднократно рассказывал ранее, да и написал в свое время.

    Вместо заключения

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

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

    ) Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «Yii» — я один из его разработчиков. У меня также есть full-time работа — и это уже не стартап — Stay.com, который занимается путешествиями.

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

    Что такое масштабирование, вообще? Это возможность увеличить производительность проекта за минимальное время путем добавления ресурсов.

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

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

    Самый классный вопрос, который задают, — а зачем оно надо, если у меня все и на одном сервере прекрасно работает? На самом-то деле, надо проверить, что будет. Т.е., сейчас оно работает, но что будет потом? Есть две замечательные утилиты — ab и siege, которые как бы нагоняют тучу пользователей конкурента, которые начинают долбить сервер, пытаются запросить странички, послать какие-то запросы. Вы должны указать, что им делать, а утилиты формируют такие вот отчеты:

    Главные два параметра: n — количество запросов, которые надо сделать, с — количество одновременных запросов. Таким образом они проверяют конкурентность.

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

    Есть еще один параметр — Response time — время ответа, за которое в среднем сервер отдал страничку. Оно бывает разное, но известно, что около 300 мс — это норма, а что выше — уже не очень хорошо, потому что эти 300 мс отрабатывает сервер, к этому прибавляются еще 300-600 мс, которые отрабатывает клиент, т.е. пока все загрузится — стили, картинки и остальное — тоже проходит время.

    Бывает, что на самом деле пока и не надо заботиться о масштабировании — идем на сервер, обновляем PHP, получаем 40% прироста производительности и все круто. Далее настраиваем Opcache, тюним его. Opcache, кстати, тюнится так же, как и APC, скриптом, который можно найти в репозитории у Расмуса Лердорфа и который показывает хиты и мисы, где хиты — это сколько раз PHP пошел в кэш, а мисы — сколько раз он пошел в файловую систему доставать файлики. Если прогнать весь сайт, либо запустить туда какой-то краулер по ссылкам, либо вручную потыкать, то у нас будет статистика по этим хитам и мисам. Если хитов 100%, а мисов — 0%, значит, все нормально, а если есть мисы, то надо выделить больше памяти, чтобы весь наш код влез в Opcache. Это частая ошибка, которую допускают — вроде Opcache есть, но что-то не работает…

    Еще часто начинают масштабировать, но не смотрят, вообще, из-за чего все работает медленно. Чаще всего лезем в базу, смотрим — индексов нет, ставим индексы — все сразу залетало, еще на 2 года хватит, красота!

    Ну, еще надо включить кэш, заменить apache на nginx и php-fpm, чтобы сэкономить память. Будет все классно.

    Все перечисленное достаточно просто и дает вам время. Время на то, что когда-то этого станет мало, и к этому уже сейчас надо готовиться.

    Как, вообще, понять, в чем проблема? Либо у вас уже настал highload, а это не обязательно какое-то бешеное число запросов и т.д., это, когда у вас проект не справляется с нагрузкой, и тривиальными способами это уже не решается. Надо расти либо вширь, либо вверх. Надо что-то делать и, скорее всего, на это мало времени, что-то надо придумывать.

    Первое правило — никогда ничего нельзя делать вслепую, т.е. нам нужен отличный мониторинг. Сначала мы выигрываем время на какой-то очевидной оптимизации типа включения кэша или кэширования Главной и т.п. Потом настраиваем мониторинг, он нам показывает, чего не хватает. И все это повторяется многократно – останавливать мониторинг и доработку никогда нельзя.

    Что может показать мониторинг? Мы можем упереться в диск, т.е. в файловую систему, в память, в процессор, в сеть… И может быть такое, что, вроде бы, все более-менее, но какие-то ошибки валятся. Все это разрешается по-разному. Можно проблему, допустим, с диском решить добавлением нового диска в тот же сервер, а можно поставить второй сервер, который будет заниматься только файлами.

    На что нужно обращать внимание прямо сейчас при мониторинге? Это:

    1. доступность, т.е. жив сервер, вообще, или нет;
    2. нехватка ресурсов диска, процессора и т.д.;
    3. ошибки.

    Как это все мониторить?

    Вот список замечательных инструментов, которые позволяют мониторить ресурсы и показывать результаты в очень удобном виде:

    Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем за 2015 год.

    Старьё! — скажите вы.
    — Вечные ценности! — ответим мы.

    highload junior Добавить метки

    С ростом популярности web-приложения его поддержка неизбежно начинает требовать всё больших и больших ресурсов. Первое время с нагрузкой можно (и, несомненно, нужно) бороться путём оптимизации алгоритмов и/или архитектуры самого приложения. Однако, что делать, если всё, что можно было оптимизировать, уже оптимизировано, а приложение всё равно не справляется с нагрузкой?

    Оптимизация

    Масштабирование

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

    Архитектура приложения

    Каждый их этих слоёв может быть масштабирован. Поэтому если в вашей системе приложение и БД живут на одном хосте – первым шагом, несомненно, должно стать разнесение их по разным хостам.

    Узкое место

    Обычно всё зависит от архитектуры приложения, но наиболее вероятными кандидатами на «узкое место» в общем случае являются БД и код. Если ваше приложение работает с большим объёмом пользовательских данных, то «узким местом», соответственно, скорее всего будет хранение статики.

    Масштабирование БД

    Снизить нагрузку на БД можно разнеся её на несколько хостов. При этом остро встаёт проблема синхронизации между ними, решить которую можно путём реализации схемы master/slave с синхронной или асинхронной репликацией. В случае с PostgreSQL реализовать синхронную репликацию можно с помощью Slony-I , асинхронную – PgPool-II или WAL (9.0). Решить проблему разделения запросов чтения и записи, а так же балансировки нагрузку между имеющимися slave’ами, можно с помощью настройки специального слоя доступа к БД (PgPool-II).

    Проблему хранения большого объёма данных в случае использования реляционных СУБД можно решить с помощью механизма партицирования (“partitioning” в PostgreSQL), либо разворачивая БД на распределённых ФС типа Hadoop DFS .

    Однако, для хранения больших объёмов данных лучшим решением будет «шардинг » (sharding) данных, который является встроенным преимуществом большинства NoSQL БД (например, MongoDB).

    Кроме того, NoSQL БД в общем работают быстрее своих SQL-братьев за счёт отсутствия overhead’а на разбор/оптимизацию запроса, проверки целостности структуры данных и т.д. Тема сравнения реляционных и NoSQL БД так же довольно обширна и заслуживает .

    Отдельно стоит отметить опыт Facebook, который используют MySQL без JOIN-выборок. Такая стратегия позволяет им значительно легче масштабировать БД, перенося при этом нагрузку с БД на код, который, как будет описано ниже, масштабируется проще БД.

    Масштабирование кода

    Далее необходимо настроить балансировку нагрузки/запросов между этими хостами. Сделать это можно как на уровне TCP (haproxy), так и на HTTP (nginx) или DNS .

    Следующим шагом нужно сделать так, что бы файлы статики, cache и сессии web-приложения были доступны на каждом хосте. Для сессий можно использовать сервер, работающий по сети (например, memcached). В качестве сервера кеша вполне разумно использовать тот же memcached, но, естественно, на другом хосте.

    Файлы статики можно смонтировать с некого общего файлового хранилища по NFS /CIFS или использовать распределённую ФС (HDFS , GlusterFS , Ceph).

    Так же можно хранить файлы в БД (например, Mongo GridFS), решая тем самым проблемы доступности и масштабируемости (с учётом того, что для NoSQL БД проблема масштабируемости решена за счёт шардинга).

    Отдельно стоит отметить проблему деплоймента на несколько хостов. Как сделать так, что бы пользователь, нажимая «Обновить», не видел разные версии приложения? Самым простым решением, на мой взгляд, будет исключение из конфига балансировщика нагрузки (web-сервера) не обновлённых хостов, и последовательного их включения по мере обновления. Так же можно привязать пользователей к конкретным хостам по cookie или IP. Если же обновление требует значимых изменений в БД, проще всего, вообще временно закрыть проект.

    Масштабирование ФС

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

    Мониторинг

    Заключение

    С ростом популярности web-приложения его поддержка неизбежно начинает требовать всё больших и больших ресурсов. Первое время с нагрузкой можно (и, несомненно, нужно) бороться путём оптимизации алгоритмов и/или архитектуры самого приложения. Однако, что делать, если всё, что можно было оптимизировать, уже оптимизировано, а приложение всё равно не справляется с нагрузкой?

    Оптимизация

    Масштабирование

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

    Архитектура приложения

    Каждый их этих слоёв может быть масштабирован. Поэтому если в вашей системе приложение и БД живут на одном хосте – первым шагом, несомненно, должно стать разнесение их по разным хостам.

    Узкое место

    Обычно всё зависит от архитектуры приложения, но наиболее вероятными кандидатами на «узкое место» в общем случае являются БД и код. Если ваше приложение работает с большим объёмом пользовательских данных, то «узким местом», соответственно, скорее всего будет хранение статики.

    Масштабирование БД

    Снизить нагрузку на БД можно разнеся её на несколько хостов. При этом остро встаёт проблема синхронизации между ними, решить которую можно путём реализации схемы master/slave с синхронной или асинхронной репликацией. В случае с PostgreSQL реализовать синхронную репликацию можно с помощью Slony-I , асинхронную – PgPool-II или WAL (9.0). Решить проблему разделения запросов чтения и записи, а так же балансировки нагрузку между имеющимися slave’ами, можно с помощью настройки специального слоя доступа к БД (PgPool-II).

    Проблему хранения большого объёма данных в случае использования реляционных СУБД можно решить с помощью механизма партицирования (“partitioning” в PostgreSQL), либо разворачивая БД на распределённых ФС типа Hadoop DFS .

    Однако, для хранения больших объёмов данных лучшим решением будет «шардинг » (sharding) данных, который является встроенным преимуществом большинства NoSQL БД (например, MongoDB).

    Кроме того, NoSQL БД в общем работают быстрее своих SQL-братьев за счёт отсутствия overhead’а на разбор/оптимизацию запроса, проверки целостности структуры данных и т.д. Тема сравнения реляционных и NoSQL БД так же довольно обширна и заслуживает отдельной статьи .

    Отдельно стоит отметить опыт Facebook, который используют MySQL без JOIN-выборок. Такая стратегия позволяет им значительно легче масштабировать БД, перенося при этом нагрузку с БД на код, который, как будет описано ниже, масштабируется проще БД.

    Масштабирование кода

    Далее необходимо настроить балансировку нагрузки/запросов между этими хостами. Сделать это можно как на уровне TCP (haproxy), так и на HTTP (nginx) или DNS .

    Следующим шагом нужно сделать так, что бы файлы статики, cache и сессии web-приложения были доступны на каждом хосте. Для сессий можно использовать сервер, работающий по сети (например, memcached). В качестве сервера кеша вполне разумно использовать тот же memcached, но, естественно, на другом хосте.

    Файлы статики можно смонтировать с некого общего файлового хранилища по NFS /CIFS или использовать распределённую ФС (HDFS , GlusterFS , Ceph).

    Так же можно хранить файлы в БД (например, Mongo GridFS), решая тем самым проблемы доступности и масштабируемости (с учётом того, что для NoSQL БД проблема масштабируемости решена за счёт шардинга).

    Отдельно стоит отметить проблему деплоймента на несколько хостов. Как сделать так, что бы пользователь, нажимая «Обновить», не видел разные версии приложения? Самым простым решением, на мой взгляд, будет исключение из конфига балансировщика нагрузки (web-сервера) не обновлённых хостов, и последовательного их включения по мере обновления. Так же можно привязать пользователей к конкретным хостам по cookie или IP. Если же обновление требует значимых изменений в БД, проще всего, вообще временно закрыть проект.

    Масштабирование ФС

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

    Мониторинг

    Заключение

    Выше кратко рассмотрено множество вариантов решений проблем масштабирования web-приложения. Каждый из них обладает своими достоинствами и недостатками. Не существует некоторого рецепта, как сделать всё хорошо и сразу – для каждой задачи найдётся множество решений со своими плюсами и минусами. Какой из них выбрать – решать вам.

    Горизонтальное масштабирование

    Для одного из PHP + MongoDB проектов возникла необходимость осуществления горизонтального масштабирования.

    Учитывая, что будет использоваться несколько серверов, как лучше реализовать актуальность своих же скриптов? Разные мелочи появляются довольно часто, как бы их из одного централизованного хранилища сразу везде обновлять? sshfs, или gluster, или есть более простые способы? В идеале хотелось бы иметь где-то директорию с ядром проекта, которое бы использовалось напрямую остальными серверами.

    Кэширование сейчас организовано в файловой системе, но, как я понимаю, будет необходимо делать его общим для всех серверов. Как это делать лучше? Завести ещё одну БД под кэш, или как-то ещё «выкручиваться»? Особенность у нас — в кэше есть данные общим объёмом в несколько гигабайт, которые изменяются от силы раз в год, а используются чуть ли не каждую минуту, именно из-за этого когда-то кэш не стали делать в redis. Как с такими данными быть, тоже в БД? И какую БД для этого выбрать?

    Правильно ли я понимаю, что при горизонтальном масштабировании сессии тоже необходимо хранить в БД?

    1 ответ 1

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

    Чем не подошел кэш в redis? — Несколько ГБ данных не создаст для него проблемы. Или вы имеете в виду, что одна запись в кэшэ занимает несколько ГБ ? — В таком случае следует разделить легкий и тяжелый кэш на раздельные сервисы.

    Нет. При горизонтальном масштабировании вы можете привязать пользователя к определенному серверу с которым он будет работать, в частности это используется для a/b-тестирования. В любом случае хранить сессии в реляционной БД не нужно, — они очень хорошо лежат в memcached.

    Горизонтальное масштабирование PHP-приложений. Масштабируемость системы

    Масштабируемость — такое свойство вычислительной системы, которое обеспечивает предсказуемый рост системных характеристик, например, числа поддерживаемых пользователей, быстроты реакции, общей производительности и пр., при добавлении к ней вычислительных ресурсов. В случае сервера СУБД можно рассматривать два способа масштабирования — вертикальный и горизонтальный (рис. 2).

    При горизонтальном масштабировании увеличивается число серверов СУБД, возможно, взаимодействующих друг с другом в прозрачном режиме, разделяя таким образом общую загрузку системы. Такое решение, видимо, будет все более популярным с ростом поддержки слабосвязанных архитектур и распределенных баз данных, однако обычно оно характеризуется сложным администрированием.

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

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

    • поддержка многопроцессорной обработки;
    • гибкость архитектуры.

    Многопроцессорные системы

    Для вертикального масштабирования все чаще используются симметричные многопроцессорные системы (SMP), поскольку в этом случае не требуется смены платформы, т.е. операционной системы, аппаратного обеспечения, а также навыков администрирования. С этой целью возможно также применение систем с массовым параллелизмом (MPP), но пока их использование ограничивается специальными задачами, например, расчетными. При оценке сервера СУБД с параллельной архитектурой целесообразно обратить внимание на две основные характеристики расширяемости архитектуры: адекватности и прозрачности.

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

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

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

    Гибкость архитектуры

    Независимо от степени мобильности, поддержки стандартов, параллелизма и других полезных качеств, производительность СУБД, имеющей ощутимые встроенные архитектурные ограничения, не может наращиваться свободно. Наличие документированных или практических ограничений на число и размеры объектов базы данных и буферов памяти, количество одновременных подключений, на глубину рекурсии вызова процедур и подчиненных запросов (subqueries) или срабатывания триггеров базы данных является таким же ограничением применимости СУБД как, например, невозможность переноса на несколько вычислительных платформ. Параметры, ограничивающие сложность запросов к базе данных, в особенности размеры динамических буферов и стека для рекурсивных вызовов, должны настраиваться в динамике и не требовать остановки системы для реконфигурации. Нет смысла покупать новый мощный сервер, если ожидания не могут быть удовлетворены из-за внутренних ограничений СУБД.

    Обычно узким местом является невозможность динамической подстройки характеристик программ сервера баз данных. Способность на ходу определять такие параметры, как объем потребляемой памяти, число занятых процессоров, количество параллельных потоков выполнения заданий (будь то настоящие потоки (threads), процессы операционной системы или виртуальные процессоры) и количество фрагментов таблиц и индексов баз данных, а также их распределение по физическим дискам БЕЗ останова и перезапуска системы является требованием, вытекающим из сути современных приложений. В идеальном варианте каждый из этих параметров можно было бы изменить динамически в заданных для конкретного пользователя пределах.

    ) Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «Yii» — я один из его разработчиков. У меня также есть full-time работа — и это уже не стартап — Stay.com, который занимается путешествиями.

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

    Что такое масштабирование, вообще? Это возможность увеличить производительность проекта за минимальное время путем добавления ресурсов.

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

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

    Самый классный вопрос, который задают, — а зачем оно надо, если у меня все и на одном сервере прекрасно работает? На самом-то деле, надо проверить, что будет. Т.е., сейчас оно работает, но что будет потом? Есть две замечательные утилиты — ab и siege, которые как бы нагоняют тучу пользователей конкурента, которые начинают долбить сервер, пытаются запросить странички, послать какие-то запросы. Вы должны указать, что им делать, а утилиты формируют такие вот отчеты:

    Главные два параметра: n — количество запросов, которые надо сделать, с — количество одновременных запросов. Таким образом они проверяют конкурентность.

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

    Есть еще один параметр — Response time — время ответа, за которое в среднем сервер отдал страничку. Оно бывает разное, но известно, что около 300 мс — это норма, а что выше — уже не очень хорошо, потому что эти 300 мс отрабатывает сервер, к этому прибавляются еще 300-600 мс, которые отрабатывает клиент, т.е. пока все загрузится — стили, картинки и остальное — тоже проходит время.

    Бывает, что на самом деле пока и не надо заботиться о масштабировании — идем на сервер, обновляем PHP, получаем 40% прироста производительности и все круто. Далее настраиваем Opcache, тюним его. Opcache, кстати, тюнится так же, как и APC, скриптом, который можно найти в репозитории у Расмуса Лердорфа и который показывает хиты и мисы, где хиты — это сколько раз PHP пошел в кэш, а мисы — сколько раз он пошел в файловую систему доставать файлики. Если прогнать весь сайт, либо запустить туда какой-то краулер по ссылкам, либо вручную потыкать, то у нас будет статистика по этим хитам и мисам. Если хитов 100%, а мисов — 0%, значит, все нормально, а если есть мисы, то надо выделить больше памяти, чтобы весь наш код влез в Opcache. Это частая ошибка, которую допускают — вроде Opcache есть, но что-то не работает…


    Еще часто начинают масштабировать, но не смотрят, вообще, из-за чего все работает медленно. Чаще всего лезем в базу, смотрим — индексов нет, ставим индексы — все сразу залетало, еще на 2 года хватит, красота!

    Ну, еще надо включить кэш, заменить apache на nginx и php-fpm, чтобы сэкономить память. Будет все классно.

    Все перечисленное достаточно просто и дает вам время. Время на то, что когда-то этого станет мало, и к этому уже сейчас надо готовиться.

    Как, вообще, понять, в чем проблема? Либо у вас уже настал highload, а это не обязательно какое-то бешеное число запросов и т.д., это, когда у вас проект не справляется с нагрузкой, и тривиальными способами это уже не решается. Надо расти либо вширь, либо вверх. Надо что-то делать и, скорее всего, на это мало времени, что-то надо придумывать.

    Первое правило — никогда ничего нельзя делать вслепую, т.е. нам нужен отличный мониторинг. Сначала мы выигрываем время на какой-то очевидной оптимизации типа включения кэша или кэширования Главной и т.п. Потом настраиваем мониторинг, он нам показывает, чего не хватает. И все это повторяется многократно – останавливать мониторинг и доработку никогда нельзя.

    Что может показать мониторинг? Мы можем упереться в диск, т.е. в файловую систему, в память, в процессор, в сеть… И может быть такое, что, вроде бы, все более-менее, но какие-то ошибки валятся. Все это разрешается по-разному. Можно проблему, допустим, с диском решить добавлением нового диска в тот же сервер, а можно поставить второй сервер, который будет заниматься только файлами.

    На что нужно обращать внимание прямо сейчас при мониторинге? Это:

    1. доступность, т.е. жив сервер, вообще, или нет;
    2. нехватка ресурсов диска, процессора и т.д.;
    3. ошибки.

    Как это все мониторить?

    Вот список замечательных инструментов, которые позволяют мониторить ресурсы и показывать результаты в очень удобном виде:

    Этот доклад — расшифровка одного из лучших выступлений на обучающей конференции разработчиков высоконагруженных систем за 2015 год.

    Старьё! — скажите вы.
    — Вечные ценности! — ответим мы.

    highload junior Добавить метки

    Возможность масштабирования информационной системы – как горизонтальное, так и вертикальное – является одним из самых важных факторов, на которые стоит обращать при выборе средства автоматизации деятельности любой организации. Если выбранное решение невозможно будет масштабировать, или каждая стадия роста бизнеса будет приводить к сложностям с сопровождением и развитием такого программного продукта, то не следует даже начинать его использовать. Мы разрабатывали СЭД ЛЕТОГРАФ с учетом высоких требований к масштабированию.

    Необходимость в горизонтальном или вертикальном масштабировании возникает в связи с созданием корпоративных высоконагруженных ИТ-систем, в которых работают тысячи или даже десятки тысяч пользователей. Однако поддерживать одновременную работу большого числа пользователей могут далеко не все СЭД. Только если в СЭД на уровне архитектуры заложены возможности по наращиванию количества пользователей без потери производительности – только в этом случае масштабирование будет успешным. Созданная нами система ЛЕТОГРАФ была разработана таким образом, чтобы идеально масштабироваться как горизонтально, так и вертикально. Это достигается как за счет архитектуры самой системы и того прикладного кода, который мы разработали, так и за счет функционала СУБД InterSystems Caché, на которой наша СЭД построена.

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

    СУБД Caché сохраняет высокую производительность даже при работе с огромными массивами данных и большим числом серверов в распределенных системах. При этом доступ к данным осуществляется через объекты, высокопроизводительные SQL-запросы и путем прямой обработки многомерных структур данных.

    Вертикальное масштабирование предполагает наращивание мощности сервера и его возможностей, связанных с дисковой подсистемой. ЛЕТОГРАФ поддерживает современную процессорную архитектуру, что позволяет обрабатывать большие объемы данных в несколько потоков. При этом сами данные в СЭД организованы таким образом, чтобы их можно было легко разносить по СХД на разные диски. Такой подход позволяет равномерно распределить нагрузку на хранилища данных и минимизировать ее при чтении данных непосредственно из базы, а значит и падения производительности системы удастся избежать даже при одновременной работе большого количества пользователей.

    Еще на этапе разработки платформы мы понимали, что вертикальное масштабирование – одна из ключевых возможностей системы, потребность в которой со временем будет только увеличиваться. Мы разработали систему таким образом, чтобы процессы работы каждого пользователя были выделены в отдельные системные процессы, которые между собой не пересекаются благодаря тому, что базы данных эффективно делят доступ к информации. При этом количество блокировок данных в СЭД ЛЕТОГРАФ минимизировано и нет «узкого горла» ни при чтении данных, ни при их записи.

    Архитектура СЭД ЛЕТОГРАФ позволяет распределять данные на несколько физических или виртуальных серверов. Благодаря такому распределению каждый из пользователей работает в изолированном процессе, а требуемые данные эффективно кэшируются с использованием технологий СУБД Caché. Время блокировки данных минимизировано: все транзакции выстроены таким образом, чтобы переводить данные в эксклюзивный режим доступа лишь на очень короткое время. При этом даже такие высоконагруженные с точки зрения количества обращений к диску данные, как журналы, индексы, данные объектов, потоки, логи действий пользователей, распределены таким образом, что средняя нагрузка на подсистему остается равномерной и не приводит к задержкам. Такой подход позволяет эффективно вертикально масштабировать систему, распределяя нагрузку между серверами или виртуальными дисками.

    Горизонтальное масштабирование – это распределение сессий пользователей по разным серверам (равномерная загрузка серверов приложений и возможность подключать дополнительные сервера приложений), а также распределение данных по разным серверам БД, что обеспечивает высокую производительность системы, при этом не приводя к снижению отказоустойчивости. Для горизонтального масштабирования в системе ЛЕТОГРАФ предусмотрен целый ряд возможностей.

    Прежде всего, это масштабирование нагрузки благодаря Enterprise Cache Protocol (ECP, протокол распределенного кэша), протоколу, используемому в СУБД InterSystems Caché. Преимущество ECP заключается в инновационном подходе к кэшированию данных. В рамках данного протокола пользовательские процессы, которые работают на серверах приложений (или ECP-клиентах) СУБД и обслуживают запросы, получают доступ к локальному кэшу недавно использованных данных. И только если этих данных недостаточно, ECP-клиент обращается к базе данных. С помощью протокола ECP выполняется автоматическое управление кэшем: наиболее часто используемые данные сохраняются в кэше, часто обновляемые данные периодически реплицируются, обеспечивая постоянное целостность и корректность данных на всех ECP-клиентах. При этом внутренний алгоритм InterSystems Caché предполагает, что базы данных синхронизируются между ECP-клиентом и ECP-сервером.

    Фактически использование технологий СУБД Caché позволяет легко и быстро масштабировать нагрузку по серверам приложений, обеспечив таким образом подключение большого числа пользователей к одному серверу базы данных благодаря использованию ECP-протокола.

    Так как информация, которую затребовал тот или иной пользователь, может быть задействована на нескольких ECP-клиентах, необходимо блокировать данные на короткий период времени, быстро выполнять транзакции, не выполняя внутренних вычислений. И мы успешно это реализовали. Данная технология позволяет нам эффективно масштабировать систему в ситуации, когда используются один сервер базы данных и несколько серверов, на которых работают пользовательские процессы. Технологическая особенность СУБД Caché заключается в том, что она поддерживает корректность транзакций в рамках одного ECP-сервера вне зависимости от количества ECP-клиентов, которые к ней подключены. В случае, когда у нас один ECP-сервер и множество ECP-клиентов, эта задача великолепно решается, потому что все транзакции идут на одном сервере базы данных.

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

    В СЭД ЛЕТОГРАФ реализован механизм шардинга, благодаря которому мы на уровне настроек системы (без применения программирования), даем возможность описать правила и принципы разнесения самих данных по разным серверам БД. Несмотря на то, что с точки зрения структуры баз данных информация, хранящаяся на каждом сервере одинакова, сама информация отличается принципиально в зависимости от организации или каких-либо других признаков, которые являются значимыми для конкретной задачи. Используя технологию шардинга можно добиться, что в 95-99 % случаев пользователи будут работать только со своей «порцией данных», и не потребуется в рамках сессии обращаться к разным серверам БД.

    На возможности масштабирования СЭД ЛЕТОГРАФ влияет и то, данные могут по разному обрабатываться. Например, в документы (даже созданные несколько лет назад) могут вноситься изменения, а в журнал действий пользователей записи только добавляются (ни одна запись не может быть ни удалена, ни изменена). Механизмы, которые используются в СЭД ЛЕТОГРАФ, позволяют дополнительно повысить производительность системы и улучшить масштабирование за счет ведения таких журналов на отдельных серверах БД – причем, как в случае односерверной, так и многосерверной конфигурации. Такой подход ориентирован на снижение нагрузки на основные сервера БД.

    Аналогичная ситуация возникает и контентом (“информационным содержанием” СЭД). Так как система ЛЕТОГРАФ работает с большим объемом контента – это терабайты данных, миллионы файлов и документов – разумно предположить, что контент, который попадает в систему, ни при каких условиях не должен пострадать. Поэтому мы также выносим хранение файлов на отдельные сервера баз данных и обеспечиваем таким образом дополнительно горизонтальное масштабирование.

    Программное обеспечение фронт-энда

    В качестве фронт-энда в СЭД ЛЕТОГРАФ используются Apache и HAProxy. HAProxy отвечает за балансировку нагрузки между веб-серверами Apache. HAProxy, как показал опыт работы системы, зарекомендовал себя как наиболее эффективное решение, способное обеспечить поддержку работы большого числа пользователей и необходимый контроль за отказоустойчивостью.

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

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

    Пример реализации проекта

    Архитектура ЛЕТОГРАФ позволяет добиться существенных результатов в сокращении времени отклика и повышении производительности системы. В рамках одного из наших проектов в СЭД хранится 23,5 Тбайт данных. Из них 14,7 Тбайт (63%) приходится на потоки (“прикрепленные к карточкам файлы”), 3,5 Тбайт (15%) – на отчетные формы, такие как таблицы отчетов, которые формируются в асинхронном режиме, могут запускаться как по расписанию, так и по требованию пользователя и представляют собой сводную таблицу, любые данные в которой можно детализировать до объекта. Еще 1,6 Тбайт (7%) – это протокол пользовательских операций, а все остальное (16%) – данные карточек и индексы.

    В данной системе работает более 11 тыс. пользователей, 2 тыс. из них работают одновременно, а в дни пиковой нагрузки число одновременно работающих в СЭД сотрудников превышает 3 тыс. Количество записей в журнале уже превысило 5,5 млрд, а учетных карточек – почти достигло полумиллиарда.

    В качестве сервера базы данных в данном проекте установлен отказоустойчивый кластер из двух физических серверов с тремя инсталляциями СУБД, а также резервный сервер. Десять серверов приложений (и один резервный) обрабатывают пользовательские сессии и обеспечивают формирование асинхронных отчетов. 2 сервера HAProxy выполняют функции балансировщиков. В случае проблем с одним из серверов, выполняется автоматическая передача его IP-адреса на другой сервер. Также предусмотрены сервер индексации файлов и сервер распознавания (обеспечивающий распознавание текста отсканированных бумажных документов при размещении электронных образов в систему).

    В СЭД ЛЕТОГРАФ предусмотрено большое количество разнообразных механизмов масштабирования. Мы предлагаем своеобразный пирог, в основе которого лежит сервер (физический или виртуальный), на который устанавливается операционная система. Поверх нее стоит СУБД InterSystems Caché, внутри которой располагается код платформы. А уже над ним – настройки системы ЛЕТОГРАФ, благодаря которым СЭД полностью конфигурируется. И такой пирог размещен на каждом сервере. Сервера между собой связаны определенным образом за счет выбранных конфигураций. И последний слой – это HAProxy, распределяющий между серверами запросы пользователей. Такая архитектура позволяет нам поддерживать масштабирование и обеспечивать все необходимые механизмы мониторинга. В результате конечные пользователи получают быстро работающую СЭД, а ИТ-специалисты – простую в управлении и обслуживании, унифицированную систему, без огромного числа составляющих, которые в случае высоконагруженных приложений приходится постоянно контролировать и администрировать. Кроме того, в зависимости от изменения потребностей организации СЭД ЛЕТОГРАФ легко переконфигурировать, добавив новые серверы или дисковые возможности.

    Данный материал является частной записью члена сообщества Club.CNews.
    Редакция CNews не несет ответственности за его содержание.

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

    Однако это поправимо. И если сейчас вы подумали о масштабировании – вы на правильном пути.

    В двух словах, масштабируемость – это способность системы обрабатывать большой объем трафика и приспособляться к его росту, сохраняя при этом необходимый UX. Существует два метода масштабирования:

    • Вертикальное (также называется scaling up): увеличение системных ресурсов, например, добавление памяти и вычислительной мощности. Этот метод позволяет быстро устранить проблемы с обработкой трафика, но его ресурсы могут быстро себя исчерпать.
    • Горизонтальное (или scaling out): добавление серверов в кластер. Рассмотрим этот метод подробнее.

    Что такое горизонтальное масштабирование?

    Проще говоря, кластер – это группа серверов. Балансировщик нагрузки – это сервер, распределяющий рабочую нагрузку между серверами в кластере. В любой момент в существующий кластер можно добавить веб-сервер для обработки большего объёма трафика. В этом и есть суть горизонтального масштабирования.

    Балансировщик нагрузки отвечает только за то, какой сервер из кластера будет обрабатывать полученный запрос. в основном, он работает как обратный прокси-сервер.

    Горизонтальное масштабирование – несомненно, более надёжный метод увеличения производительности приложения, однако оно сложнее в настройке, чем вертикальное масштабирование. Главная и самая сложная задача в этом случае – постоянно поддерживать все ноды приложения обновленными и синхронизированными. Предположим, пользователь А отправляет запрос сайту mydomain.com, после чего балансировщик передаёт запрос на сервер 1. Тогда запрос пользователя Б будет обрабатываться сервером 2.

    Что произойдёт, если пользователь А внесёт изменения в приложение (например, выгрузит какой-нибудь файл или обновит содержимое БД)? Как передать это изменение остальным серверам кластера?

    Ответ на эти и другие вопросы можно найти в этой статье.

    Разделение серверов

    Подготовка системы к масштабированию требует разделения серверов; при этом очень важно, чтобы серверы с меньшим объёмом ресурсов имели меньше обязанностей, чем более объёмные серверы. Кроме того, разделение приложения на такие «части» позволит быстро определить его критические элементы.

    Предположим, у вас есть PHP-приложение, позволяющее проходить аутентификацию и выкладывать фотографии. Приложение основано на стеке LAMP. Фотографии сохраняются на диске, а ссылки на них – в базе данных. Задача здесь заключается в поддержке синхронизации между несколькими серверами приложений, которые совместно используют эти данные (загруженные файлы и сессии пользователя).

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

    В дальнейшем можно настроить балансировку нагрузки; об этом можно прочесть в руководстве « »

    Сессионная согласованность

    Разделив веб-сервер и базу данных, нужно сосредоточиться на обработке пользовательских сессий.

    Реляционные базы данных и сетевые файловые системы

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

    Однако это решение не самое надёжное, потому что в таком случае увеличивается нагрузка. Сервер должен вносить в БД каждую операцию чтения и записи для каждого отдельного запроса, и в случае резкого увеличения трафика база данных, как правило, отказывает раньше других компонентов.

    Сетевые файловые системы – ещё один простой способ хранения данных; при этом не требуется вносить изменения в базу исходных текстов, однако сетевые системы очень медленно обрабатывают I/O операции, а это может оказать негативное влияние на производительность приложения.

    Липкие сессии

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

    Однако это решение тоже имеет один серьёзный недостаток. Теперь балансировщик не только распределяет нагрузку, у него появляется дополнительная задача. Это может повлиять на его производительность и привести к сбою.

    Серверы Memcached и Redis

    Также можно настроить один или несколько дополнительных серверов для обработки сессий. Это самый надёжный способ решения проблем, связанных с обработкой сессий.

    Заключительные действия

    Горизонтальное масштабирование приложения сначала кажется очень сложным и запутанным решением, однако оно помогает устранить серьёзные проблемы с трафиком. Главное – научиться работать с балансировщиком нагрузки, чтобы понимать, какие из компонентов требуют дополнительной настройки.

    Масштабирование и производительность приложения очень тесно связаны между собой. Конечно, масштабирование нужно далеко не всем приложениям и сайтам. Однако лучше подумать об этом заранее, желательно ещё на стадии разработки приложения.

    Модель доверенная подсистема (или доверенный сервер)

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

    Модель с применением множества доверенных удостоверений сервиса

    Вертикальное и горизонтальное масштабирование

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

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

    горизонтальное (больше блоков).

    При вертикальном масштабировании поддержка повышенной нагрузки обеспечивается через введение в существующие серверы дополнительного оборудования, такого как процессоры, оперативная память и сетевые интерфейсные платы (network interface cards, NIC). Такой простой вариант не добавляет затрат на обслуживание и поддержку, но может быть экономически выгодным лишь до определенного момента. Однако всегда сохраняется вероятность сбоя, что является риском. Кроме того, введение дополнительного оборудования в существующие серверы обеспечивает желаемые результаты не бесконечно, и получение последних 10% расчетной производительности путем наращивания мощностей одного компьютера может быть очень дорогим удовольствием.

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

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

    Вопросы вертикального масштабирования

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

    Проектирование с поддержкой горизонтального масштабирования

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

    Узкие места идентификации и горизонтального масштабирования . Часто узким местом являются совместно используемые плохо масштабируемые в вертикальном направлении ресурсы. Например, имеется единственный экземпляр SQL Server, с которым работают множество серверов приложений. В этом случае разделение данных таким образом, чтобы они могли обслуживаться несколькими экземплярами SQL Server, обеспечит возможность горизонтального масштабирования решения. Если существует вероятность того, что узким местом станет сервер базы данных, предусмотрите секционирование данных при проектировании, это избавит от многих проблем в будущем.

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

    Компромиссы и последствия их принятия

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

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

    Как правило, выполняется оптимизация цены и производительности в рамках, налагаемых всеми остальными ограничениями. Например, использование четырех 2-процессорных Веб-

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

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

    Компоненты без сохранения состояния

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

    Секционирование данных и базы данных

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

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

    Принимаемые в сценариях развертывания решения о секционировании хранилища данных во многом определяются типом данных. Рассмотрим значимые факторы:

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

    тиражирование требует применения механизмов обеспечения синхронизации системы.

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

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

    Данные с отложенной синхронизацией . Некоторые используемые в приложениях данные не требуют немедленной синхронизации или синхронизации вообще. Отличный пример – такие данные онлайн-магазинов, как «С товаром Х часто покупают Y и Z». Эти данные извлекаются из основных данных, но не требуют обновления в режиме реального времени. Проектирование стратегий, обеспечивающих перевод данных из основных в секционируемые (динамические) и затем в статические, является ключевым фактором в построении высокомасштабируемых приложений.

    Вертикальное и горизонтальное масштабирование, scaling для web

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

    Возможности для масштабирования для серверов баз данных определяются применяемыми программными решениями: чаще всего это реляционные базы данных (MySQL, Postgresql) или NoSQL (MongoDB, Cassandra и др).

    Горизонтальное масштабирование для серверов баз данных при больших нагрузках значительно дешевле

    Веб-проект обычно начинают на одном сервере, ресурсы которого при росте заканчиваются. В такой ситуации возможны 2 варианта:

    • перенести сайт на более мощный сервер
    • добавить еще один сервер небольшой мощности с объединить машины в кластер

    MySQL является самой популярной RDBMS и, как и любая из них, требует для работы под нагрузкой много серверных ресурсов. Масштабирование возможно, в основном, вверх. Есть шардинг (для его настройки требуется вносить изменения в код) и репликация, которая может быть сложной в поддержке.

    Вертикальное масштабирование

    NoSQL масштабируется легко и второй вариант с, например, MongoDB будет значительно выгоднее материально, при этом не потребует трудозатратных настроек и поддержки получившегося решения. Шардинг осуществляется автоматически.

    Таким образом с MySQL нужен будет сервер с большим количеством CPU и оперативной памяти, такие сервера имеют значительную стоимость.

    Горизонтальное масштабирование
    С MongoDB можно добавить еще один средний сервер и полученное решение будет стабильно работать давая дополнительно отказоустойчивость.

    Scale-out или горизонтальное масштабирование является закономерным этапом развития инфраструктуры. Любой сервер имеет ограничения и когда они достигнуты или когда стоимость более мощного сервера оказывается неоправданно высокой добавляются новые машины. Нагрузка распределяется между ними. Также это дает отказоустойчивость.

    Добавлять средние сервера и настраивать кластеры нужно начинать когда возможности для увеличения ресурсов одной машины исчерпаны или когда приобретение сервера мощнее оказывается невыгодно

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

    Добавить комментарий