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

Олег Спиряев

В последнее время нередки утверждения, что серверы среднего и старшего класса активно заменяются на группы серверов начального уровня, объединенные в стойки или кластеры. Однако некоторые эксперты с этим не согласны. Так, по данным 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.

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

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

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

Но в какой-то момент, траффик начинает расти очень медленно, кто-то опубликовал ссылку на ваше приложение в 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 .

) Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «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 год.

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

Здравствуйте! Я Александр Макаров, и вы можете меня знать по фреймворку «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 — это принципы, которые позволяют избежать связанности именно в коде. Но связанность в коде на разнос по серверам, конечно, влияет, но не настолько, насколько связанность доменного слоя с нашим окружением. Если мы в контроллере пишем много-много кода, получается, что в другом месте мы это использовать, скорее всего, не сможем. Нам непросто будет все это переносить из веб-контроллера в консоль и, соответственно, сложнее переносить на другие сервера и там обрабатывать по-другому.


Service-oriented architecture.

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

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

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

  2. правильное решение — бить на отдельные логические части, т.е. если в областях 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 — http://martinfowler.com/bliki/BoundedContext.html (то, о чем было выше — если у вас две области вроде как пересекаются, но они
    разные, то стоит некоторые сущности продублировать, такие как модель user);
  • про DDD в общем — — ссылка еще на одну книгу.

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

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

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

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

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


Контакты

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

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

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

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

К концу 2012 года более 50% приложений работающих на х86 платформе виртуализированы. Вместе с тем виртуализировано только 20% бизнес критических приложений.

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

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

Тогда если доверие или стабильность не являются проблемой в чём же причина того что ИТ отделы еще не виртуализировали оставшиеся приложения?

Scale out
Scale out или горизонтальное масштабирование - добавление новых ресурсов в инфраструктуру, например, серверов в кластер.

Так как цены продолжают падать, а производительность расти то дешёвые, commodity (широкого потребления) сервера являются идеальным решением для горизонтального масштабирования, и могут быть собраны в большие кластера для объединения вычислительных ресурсов.

Последние семь лет архитекторы инфраструктур на VMware молились на горизонтальное масштабирование. Кто-то может аргументировать за использование именного этого подхода, но он тоже имеет свои нюансы, и всё зависит от требований бизнеса. Плюс горизонтального масштабирования в том, что commodity сервера дёшевы, и в случае выхода сервера из строя это влияет на небольшое количество ВМ. Минус в бОльших затратах на лицензии на vSphere, большие требования к площади ЦОД, и обычно такие commodity сервера не обладают большими вычислительными ресурсами.

Scale up
Вертикальное масштабирование - добавление вычислительных ресурсов в какой-то уже используемый сервер. Обычно это процессоры или оперативная память.

Обычно такие сервера довольно мощные - с поддержкой 4 процессоров и 512ГБ памяти. Кроме того встречаются системы с 8 процессорами и 1ТБ памяти, а некоторым повезло увидеть даже 16-ти процессорные сервера с 4ТБ памяти. И нет, это не мейнфреймы или что-то типа того, это сервера на основе классической х86 архитектуры.

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

  • Недостаточные возможности по масштабированию. Нагрузки с высокими требованиями к объёму вычислительных ресурсов являются проблемой из-за ограниченного объёма ресурсов доступных с дешёвыми commodity серверами.
  • Недостаточная надёжность. Commodity оборудование или аппаратное обеспечение использующее такие компоненты может быть менее надёжным. Проблему надёжности можно решить с помощью функций о которых я расскажу в следующих статьях.
  • Увеличение сложности управления и рост операционных расходов. Легче управлять 100 серверами, а не 1000, ну и, как следствие, 10 серверами управлять проще чем 100. Тоже самое касается и операционных расходов - 10 серверов гораздо дешевле поддерживать чем 100.
Вертикальное масштабирование отлично подходит для бизнес критических приложений с их огромными требованиями к ресурсам. Привет, Monster VM! Все эти прожорливые критичные базы данных, огромные ERP системы, системы аналитики больших данных, JAVA приложения и так далее и тому подобное получат прямую выгоду от вертикального масштабирования.

С выходом vSphere 5 количество ресурсов, доступных одной ВМ выросло в 4 раза.

А с выходом vSphere 5.1 монструозные ВМ могут быть еще монструознее.

Для того чтобы vSphere 5.1 могла запустить ВМ-монстра планировщику необходимо иметь и спланировать запуск потоков на 64 физических процессорах. Не так много серверов, которые могут поддерживать столько ядер, а серверов с поддержкой 16 сокетов и 160 ядер и того меньше.

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

Glueless архитектура
Данная архитектура была разработана в Intel, и представлена в Intel Xeon E7.

Для связи между устройствами ввода-вывода, сетевыми интерфейсами и процессорам используется специально разработанная шина QPI.

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

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

Преимущества такой архитектуры:

  • Нет необходимости в специальной разработке или специализации у производителя серверов
  • Любой производитель серверов может выпускать 8-ми процессорные сервера
  • Снижается стоимость как 4-ёх так и 8-ми процессорного сервера
Недостатки:
  • Общая стоимость владения растёт при горизонтальном масштабировании
  • Архитектура ограничена 8-ми процессорными серверами
  • Тяжело поддерживать целостность кэша при увеличении сокетов
  • Нелинейный рост производительности
  • Соотношение цены к производительности падает
  • Неоптимальная эффективность при использовании больших ВМ
  • Вплоть до 65% пропускной способности шины уходит на широковещательные сообщения болтливого протокола QPI
В чём же причина болтливости протокола QPI? Для того чтобы достичь целостности процессорного кэша каждая операция на чтение должна быть реплицирована на все процессоры. Это можно сравнить с широковещательным пакетом в IP сети. Каждый процессор должен проверить у себя затребованную строку памяти, и в случае использования последней версии данных предоставить её. В случае если актуальные данные находятся в другом кэше протокол QPI с минимальными задержками копирует данную строку памяти из удалённого кэша. Таким образом на репликацию каждой операции чтения тратиться пропускная способность шины и такты кэша, которые могли бы использоваться для передачи полезных данных.

Основные приложения, производительность которых страдает от недостатков протокола QPI это Java приложения, большие БД, чувствительные к задержкам приложения.

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

Glued архитектура
Для решения описанных выше проблем разработчики аппаратного обеспечения разработали glued архитектуру. Данная архитектура использует внешний контроллер нод для организации взаимосвязи островков QPI - кластеров процессоров.


Intel QPI предлагает специальное масштабируемое решение - eXternal Node-Controllers (или XNC), практическая реализация которого разрабатывается сторонними OEM компаниями. Внешний контроллер нод, используемый начиная с Intel Xeon E7-4800, со встроенным контроллером памяти, включает в себя также систему Cache Coherent Non-Uniform Memory Access (ccNUMA) задача которой отслеживать актуальность данных в каждой строке памяти процессорного кэша были актуальные данные.

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




Top