Производительность ABL (4GL): с чего начать?
«Никто не может заставить вас почувствовать себя плохо, если только вы сами этого не позволите»
Элеонор Рузвельт.
Разработчики приложений, создающие различные пользовательские интерфейсы (GUI, CHUI, WebSpeed, Web Client и т.п.), должны не только уметь писать эффективный ABL-код, чтобы обеспечить хорошую производительность своего приложения, но и часто вынуждены дорабатывать чужой для тех же целей.
В этой и, возможно, в последующих статьях я расскажу о различных техниках, позволяющих писать программный код, который будет исполняться быстрее, потреблять меньше ресурсов, и обеспечит повышенное доверие пользователей к системе.
Таков мой план. Но для начала разберёмся с основами.
Что такое настройка производительности?
Любому приложению в какой-то момент своего жизненного цикла требуется тюнинг. Поэтому разработчики приложения должны уметь определять причины замедления производительности для того, чтобы заранее предотвратить их, когда это возможно и быстро исправить, когда они произойдут. При этом понимание производительности – это прежде всего искусство, а не наука, поскольку производительность почти всегда является относительной, а не абсолютной величиной. Иными словами, при разных условиях и требованиях понимание хорошей производительности может существенно отличаться. Мы можем опираться либо на собственные ощущения того, что что-то работает недостаточно быстро, или можем измерить насколько хорошо работает приложение сегодня, а затем сравнить результат с тем, насколько хорошо оно работало в прошлом.
Настройка производительности – это процесс улучшения и ускорения работы системы за счёт более эффективного использования доступных ресурсов.
Хорошо отлаженное приложение имеет массу преимуществ, в том числе:
- высокая скорость выполнения задач в установленные сроки;
- повышенная эффективность больших или критических задач, не приводящих к чрезмерному потреблению системных ресурсов.
Кто отвечает за производительность?
На производительность приложения могут влиять проблемы, связанные с одним или более компонентов общей среды, в которой оно работает. За каждый компонент отвечает функциональная группа внутри организации, с которой обязательно следует наладить хороший контакт, так как с ними придётся взаимодействовать:
- Приложение – взаимодействие с разработчиками приложения.
- Сеть – взаимодействие с сетевыми администраторами.
- База данных – взаимодействие с администраторами баз данных.
- Операционная система – взаимодействие с системными администраторами.
- Сервера (железо) – взаимодействие с системными администраторами.
Все группы специалистов должны тесно работать вместе, чтобы обеспечить высокую производительность и эффективное потребление ресурсов бизнес-приложением.
Производительность зависит от времени
Даже хорошо спроектированное приложение со временем может демонстрировать ухудшение производительности. Факторами, влияющими на такие провалы в производительности, могут быть:
- Подключение большего количества пользователей.
- Добавление большего количества записей в таблицы.
- Повышенная пользовательская активность.
- Увеличение объёма сетевого трафика.
Жизненный цикл приложения и производительность
Вопросам производительности следует уделять внимание на каждом этапе цикла разработки и эксплуатация приложения. Как правило это четыре основных этапа:
- Проектирование.
- Разработка.
- Тестирование.
- Развёртывание.
Этап 1: Проектирование
Первый этап в разработке приложения – это проектирование.
Очень важно подумать о производительности в самом начале цикла разработки на этапе проектирования, как минимум, необходимо учитывать следующее:
- Должна быть правильно спроектирована схема базы данных, в частности таблицы и индексы, в соответствии с бизнес-требованиями и принципами реляционной модели и проектирования производительных баз данных.
- Следует рассмотреть и максимально учесть нетипичные варианты использования.
- Необходимо всегда отделять программирование бизнес-логики от логики пользовательского интерфейса.
- Предусмотреть и учесть возможные будущие модификации.
Анализируя бизнес-требования посмотрите на существующие бизнес-процессы:
- Достаточно ли хорошо они работают в своём текущем виде?
- Если ответ «Да», то можно ли транслировать их в разрабатываемое приложение?
- Если ответ «Нет», то что работает плохо и как это исправить для применения в приложении?
Если вы потратите достаточно времени на проектирование приложения, то в конце концов это приведёт к экономии средств на протяжении всего срока его жизни. Гораздо дороже обойдётся изменение кода, когда приложение уже находится в промышленной эксплуатации много лет, чем если будет потрачено время на планирование производительности на этапе проектирования.
Планирование эффективного приложения
Ваше приложение может использоваться различными категориями пользователей на разных устройствах и конфигурациях. При этом приложение будет работать хорошо, если оно было хорошо спроектировано. Хорошее проектирование должно учитывать:
- Распределённые вычисления.
- Периодические и постоянные подключения.
- Модульность.
Распределённые вычисления
Проектировать приложения следует в соответствии с распределённой вычислительной моделью, также известной как многоуровневая архитектура. Благодаря этой модели логика приложения может быть распределена между множеством машин.
В многоуровневой архитектуре разделение бизнес логики и пользовательского интерфейса необходимо, как минимум, по двум причинам:
- Бизнес-логика определяется потребностями бизнеса.
- Пользовательский интерфейс может отличаться для разных устройств и сред окружения.
Сосредоточьте свои усилия на бизнес-логике на начальном этапе проектирования. Поскольку пользовательский интерфейс(ы) намного легче модифицировать, внимание к нему должно иметь более низкий приоритет.
Периодические и постоянные подключения
При проектировании приложения учитывайте потребности мобильных пользователей. Таким пользователям вероятно необходимо иметь возможность работать с приложением без доступа к сети, то есть подключение к основной системе будет периодическим. При этом следует предусмотреть локальное хранение данных на персональном устройстве с возможностью их последующей синхронизации во время очередного подключения.
Старайтесь не допускать длительных постоянных подключений. Следуйте принципу “пришёл – сделал – ушёл”.
Модульность
Всегда старайтесь разделять данные и функциональные части приложения на отдельные модули, как минимум, это будет способствовать их распределению между разными базами данных и серверами приложений с возможностью балансировки нагрузки. Такой подход обеспечит высокую общую производительность приложения.
Модули можно группировать по функциональным возможностями или по бизнес-процессам. Например, процесс оформления заказа может быть отделён от процесса оплаты этого заказа. Модуль для ведения бухгалтерии должен быть отделён от модуля для отдела продаж или складского учёта.
Этап 2: Разработка
Теперь рассмотрим второй этап в процессе создания приложения.
Во время проектирования приложения не забывайте об использовании передовых и эффективных методов.
Увеличение производительности приложения на стадии разработки обеспечивается написанием эффективного кода. Здесь существует две области, которые имеют наибольшее влияние на производительность – это запросы и транзакции.
Наиболее распространённой причиной медленной работы приложения является использование неэффективных запросов. Даже если большинство запросов эффективны, всего один запрос с неправильным индексом может существенной повлиять на производительность, создавая высокую нагрузку чрезмерным чтением данных на сервере. Поэтому важно правильно спроектировать индексы, которые обеспечат оптимальный доступ к базе данных, и разработать запросы, которые будут эффективно использовать эти индексы.
Рассмотрим простой пример того, почему важно использовать эффективные запросы.
Предположим, что мы хотим отправить email-рассылку всем клиентам, которые живут в районе с почтовым индексом 12345. Что произойдёт, если мы напишем простой оператор FOR EACH, чтобы найти записи, соответствующие этому индексу? Обратите внимание, поле PostalCode в базе данных Sports2000 не индексируется.
FOR EACH Customer WHERE PostalCode MATCHES “12345” NO-LOCK.
Во-первых, клиентский процесс запросит все записи из таблицы, в которых поле ProstalCode соответствует значению 12345. Поскольку поле не индексировано, то клиенту будут возвращены абсолютно все записи из таблицы Customer. Это будет сделано не очень эффективно и очень медленно особенно из большой базы данных.
Во-вторых, после получения этих данных, клиентский процесс должен выполнить в них поиск, чтобы найти записи с требуемым соответствием. Это ещё больше снижает эффективность и замедляет производительность.
Ситуация выглядела бы гораздо лучше, если бы поле PostalCode было проиндексировано. В этом случае из таблицы были бы извлечены и переданы клиенту только необходимые данные.
Другое важное узкое место, особенно в приложениях с базами данных — это конкуренция за блокировки записей.
Разработчики должны организовывать свои транзакции так, чтобы ограничивать их область и время действия, используя наиболее эффективную стратегию, максимально соответствующую требованиям бизнес-правил.
Тема управления транзакциями заслуживает отдельной большой статьи, поэтому, оставьте свой комментарий внизу страницы о том, была бы интересна вам такая статьи или нет.
Этап 3: Тестирование
Часто распространённая ошибка разработчиков и тестировщиков – это использование во время тестирования небольших тестовых баз данных. Как правило, приложение будет хорошо работать с такими базами во время тестирования, но сильно просядет по производительности при работе с реальными большими данными. Поэтому условия тестирования должны максимально соответствовать характеристикам реальной производственной среды.
Существует две основные причины для тестирования приложения перед развёртыванием:
- Поиск ошибок в программном коде и логике.
- Определение проблем с производительностью.
Ошибки в коде обычно обнаруживаются бета-тестерами. В то время как проблемы с производительностью могут не проявить себя во время тестирования если не была создана соответствующая тестовая среда.
Независимо от того, разрабатываете ли вы новый код или улучшаете существующий, вы всегда должны тестировать его в наиболее реалистичной среде.
Некоторые факторы, которые следует учитывать при создании такой среды:
В идеале тестовая среда должна включать: | При тестировании вы должны: |
Базу данных того же размера, что и производственная и даже больше. | Проверить небольшие таблицы на возможность будущего роста. Как поведёт себя таблица при увеличении её объёма? |
Копию производственной базы данных. | Написать процедуру заполнения, чтобы добавлять тестовые данные. |
Архитектуру развёртывания: host-bases, client-server, n-tier. | Тестировать с помощью удалённых подключений. |
К сожалению, это всё в идеальном варианте. Как правило, невозможно точно воспроизвести производственную среду.
Почему я должен тестировать с большой базой данных?
Небольшие базы данных скрывают проблемы с индексацией. Неэффективный код не проявит себя как неэффективный с такой базой, независимо от того, насколько серьёзные у него проблемы.
Например, запрос, который не использует индекс, будет работать так же быстро, как индексированный запрос в одной и той же базе данных Sports2000, так как в её таблице Customer всего 1000 записей, а не сотни тысяч как в реальной производственной базе данных.
Этап 4: Развёртывание
Обычно после того, как приложение развёрнуто в производственной среде, его тюнинг редко рассматривается, потому что Progress «просто работает». Однако это может скрывать плохое проектирование и неэффективный код. Такие проблемы становятся очевидны не сразу и не проявляются до тех пор, пока приложение не отработает в течение длительного периода времени.
Настройка производительности приложения после развёртывания представляет собой циклический четырёхступенчатый процесс:
- Пользователи жалуются на проблемы в приложении.
- Разработчики используют диагностические средства для поиска причины проблемы.
- После обнаружения причины, разработчики корректируют код для её устранения.
- Изменённый код проверяется и тестируется, предпочтительно на копии производственной базы данных.
После четвёртого шага изменённый и протестированный код внедряется в производственную среду. И если он по-прежнему не работает должным образом, и пользователи продолжают жаловаться, то весь процесс повторяется с первого шага.
Рассмотрим это подробнее.
Шаг 1: Получение сообщений от пользователей
Итак, пользователь жалуется – что делать дальше?
Пользователи могут жаловаться в нескольких случаях, если приложение работает медленнее, чем обычно, или оно не выполняет ожидаемые функции. Однако жалобы могут быть единичными, а не надлежащее поведение приложения не воспроизводимым. Поэтому заведите журнал пользовательских обращений (жалоб), что позволит определить, является ли жалоба единичным инцидентом или она указывает на тенденцию.
Задайте пользователю следующие вопросы:
- Какие действия пользователя предшествовали возникновению проблемы с производительностью?
- Какое приблизительное время работы приложения в нормальных условиях и сейчас?
- Менялись ли условия работы, например, были заданы не типичные условия выборки данных для отчёта – была попытка получить отчёт за несколько лет вместо одного месяца в стандартном случае.
- Всё прочее, что пользователь мог заметить и что может помочь указать на источник проблемы.
Шаг 2: Поиск причины проблемы
Теперь необходимо определить, что стало причиной проблемы: аппаратные средства, сеть, операционная система, база данных или ваше программное обеспечение?
Если проблема связана с приложением, то используйте соответствующие диагностические инструменты для поиска причины – PROMON, PROFILER и Virtual System Tables (VST).
Если проблема не вызвана вашим приложением, то обратитесь к соответствующей функциональной группе в организации.
Шаг 4: Исправление
Следуйте рекомендациям по программированию на ABL(4GL) для устранения обнаруженной проблемы.
О некоторых из таких рекомендаций, в частности о создании эффективных запросов и индексов, о правильном выборе области действия транзакции и стратегии локировки записей, я постараюсь рассказать в следующих статьях.
Шаг5: Проверка и тестирование
После исправления своего кода всегда проверяйте что:
- изменение действительно устраняет выявленную проблему;
- ваши изменения не создали новых проблем.
Попросите нескольких пользователей протестировать приложение, для получения точного результата.
Заключение
Помимо реагирования на жалобы пользователей, всегда следует применять превентивные меры для предупреждения и предварительного обнаружения и исправления проблем с производительностью. Настройку производительности следует учитывать:
- с каждым выпуском нового кода;
- в рамках стандартного тестирования;
- всякий раз, когда поступают обращения пользователей о задержках.
И в завершение ответьте всего на один вопрос, лучше в комментариях к этой статье, истинно ли следующее утверждение: «Если правильно выполнить предварительный тюнинг приложения, то вы никогда не столкнётесь с проблемой производительности?».
Метка:Tuning Progress 4GL