Архитектура интеграции со средой CLR — среда размещения CLR

Область применения: SQL Server Управляемый экземпляр SQL Azure

Интеграция SQL Server с средой clR платформа .NET Framework позволяет программистам баз данных использовать такие языки, как Visual C#, Visual Basic .NET и Visual C++. С помощью этих языков программисты могут создавать различные объекты бизнес-логики, например: функции, хранимые процедуры, триггеры, типы данных и агрегаты.

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

Среда CLR и SQL Server отличаются средами времени выполнения таким образом, как они обрабатывают память, потоки и синхронизацию. В этой статье описывается способ интеграции этих двух раз выполнения, чтобы все системные ресурсы управляли единообразно. В этой статье также рассматривается способ интеграции безопасности доступа к коду 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 для доступа к таким ресурсам. Система должна обеспечить безопасный способ доступа к ресурсам компьютера за пределами процесса ядро СУБД. Дополнительные сведения см. в статье CLR Integration Security.

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

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

Службы CLR

Среда CLR предоставляет ряд служб для достижения целей разработки интеграции СРЕДЫ CLR с SQL Server.

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

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

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

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

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

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

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

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

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

Атрибуты защиты узла (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 и управлять их приоритетом. Такие вышедшие из-под контроля потоки приостанавливаются и возвращаются в очередь. Потокам, которые были повторно обнаружены как вышедшие из-под контроля, запрещается выполняться в течение определенного периода времени, чтобы обеспечить выполнение других рабочих потоков.

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

  • Если код вызывает ОС SQL (например, запрашивать данные)
  • Если достаточно памяти выделено для активации сборки мусора
  • Если код входит в режим предварительной подготовки, вызывая функции ОС

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

// Example 1: Manually yield to SOS scheduler.
for (int i = 0; i < Int32.MaxValue; i++)
{
 // *Code that does compute-heavy operation, and does not call into
 // any OS functions.*

 // Manually yield to the scheduler regularly after every few cycles.
 if (i % 1000 == 0)
 {
   Thread.Sleep(0);
 }
}
// Example 2: Use ThreadAffinity to run preemptively.
// Within BeginThreadAffinity/EndThreadAffinity the CLR code runs in preemptive mode.
Thread.BeginThreadAffinity();
for (int i = 0; i < Int32.MaxValue; i++)
{
  // *Code that does compute-heavy operation, and does not call into
  // any OS functions.*
}
Thread.EndThreadAffinity();
Масштабируемость: общее управление памятью

СРЕДА 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
Управление доступом для кода Только выполнение Выполнение и доступ к внешним ресурсам С неограниченным доступом
Ограничения модели программирования Да Да Без ограничений
Требование к проверяемости Да Да Нет
Возможность вызова машинного кода No No Да

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 также запрещает вызовы платформа .NET Framework API, аннотированные атрибутами защиты узла SharedState, Sync и ExternalProcessMgmt. Это позволяет безопасно и EXTERNAL_ACCESS сборкам вызывать все API, которые обеспечивают общий доступ к состоянию, выполняют синхронизацию и влияют на целостность процесса SQL Server. Дополнительные сведения см. в разделе "Ограничения модели программирования интеграции CLR".

См. также

Безопасность интеграции со средой CLR
Производительность интеграции со средой CLR