GWT – подглядываем в передаваемые данные

imageGWT – отличный фреймворк. Я — Java-разработчик, и мне доводилось работать с тонкими клиентами с использованием JSP, JSF и GWT. Про JSP говорить особо нечего, технология сейчас практически вымерла, а вот в JSF-е пришлось повариться пару лет на двух проектах, и впечатления, мягко говоря, не из лучших: мешанина JSTL, HTML, JavaScript и прочего доставляет несказанное “удовольствие”, доходящее до экстаза в моменты разбора непонятного поведения какой-нибудь сложной страницы. Да, в примерах все выглядит аккуратно и просто, но реальная жизнь не такая, и JSF-страницы проекта даже среднего размера и, вроде бы, с грамотным неторопливым подходом при проектировании, с использованием шаблонов, все равно начинает “попахивать”, особенно в части читабельности. В GWT все достаточно аккуратно, ведь пишем на родном языке Java, пусть и в урезанном варианте, но того что есть более чем достаточно.

Если говорить о том, что в GWT на клиента грузятся огромные файлы JavaScript-а, то тут мнение мое такое. В GWT при первом входе на клиента грузится логика, пусть и много, но лишь один раз. После загрузки между клиентом и сервером ходят только чистые данные бизнес-логики. Конкретно у меня первая загрузка 3МБ, затем AJAX-запросы/ответы, тут уж зависит от того, что у вас за объемы данных. В JSF-е же, при входе на любую страницу в браузер идут и данные и описание интерфейса, в котором они отображаются. В большинстве случаев размер описания интерфейса (html-а) во много раз больше размера самих данных. Чтобы показать на клиенте 1КБ данных (несколько строчек таблицы, например), вам придется передать в браузер 15-30 кБ html-а (считаем, что изображения и скрипты закешированы). А ведь данных на странице обычно гораздо больше: заголовки, меню, различные блоки и т.д. Фактически, достаточно насыщенная данными и функционалом страница обычно весит не менее 100-200 кБ. GWT же для отображения такой же страницы заберет с сервера 1 кБ данных и всё. Если пользователи постоянные и подолгу находятся на сайте, то потеря первичных 3МБ компенсируется за полчаса. С учетом этого, GWT идеально подходит для реализации рабочих мест, а вот для обычных сайтов он может быть не так хорош.

В любом случае, это лишь вступление для того, чтобы немного “окунуться” в рассматриваемую тему, а статья не о сравнении технологий, а о том, как подглядывание за данными, которые ходят между браузером и сервером, может помочь в решении проблем и в оптимизации клиент-серверного взаимодействия. На момент написания, у нас использовался уже очень сильно устаревший GWT 1.5, а для передачи DTO столь же старая и уже не поддерживаемая библиотека Gilead. У меня в планах обновление до последней версии GWT и отказ от Gilead в пользу GWT-шного RequestFactory. Независимо от технологий, инструментарий и методы отладки остаются теми же. Я использовал FireFox с установленным плагином FireBug.

Как мы нашли утечку памяти

Однажды мы решили обновить используемые технологии – GWT, Gilead, JBoss, Hibernate. Заменили библиотеки, развернули сервер, перекомпилировали проект. Запустили, оттестировали, и решили выходить на промышленную эксплуатацию. Обновили сервер, ждем. Первые отзывы – работает быстрее. Через час все начало “подвисать”, через 15 минут “встало колом”, еще чуть позже сервер упал по OutOfMemory. Начали судорожно пытаться разобраться в проблеме, перезапускали сервер каждый час в это время. Опять же, статья не совсем об этом, кончилось тем, что утечку обнаружить так и не удалось, и мы откатились на старую версию. Я долго пытался анализировать дампы, делать нагрузочное тестирование, но так и не нашел источник проблемы.

Спустя месяц, тестировщик стал жаловаться на то, что один из журналов в Системе долго открывается (ему в свою очередь на это пожаловались пользователи). У меня эта проблема не воспроизводилась, я попросил его установить FireFox и FireBug и посмотреть, что там происходит. Оказалось, что при открытии журнала на клиента грузится пакет размером около 4-х мегабайт (!!!), для того, чтобы отобразить табличку из десятка записей. Источник проблемы был сразу найден – на сервере, при выборке данных для отображения, не было установлено ограничение на количество записей, считываемых из БД, и на клиента грузилось все содержимое таблицы БД. У меня в тестовой базе разработчика в таблице было полсотни записей, а у тестировщика был свежий дамп промышленной базы с тысячами записей в этой таблице. Исправление проблемы – добавление одной строчки кода.

Я думаю, что причина “падения” сервера при обновлении технологий была именно в этом журнале. Почему старые технологии справлялись? Видимо, в них меньше использовалось кеширование данных (косвенно подтверждается отзывами о том, что новые технологии работали быстрее). К сожалению, фейл настолько сильно ударил по нашим пользователям (и конечно же по нам, разработчикам и внедренцам), что следующая попытка обновления JBoss была выполнена только через год, касательно же GWT и Gilead официальных планов вообще нет. Вот так вот забытая строчка кода может порушить грандиозные планы, украсть сотни человекочасов работы, и добавить седых волос множеству людей.

Как сэкономить сетевой трафик и память

Не поленитесь, и потратьте пару часов на то, чтобы просмотреть в FireBug что передается на сервер и обратно, можно обнаружить интересные вещи. Конкретный пример: клиент (браузер) периодически запрашивает с сервера наличие уведомлений. По сути, надо передать на сервер данные о том, кто запросил, в ответ получить список. У нас на клиенте хранится объект User, который содержит в себе немало информации о нем, в том числе различные списочные данные. Так вот, метод, запрашивающий данные с сервера был реализован просто – передается объект User целиком. Точно также реализованы и очень многие другие методы. Посмотрев под отладкой, я увидел, что размер сериализованного в строку и передаваемого на сервер User-а 15кБ. А ведь на сервере в кеше сессии пользователя есть копия этого объекта, а для получения запрашиваемых методом данных вообще достаточно идентификатора пользователя. Если заменить в методе объект User на его ID, размер запроса можно уменьшить с 15кБ до 50-100 байт, а то и вовсе вызывать метод без параметров, а данные о пользователе брать из текущей сессии.

Казалось, что для современной сетевой инфраструктуры 15кБ? Пыль! Но не следует забывать, что запросов много, и пользователь в системе не один. К тому же, кроме сетевых ресурсов, на сервере расходуются ресурсы процессора и памяти на то, чтобы преобразовать полученные 15кБ в Java-объект User, из которого будет гордо вытащен ID для запроса, а все остальное будет оставлено сборщику мусора.

Как я делал нагрузочное тестирование

Когда у нас стал падать сервер при обновлении технологий, одной из попыток обнаружения источника проблемы было проведение нагрузочного тестирования. Быстрый поиск и просмотр бесплатных утилит и программных библиотек не помог в создании среды тестирования, поэтому я решил попробовать написать что-то простейшее самостоятельно. Всё, что отсылает на сервер GWT, – это HTTP-запросы, а значит можно попробовать сэмулировать их стандартными средствами языка Java. Только вот, что именно передавать в запросах? Опять же, на помощь пришел FireBug. Заходим в клиентскую часть, выполняем любые действия, в FireBug-е забираем содержимое POST-запросов. Самописная утилита для нагрузочного тестирования получилась совсем небольшой и вполне функциональной. Некий объект Пользователь выполняет повторяющийся набор действий, т.е. отправку HTTP-запросов. В разных потоках запускаются несколько десятков/сотен таких объектов и дают достойную нагрузку на сервер. Прямо сейчас тестирую под нагрузкой Систему для проверки после перехода на JBoss 7: ресурсы процессора используются сервером на 90%, за ночь съелось 500МБ памяти, при входе в клиентскую часть ощутимая «заторможенность», а это значит, что нагрузка хорошая!

Заключение

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

Похожие публикации

AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 13

    +1
    Конкретно у меня первая загрузка 3МБ

    Так и хочется воскликнуть: НИ ХРЕНА СЕБЕ!

    Поясню: я конечно понимаю, что сейчас вроде как везде широкополосный интернет, но давайте вспомним про мобильный интернет в России…
      +4
      Ну, у нас не сайт, а рабочее место, реализованное в виде «тонкого клиента». Т.е., это не главная страничка портала, а полнофункциональное приложение с большим количеством функций. 3-мегабайтовый скрипт, сгенерированный GWT, грузится один раз после очередного обновления промышленного сервера (обычно, не чаще одного раза в месяц) и кешируется браузером. 3МБ раз в месяц — совсем немного, а дальше ходят только чистые данные. Так что мобильный интернет — не наша специфика.
        +2
        Про Code Splitting вы не слышали?
          +1
          Спасибо, слышал. Но не вижу никакого смысла его применения конкретно в нашем проекте. Еще раз повторю — пользователю загружается 3МБ JavaScript раз в месяц, это немного даже для возможностей сетей десятилетней давности. Специально спросил сейчас у специалиста поддержки, он сказал что пользователи не жалуются на то, что после обновления первый вход в систему длится дольше. А заниматься преждевременной оптимизацией — плохая практика.
      0
      про jsf о какой версии такие ваши впечатления?
      по мне так вобще отличная штука начиная с версии 2, читабельность, разбивка на шаблоны, навигация, доступ к бинам и тд…
      можно любой html шаблон разрезать и натянуть какими нужно кусками, аякс, частичный рендеринг…
      только скорости под нагрузками можно добавить это да
        0
        О спецификации версии 1.2. Я слышал о том, что в версии 2 многое стало лучше, но вещь это достаточно свежая и сталкиваться на практике не приходилось. Если попаду на новый проект с тонким клиентом, обязательно рассмотрю JSF 2 как вариант реализации клиентской части.

        PS Насчет "любой html шаблон разрезать и натянуть какими нужно кусками, аякс, частичный рендеринг" — это у нас и в 1.2 работало, реализация RichFaces.
          +1
          JSF 2 и выше вполне достойная вещь, позволяющая практические без написания JS кода делать нормальные веб приложения.
        +1
        Не очень понятен смысл написания собственных инструментов для тестирования. Тот же JMeter, настроенный как прокси, может записать все запросы из браузера. Всего делов-то: выкинуть ненужное, залупить (от loop) этот запрос, настроить сохранение ошибок, да задать правила построения уродских графиков.
          0
          Поддерживаю, но лишь отчасти. На самом деле разработанный модуль тестирования немного сложнее, чем я написал (т.к. статья была не об этом). Модуль осуществляет логин пользователей, подгруженных из базы либо текстового файла, и последующую передачу запросов с персональным куки (JSESSIONID) для каждого пользователя. При этом, вытащенные из FireBug запросы отправляются не в исходном виде, а с подменой некоторых частей персонально для каждого робо-пользователя (специфика бизнес-логики).

          Возможно, есть готовые инструменты, которые могут все это осуществить, но я разработчик, а не специалист по автоматизированному тестированию, и, к сожалению, не разбираюсь в них.
            0
            Я тоже разработчик, но очень рад что наткнулся на JMeter. Разумеется, там также можно сделать X потоков с разными JSESSIONID.
            Кроме того, можно например инкрементить некий счётчик, и использовать его в переменных (например, если надо залогинить юзеров user1..user100 с паролем user). Но вот если данные совсем непредсказуемые, то да — с этим хуже.
            Самые крутые JMeter'овцы QA-шники вроде бы умеют парсить ответ веб-сервера регэкспом и заносить совпадения в переменные, это я не умею.
          +2
          А ведь данных на странице обычно гораздо больше: заголовки, меню, различные блоки и т.д. Фактически, достаточно насыщенная данными и функционалом страница обычно весит не менее 100-200 кБ. GWT же для отображения такой же страницы заберет с сервера 1 кБ данных и всё.

          На дворе 2006 год? И к тому же, давайте сравнивать котлеты с котлетами (тонкие клиенты или SPA), а не с олдскульной полной загрузкой HTML на каждый чих): XHR был ещё в IE5 в 1999 году; 2006 год — во всех популярных на тот момент браузерах.

          Хотя я понимаю, почему вы используете GWT — веб-приложением занимаются явисты. Переход на стэк HTML5 — это новый отдел фронтендеров и соответственно другой бюджет отдела разработки. Возможно текущие задачи GWT решает (хоть и не лучшим способом). Но вы должны понимать, что вы отстаёте и чем дольше будете сидеть на нём, тем сложнее будет переход на современный стэк создания SPA, а это быстрая и комфортная работа с любого девайса, где есть браузер.

          Если есть желание уже начать переходить, попробуйте начать писать клиент на Angular.js + HTML5 (на ангуляре пишутся большие корпоративные SPA — десятки тысяч SLOC).
            0
            Ну во-первых, краткое упоминание пары технологий в статье ни в коем случае не преследовали целью полноценного сравнения. Я сразу открестился от этого, написав, что это "чтобы немного “окунуться” в рассматриваемую тему".

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

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

            В-четвертых, «чтобы купить что-то хорошее, надо сначала продать что-то хорошее». Какие бы экономные технологии вы бы не использовали, вы не сможете выполнить сколь-нибудь сложную логику на клиенте, не заставив его перед этим что-то загрузить. У меня пользователь целый день сидит на своем рабочем месте и переходит по страницам. Как бы вы не экономили на частичном обновлении страниц, за день в любом случае набежит не один мегабайт метаданных, описывающих интерфейс.
              +1
              Вы посвятили второй абзац сравнению GWT + AJAX со способом получения готовых страниц (или кусков html-кода), полностью генерируемых на сервере, который (в контексте SPA) использовался со времён веб 1.0, в то время как AJAX, JSON, client-side templating, routing уже давно доступны + сегодняшний стэк HTML5. Не было бы этого некорректного сравнения — не было бы и моего комментария.

              Во-вторых, я не писал «плохо решает». GWT пока всех полностью устраивает? — вот и отлично. Возможно скоро поменяются бизнес-процессы и люди захотят работать мобильно, с помощью планшетов или мобильных, а там свои нюансы и, я думаю, вы не станете отрицать, что стэк HTML5 там куда как актуальнее. Вот тогда и начнётся работа по оптимизации.

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

          Самое читаемое