Каждое успешно масштабирующееся приложение ASP.NET, с которым я когда-либо работал в качестве консультанта, было результатом совместных усилий разработчиков (создавших его) и сетевых администраторов (реально работающих на нем). Увы, в начале жизненного цикла приложения не всегда ясно, что это сотрудничество является ключевым. Как следствие, мне почти не предоставлялось возможности вмешаться в начале жизненного цикла приложения – лишь в печальном конце, там где появляются проблемы.
Простая истина состоит в том, что ни одно приложение не масштабируется эффективно с первого раза – сделать все правильно с ходу невозможно. Чтобы успешно масштабировать приложение, необходимо понимать, как оно было построено, а также как работает его среда эксплуатации. Другими словами, необходима информация как от разработчиков, так и от специалистов по сетям. Без этих общих знаний успех невозможен.
Основы масштабирования
Перед погружением в тему, давайте определим, что требуется для реального масштабирования приложения ASP.NET. Обычно применяются две фундаментальные стратегии, специализация и распределение, и в большинстве крупных масштабируемых приложений ASP.NET применяются обе. Более того, все известные приемы, помогающие в масштабировании приложения ASP.NET, сводятся к тому или другому.
Специализация включает выделение элементов приложения, чтобы масштабировать их независимо. Например, можно создать специальные серверы изображений вместо использования тех же серверов, что визуализируют страницы ASP.NET. Оптимальная настройка сервера изображений существенно отличается от таковой для сервера ASP.NET. Кроме того, отделение запросов изображений от остальной части приложения открывает возможность использования ресурсов от сторонних производителей для предоставления изображений. Тот же подход применим к другим файлам ресурсов.
Распределение, с другой стороны, подразумевает симметричное растягивание приложения на несколько серверов, обычно именуемых веб-фермой. Приложения ASP.NET в особенности подходят для распределения, поскольку каждый отдельный запрос страницы относительно мал и взаимодействия определенного пользователя во многом зависят от других пользователей. Распределение на деле является воплощением философии «масштабирования в стороны», при которой несколько серверов средней производительности работают вместе, обслуживая пользователей, а не подхода «масштабирования вверх», при котором все делает один большой сервер.
Сочетание специализации и распределения повышает эффективность – распределять можно только элементы приложения, нуждающиеся в дополнительной производительности. Например, если созданы специальные серверы изображений, но предоставление изображений все еще неадекватно, можно добавить серверы лишь для изображений, а не для всего приложения. Важно помнить про эти стратегии, когда углубляешься в улучшение производительности и масштабируемости своего приложения ASP.NET.
Встреча разумов
В жизненном цикле каждого приложения ASP.NET есть момент, когда разработчики, и специалисты по сети/ИТ, вероятно, встретятся. Если повезет, это произойдет до развертывания приложения, но порой это происходит только после возникновения кризиса – например, когда приложение отлично работает в тестовой среде, затем поставляется пользователям и еле ползет у них. (В таких случаях и вызывают консультантов вроде меня.)
Когда разработчики и специалисты по сетям встречаются, основной целью является обмен информации. Разработчик обладают ключевыми знаниями о приложении, а обслуживающий персонал сети – о среде, где оно эксплуатируется. Обеим группам нужно усвоить данные друг друга, и чем раньше в жизненном цикле приложения это произойдет, тем лучше.
Эта встреча не должна впервые состояться в момент кризиса. Без общего взаимопонимания между двумя группами понять, почему приложение не работает так, как требуется, очень сложно. Вдобавок, слишком просто, выгораживая себя, решить, что проблема является исключительно проблемой другой группы. А это просто не может быть верным – для решения любой проблемы существенной сложности неизбежно требуются усилия обеих групп.
Но и в хорошие времена такая встреча может быть непростой. Те, которые устраивал я, обычно начинались с сетевиками на одной стороне стола, а разработчиками на другой. Следует дуэль взглядов. Чтобы начать разговор, я обрисовываю цель встречи, а именно обмен знаниями. Не имеет значения, с кого начинать. Я начну с того, что специалистам по сетям нужно узнать от разработчиков.
Что специалистам по сетям нужно узнать от разработчиков
Каждое приложение ASP.NET имеет свои тонкости, существуют ключевые элементы, применимые во всех случаях. Одним из них является файл web.config (см. рис. 1). Web.config – это точка пересечения между разработкой и работой с сетью. Порой он настраивается разработчиками, порой специалистами по сетям. Так или иначе, содержание web.config накладывает ограничения на состав оборудования и настройку сети и прямо влияет на работу приложения. Подробное изучение всех мелких аспектов файла web.config может легко занять целую книгу; здесь же следует просто понять, что обеим группам необходимо изучить файл web.config и согласиться насчет того, что значит представляемая им настройка, а также того, какое влияние различные параметры будут иметь на приложение и на среду.
Рис. 1 Базовый файл web.config, показывающий некоторые параметры приложения и индивидуализированную настройку ошибок
Например, раздел <authorization> файла web.config указывает, как будет проводиться проверка пользователей в приложении, определяя тем самым зависимость. Если приложение использует проверку подлинности Windows®, оно может зависеть от Active Directory®. Если оно использует проверку подлинности на основе форм, зависимость будет от хранилища данных учетных записей пользователей. Это определенно стоит беседы.
Стоит отметить раздел <customErrors>, поскольку он определяет, как сбой видят пользователи. Это несложный параметр, но его стоит обсудить просто ради того, чтобы понять, какими будут страницы ошибок. На раннем этапе цикла сотрудничества специально настроенные страницы ошибок, вероятно, отсутствуют – об этом тоже стоит побеседовать.
Раздел <appSettings> файла web.config может быть особенно важен. В нем разработчики обычно припрятывают глобальные значения, такие как строки подключения для баз данных. Это отличный источник зависимостей и ключевая часть планирования отказоустойчивости, смягчения проблем и т.д. Но поскольку раздел <appSettings> полностью индивидуален, он может содержать что угодно, а его содержимое – требовать долгих объяснения для понимания. В этом разделе часто оставляются потерянные объекты – значения которые на деле не используются нигде в приложении.
Даже если разработчики не используют <appSettings>, сетевики/эксплуатационщики могут желать, чтобы они его использовали, – сведение всех строк подключения к базам данных сюда является эффективным способом создания простой стратегии отказоустойчивости. Если сервер базы данных ломается, можно вставить строку замены, указывающую на другой сервер базы данных. Ухватившись за эту возможность на раннем этапе разработки, можно повысить надежность приложения и простоту его обслуживания.
Наконец, стоит обратить внимание, что с точки зрения масштабирования абсолютным значением ключа в файле web.config является тег <sessionState>, определяющий, где будут храниться данные сеанса для приложения. По умолчанию, данные сеанса хранятся "InProc", или в пространстве процессов приложения ASP.NET. Если данные сеанса настраиваются с учетом этого, то вся балансировка нагрузок должна быть «прилипчивой» – определенный пользователь всегда должен возвращаться к тому же серверу, где находятся данные сеанса. Это предмет для большого разговора между разработчиками и сетевиками, поскольку он прямо влияет на способы масштабирования и отказоустойчивости. Ранее обсуждение этого может сэкономить массу нервов, ушедших бы на устранение неполадок приложения.
После того, как разговор доходит до состояния сеанса, оттуда легко перейти к требованиям балансировки нагрузки приложения в целом. Некоторым средам необходимо специальное оборудование для балансировки нагрузки с конкретными функциями – но если приложение не поддерживает эти функции, они немногого стоят. Я сталкивался с ситуациями, когда аппаратная балансировка нагрузки использовалась с приложением ASP.NET, хранившим данные сеанса в процессе. В результате порой безо всякого объяснения терялись сеансы. Это выглядело как ошибка в приложении, но на деле было следствием неправильной настойки.
Специалистам по сети нужно четко знать от разработчиков, какие именно схемы балансировки нагрузки будут работать для приложения. Это вполне двустороннее обсуждение того, какие схемы балансировки нагрузки доступны и что приложение может выдержать. Серьезным преимуществом проведения такого обсуждения на раннем этапе разработки приложения заключается в том, что можно заранее запланировать переход на беспроцессную, не имеющую привязок, схему балансировки нагрузки.
К тому времени, как приложение ASP.NET готово к развертыванию (или находится в процессе первоначального развертывания), разработчики будут иметь хорошее представление о том, какие области приложения работают быстро, а какие медленно. Что важнее всего, они будут чувствовать, где в системе находятся «узкие места» и потенциальные опасные точки. Если группа работы с сетью/эксплуатации знает об этих узких местах, она может подготовиться к проблемам заранее и, возможно, даже избежать их.
Например, я однажды работал с приложением, производившим обширный процесс загрузки данных каждую ночь во время простоя приложения. Разработчики создали механизм загрузки данных, протестировали его и поняли, как он работает. Они знали, что он создавал большую нагрузку для базы данных, но он был эффективным и хорошим путем решения проблемы.
Но они не удосужились сообщить работающей с сетью группе, что такой процесс существует или что по расписанию он происходит в час ночи – точно во время, на которое последняя запланировала резервное копирование базы. База оставалась в рабочем состоянии, но работала гораздо медленнее во время процесса резервного копирования, поскольку все транзакции, отправляемые базе данных, удерживались в журнале транзакций.
Конфликт был определен, лишь когда сочетание одновременной загрузки данных и резервного копирования вызвало исчерпание журналом транзакций свободного места на диске. Перенос загрузки данных на три часа ночи полностью решил проблему – но лишь после нескольких дней кризиса.
Ранняя беседа об элементах рабочей нагрузки такого рода в приложении может спасти от многих неприятностей впоследствии.
Что разработчикам по сетям нужно узнать от специалистов по сетям
Я люблю начинать часть встречи, где народ, работающий с сетью, объясняет свой мирок разработчикам, с представления схемы сети. Слишком часто разработчики видят сеть, как показано на рис. 2 – то есть, не как сеть, а просто как веб-серверы, обозреватели и Интернет.
Рис. 2. Простое представление сети в глазах разработчика
Реальность, само собой, куда сложнее. Схема, подобная рис. 3, ближе к истине, хоть и является упрощенной. При взгляде на рис. 3 немедленно возникают дополнительные вопросы, вроде: «Как пользователи виртуальной частной сети (Virtual Private Network – VPN) работают с этим приложением» или: «В чем разница проверки подлинности для внутреннего пользователя и общего пользователя» и так далее.
Рис. 3. Реальная картина сети, которую нужно понять разработчикам
Очевидно, что простого предоставления схемы сети недостаточно. Также важно объяснить сеть во всех подробностях, поскольку по простому взгляду на схему нельзя сказать, какие элементы повлияют на приложение. Необходимо рассказать о реальном процессе подключения общего пользователя, пользователя VPN и внутреннего пользователя. А рассказ о различных существующих, особенно в более сложных сетевых архитектурах в стиле DMZ, правилах брандмауэра естественным образом высветит потенциальные проблемы приложения.
Очевидно, что лучше всего провести все эти беседы до развертывания приложения и даже до начала разработки – но, что бы не произошло, рано или поздно они состоятся, и знакомство со всей схемой сети всех присутствующих за столом абсолютно необходимо для них.
Работа с сетью также является ареной моделей отказоустойчивости и избыточности, но без некоторой поддержки в программе или, как минимум, учета поведения эти модели редко работают как планируется. Необходимо подробно обсудить, на что похожи различные случаи сбоев. Если в базе данных действует кластеризация, это повлияет на код, связанный с доступом к базе данных. Например, могут ли запросы выполняться повторно после переключения сервера? Если доступен избыточный веб-узел, как на него будут реплицироваться данные? Как происходит переключение с одного узла на другой?
Опять же, проведение обсуждения пораньше помогает, но лучше поздно, чем никогда, – всем, кто связан с приложением, нужно понимать, как работают такие вещи. Нет ничего более раздражающего, чем отказоустойчивое решение, которое не работает, когда это нужно.
Наконец, следует поделиться еще одним ключевым сетевым ресурсом – рабочими журналами. Я всегда рекомендую делать рабочие журналы доступными группе разработки. Обычная реакция от людей, работающих с сетью на такой запрос: «Попросите их у меня, и я отошлю их вам». Я не думаю, что этого достаточно – гораздо эффективнее дать разработчикам возможность извлекать журналы самим, как правило, с веб-узла резервного копирования.
Рабочие журналы важны в ходе кризиса. Часто они являются лучшим (и единственным) источником реальных, опытных данных о том, что случилось. Но они не менее ценны и в более нормальных обстоятельствах. Когда разработчики имеют постоянный доступ к рабочим журналам, они могут проверять в них, как ведет себя новая функция. А это отличный способ обнаружить, что функция не делает того, что от нее ожидается, и исправить проблему, пока она не переросла в кризис. Когда у всех есть доступ к журналам, можно быстрее реагировать на проблемы и скорее исправлять их.
Возвращаясь к масштабированию
Смысл встречи между разработчиками и сетевиками заключается в понимании всего масштаба проблем, окружающих масштабирование приложения ASP.NET. Реальная среда, в которой эксплуатируется приложение, прямо влияет на то, как будет работать выполняемый приложением код. Все имеющиеся стратегии, связанные с масштабированием, влияют на его поведение в среде. Применение стратегии специализации, такой как выделение связанных с SSL частей приложения, может потребовать изменений в сетевой среде и, возможно, в самих серверах.
Даже изменение, которое, на первый взгляд, затрагивает лишь код, скажем использование кэширования, может затронуть среду. Это вызвано тем, что при добавлении кэширования данных к приложению ASP.NET уменьшается число вызовов к базам данных, в обмен на увеличение использования памяти. В результате может возрасти нужное число серверов ASP.NET или число повторных использований рабочих потоков на серверах, что вызовет события на стороне наблюдения за сетью.
Масштабирование приложения ASP.NET влияет как на персонал, занимающийся разработкой, так и работающий с сетью – так что имеет смысл задействовать в принятии решений обе группы. Часто сотрудничество может дать оригинальные решения, которые не обнаружились бы при работе по отдельности. Например, люди, работающие с сетью, могут знать о существующих аппаратных решениях внутри компании, которые могут помочь разработчикам обеспечить выполнение требований к производительности и масштабированию. Обсуждение различных деталей приложения и среды откроет эти возможности.
Совместная борьба с огнем
Материалы по масштабированию приложений ASP.NET
Кризис в масштабировании не является автоматически плохой вещью – на деле это обычно хорошая вещь, поскольку он создается избытком пользователей, желающих использовать приложение, что доказывает ценность приложения! Однако теперь необходимо заставить приложение работать.
Порой кризисы масштабирования вызываются каким-то другим событием – возможно, компания проводит рекламную акцию, или о ней заговорили в блогах, или социальная сеть одновременно направила на ее веб-узел огромное количество людей. И внезапно сотрудникам приходится тушить пожар кризиса, чтобы работа приложения продолжилась. Как можно догадаться, сценарий такого рода лучше проработать прежде, чем он произойдет реально. А демонстрация того, как сотрудничество может помочь организации пережить подобный кризис, является отличным способом завершить встречу между разработчиками и сетевиками.
Первый вопрос по борьбе с кризисом такой: «Как мы обнаруживаем, что веб-узел задыхается под нагрузкой?» Слишком часто ответ бывает: «Мы получаем звонок от руководителя технологического отдела». Когда первым признаком проблем с веб-узлом является звонок от кого-то извне, это проблема. Приличное измерение должно сообщить о проблеме прежде, чем зазвонит телефон. Оно не остановит сам звонок, но, по крайней мере, даст время подготовиться к ответу. Ответы типа "В самом деле?" не улучшают карьерных перспектив.
Следующий вопрос – кому звонить первому? Кто отвечает за событие? Часто человек, работающий с сетью, получает первое предупреждение, а он может быть относительно неопытен, так что необходим четкий план решения. Кому звонить дальше? Задача состоит в выполнении ранней, быстрой диагностики, чтобы установить тип возникшей проблемы. Если это сбой в работе сети, дело одно. Но если это проблема масштабирования, то совсем другое. В случае проблем масштабирования рекомендуется раннее подключение кого-нибудь из группы разработки.
Всем вовлеченным в пожарные меры нужна хорошая информация, ключом к которой являются эффективные права доступа. Цель состоит в том, чтобы распределить как можно больше информации, чтобы можно было эффективно поставить диагноз, и это должно в итоге диктовать масштаб решения.
Часто если единственным решением является написание кода, событие закончится, прежде чем это можно будет сделать. Само собой, событие следует отметить, чтобы уточнить приоритеты разработки на будущее, но вряд ли разумно пытаться написать кучу кода и воткнуть его в рабочую среду без тщательного тестирования. Правило №1 любого пожарного – не раздувайте огонь.
Когда дело доходит до проблем масштабирования, порой решение заключается в том, чтобы просто переждать. Но это остается решением, которое можно принять.
В то же время планирование на подобные случаи означает возможность быстро применить различные приемы. Направление ресурсов как отдела работы с сетью, так и отдела разработки на решение проблемы масштабирования часто решает ее за примечательно быстрое время, возможно достаточно быстро, чтобы сделать рекламную акцию еще большим успехом.
В заключение можно сказать, что урок, преподанный рассмотрением вопроса с точки зрения сети, состоит в том, что хорошо масштабируемое, высокопроизводительное приложение ASP.NET представляет успешное взаимодействие между людьми, создающими приложение, и теми, кто развертывает и эксплуатирует его.
Сотрудничество неизбежно, так что лучше начать его раньше, со встреч между группами для обмена информацией. Цель встречи заключается в достижении понимания и согласия по всем элементам приложения, тому, что оно делает, как оно работает, от чего оно зависит, как оно ведет себя под нагрузкой и как оно переносит проблемы, возникающие с течением времени.
Когда такое сотрудничество действительно эффективно, результатом является более гибкая компания, способная быстро отвечать на проблемы и четко довести до всех, кому необходимо, что требуется приложению для успеха в будущем.