Стратегии масштабирования для приложений ASP.NETИсточник: cyberguru
Как советников по производительности ASP.NET нас обычно привлекают к проекту, когда проблемы уже возникли. Во многих случаях, вызов приходит только тогда, когда приложение уже в производстве. То, что работало отлично для разработчиков, не работает для пользователей. Жалоба: веб-узел работает слишком медленно. Руководство хочет знать, в чем причина и почему ее не обнаружили при тестировании. Разработчики не могут воспроизвести проблему. По крайней мере, один человек утверждает, что ASP.NET не масштабируется. Звучит знакомо? Некоторые из наиболее нагруженных веб-узлов в мире работают на ASP.NET. MySpace является прекрасным примером; он, между прочим, был перенесен на ASP.NET после работы на серии различных платформ. Факты таковы, проблемы с производительностью могут прокрасться в веб-приложения при их масштабировании вверх, и в таком случае возникает необходимость найти реальную проблему, а также лучшие стратегии ее устранения. Сложнейшей из задач, с которыми при этом придется столкнуться, является создание набора показателей, охватывающих все стороны производительности приложения. Понять, куда следует направить усилия, можно лишь взглянув на проблему в целом. Уравнение производительностиВ сентябре 2006 года Питер Севчик (Peter Sevcik) и Ребекка Ветцель (Rebecca Wetzel) из компании NetForecast опубликовали документ, именуемый "Field Guide to Application Delivery Systems" ("Полевое руководство по системам доставки приложений"). Основное внимание в документе было уделено улучшению производительности приложений в глобальных сетях (wide area network - WAN), и в нем было приведено уравнение с рис. 1. Это уравнение рассматривает производительность глобальных сетей, но с несколькими мелкими изменениями его можно использовать и для измерения производительности веб-приложений. Измененное уравнение показано на рис. 2, а его элементы объяснены на рис. 3. Рис. 1 The Original Performance Equation
Рис. 2 The Web Version of the Performance Equation Рис. 3 Элементы уравнения производительности
Теперь, когда у нас есть формула, задача заключается в том, чтобы замерить каждый элемент. С конечным значением, временем ответа, это сделать достаточно легко - имеется ряд средств, способных засечь, сколько именно времени занимает весь процесс Объем полезных данных можно измерить с помощью различных средств (отличным вариантом является websiteoptimization.com/services/analyze), точно так же, как и пропускную способность (см. speedtest.net) и время приема-передачи (используя программу Ping). Средства вроде websiteoptimization.com/services/analyze также сообщат размер HTML, CSS, JavaScript, изображений и прочих частей веб-страницы. Число одновременных запросов по сути являются постоянной (для Internet Explorer® по умолчанию используется 2). В результате остаются только Cs и Cc (времена вычислений на сервере и клиенте), измерение которых требует некоторых дополнительных усилий от разработчика. Написание кода на странице ASP.NET, отмечающей точную секунду, когда начинается исполнение страницы, и вычитающей это время из текущего времени при завершении исполнения, является сравнительно простой задачей. Это же верно и для клиента - небольшой кусок кода на JavaScript может быть исполнен прямо наверху страницы HTML, чтобы отметить время и затем вычесть время на момент запуска события OnLoad при завершении страницы. Все эти элементы можно внести в программный код, если требуется создать для веб-узла режим отладки, использующий уравнение производительности. Имеется убедительная причина так и сделать: постоянное выполнение элементов уравнения производительности на обозревателе позволяет легко обнаружить, в чем состоят проблемы производительности. Для примера, предположим, что имеется приложение ASP.NET, пользователи которого находятся на другом континенте и имеют низкую пропускную способность. При высоком времени проверки связи (> 200 мс) и низкой пропускной способности (< 500 кб/с) для пользователей наверняка будет иметь значение общий объем полезных данных и число приемов-передач в приложении. Взгляд на приложение в контексте возможностей этих пользователей важен, поскольку их впечатления будут весьма отличаться от впечатления разработчика. Проблемы масштабированияКак консультанты мы знаем, что когда приложение хорошо работает в тестовой среде и плохо в реальном мире, речь, вероятно, идет о проблеме масштабирования. Обычно единственной разницей между двумя ситуациями является число одновременных пользователей. Если приложение работает плохо все время, то это уже проблема производительности, а не масштабирования. Для улучшения масштабирования можно применить три возможные стратегии: специализацию, оптимизацию и распределение. Варианты их применения бывают разными, но сами стратегии просты и последовательны. Задача специализации - разбить приложение на более мелкие части, чтобы выделить проблему. Например, в ее рамках можно обдумать перенос статических файлов ресурсов, такие как файлы изображений, CSS и JS прочь с серверов ASP.NET. Сервер, настроенный под ASP.NET, не слишком хорошо подходит для того, чтобы поставлять эти типы файлов. По этой причине отдельная группа серверов IIS, специально настроенных для поставки файлов ресурсов, может существенно повлиять на масштабируемость используемого приложения. Если выполняются большие объемы сжатия или шифрования (для SSL), может помочь установка специальных серверов для SSL. Следует знать, что существует даже специализированное оборудование для сжатия и терминации SSL. Хотя более традиционные стратегии разбиения уровней сервера на составные части могут предложить выделение отдельных серверов для доступа к данным, сложных вычислений и так далее, независимых от собственно создания веб-страниц, лично я предпочитаю иметь пять веб-серверов, которые выполняют весь спектр операций, чем три веб-сервера и два сервера бизнес-объектов. Все эти внепроцессные вызовы между веб-серверами и серверами бизнес-объектов поглощают много ресурсов. К специализации следует прибегать только ради известного и ожидаемого улучшения. И быстрейшее решение - не всегда лучшее. Целью масшабирования является единообразие производительности. По мере увеличения нагрузки диапазон производительность желательно сужать - будь пользователей двое или тысяча, определенная страница должна отображаться для них за одно и то же время. Рано или поздно для более эффективного масштабирования будет необходимо оптимизировать код сервера. Практически все аспекты уравнения производительности масштабируются линейно, за исключением времени вычислений на сервере - всегда можно увеличить пропускную способность (и понять, когда это нужно, довольно просто), а время вычислений на клиенте не меняется по мере роста числа клиентов. Другие элементы уравнения производительности также сохраняют свой характер при масштабировании. Но время вычислений на сервере потребует настройки при увеличении числа пользователей. Оптимизация кодаПри оптимизации серверного кода весь фокус состоит в использовании тестирования для проверки наличия реальных результатов. Для анализа приложения и поиска мест в приложении, вызывающих наибольшие затраты времени, следует использовать профилирование. Весь процесс должен быть основан на эксперименте: используйте средства чтобы найти код, который следует улучшить, улучшите код, проведите тестирование, чтобы увидеть, улучшилась ли производительность, повторяйте до получения нужных результатов. Для действительно крупных веб-узлов настройку производительности часто сравнивают с покраской моста "Золотые врата": к тому времени, как докрасишь его до конца, в начале краска уже облезла, и пора браться за дело снова. Меня всегда поражает число людей, считающих, что масштабирование начинается с распределения. "Нужно больше оборудования!" - кричат они. Не поймите меня неправильно: добавление оборудования, без сомнения, может помочь. Но без специализации и оптимизации отдача будет минимальной. Специализация позволяет распределять составные части приложения нужным образом. Например, если отделены серверы изображений, то их можно легко масштабировать независимо от остальной части приложения. Оптимизация также дает дополнительные дивиденды при распределении, уменьшая объем работы, необходимый для определенной операции. Это напрямую выливается в уменьшение числа серверов, необходимых для обслуживания того же числа пользователей. Балансировка нагрузкиЧтобы применить распределение, необходимо добавить новые серверы, продублировать приложение на них и организовать балансировку нагрузки. Для балансировки нагрузки можно использовать службу балансировки сетевой нагрузки (Network Load Balancing - NLB), входящую во все версии Windows Server® 2003. NLB делает каждый сервер равноправным партнером в отношении балансировки нагрузки. Все они используют одинаковый алгоритм балансировки, и все они прослушивают весь трафик на общем виртуальном IP-адресе. Основываясь на алгоритме балансировки нагрузки, каждый сервер знает, какой сервер должен работать над каждым конкретным запросом. Каждый сервер в кластере оправляет периодический сигнал, давая остальным знать, что он работоспособен. При сбое сервера периодический сигнал для него останавливается, и остальные серверы компенсируют потерю выбывшего автоматически. СходствоВ конечном счете, сложность эффективного распределения состоит в ликвидации сходства. Например, при наличии только одного веб-сервера хранение на нем данных сеанса вполне понятно. Но где хранить сведения о сеансе при наличии более чем одного веб-сервера? Один из подходов заключается в хранении их на веб-сервере и использовании сходства. По сути это значит, что первый запрос от определенного пользователя проходит процедуру балансировки нагрузки, но после этого все последующие запросы от данного пользователя/сеанса отправляются на тот же сервер, что и первый запрос. Этот подход прост, его поддерживает каждое решение балансировки нагрузки, и в некоторых случаях он даже осмыслен. Но в долгосрочной перспективе сходство создает затруднения. Хранение данных сеанса в процессе может быть быстрым, но если рабочий процесс ASP.NET перезапускается, все эти сеансы погибают. А рабочие процессы перезапускаются по множеству причин. При высокой нагрузке IIS может перезапустить рабочий процесс ASP.NET, посчитав его зависшим. Более того, по умолчанию IIS 6.0 перезапускает рабочий процесс каждые 23 часа. Это можно скорректировать, но, так или иначе, пользователям угрожает потеря данных их сеанса, пока они в процессе. Пока веб-узел невелик, это не такая уж проблема, но по мере его роста и увеличения занятости растет и она. И это еще не все. В случае балансировки нагрузки по IP-адресу один из серверов непременно столкнется с мега-прокси (вроде AOL) и будет неспособен обслужить всю эту нагрузку самостоятельно. Кроме того, перевод серверов на новые версии приложения становится более сложным - необходимо либо ждать часами, пока пользователи закончат операции на веб-узле, либо раздражать этих пользователей, прерывая их сеансы. Становится проблемой и надежность: с потерей сервера теряется масса сеансов. Устранение сходства является ключевой задачей распределения. Это требует вывода данных о состоянии сеанса из процесса, что означает уменьшение производительности ради увеличения масштабируемости. При выводе сеанса из процесса данные сеанса сохраняются там, где к ним могут получить доступ все веб-серверы - либо в SQL Server®, либо на сервере состояния ASP.NET. Это настраивается в web.config. Поддержка внепроцессного сеанса также требует определенных усилий по написанию кода. Все классы, которые будут храниться в объекте Session ("Сеанс"), следует пометить атрибутом Serializable ("Сериализуемый"). Это значит, что все данные в классе должны быть либо сериализуемыми, либо помеченными как NonSerialized ("Не сериализуемые"), чтобы класс был проигнорирован. Если не разметить классы, то возникнут ошибки при переносе сеанса сериализатором из процесса в хранилище. Наконец, вывод сеанса из процесса является отличным способом обнаружить, что в объекте сеанса находится слишком много данных, поскольку теперь пользователю приходится расплачиваться за двукратное перетаскивание этой горы данных туда и сюда по сети (первый раз для получения ее в начале страницы, второй раз для возвращения ее в конце страницы) при каждом запросе страницы. Разобравшись с объектом сеанса, переходите к другим проблемам сходства, таким как членство и диспетчер ролей. Каждая из них представляет свои сложности при устранении сходства. Но чтобы приложение ASP.NET действительно могло масштабироваться вверх, необходимо отловить все возможные формы сходства и устранить их. Все стратегии, о которых рассказано к этому моменту, применимы для практически любого веб-приложения, нуждающегося в масштабировании. На самом деле, их можно применить к масштабированию практически любого приложения с использованием любой технологии. Теперь давайте взглянем на некоторые методики, уникальные для ASP.NET. Сведение к минимуму объема полезных данныхВзгляд на уравнение производительности позволяет увидеть, что объем полезных данных играет значительную роль, особенно в случае ограниченной пропускной способности. Уменьшение размера объема полезных данных улучшит время реакции, даст некоторые преимущества для масштабирования благодаря уменьшению числа перемещаемых байтов и может даже позволить сэкономить сколько-то денег на оплате пропускной способности. Один из простейших способов уменьшить объем полезных данных - включить сжатие. В IIS 6.0 можно указать, следует ли сжимать статические файлы, динамически созданные ответы (страницы ASP.NET, например) или то и другое (см. рис. 4).
Рис. 4 Configuring Compression Server-Wide in IIS 6.0 IIS 6.0 сжимает статические файлы по требованию, сохраняя их в указанном кэше сжатых файлов. Для динамически созданных ответов копии не сохраняется, они сжимаются каждый раз. IIS 7.0 подходит к сжатию более разумно, сжимая только часто используемые файлы. При сжатии тратится процессорное время, но на специализированном веб-сервере мощности ЦП обычно имеется в избытке. Тем не менее, IIS 7.0 дополнительно оптимизирован так, что процессы сжатия откладываются, когда процессор серьезно загружен. Существуют также специализированные устройства сжатия, независимые от самого веб-сервера. Другая область с богатыми возможностями уменьшения объема данных - состояние представления (ViewState). В ходе разработки использование состояния представления может запросто выйти из-под контроля. Большинство веб-элементов управления используют состояние представления в какой-то мере, так что на страницах, где их много, состояние представления может разрастись до тысяч байтов. Чтобы уменьшить использование состояния представления, отключайте его на элементах управления, когда оно не нужно. В некоторых случаях разработчики даже устраняют элементы управления, чтобы уменьшить состояние представления. Но это не всегда обязательно. Большинство современных веб-элементов управления чувствительны к проблеме избыточного состояния представления и предоставляют детальный контроль над его размером. Существует также оборудование, способное удалять и заменять состояние представления, не изменяя код или то, как работает приложение. Одной из наиболее эффективных технологий уменьшения объема данных является AJAX. Если не считать, конечно, того, что AJAX, на самом деле, не уменьшает их объем - он просто уменьшает видимый объем полезных данных, увеличивая общее число байтов, отправляемых обозревателю. Использование AJAX делает родительскую страницу меньше, так что время первоначальной визуализации сокращается. Отдельные элементы на данной странице после этого направляют собственные запросы серверу для заполнения данных. По сути, AJAX распределяет нагрузку по времени, давая пользователю что-либо видимое, пока загружаются прочие части. Так что использование AJAX улучшит обслуживание пользователей в целом, но не забудьте заглянуть в уравнение производительности, чтобы измерить цену этого. AJAX обычно увеличивает время вычислений на клиенте, порой так радикально, что производительность может стать неприемлемой. Если обращения AJAX к серверу для заполнения отдельных элементов заменяют запросы целых страниц, в итоге объем приемов-передач уменьшится. Но во многих случаях этот объем для каждого конкретного пользователя, наоборот, возрастает. Необходимо прилежное тестирование, чтобы узнать, улучшает ли AJAX производительность или понижает ее. КэшированиеСпециалисты по масштабированию приложений ASP.NET много говорят о кэшировании. В основе своей кэширование предназначено для перемещения данных ближе к пользователю. В типичном приложении ASP.NET до его оптимизации практически все данные, нужные пользователю, хранятся в базе данных и извлекаются из нее при каждом запросе. Кэширование изменяет это поведение. ASP.NET реально поддерживает три формы кэширования: кэширование страниц (также известное как выходное кэширование), частичное кэширование страниц и программное кэширование (также известное как кэширование данных). Кэширование страниц намного проще остальных форм кэширования. Для его использования добавьте директиву @OutputCache к странице ASP.NET и включите правило, чтобы указать срок ее истечения. Например, можно указать, что страницу следует кэшировать в течение 60 секунд. При наличии такой директивы первый запрос страницы будет произведен как обычно и получит доступ к базе данных и прочим ресурсам, которые могут быть нужны для создания страницы. После этого страница удерживается в памяти веб-сервера 60 секунд, и все запросы к ней обслуживаются напрямую из памяти. Увы, хотя этот пример и прост, он игнорирует фундаментальную истину кэширования страниц: практически не существует страниц ASP.NET, которые были бы достаточно статичны для кэширования их целиком на сколь-либо заметный промежуток времени. Здесь-то и помогает частичное кэширование страниц. С его помощью можно пометить части страницы ASP.NET как кэшируемые, чтобы вычислялись только регулярно изменяющиеся части. Этот метод более сложен, но эффективен. Наибольшей, может быть, широтой возможностей (и наибольшей сложностью) отличается программное кэширование, уделяющее основное внимание объектам, используемым страницей. Наиболее распространенное использование программного кэширования - хранение данных, извлеченных из базы данных. Наиболее очевидная проблема с кэшированием данных состоит в том, что нижележащие данные могут измениться после их кэширования. Истечение срока кэширования - это крупнейшая сложность при применении любой формы кэширования. Но необходимо также подумать и о памяти. На загруженном сервере ASP.NET память становится существенной проблемой по ряду причин. При каждом вычислении страницы ASP.NET используется некоторое количество памяти. И Microsoft® .NET Framework настроена на очень быстрое выделение памяти, но сравнительно медленное ее высвобождение через сбор мусора. Рассказа о сборе мусора и выделении памяти .NET хватит на отдельную статью (написанную уже не раз). Достаточно сказать, что на загруженном веб-сервере 2 ГБ пространства памяти, доступных приложению ASP.NET, пользуются большим спросом. В идеале большая часть этого использования памяти является временным, поскольку память выделяется переменным и структурам, используемым при вычислении веб-страницы. Но когда речь заходит о постоянных объектах памяти, подобных внутрипроцессному сеансу и объектам кэша, использование памяти создает куда больше проблем. И, само собой, эти проблемы всплывают только при серьезной загрузке приложения. Представьте себе следующую ситуацию: веб-узел ходит ходуном благодаря какой-нибудь новой рекламной акции, тысячи пользователей щелкают ссылку на него, и его хозяин делает приличные деньги. Чтобы поддержать хорошую скорость реакции, части страниц и группы объектов данных кэшируются при каждой возможности. Каждый запрос страницы пользователем поглощает немного памяти, так что индикатор потребляемой памяти продолжает ползти вверх. Тем быстрее, чем больше пользователей. Возникают также большие скачки от кэша и объектов сеанса. Когда общий процент используемой памяти приближается к пределу памяти кэша ASP.NET по умолчанию (90%), вызывается событие сборки мусора. Событие сборки мусора проходит по пространству памяти, перемещая вниз задержавшиеся в ней объекты (вроде объектов кэша и объектов сеанса) и освобождая более не используемую память (которая была задействована для вычисления веб-страниц). Освобождение неиспользуемой памяти происходит быстро - в отличие от перемещения задержавшихся объектов. Так что чем их больше, тем сложнее сборщику мусора выполнить его работу. Этот тип проблемы можно опознать в perform.exe по большому числу коллекций gen-2. И помните, что пока идет сборка мусора, этот сервер ASP.NET не может обслуживать страницы; все остальное ждет в очереди, ожидая завершении процесса сборки мусора. А IIS наблюдает за этим. Если покажется, что процесс занимает слишком долго и, возможно, завис, то рабочий поток будет перезапущен. И хотя это очень быстро высвободит массу памяти, выбросив все эти задержавшиеся в памяти объекты, некоторые клиенты явно будут недовольны. Сейчас существует исправления для ASP.NET, автоматически удаляющее объекты из программного кэша при недостатке памяти, что, на первый взгляд, может показаться хорошей идеей. Это лучше, чем полный отказ. Просто помните, что при каждом удалении чего-либо из кэша код со временем поместит этот объект обратно. В момент кэширования возникает риск, что оно окажется неверным. Возьмем, для примера, базу данных каких-нибудь штуковин и соответствующую страницу заказов. В первоначальном воплощении страницы штуковин каждая визуализация страницы включала в себя запрос от базы данных относительно числа штуковин, остающихся в каталоге. Проанализировав запросы, скорее всего можно найти, что в 99% случаев каждый раз извлекается одно и то же число. Так почему бы не кэшировать его? Простым способом сделать это будет кэширование на время. Так что каталог штуковин кэшируется, допустим, на час. Недостаток такого подхода заключается в том, что кто-нибудь, купив штуковину и перейдя обратно на страницу, увидит, что каталог не изменился. Это вызовет жалобы. Но гораздо более проблематично то, что кто-нибудь может увидеть в каталоге и купить штуковину, которая уже продана. Можно создать систему недопоставки, но, так или иначе, клиент будет разочарован. Возможно проблема состоит в схеме истечения срока кэширования: истечение срока по времени неудовлетворительно. Можно кэшировать число в каталоге до момента, когда кто-нибудь купит штуковину, после чего завершить пребывания объекта в кэше. Это более логично, но что произойдет при наличии более чем одного сервера ASP.NET? В зависимости от сервера, в каталоге будет указываться разное число штуковин. Если учесть, что получение нового каталога (добавляющего к цифрам) даже не пройдет через веб-приложение, то получается целый новый способ сделать все неправильно. Синхронизация истечений срока кэширования между серверами ASP.NET возможна, но требует осторожности. Объем общения между веб-серверами возрастает в геометрической прогрессии по мере роста числа объектов кэша на них. Также необходимо тщательно изучить влияние истечения срока кэширования на производительность. В условиях высокой загрузки истечение срока нахождения объекта в кэше может доставить массу неприятностей. Для примера, предположим, что имеется ресурсоемкий запрос, тратящий 30 секунд на возвращение из базы данных. В целях экономии ресурсов и потому, что в периоды нагрузки эту страницу запрашивают каждую секунду, запрос кэширован. Код обработки объектов кэша довольно прост. Вместо извлечения данных из базы данных по мере нужды приложение сперва проверяет, заполнен ли объект кэша. Если да, оно использует данные из объекта кэша. Если нет, оно исполняет код для извлечения данных из базы и затем заполняет объект кэша этим данными, после этого продолжается нормальное исполнение кода. Проблема в том, что если имеется запрос, выполняющийся за 30 секунд, а страница исполняется каждую секунду, за время, необходимое для заполнения элемента кэша, поступит еще 29 запросов, и каждый из них попытается заполнить элемент кэша собственными запросами к базе данных. Чтобы решить эту проблему, можно добавить блокировку потока, чтобы предотвратить запрос данных из базы данных исполнениями других страниц. А теперь пройдемся по этому случаю снова: приходит первый запрос, обнаруживает, что элемент кэша не заполнен, применяет блокировку к коду и выполняет запрос на заполнение объекта кэша. Второй запрос прибывает через секунду, пока первый еще работает, обнаруживает, что объект кэша не заполнен, но существует блокировка и блокируется. Как и следующие 28 запросов. Затем первый из них завершает свой процесс, снимает блокировку и продолжает. Что происходит с остальными 29 запросами? Они больше не блокированы, так что они также продолжают исполняться. Но они уже проверили объект кэша на заполненность (в момент, когда он не был заполнен). Так что они попытаются ухватить блокировку, одному это удастся, и он выполнит запрос снова. Проблема ясна? Другие запросы, прибывающие после того, как первый запрос завершил заполнение объекта кэша, будут работать нормально, но запросы, прибывшие в ходе этого процесса, попадают в трудную ситуацию. Необходимо написать код для избежания этого. Если запрос сталкивается с блокировкой, то после ее отмены он должен проверить снова, не заполнен ли объект, как показано на Рис. 5. Скорее всего, теперь он заполнен, этим и было обусловлено само наличие блокировки. Хотя возможно и обратное из-за того, что какая-то другая часть кода вновь сделала объект кэша истекшим. Рис. 5 Проверка, блокировка и повторная проверка объекта кэша// check for cached results Написание хорошо работающего кода кэширования - трудная работа, но отдача может быть громадной. Однако кэширование повышает сложность, так что используйте его с умом. Убедитесь, что эта сложность даст реальные выгоды. Всегда тестируйте код кэширования для подобных сложных случаев. Что произойдет при нескольких одновременных запросах? Что произойдет при быстрых истечениях срока кэширования? Ответы на эти вопросы необходимо знать. Код кэширования должен решать, а не обострять проблемы масштабирования,. Масштабирование баз данныхНормальный подход к масштабированию веб-узлов - это добавление систем вместо их наращивания. В основном это обусловлено ограничениями потоков и памяти ASP.NET в сочетании с краткосрочной природой веб-запросов. Однако, когда дело доходит до масштабирования баз данных, обычной практикой является наращивание - одна гигантская система, возможно две в кластере (хотя только одна реально несет на себе базу данных в каждый конкретный момент времени). Но рано или поздно каждое крупное веб-приложение доходит до стадии, когда одной базы данных недостаточно. Необходимо расширяться. Если возможно, достаточно применить те же стратегии масштабирования, что и к самому веб-приложению. Первым действием всегда является специализация - разбиение базы данных на логические разделы. Эти разделы могут быть основаны на разделении данных, возможно по регионам. В результате получится несколько баз данных, каждая из которых содержит часть изначальной базы данных. Например, один сервер будет содержать данные по восточному берегу США, а второй по западному берегу. Однако действительно большие веб-приложения разделяют свои базы данных на базы чтения и записи (см. рис. 6). Базы данных чтения предназначены только для чтения, они получают свои данные от баз данных записи посредством репликации. Все запросы данных направляются базам данных чтения, оптимизированным на как можно более быстрое чтение данных. Базы данных чтения по своей природе легко распределяемы.
Рис. 6 Distributed Database Architecture Все запросы на запись данных отправляются базам данных записи, которые разбиты на разделы и настроены на эффективную запись. Репликация перемещает новые данные с баз записи на базы чтения. Создание таких специализированных баз данных ведет к задержке: у записи будет уходить некоторое время на распределение по базам данных чтения. Но если с задержкой удастся разобраться, то потенциал масштабирования огромен.
Бесконечная работа над масштабированиемПока приложение продолжает расти, продолжит расти и работа по его масштабированию. Приемы ASP.NET, эффективно работающие с 10 000 одновременно подключенных пользователей, не так эффективны для 100 000, а для 1 миллиона пользователей правила меняются снова. Конечно, производительность может полностью зависеть от приложения, в некоторых из тех, что мы видели, проблемы с масштабированием начинались при менее чем тысяче пользователей! Правило эффективного масштабирования - семь раз отмерь, один раз отрежь. Используйте тестирование, чтобы убедиться, что работа делается там, где нужно. Тестируйте свою работу, чтобы убедиться, что внесены улучшения, а не просто изменения. Даже в конце цикла разработки концентрируйтесь на оптимизации для масштабирования. Необходимо знать, где находятся самые медленные части приложения. Будем надеяться, они достаточно быстры для сегодняшних пользователей, позволяя работать над тем, что потребуется пользователям завтра. Ричард Кэмпбелл (Richard Campbell) является региональным директором Майкрософт, обладателем звания MVP по ASP.NET и одним из ведущих ток-шоу с передачей звука через Интернет .NET Rocks для разработчиков для .NET (dotnetrocks.com). Он провел три года консультируясь с компаниями по вопросам производительности и масштабирования ASP.NET, а также является одним из основателей компании Strangeloop Networks. Kent Alstad является техническим директором компании Strangeloop Networks (strangeloopnetworks.com) и основным автором либо одним из соавторов всех ожидающих регистрации патентов Strangeloop. Прежде чем принять участие в создании Strangeloop, он занимался созданием многочисленных высокопроизводительных, высокомасштабируемых приложений ASP.NET и консультациями по ним. |