Архитектура интеграции СРЕДЫ CLR — размещенная среда CLR
Область применения: SQL Server Управляемый экземпляр SQL Azure
Интеграция SQL Server с средой CLR .NET Framework позволяет программистам баз данных использовать такие языки, как C#, Visual Basic .NET и Visual C++. С помощью этих языков программисты могут создавать различные объекты бизнес-логики, например: функции, хранимые процедуры, триггеры, типы данных и агрегаты.
Среда CLR включает собранные мусором память, предварительное потоки, службы метаданных (отражение типа), возможность проверки кода и безопасность доступа к коду. В среде CLR метаданные используются для обнаружения и загрузки классов, размещения экземпляров в памяти, разрешения вызовов методов, формирования машинного кода, обеспечения безопасности и определения границ контекста времени выполнения.
Среда CLR и SQL Server отличаются средами времени выполнения таким образом, как они обрабатывают память, потоки и синхронизацию. В этой статье описывается способ интеграции этих двух раз выполнения, чтобы все системные ресурсы управляли единообразно. В этой статье также рассматривается способ интеграции безопасности доступа к коду CLR и безопасности SQL Server для обеспечения надежной и безопасной среды выполнения для пользовательского кода.
Основные понятия архитектуры СРЕДЫ CLR
На платформе .NET Framework программист использует язык высокого уровня, который реализует класс, определяющий его структуру (например, поля или свойства класса) и методы. Некоторые из этих методов могут быть статическими функциями. Компиляция программы создает файл, называемый сборкой, содержащей скомпилированный код на общем промежуточном языке (CIL), и манифест, содержащий все ссылки на зависимые сборки.
Примечание.
Сборки — важнейший элемент архитектуры CLR. Это единицы упаковки, развертывания и управления версиями кода приложения в .NET Framework. С помощью сборок можно развертывать код приложений в базе данных и предоставлять единообразный способ администрирования, создания резервных копий и восстановления законченных приложений базы данных.
Манифест сборки содержит метаданные о сборке, описывающие все структуры, поля, свойства, классы, связи наследования, функции и методы, определенные в программе. Манифест устанавливает идентификационные данные сборки, указывает файлы, образующие реализацию сборки, задает типы и ресурсы, составляющие сборку, конкретизирует зависимости времени компиляции от других сборок и регламентирует набор разрешений, необходимых для правильного выполнения сборки. Эти сведения используются во время выполнения для разрешения ссылок, применения политики привязки версии и проверки целостности загруженных сборок.
Платформа .NET Framework поддерживает пользовательские атрибуты для аннотирования классов, свойств, функций и методов с дополнительной информацией, которую приложение может записывать в метаданных. Все компиляторы .NET Framework воспринимают эти заметки без интерпретации и хранят их как метаданные сборки. Эти заметки можно анализировать так же, как любые другие метаданные.
Управляемый код — это CIL, выполняемый в среде CLR, а не непосредственно операционной системой. Приложения с управляемым кодом используют средства служб CLR, такие как автоматическая сборка мусора, проверка типов на стадии выполнения и обеспечение безопасности. Эти службы помогают обеспечить единообразное поведение приложений с управляемым кодом независимо от платформы и языка.
Цели разработки интеграции СРЕДЫ CLR
Если пользовательский код выполняется в среде, размещенной в среде CLR, в SQL Server (называемой интеграцией CLR), применяются следующие цели проектирования:
Надежность (безопасность)
Пользовательский код не должен быть разрешен для выполнения операций, скомпрометируя целостность процесса ядра СУБД, например всплывающее окно сообщения, запрашивающее ответ пользователя или выход из процесса. Пользовательский код не должен перезаписывать буферы памяти ядра СУБД или внутренние структуры данных.
Масштабируемость
SQL Server и CLR имеют разные внутренние модели для планирования и управления памятью. SQL Server поддерживает совместную, не предупреждающую модель потоков, в которой потоки добровольно предоставляют выполнение периодически или когда они ожидают блокировки или ввода-вывода. Среда CLR поддерживает модель потоков с вытеснением. Если пользовательский код, выполняемый внутри SQL Server, может напрямую вызывать примитивы потоков операционной системы, то он не интегрируется в планировщик задач SQL Server и может снизить масштабируемость системы. Среда CLR не отличается от виртуальной и физической памяти, но SQL Server напрямую управляет физической памятью и требуется для использования физической памяти в пределах настраиваемого ограничения.
Если должно быть обеспечено масштабирование системы управления реляционной базой данных (СУРБД) в целях одновременной поддержки тысяч пользовательских сеансов, то приходится решать сложные задачи интеграции в связи с применением разных моделей организации потоков, планирования и управления памятью. Архитектура должна гарантировать, что масштабируемость системы не скомпрометирована пользовательским кодом, вызывающим интерфейсы программирования приложений (API) для потоков, памяти и синхронизации примитивов синхронизации напрямую.
Безопасность
Пользовательский код, выполняющийся в базе данных, должен соответствовать правилам проверки подлинности и авторизации SQL Server при доступе к объектам базы данных, таким как таблицы и столбцы. Кроме того, администраторы баз данных должны иметь возможность управлять доступом к ресурсам операционной системы, таким как файлы и сетевой доступ, осуществляемым из пользовательского кода, который выполняется в базе данных. Эта практика становится важной как управляемые языки программирования (в отличие от неуправляемых языков, таких как Transact-SQL), предоставляют API для доступа к таким ресурсам. Система должна обеспечить безопасный способ доступа к ресурсам компьютера за пределами процесса ядро СУБД. Дополнительные сведения см. в безопасности интеграции CLR.
Производительность
Управляемый пользовательский код, работающий в ядро СУБД, должен иметь вычислительную производительность, сравнимую с тем же кодом, выполняемым за пределами сервера. Доступ к базе данных из управляемого пользовательского кода не так быстро, как собственный Transact-SQL. Дополнительные сведения см. в разделе Производительность архитектуры интеграции СРЕДЫ CLR.
Службы CLR
Среда CLR предоставляет несколько служб, которые помогают достичь целей разработки интеграции СРЕДЫ CLR с SQL Server.
Проверка безопасности типов
Типизированный код — это код, который обращается к структурам памяти только строго определенными способами. Например, при наличии допустимой ссылки на объект типизированный код может обращаться к памяти с фиксированными смещениями, соответствующими фактическим полям элементов. Однако если код обращается к памяти при произвольных смещениях внутри или вне диапазона памяти, принадлежащую объекту, то он не является типобезопасной. Когда сборки загружаются в среде CLR, перед компиляцией CIL с помощью JIT-компиляции среда выполнения выполняет этап проверки, который проверяет код для определения его безопасности типа. Код, успешно прошедший эту проверку, называется «проверяемым типизированным кодом».
Домены приложений
Среда CLR поддерживает понятие доменов приложений как зон выполнения внутри основного процесса, в который можно загрузить и выполнить сборки управляемого кода. Граница домена приложения обеспечивает изоляцию между сборками. Сборки изолированы с точки зрения видимости статических переменных и элементов данных, а также возможности динамического вызова кода. Домены приложений также обеспечивают механизм для загрузки и выгрузки кода. Код можно выгрузить из памяти, только выгрузив домен приложения. Дополнительные сведения см. в разделе "Домены приложений" и "Безопасность интеграции среды CLR".
Безопасность доступа к коду (CAS)
Система безопасности CLR обеспечивает способ выбора типа операций, которые могут быть выполнены управляемым кодом, назначая разрешения коду. Разрешения доступа для кода назначаются на основе удостоверения кода (например, подпись сборки или происхождение кода).
Среда CLR обеспечивает применение политики уровня компьютера, которую может назначить администратор компьютера. Эта политика предоставляет разрешения для любого управляемого кода, выполняемого на компьютере. Кроме того, существует политика безопасности на уровне узла, которую можно использовать узлами, такими как SQL Server, для указания дополнительных ограничений управляемого кода.
Если управляемый API в .NET Framework предоставляет операции с ресурсами, защищенными разрешением доступа к коду, API требует разрешения перед доступом к ресурсу. В силу этого требования система безопасности CLR запускает исчерпывающую проверку каждого блока кода (сборки) в стеке вызова. Доступ к ресурсу предоставляется только в том случае, если у всей цепочки вызовов есть разрешение.
Возможность динамического создания управляемого кода с помощью API Reflection.Emit
не поддерживается в среде, размещенной в среде CLR в SQL Server. Такой код не имеет разрешений CAS для запуска и поэтому завершится ошибкой во время выполнения. Дополнительные сведения см. в безопасности доступа к коду clR.
Атрибуты защиты узла (HPAs)
Среда CLR предоставляет механизм для анотации управляемых API, которые являются частью .NET Framework с определенными атрибутами, которые могут быть заинтересованы в узле среды CLR. Примеры таких атрибутов включают следующее.
SharedState
, указывающий, предоставляет ли API возможность создавать или управлять общим состоянием (например, поля статического класса).Synchronization
, указывающее, предоставляет ли API возможность выполнять синхронизацию между потоками.ExternalProcessMgmt
, который указывает, предоставляет ли API способ управления процессом узла.
Учитывая эти атрибуты, узел может указать список HPAs, например атрибут 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()
в любых разделах кода, которые, как ожидается, будут длительными. В следующих примерах кода показано, как вручную получить данные с помощью каждого из этих методов.
Примеры
Ручное выполнение планировщика SOS
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);
}
}
Использование ThreadAffinity для предварительного выполнения
В этом примере код CLR выполняется в режиме предварительной подготовки в BeginThreadAffinity
и EndThreadAffinity
.
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 |
---|---|---|---|
Code Access Security |
Только выполнение | Выполнение и доступ к внешним ресурсам | С неограниченным доступом |
Programming model restrictions |
Да | Да | Без ограничений |
Verifiability requirement |
Да | Да | Нет |
Ability to call native code |
Нет | Нет | Да |
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.