Борьба со снижением производительности при сопряжении COBOL с другими языками

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

Джудит Майерсон, инженер, разработчик архитектуры систем, консультант

Джудит М. Майерсон (Judith M. Myerson) - разработчик архитектуры систем, инженер, писатель. В сферу ее интересов входят технологии промежуточного программного обеспечения, системы масштаба предприятия, технологии баз данных, разработка приложений, управление сетями, распределенные системы, технологии на основе компонентов и управление проектами. С ней можно связаться по электронной почте: jmyerson@bellatlantic.net



17.06.2013

Введение

Несколько десятилетий назад, когда я впервые начала использовать COBOL на мейнфреймах, я столкнулась с тем, что он не умеет работать в связке с другими языками. Я обсудила вопрос влияния COBOL на производительность при его сопряжении с другими языками программирования с профессором и попросила сделать эту тему предметом моей научной диссертации.

Чтобы выяснить, как именно COBOL может влиять на производительность, я экспериментировала с интерфейсами COBOL/Fortran на основе спецификаций "A Fortran Interface to the CODASYL database task group specifications" (см. раздел Ресурсы). В те дни Fortran был очень популярен.

Я обнаружила, что некоторые типы данных COBOL не имеют своих эквивалентов в Fortran. Ненужные данные или объекты оставались на диске. Когда выделялся больший объем оперативной памяти, чем требовалось, возникали признаки переполнения стека. Я исправляла эти проблемы путем использования корректных типов данных Fortran/COBOL. Ограничения памяти я обходила путем вызова и закрытия подпрограмм по мере необходимости. Максимальные возможности процессоров, существовавших в то время, были очень малы по сравнению с сегодняшними.

В этой статье я дам вам несколько советов о том, как избежать проблем с производительностью при использовании COBOL совместно с Java, C/C++, DB2 и Oracle. Будут рассмотрены следующие вопросы:

  1. Предотвращение превышений лимита времени.
  2. Использование сценариев сборки.
  3. Правила преобразования данных.
  4. Предотвращение утечек памяти.
  5. Удаление локальных ссылок.

Влияние на производительность: Java и C/C++

Когда я впервые начала работать с Fortran, этот язык был широко распространен в среде программистов. Сегодня в качестве интерфейсов COBOL наиболее часто используются Java® и C/C++. Fortran в наши дни потерял свою широкую популярность, хотя по-прежнему широко применяется в научных вычислениях.

Java в качестве интерфейса

Можно заставить написанную на COBOL программу вызвать программу на Java, которая бы, в свою очередь, вызывала другую программу на COBOL. Если Java-приложения написаны не очень аккуратно, можно столкнуться с проблемами памяти, приводящими к снижению производительности. В их число входят высокая загрузка и утечки памяти, а также неэффективное создание объектов и неэффективная работа сборщика мусора (garbage collector). Среди других проблем производительности – проблемы, связанные с отслеживанием локальных ссылок на объекты и использованием локальных ссылок в потоках.

Утечки памяти в Java возникают из-за использования ссылок на ставшие ненужными объекты. Высокая загрузка памяти является результатом неэффективно сконфигурированных кэшей и большого числа активных пользователей, одновременно работающих с системой.

Неэффективное создание объектов дает о себе знать при увеличении пользовательской нагрузки, когда сборщик мусора должен постоянно очищать кучу. Это может привести к тому, что сборщик мусора начинает использовать очень много ресурсов процессора. Неэффективная работа сборщика мусора проявляется при его неверной настройке.

Локальные ссылки на объекты действительны только в период выполнения вызванного метода. Автоматическое освобождение локальных ссылок не всегда происходит после завершения работы метода. Глобальные ссылки действительны до тех пор, пока не будут удалены явным образом. Локальные ссылки перестают быть действительными, когда они передаются из одного потока в другой. Чтобы гарантировать, что объекты не будут удалены раньше времени во время процедуры сбора мусора, локальные и глобальные ссылки отслеживаются виртуальной машиной Java (JVM).

Если вы не освобождаете локальные ссылки явным образом, вы можете столкнуться с нехваткой памяти, как описано в следующих двух случаях:

  • Случай 1. Вы пытаетесь получить доступ к большому объекту из метода для создания локальный ссылки на объект для объемных вычислений. Локальная ссылка препятствует освобождению объекта во время процедуры сбора мусора.
  • Случай 2. Вы не используете все созданные в методе локальные ссылки одновременно. В методе COBOL вы поочередно обращаетесь к большому массиву объектов, получаете элементы в качестве локальных ссылок и выполняете действия над элементами в каждой итерации. Локальные ссылки на элемент массива не освобождаются автоматически после каждой итерации.

C/C++ в качестве интерфейса

Если в приложении C/C++ используется слишком большой объем памяти стека вызовов, это может привести к переполнению стека. Выделение памяти в стеке может превысить ее реальный объем. Размер стека в обратном вызове зависит от архитектуры системы и количества доступной памяти.

Каждое переполнение стека усугубляет ситуацию, уменьшая эффективный размер стека для конкретного приложения C/C++. Что касается многопоточных приложений, то программам, использующим потоки, доступен меньший объем памяти стека для каждого потока, чем однопоточным программам или программам, не использующих потоки.

При совместном использовании COBOL и C/C++ проблемы производительности возникают при попытках вызвать функции одного языка, уменьшающие размер фреймов стека программ другого языка. Для языков, не инициирующих уменьшение и уничтожение активных фреймов стека, негативные эффекты могут привести к переполнению стека.

Так, могут не выполняться обычные функции языка программирования, отвечающие за очистку или выход – например, закрытие файлов из COBOL во время завершения процесса выполнения или очистка динамически полученных ресурсов посредством непреднамеренно завершенной функции языка программирования.

Влияние на производительность интерфейса: IBM DB2 и Oracle

IBM COBOL для AIX® используется вместе с СУБД IBM DB2® и сертифицирован для работы с клиентами Oracle, а также с клиентами Oracle, работающими с Tuxedo. Приложения COBOL, выполняющие встроенные операторы SQL, взаимодействуют с DB2 и Oracle через рабочую область памяти, которая называется SQL Communications Area (SQLCA). Прежде чем выполнить операторы SQL, система проверяет права доступа и роли, определяет первичный ключ и ищет внешний ключ. Также проверяются ограничения и индексы и выполняются все сложные действия, связанные с оптимизатором и контролем транзакций. Система выполняет блокировки, журналирование, фиксации и откаты транзакций.

Если принять все значения по умолчанию или неверно настроить любое из них, можно получить ошибку при выполнении команды SQL. Все результаты операции возвращаются в поля SQLCODE и SQLSTATE области SQLCA. Поле SQLCODE содержит ключевую информацию о статусе выполнения оператора SQL (успех или ошибка).

Долгое время ожидания при блокировках

Одна из причин превышения лимита времени заключается в том, что объект блокируется другим пользователем или сеансом, но приложение не может обнаружить наличие этой блокировки. Приложение ожидает возможности получить доступ к объекту до тех пор, пока не истечет время ожидания DB2.

Если не изменять значение по умолчанию -1 для параметра LOCK TIMEOUT, то при попытках доступа или редактирования объекта задержек ожидания блокировок не будет. Если для встроенного оператора SQL установить значение параметра SET CURRENT LOCK TIMEOUT равным 10 или 15 секундам, то возникнут слишком долгие задержки ожидания.

Слишком долгое время ожидания при блокировках может привести к отрицательным эффектам. Во-первых, это будет раздражать пользователей. Во-вторых, если текущая часть работы не будет сохранена вследствие отката транзакции, это приведет к недовольству пользователей. Результаты неудачной операции возвращаются в поле SQLCODE.

Например, SQLCODE = -901 свидетельствует об ошибке, связанной с временем ожидании блокировки, и о том, какое значение было задано для параметра LOCKTIMEOUT. SQLCODE = -911 означает, что возникла взаимоблокировка, время ожидания истекло и был выполнен откат. SQLCODE = -913 означает то же самое, но без выполнения отката.

SQLCODE является частью записи SQLCA в разделе WORKING-STORAGE SECTION или LINKAGE SECTION приложения. Проще добавить коды SQLCODE в файл sqlca.cbl. Эта простая программа является частью раздела LINKAGE SECTION файла checkerr.cbl – утилитой, выполняющей проверку ошибок в DB2-программе сборки приложений COBOL в сценарии AIX (bldapp).

Повышенные требования к памяти

Во встроенных операторах COBOL хранимые процедуры обладают многими преимуществами по сравнению с динамическим SQL, включая лучшую производительность и масштабируемость. Хранимые процедуры оптимизированы и хранятся в виде кода, написанного на "родном" языке программирования. Хранимая процедура готова к выполнению сразу же при вызове. Напротив, при отправке оператора SQL обработчик запросов должен выполнить его разбор и анализ, а затем создать план запроса для выполнения.

Однако имеется одно препятствие. Вызовы хранимых процедур могут предъявлять повышенные требования к памяти. Если эти требования слишком высоки, выполнение SQL-выражения завершится неудачей.

Советы по улучшению производительности

Ниже я приведу несколько советов, которые помогут избежать снижения производительности при совместном использовании COBOL с Java, C/C++, DB2 и Oracle.

  • Предотвращение превышения времени ожидания.
  • Использование сценариев сборки.
  • Предотвращение утечек памяти.
  • Удаление локальных ссылок.

Совет 1: предотвращение превышения времени ожидания

Если в любом из полей SQLCODE содержится ошибка, указывающая на превышение времени ожидания, то необходимо убедиться в том, что значение по умолчанию параметра LOCKTIMEOUT было изменено и установлено в 10 или 15 секунд. Узнать значение параметр LOCKTIMEOUT можно с помощью следующей команды:

db2 "get db cfg  for DBNAME"

Далее найдите следующий фрагмент текста:

Lock timeout (sec) (LOCKTIMEOUT) = 30

В данном случае значение параметра LOCKTIMEOUT слишком велико, поэтому рекомендуется уменьшить его до 10 секунд с помощью следующей команды:

 db2 "update db cfg for DBNAME using LOCKTIMEOUT 10"

Предполагая, что проблемы, связанные с временем ожидания блокировок, отсутствуют, посмотрите на следующие строки из листинга 1.

Листинг 1. Результаты статистики времени ожидания
Locks held currently = 0
Lock waits = 0
Time database waited on locks (ms) =0
Lock list memory in use (Bytes) = 576
Deadlocks detected = 0
Lock escalations = 0
Exclusive lock escalations =  0
Agents currently waiting on locks = 0
Lock timeouts = 0

Из листинга 1 видно, что размер задействованной памяти, содержащей список блокировок, составляет 576 байтов. Если этот размер превышает 50% от значения заданного вами параметра LOCKLIST, увеличьте количество 4-килобайтных страниц в конфигурации базы данных LOCKLIST.

После исправления значения параметра LOCKTIMEOUT проверьте, что проблемный объект заблокирован, и выполните необходимые действия по его разблокировке от имени заблокировавшего его пользователя. Просмотрите главный журнал DB2 и найдите процесс, удерживающий блокировки DB2.

Если между DB2 Connect™ и вашей системой или между DB2 Connect и DB2 установлен брандмауэр, то может потребоваться проверить, не влияет ли он на время ожидания.

Совет 2: использование сценариев сборки

В состав DB2 входят сценарии сборки, включая утилиту для проверки на наличие ошибок во время компиляции и компоновки приложений, использующих встроенный SQL языка COBOL и API-интерфейсы DB2. Эти сценарии, а также примеры приложений, которые можно собрать с помощью этих сценариев, можно найти в директории sqllib/samples/cobol. Файл сборки bldapp содержит команды для сборки DB2-приложения, как показано ниже:

Листинг 2. Пример сценария сборки приложения
#! /bin/sh
# SCRIPT: bldapp
#
# PART 1: Check if an embedded SQL program exists.
#
# Usage: bldapp <prog_name> [ <db_name> [ <userid> <password> ]]
# Set DB2PATH to where DB2 will be accessed.
# The default is the standard instance path.
DB2PATH=$HOME/sqllib
# If an embedded SQL program, precompile and bind it.
#
if [ -f $1".sqb" ]
then
./embprep $1 $2 $3 $4
fi
#
# PART 2: Compile checkerr.cbl error checking utility.
#
cob2 -qpgmname\(mixed\) -qlib -I$DB2PATH/include/cobol_a \
-c checkerr.cbl
#
# PART 3: Compile the program.
#
cob2 -qpgmname\(mixed\) -qlib -I$DB2PATH/include/cobol_a \
-c $1.cbl
#
# PART 4: Link the program.
#
cob2 -o $1 $1.o checkerr.o -L$DB2PATH/lib -ldb2

Первый параметр, $1 в первой чачсти листинга задает имя исходного файла. Поскольку сборка приложений с поддержкой встроенного SQL (файлы с расширением .sqb) требует активного подключения к базе данных, используются три дополнительных параметра: второй параметр, $2, задает имя базы данных, к которой выполняется подключение; третий параметр, $3 – идентификатор пользователя базы данных, а параметр $4 – его пароль.

В случае приложения, использующего встроенный SQL, bldapp передает эти параметры в сценарий предварительной компиляции и связывания, который называется embprep. Если имя базы данных не указано, то используется имя по умолчанию. Идентификатор и пароль пользователя требуются только в том случае, если экземпляр, на котором была выполнена сборка приложения, отличается от экземпляра, на котором расположена база данных.

Во второй и третьей частях листинга продемонстрированы одинаковые опции компилятора для утилиты проверки на наличие ошибок и приложения, использующего встроенный SQL. Единственное различие заключается в названии приложения COBOL: checkerr.cbl и $1.cbl. Параметр $1 был передан в качестве имени исходного приложения, которое мы указали.

Ниже описывается каждая опция компилятора:

Таблица 1. Опции компилятора
cob2Имя компилятора IBM COBOL Set Compiler.
-qpgmname\(mixed\)Указывает компилятору разрешить вызовы CALL точек входа библиотек с именами в смешанном регистре.
-qlibУказывает компилятору обрабатывать операторы COPY.
-cВыполнение только компиляции.
-I$DB2PATH/include/cobol_aЗадает местоположение include-файлов DB2.

В четвертой части демонстрируются опции компоновки приложения, описание которых приводится ниже:

Таблица 2. Опции компоновки
>-o $1Определяет выходной формат как файл совместно используемой библиотеки.
$1.oУказывает object-файл хранимой процедуры.
checkerr.oВключает object-файл утилиты для проверки ошибок.
-L$DB2PATH/libЗадает местоположение совместно используемых библиотек времени выполнения DB2. Если опция -L не указана, то компилятор использует следующий путь: /usr/lib:/lib.
-ldb2Выполняет компоновку с библиотекой managerlibrary базы данных.

Совет 3: предотвращение утечек памяти

Для предотвращения утечек памяти следует завершать все загруженные из Java приложения COBOL раньше, чем являющийся их владельцем Java-объект попадет в список сборщика мусора. Используйте следующий вызов из метода "finalize" Java-объекта:

runtime.cobcancel("program")

Здесь program – это имя приложения COBOL, загруженного с помощью вызова runtime.cobload(). В листинг 3 представлен пример использования метода "finalize" в Java-приложении:

Листинг 3. Пример метода "finalize"
protected void finalize()
{
    try
    {
        runtime.cobcancel("demoFinalizers");
        System.out.println("demoFinalizers - finalize'ed");
    }
    catch(Exception e)
    {
        System.out.println(
                 "Error during finalize : "+e.getMessage());
    }
}

Совет 4: удаление локальных ссылок

Ненужные ссылки необходимо освобождать явным образом. В противном случае система может столкнуться с нехваткой памяти, требуемой для отслеживания локальных (и глобальных) ссылок виртуальной машиной JVM.

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

Теперь предположим, что вы создали большое количество локальных ссылок в методе, но не используете все их одновременно. Поскольку для отслеживания каждой локальной ссылки виртуальной машине JVM требуется свободная память, следует освободить ненужные ссылки.

Например, в методе COBOL можно поочередно обращаться к элементам большого массива объектов, получать элементы в качестве локальных ссылок и в каждой итерации работать с одним элементом. После каждой итерации можно освобождать локальную ссылку на элемент массива.

Во всех случаях локальные ссылки действительны только в том потоке, в котором они были созданы. Не передавайте ссылки из одного потока в другой. Если вы сделаете это, вы не сможете освободить их, когда они станут не нужны. Всегда следует преобразовывать локальные ссылки в глобальные, когда существует вероятность использования одной ссылки в нескольких потоках.

Заключение

Для предотвращения возникновения проблем с производительностью при совместном использовании COBOL с другими языками необходимо заранее подумать над тем, как избежать таких ситуаций. Разработчикам программного обеспечения следует общаться с командами программистов и заранее обсуждать все вопросы, связанные с временем блокировок, утечками памяти и удалением локальных ссылок. В свою очередь, программистам следует обновить сценарии сборки для упрощения своих задач.

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=AIX и UNIX
ArticleID=934192
ArticleTitle=Борьба со снижением производительности при сопряжении COBOL с другими языками
publish-date=06172013