Net Форумы

 
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   РегистрацияРегистрация 
 ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход 
Генеральный спонсор: www.Net.Ru - серьезный, профессиональный хостинг.

Оптимизация архитектуры веб-приложений крупных сайтов
На страницу 1, 2  След.
 
Начать новую тему   Ответить на тему    Список форумов Net Форумы -> Java - сервлеты и JSP
Предыдущая тема :: Следующая тема  
Автор Сообщение
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 11.03.2006 00:34    Заголовок сообщения: Оптимизация архитектуры веб-приложений крупных сайтов Ответить с цитатой

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

Сначала попробую систематизировать возможные узкие места (если что — дополняйте):

1. Нехватка CPU.
2. Нехватка RAM.
3. Задержки при выполнении запросов к Database.
4. Задержки из-за HDD/Network IO.

Попробую вкратце описать возможные пути решения по этим пунктам.
Начну снизу (как с наименее интересных мне пунктов).

4. Задержки из-за HDD/Network IO могут быть в случае частого обращения.
- кеширование на уровне файловой системы;
- кеширование в RAM для часто используемых данных.

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

2. Нехватка RAM:
- минимизация создания объектов;
- применение пулов часто используемых объектов, вместо создания новых при каждом запросе;
- уменьшение кеширования данных.

1. Нехватка CPU:
- расширенное кеширование данных;
- оптимизация бизнес-логики;
- кеширования статики в JSP.

С пунктами 3,4 более-менее все понятно. На пунктах 1-2 хотелось бы остановиться подробней, тем более что они являются наиболее проблемными.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 11.03.2006 00:39    Заголовок сообщения: Ответить с цитатой

Итак, что мы имеем:

1. Сайт на Struts (или др., реализующий паттерн MVC) объемом несколько десятков тысяч динамических страниц.
2. Данные хранятся в MySQL, файлах xml.
3. В качестве view-layer используются разные схемы: jsp-представление либо xslt-преобразование xml-потока данных в итоговый html.
4. Информация на сайте обновляется ежедневно (а вернее, в течение суток — обновления прайсов, объявления и т.п.), однако основной режим работы сайта — считывание информации посетителями (число просмотров/число обновлений > 30).

С ростом посещаемости такого сайта, естественно, возрастает потребление ресурсов CPU/RAM. Что можно предложить для оптимизации?

1. Т.к. Resin работает в связке с Apache, по максимуму разгрузить Resin: отдать Апачу — апачево (графику, файлы CSS, JS, html — короче, всю статику).

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

3. Перевести редко изменяемые страницы на статику – html, ssi или jsp (почему и jsp отношу к статике, расскажу дальше), чтоб опять-таки разгрузить Resin.

4. Для всех динамических страниц, которые не могут быть переведены на статику (изменяются достаточно часто, или по каким-то другим причинам), постараться выводить корректные значения заголовков Last-Modified и Expires, чтоб разгрузить Resin за счет акселератора.

5. Кешировать статические части jsp-страниц (шапки, блоки навигации, меню и т.п.).

П.п. 1-4 уменьшают кол-во запросов к Resin, а, следовательно, уменьшают кол-во запросов к СУБД, файловой системе, реже выполняется код, создается меньше объектов в ОЗУ. Т.е. эти пункты одновременно уменьшают потребление ресурсов и RAM , и CPU. П.5. в основном направлен на снижение нагрузки на CPU и уменьшение времени генерации страниц (примитивно говоря, за счет вывода статичных блоков jsp-страниц одним оператором println() вместо множества), в то время, как потребление RAM, теоретически, может увеличивать (кеширование все-таки). Теоретически, т.к. сами не использовали, и опытных данных нет.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 11.03.2006 00:41    Заголовок сообщения: Ответить с цитатой

С п.п. 1-2 все предельно ясно.

П.3. Перевод редко изменяемых страниц на статику.

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

И тут возникает вопрос, какую технологию для статики выбрать:
- при использовании SSI разгружаем Resin, т.к. сборка осуществляется Apache;
- с другой стороны, данных о том, что "легче" для сервера (CPU/RAM) - сборка ssi или jsp при кол-ве включений в пределах десятка — мы не нашли. Есть у кого-нибудь хоть какие-то данные по этому поводу?
- существенный недостаток такой "статики" — необходимость перекомпиляции всех jsp-страниц (парсинг Апачем в случае SSI до попадания обновленной страницы в кеш акселератора) сервера, если в шаблон были внесены изменения. При больших объемах сайта (несколько десятков тысяч страниц) затраты на перекомпиляцию могут быть существенны. Не сведет ли это на "нет" такую оптимизацию?

Не «легче» ли для сервера будет применение подхода, описанного в п.4?

П.4. Вывод корректных значения заголовков Last-Modified и Expires.

В этом случае после первого запроса страница попадает в кеш акселератора (если не установлены соответствующие заголовки no-cache). И уже от его настроек и ресурсов будет зависеть, насколько снизится нагрузка на сервер – будет ли формироваться запрос If-Modified-Since, если клиент (браузер) не сформировал данный запрос, но страница присутствует в кеше, насколько велик размер кеша акселератора и др. По поводу особенностей настроек акселераторов на этом хостинге хотелось бы услышать ответы ув. техподдержки.

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

Плюс ко всему, для определения соответствующих дат и формирования этих заголовков в приложении чаще всего приходится извлечь необходимую информацию (контент) из БД (файлового хранилища и др.), проанализировать и только после этого принять решение — приступить к формированию представления страницы или выдать заголовок Not Modified. Т.е. снижаем нагрузку на CPU/RAM только на уровне View (я веду речь об оптимизации веб-приложений, реализующих паттерн MVC, в частности написанных на Struts). Но и эту проблему можно решить за счет кеширования веб-приложениием заголовков наиболее часто запрашиваемых страниц и обновлять их при внесении изменений. Тогда мы сможем разгрузить сервер еще на уровнях Model и Controller.

Вобщем, интересуют мысли, идеи, по всему выше написанному и, в особенности, по последним двум пунктам (п.п.3-4.). Кто сталкивался с подобными проблемами, как решали? Думаю, данная тема может быть интересна многим.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 14.03.2006 11:25    Заголовок сообщения: Ответить с цитатой

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

Про передать апачу апачево - абсолютно верно. Для этого стандартная рекомендация - если в корне сайта через .htaccess все запросы заворачиваются в резин через .htaccess директиву SetHandler caucho-request, то в подкаталогах со статикой этот хэндлер через .htaccess нужно убрать.

Про JSP. В Резине использовние JSP не снижает нагрузку. Даже повышает, и при этом достаточно сильно. JSP сначала переводится в java-код и затем компилируется в сервлет. У резина компиляция _очень_ ресурсоемкая, на компиляцию банальной HelloWorld.jsp уйдет около 5 секунд CPU. Скомпилированные из JSP сервлеты перекомпилируется при каждом рестарте резина.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 14.03.2006 11:40    Заголовок сообщения: Ответить с цитатой

Перевод редко изменяемых страниц - в каком-то виде акселератор это же и делает, только делает прозрачно для приложения.

Но для java-приложений обычным добавлением Last-modified и Expires вря ли все ограничится. Сервер приложений по умолчанию создает сессию и передает ее в куках. Поэтому если кому-то попадется закэшированная страница, которая была сгенерирована для другого пользователя и выставляла ему сессию через Set-cookie, то эта сессия окажется у другого пользователя. Здесь самый простой паттерн - разделять логически сайт на части, где требуется удержание сессии с клиентом и те, где не требуется - общая часть.

Если пользователь с установленными куками сессии ходит по общей части - проблемы это никакой не создаст. Главное, чтобы если приложение в общей части получило запрос от пользователя без сессии, оно не пыталось их установить. В крайнем случае, если это уже жестко зашито в код, запретило акселератору кэшировать ответ (через заголовок Cache-control: no-cache)
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 14.03.2006 12:09    Заголовок сообщения: Ответить с цитатой

Кэш акселератора составляет от 1 до 10 Гб. Максимальный срок хранения объекта в кэше - 24 часа. Если у объекта есть Expires, срок годности устанавливается в него, но все-равно не больше, чем 24 часа с момента запроса. Кроме того, используется и Last-modified заголовок - он тоже ограничивает срок годности: срок от последнего изменения объекта до момента запроса поделенный пополам. Т.е. если объект был изменен за 2 часа до запроса, то масксимальный срок его жизни будет 1 час.

Если запрос к объекту поступит уже после истечения его "срока годности", объект перезапросится у веб-сервера.

Когда клиент запрашивает с if-modified-since, если объект находится в кэше и не устарел, запрос к веб-серверу не направляется.

Из кэша можно принудительно удалить документ, если послать ему запрос с методом PURGE, это можно сделать и из приложения. Например, после изменения каких-то данных на сайте послать акселератору запрос на удаление страниц, на которых может отразиться это изменение.

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

Например, при генерации первой страницы, у которой есть маленький блок новостей и блок специальные предложения - класть для этого urlа в лог dependency на области (news, offer). При генерации страницы раздела новостей - только на news. Там, где добавляется новость, указываем, что при этом изменяется область news и после операции выполняем очистку всех урлов с этой зависимостью.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 16.03.2006 14:49    Заголовок сообщения: Ответить с цитатой

О кэширование сгенерированных компонентов страницы

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

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

Хранить кэшированные страницы в базе - наоборот, практически на порядок медленнее. Тем более неправильным является мнение, что быстрее сгенерировать страницу из данных, находящихся в базе, чем брать ее из файлового кэша - это совершенно не так.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 16.03.2006 20:01    Заголовок сообщения: Ответить с цитатой

Цитата:
Сервер приложений по умолчанию создает сессию и передает ее в куках.

Не совсем понятно это утверждение. Разве это зависит не от самого приложения? Если я не устанавливаю сессию внутри приложения (например, request.getSession(true);), не работаю с куками, почему сервер должен устанавливать сессию?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 16.03.2006 20:04    Заголовок сообщения: Ответить с цитатой

Цитата:
Про JSP. В Резине использовние JSP не снижает нагрузку. Даже повышает, и при этом достаточно сильно. JSP сначала переводится в java-код и затем компилируется в сервлет. У резина компиляция _очень_ ресурсоемкая, на компиляцию банальной HelloWorld.jsp уйдет около 5 секунд CPU. Скомпилированные из JSP сервлеты перекомпилируется при каждом рестарте резина.

Да, есть наблюдения, когда после изменения какой-нибудь включаемой части (jsp-страницы) в результате последовательной перекомпиляции нескольких страниц (вызванной несколькими запросами подряд), резин уходил в даун, выдавая 503 ошибку. В случае, когда один и тот же изменяемый блок (jsp) включается большим числом jsp-страниц, и изменения происходят часто, имеет смысл включать его директивой <jsp:include page=”page_src.jsp" flush="true" />, а не <%@ include file=”page_src.jsp" %> (если, конечно, включаемый блок не содержит jsp-кода). Тогда не будет множественной перекомпиляции страниц.

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


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 16.03.2006 20:04    Заголовок сообщения: Ответить с цитатой

Цитата:
Перевод редко изменяемых страниц - в каком-то виде акселератор это же и делает, только делает прозрачно для приложения.

Вопрос в другом — какая именно страница будет попадать в кеш акселератора при первом к ней запросе — результат работы сервлета (динамическая страница, отдаваемая резином) с соответствующими запросами к БД, файловой системе и т.п. или предварительно сгенерированная страница SSI (отдаваемая апачем)? Какой подход создаст меньшую нагрузку на сервер, с учетом того, что страницы в кеше хранятся, как вы говорите, 24 часа? Конечно, многое зависит от внутренней структуры приложения, в частности от того, как, например, будут создаваться итоговые страницы SSI. Вполне логичным (с т.з. универсальности) для генерации было бы использование xml-шаблонов страниц с соответствующими xslt-преобразованиями, а это тоже достаточно ресурсоемкие технологии. Многое зависит также от характера нагрузки на сайт, его объема и частоты обновлений.

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

Хотя возможно, есть ньюансы, о которых я не знаю и которые сведут «на нет» все мои рассуждения. Smile
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 17.03.2006 16:21    Заголовок сообщения: Ответить с цитатой

Ser G писал(а):
Цитата:
Сервер приложений по умолчанию создает сессию и передает ее в куках.

Не совсем понятно это утверждение. Разве это зависит не от самого приложения? Если я не устанавливаю сессию внутри приложения (например, request.getSession(true)Wink, не работаю с куками, почему сервер должен устанавливать сессию?


Просто сервлеты нет. А JSP по дефолту заводит сессию и отдает в куках:

Код:
cv@cv$ hreq example.inc.ru /hello.jsp
HTTP/1.0 200 OK
Date: Fri, 17 Mar 2006 13:20:57 GMT
Server: Apache/1.3.33 (Unix) mod_fastcgi/2.4.2 Resin/2.1.12 PHP/4.4.2
Set-Cookie: JSESSIONID=aD2SvIqhHqs6; path=/
Content-Type: text/html
X-Cache: MISS from root2.net.incru.net
Connection: close


<HTML>
<HEAD>
<TITLE>hello.jsp</TITLE>
</HEAD>
<BODY>
<H1>hello.jsp</H1>

JSP example
</BODY>
</HTML>
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
CV
Core team


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 17.03.2006 16:28    Заголовок сообщения: Ответить с цитатой

Ser G писал(а):

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


Если предварительно генерировать в SSI, то на одну лишь предварительную генерацию невостребованных страниц уйдет куча лишних ресурсов.

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


Зарегистрирован: 01.01.1970
Сообщения: 965

СообщениеДобавлено: 17.03.2006 16:32    Заголовок сообщения: Ответить с цитатой

Из нюансов использования кэша страниц в сервлетах - делать сервлет максимально простым и не плодить объектов без необходимости. Не использовать пулы, не пытаться кэшировать особенно частые страницы в памяти jvm. Делать кэширующую часть максимально простой.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Ser G
Member


Зарегистрирован: 01.01.1970
Сообщения: 138
Откуда: Краснодар

СообщениеДобавлено: 14.03.2007 18:05    Заголовок сообщения: Ответить с цитатой

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

Есть у кого-нибудь опыт их использования? Поделитесь Smile
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Се ля ви
Member


Зарегистрирован: 07.02.2007
Сообщения: 8
Откуда: Москва

СообщениеДобавлено: 06.04.2007 14:14    Заголовок сообщения: Ответить с цитатой

Ser G писал(а):
1. Т.к. Resin работает в связке с Apache, по максимуму разгрузить Resin: отдать Апачу — апачево (графику, файлы CSS, JS, html — короче, всю статику).

Меня терзают смутные сомнения... А как насчёт вялой и простой полу-динамики, которую можно впихнуть в SSI - стоит это делать или нет для увеличения производительности?
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Показать сообщения:   
Начать новую тему   Ответить на тему    Список форумов Net Форумы -> Java - сервлеты и JSP Часовой пояс: GMT + 3
На страницу 1, 2  След.
Страница 1 из 2

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Powered by phpBB
Русская поддержка phpBB