Как я могу сделать мои приложения хорошо масштабируемыми? - PullRequest
8 голосов
/ 03 сентября 2008

Какого рода проектные решения помогают хорошо масштабировать приложение?

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

Ответы пока
1) Определить масштабирование. Вам нужно масштабировать для большого количества пользователей, трафика, объектов в виртуальной среде?
2) Посмотрите на ваши алгоритмы. Будет ли объем работы, который они выполняют, линейно масштабироваться с фактическим объемом работы, т. Е. Количеством элементов, которые нужно просмотреть, числом пользователей и т. Д.?
3) Посмотрите на ваше оборудование. Ваше приложение разработано так, что вы можете запустить его на нескольких машинах, если не можете идти в ногу?

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

Ответы [ 7 ]

11 голосов
/ 03 сентября 2008

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

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

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

6 голосов
/ 17 сентября 2008

Хорошо, значит, вы достигли ключевой точки в использовании «большой буквы O». Это одно измерение, которое, безусловно, может укусить вас сзади, если вы не обращаете внимания. Есть и другие измерения, которые некоторые люди не видят сквозь очки «большого О» (но если вы посмотрите поближе, они действительно есть).

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

Концепция профилирования также является ключевой. Вы должны быть тщательно и точно проинструктированы для всех движущихся частей архитектуры, чтобы выявлять и устранять любые недостатки. Скажем, например, вы создаете 3-уровневое многопоточное веб-приложение MVC2 с либеральным использованием AJAX и обработки на стороне клиента вместе с OR Mapper между вашим приложением и БД. Упрощенный линейный поток запросов / ответов выглядит следующим образом:

browser -> web server -> app server -> DB -> app server -> XSLT -> web server -> browser JS engine execution & rendering

У вас должен быть какой-то метод измерения производительности (время отклика, пропускная способность, измеренная в «материале в единицу времени» и т. Д.) В каждой из этих отдельных областей, а не только на уровне блока и ОС (ЦП, память, диск i). / о и т. д.), но характерно для каждого уровня обслуживания. Поэтому на веб-сервере вам нужно знать все счетчики для веб-сервера, который вы используете. На уровне приложений вам понадобится это плюс обзор любой виртуальной машины, которую вы используете (jvm, clr, что угодно). Большинство сопоставителей OR проявляются внутри виртуальной машины, поэтому убедитесь, что вы обращаете внимание на все особенности, если они видны вам на этом уровне. Внутри БД вам нужно знать все , которое выполняется, и все конкретные параметры настройки для вашего вида БД. Если у вас большие деньги, BMC Patrol - неплохая ставка для большинства из них (с соответствующими модулями знаний (KM)). На дешевом конце вы, конечно, можете кататься самостоятельно, но ваш пробег будет варьироваться в зависимости от вашего опыта.

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

Итак, учитывая эту проблемную область, какие решения вы могли бы принять, чтобы помочь с масштабируемостью?

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

  2. Отказоустойчивость сеанса на каждом уровне. Нужно или нет? Мы предполагаем, что каждый уровень будет кластером блоков горизонтально под некоторым механизмом распределения нагрузки. Балансировка нагрузки, как правило, очень легкая, но некоторые реализации аварийного переключения сеанса могут быть тяжелее, чем хотелось бы. Кроме того, если вы работаете с липкими сессиями, это может повлиять на ваши параметры в архитектуре. Вы также должны решить, привязывать ли веб-сервер к определенному серверу приложений или нет. В мире удаленного взаимодействия .NET, вероятно, проще связать их вместе. Если вы используете стек Microsoft, может быть более масштабируемым сделать 2-уровневый (пропустить удаленное взаимодействие), но вы должны сделать существенный компромисс безопасности. Что касается Java, я всегда видел его как минимум 3-х уровневый. Нет причин делать это иначе.

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

  4. ИЛИ неэффективность картографа. Существует несоответствие импеданса между проектированием объекта и реляционным проектированием. Конструкция «многие ко многим» в СУБД находится в прямом конфликте с иерархиями объектов (person.address vs. location.resident). Чем сложнее ваши структуры данных, тем менее эффективным будет ваше OR ORMAP. В какой-то момент вам, возможно, придется обрезать приманку в одноразовой ситуации и сделать более ... эээ ... примитивный подход к доступу к данным (хранимая процедура + уровень доступа к данным), чтобы выжать больше производительности или масштабируемости из особенно уродливый модуль. Понять стоимость и принять осознанное решение.

  5. XSL-преобразования. XML - замечательный, нормализованный механизм для передачи данных, но человек может быть собакой огромной производительности! В зависимости от того, сколько данных вы носите с собой и какой анализатор вы выбираете, и насколько сложна ваша структура, вы можете легко нарисовать себя в очень темном углу с помощью XSLT. Да, академически это блестяще чистый способ создания презентационного уровня, но в реальном мире могут возникнуть катастрофические проблемы с производительностью, если вы не обращаете на это особого внимания. Я видел, как система потребляет более 30% времени транзакции только в XSLT. Не очень приятно, если вы пытаетесь увеличить базу пользователей в 4 раза, не покупая дополнительные коробки.

  6. Можете ли вы купить выход из варки масштабируемости? Абсолютно. Я наблюдал, как это происходит больше раз, чем я хотел бы признать. Закон Мура (как вы уже упоминали) действует и сегодня. На всякий случай имейте под рукой немного дополнительных денег.

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

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

4 голосов
/ 03 сентября 2008

Что ж, есть блог под названием High Scalibility , который содержит много информации по этой теме. Некоторые полезные вещи.

3 голосов
/ 03 сентября 2008

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

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

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

2 голосов
/ 03 сентября 2008

Джефф и Джоэл обсуждают масштабирование в подкасте Stack Overflow # 19 .

1 голос
/ 03 сентября 2008

FWIW, большинство систем будут масштабироваться наиболее эффективно, игнорируя это до тех пор, пока это не станет проблемой - закон Мура все еще действует, и если ваш трафик не растет быстрее, чем закон Мура, обычно дешевле просто купить большую коробку (за 2 доллара или $ 3K за штуку), чем платить разработчикам.

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

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

1 голос
/ 03 сентября 2008

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

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

Один из способов подойти к этому:

    for each car {
       determine my position;  
       for each car {  
         add my position to this car's map;  
       }
    }

Это кажется простым: посмотрите на положение первого автомобиля, добавьте его на карту любого другого автомобиля. Затем посмотрите на положение второго автомобиля, добавьте его на карту каждого другого автомобиля. И т.д.

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

Игнорирование того, сколько других вещей нужно сделать с каждым автомобилем (например, для расчета местоположения отдельного автомобиля может потребоваться фиксированное количество шагов), для N автомобилей, требуется N 2 «посещения автомобилей» для запуска этого алгоритма . Это не проблема, когда у вас 5 машин и 25 ступеней. Но когда вы добавите автомобили, вы увидите, что система заболочена. 100 автомобилей сделают 10 000 шагов, а 101 машина сделает 10 201 шагов!

Лучше было бы отменить вложение циклов for.

    for each car {  
      add my position to a list;  
    }  
    for each car {    
      give me an updated copy of the master list;  
    }

В этой стратегии число шагов кратно N, а не N 2 . Таким образом, 100 автомобилей потребуют в 100 раз больше работы, чем 1 автомобиль, а НЕ в 10 000 раз больше работы .

Эта концепция иногда выражается в «большой О нотации» - количество необходимых шагов «большой О из N» или «большой О из N 2 ».

Обратите внимание, что эта концепция касается только масштабируемости, а не оптимизации количества шагов для каждого автомобиля. Здесь нас не волнует, нужно ли 5 ​​или 50 шагов на машину - главное, чтобы N машин делали (X * N) шагов, а не (X * N 2 ).

...