среда, 18 мая 2016 г.

MUMPS: Память и сборка мусора

Одним из важных практических вопросов применения MUMPS систем является отношение к памяти, принятое в системах такого класса и исторически сложившиеся традиции или поведение систем, наиболее ожидаемое разработчиками.

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

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

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

Выход за пределы расходования памяти может быть двух типов:
  • Процесс захватывает дополнительное пространство памяти для размещения данных.
  • Процесс захватывает дополнительное пространство памяти из-за фрагментации используемого пространства.
Оба случая MUMPS системы стремятся предотвратить и применяют улучшенные алгоритмы повторного использования памяти для снижения фрагментации, а также генерируют ошибку невозможности размещения дополнительных данных в случае исчерпания отведенных пределов.

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

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

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

Если разработчики обнаруживают, что административно установленные ими ограничения для локальных переменных недостаточны, пределы могут быть изменены. В некоторых реализациях MUMPS систем возможно программное управление объемом локальных переменных для запускаемого процесса, его можно указать в качестве параметра команды job.

Сами по себе MUMPS системы также применяют меры по ограничению внутренних пределов памяти для служебных целей, стремясь не выходить на неограниченное ее потребление.

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

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

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

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

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

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

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

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

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

В частности, типичное клиентское приложение может захватывать непредсказуемые объемы памяти и руководствоваться иными правилами обработки данных. Например обрабатывать большие объемы в памяти, не используя подкачку и кеширование, как это делают СУБД. Что может приводить к непредсказуемому переходу множества процессов в свап и к резкому замедлению общей работы. Многие программы, написанные в стиле клиентского приложения, могут вообще не содержать обработки исчерпания ресурса или выхода за поддерживаемые пределы, и аварийно завершают работу при работе с данными, если их объем стал чуть больше чем тот, который они могут обработать в обычном стиле.

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

Кроме них также могут сущестовать реализации с самостоятельным переключением контекста job-ов, не использующие ни потоки, ни процессы операционных систем. Для таких систем расчет памяти делается, по сути, также, как и для многопоточных.

Различие многопроцессных и многопоточных систем в отношении к памяти состоит в том, что потоки живут внутри адресного пространства процесса и пользуются его единым адресным пространством, а различные процессы пользуются собственными адресными пространствами. В 32-битных системах, весьма распространенных ранее, ныне, и, весьма вероятно, некоторое время еще, общее пространство составляет 4 гигабайта. Из них 1 гигабайт отводится на область, управляемую автоматически операционной системой, где размещаются кодовые сегменты, как самого процесса так и служебных библиотек. 1 гигабайт по умолчанию не используется, но может быть использован для данных, если включить в операционной системе специальную опцию и отметить исполняемый файл специальным образом. Но, по умолчанию, тиражное и массовое программное обеспечение такими опциями не пользуется. И оставшиеся 2 гигабайта отдаются процессу на пространство данных. Обычная практика применения систем серверного класса состоит в том, что возможность увеличить что-либо в полтора раза обычно не является заметным практическим решением. Вот в этих пределах процесс сервера должен разместить вообще все данные, которыми он пользуется в памяти. Точнее говоря, может использовать только это адресное пространство.

Если MUMPS система выполнена в многопоточной схеме или в схеме с самостоятельным переключением контекста job, то все, то есть вообще все области данных, все кеши и все области локальных переменных, должны разместиться в пределах этих 2 гигабайт. В случае, например, если нужно отвести 8 мегабайт на локальные переменные для одного job, то 128 таких job уже должны занять пространство адресов 1 гигабайт. Если надо иметь возможность запустить больше job, то расход пространства соответственно увеличивается. Оставшееся пространство также должно быть занято под различного рода кеши. Таким образом, в случае применения многопоточной схемы администратор при росте числа выполняемых job должен либо сокращать области кешей, либо такой сервер не сможет в итоге обслужить больше чем определенное число job.

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

В случае применения 64-битной архитектуры такие различия между многопоточными и многопроцессными реализациями стираются из-за практически неограниченного 64-битного пространства. Хотя, если система изначально была разработана для того, чтобы работать и на 32-битной архитектуре, то ее 64-битный вариант не подвергается архитектурной переделке на многопоточную схему из-за отсутствия такой необходимости. Что интересно, встречаются разработки, выполненные на вполне современных интерпретирующих языках и успешно работающие на современных 64-битных системах, но содержащие проблемы при работе на 32-битных реализациях тех же интерпретаторов именно из-за отношения к объему памяти, доступному одному процессу.

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

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

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

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

Первые два случая, многопроцессный и многопоточный, используют вытесняющую многозадачность, а второй, с самостоятельным переключением контекстов job, кооперативную многозадачность.

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

Подробнее о книге "MUMPS СУБД"

Комментариев нет:

Отправить комментарий