Поделиться через


Среда размещения CLR

Среда CLR платформы Microsoft .NET Framework представляет собой среду для выполнения кода на многих современных языках программирования, в том числе Microsoft Visual C#, Microsoft Visual Basic и Microsoft Visual C++. Среда CLR характеризуется применением памяти со сбором мусора, потоковой обработки с вытеснением, службы метаданных (отражения типа), проверки кода и управления доступом для кода. В среде CLR метаданные используются для обнаружения и загрузки классов, размещения экземпляров в памяти, разрешения вызовов методов, формирования машинного кода, обеспечения безопасности и определения границ контекста времени выполнения.

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

Основные понятия архитектуры CLR

На платформе .NET Framework программист использует язык высокого уровня, который реализует класс, определяющий его структуру (например, поля или свойства класса) и методы. Некоторые из этих методов могут быть статическими функциями. В результате компиляции программы формируется файл, называемый сборкой, который содержит скомпилированный код на промежуточном языке Майкрософт (MSIL), и манифест, содержащий все ссылки на зависимые сборки.

ПримечаниеПримечание

Сборки — важнейший элемент архитектуры CLR. Они представляют собой средства упаковки, развертывания и управления версиями кода приложений на платформе .NET Framework. С помощью сборок можно развертывать код приложений в базе данных и предоставлять единообразный способ администрирования, создания резервных копий и восстановления законченных приложений базы данных.

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

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

Управляемый код представляет собой код MSIL, выполняемый в среде CLR, а не непосредственно операционной системой. Приложения с управляемым кодом используют средства служб CLR, такие как автоматическая сборка мусора, проверка типов на стадии выполнения и обеспечение безопасности. Эти службы помогают обеспечить единообразное поведение приложений с управляемым кодом независимо от платформы и языка.

Цели проектирования при интеграции со средой CLR

Если пользовательский код выполняется в среде размещения CLR в SQL Server (что принято называть интеграцией со средой CLR), то ставятся следующие цели проектирования.

Надежность (безопасность)

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

Масштабируемость

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

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

Безопасность

Пользовательский код, выполняемый в базе данных, должен соответствовать правилам проверки подлинности и авторизации SQL Server при доступе к таким объектам базы данных, как таблицы и столбцы. Кроме того, администраторы баз данных должны иметь возможность управлять доступом к ресурсам операционной системы, таким как файлы и сетевой доступ, осуществляемым из пользовательского кода, который выполняется в базе данных. Это становится необходимым, поскольку управляемые языки программирования (в отличие от неуправляемых языков наподобие Transact-SQL), предоставляют API для доступа к таким ресурсам. Система должна предоставить безопасный способ доступа пользовательского кода к ресурсам компьютера вне процесса компонента Database Engine. Дополнительные сведения см. в разделе Безопасность интеграции со средой CLR.

Производительность

Управляемый пользовательский код, выполняемый в компоненте Database Engine, должен обеспечивать вычислительную производительность, сравнимую с выполнением того же кода вне сервера. Доступ к базам данных из управляемого пользовательского кода осуществляется не так быстро, как из собственного кода Transact-SQL. Дополнительные сведения см. в разделе Производительность интеграции со средой CLR.

Службы CLR

Среда CLR предоставляет ряд служб, чтобы облегчить достижение целей проектирования для интеграции среды CLR с SQL Server.

Проверка безопасности типов

Типизированный код — это код, который обращается к структурам памяти только строго определенными способами. Например, при наличии допустимой ссылки на объект типизированный код может обращаться к памяти с фиксированными смещениями, соответствующими фактическим полям элементов. Но если код обращается к памяти с произвольными смещениями внутри и вне области памяти, которая принадлежит к объекту, то код нетипизированный. Если выполняется загрузка сборок в среду CLR до компиляции MSIL с использованием JIT-компиляции, то на этапе проверки во время выполнения код анализируется, чтобы можно было определить безопасность типов. Код, успешно прошедший эту проверку, называется «проверяемым типизированным кодом».

Домены приложений

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

Управление доступом для кода (CAS)

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

Среда CLR обеспечивает применение политики уровня компьютера, которую может назначить администратор компьютера. Эта политика предоставляет разрешения для любого управляемого кода, выполняемого на компьютере. Кроме того, существует политика безопасности на уровне узла, которую можно использовать на таких узлах, как SQL Server, чтобы указать дополнительные ограничения для управляемого кода.

Если управляемый API на платформе .NET Framework предоставляет операции над ресурсами, защищенные набором разрешений на доступ к коду, то API потребует разрешение перед доступом к ресурсу. В силу этого требования система безопасности CLR запускает исчерпывающую проверку каждого блока кода (сборки) в стеке вызова. Только если вся цепочка вызовов имеет разрешение, будет предоставлен доступ к ресурсу.

Обратите внимание, что возможность динамического создания управляемого кода с использованием API Reflection.Emit в среде размещения CLR в SQL Server не поддерживается. Такой код не будет иметь разрешений CAS для выполнения и поэтому завершится неудачей во время выполнения. Дополнительные сведения см. в разделе Управление доступом для кода на основе интеграции со средой CLR.

Атрибуты защиты узла (HPA)

Среда CLR обеспечивает механизм для аннотирования управляемых API, которые являются частью платформы .NET Framework с определенными атрибутами, которые могут представлять интерес для узла CLR. Примеры таких атрибутов включают следующее.

  • SharedState, который указывает, обеспечивает ли API возможность создавать или управлять общим состоянием (например, статическими полями классов).

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

  • ExternalProcessMgmt, который указывает, предоставляет ли API возможность управлять основным процессом.

С учетом этих атрибутов узел может указать список атрибутов защиты узла, таких как атрибут SharedState, которые должны быть запрещены в управляемой среде. В этом случае среда CLR запрещает попытки пользовательского кода, которые направлены на вызов API, внесенных атрибутами защиты узла в запрещенный список. Дополнительные сведения см. в разделе Атрибуты защиты узла и программирование средств интеграции со средой CLR.

Совместная работа SQL Server и среды CLR

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

Масштабируемость: общая организация потоков, планирование и синхронизация

В среде CLR происходит вызов API SQL Server для создания потоков, как для выполнения пользовательского кода, так и для собственного внутреннего использования. Чтобы синхронизировать несколько потоков, среда CLR вызывает объекты синхронизации SQL Server. Это позволяет планировщику SQL Server запланировать другие задачи, когда поток ожидает объект синхронизации. Например, когда среда CLR запускает сбор мусора, все потоки ожидают завершения сбора мусора. Потоки CLR и ожидаемые ими объекты синхронизации известны планировщику SQL Server, поэтому SQL Server может планировать потоки, которые выполняют другие задачи базы данных, не связанные со средой CLR. Это также позволяет SQL Server обнаруживать взаимоблокировки с участием блокировок, установленных объектами синхронизации CLR, и использовать традиционные методы снятия взаимоблокировок.

Управляемый код выполняется в SQL Server с приоритетным прерыванием. Планировщик SQL Server обеспечивает обнаружение и останов потоков, не возвращающих управление в течение значительного времени. Возможность связывания потоков CLR с потоками SQL Server обусловливает то, что планировщик SQL Server может определять вышедшие из-под контроля потоки в среде CLR и управлять их приоритетом. Такие вышедшие из-под контроля потоки приостанавливаются и возвращаются в очередь. Потокам, которые были повторно обнаружены как вышедшие из-под контроля, запрещается выполняться в течение определенного периода времени, чтобы обеспечить выполнение других рабочих потоков.

ПримечаниеПримечание

Продолжительно выполняемый управляемый код, который обращается к данным или выделяет достаточно памяти, чтобы запустить сбор мусора, осуществляет возврат управления автоматически. Продолжительно выполняемый управляемый код, который не обращается к данным или не выделяет достаточно памяти, чтобы запустить сбор мусора, должен явно возвращать управление путем вызова функции System.Thread.Sleep() платформы .NET Framework.

Масштабируемость: совместное управление памятью

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

Надежность: домены приложений и невосстанавливаемые исключения

Когда управляемый код в API .NET Framework встречает критические исключения, такие как нехватка памяти или переполнение стека, не всегда удается выполнить восстановление после отказа и обеспечить согласованную и правильную семантику для их реализации. Эти API активизируют исключение прерывания потока в ответ на такие отказы.

При размещении в SQL Server такие прерывания потока обрабатываются следующим образом: среда CLR обнаруживает любое общее состояние в домене приложения, в котором происходит прерывание потока. Для этого среда CLR проверяет присутствие объектов синхронизации. Если в домене приложения имеется общее состояние, то выгружается сам домен приложения. В результате выгрузки домена приложения останавливаются транзакции базы данных, выполняемые в это время в домене приложения. Поскольку присутствие общего состояния может увеличить влияние таких критических исключений на пользовательские сеансы, отличные от сеанса, вызвавшего исключение, в SQL Server и среде CLR приняты меры для уменьшения вероятности возникновения общего состояния. Дополнительные сведения см. в документации по .NET Framework.

Безопасность: наборы разрешений

SQL Server позволяет пользователям указывать требования к надежности и безопасности для кода, развернутого в базе данных. При передаче сборки в базу данных автор сборки может указать один из трех наборов разрешений для этой сборки: SAFE, EXTERNAL_ACCESS и UNSAFE.

Набор разрешений

SAFE

EXTERNAL_ACCESS

UNSAFE

Управление доступом для кода

Только выполнение

Выполнение и доступ к внешним ресурсам

Неограниченный доступ

Ограничения модели программирования

Да

Да

Без ограничений

Требование к проверяемости

Да

Да

Нет

Возможность вызова машинного кода

Нет

Нет

Да

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

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

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

SQL Server использует уровень политики CAS на уровне узла, чтобы установить политику узла, которая предоставляет один из трех наборов разрешений на основе набора разрешений, хранимого в каталогах SQL Server. Управляемый код, выполняемый внутри базы данных, всегда получает один из этих наборов разрешений доступа для кода.

Ограничения модели программирования

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

С учетом этих факторов не рекомендуется использовать статические переменные и статические элементы данных классов, используемых в SQL Server. Для сборок SAFE и EXTERNAL_ACCESS в SQL Server анализируются метаданные сборки во время выполнения инструкции CREATE ASSEMBLY и отменяется создание таких сборок, если будет обнаружено использование статических элементов данных и переменных.

SQL Server запрещает также вызовы к API .NET Framework, аннотированные атрибутами защиты узла SharedState, Synchronization и ExternalProcessMgmt. Это не позволяет сборкам SAFE и EXTERNAL_ACCESS направлять вызовы к любым API, которые поддерживают общее состояние, выполнение синхронизации и влияют на целостность процесса SQL Server. Дополнительные сведения см. в разделе Ограничения модели программирования на основе интеграции со средой CLR.