CLR 호스팅 환경

Microsoft .NET Framework CLR(공용 언어 런타임)은 Microsoft Visual C#, Microsoft Visual Basic 및 Microsoft Visual C++ 비롯한 다양한 최신 프로그래밍 언어를 실행하는 환경입니다. CLR에는 가비지 수집되는 메모리, 선점형 스레딩, 메타데이터 서비스(형식 리플렉션), 코드 안정성, 코드 액세스 보안 등의 기능이 있습니다. CLR에서는 메타데이터를 사용하여 클래스를 찾아 로드하고, 메모리에 인스턴스를 배치하고, 메서드 호출을 확인하고, 네이티브 코드를 생성하고, 보안을 강화하며, 런타임 컨텍스트 경계를 설정합니다.

CLR 및 SQL Server 메모리, 스레드 및 동기화를 처리하는 방식에서 런타임 환경과 다릅니다. 이 항목에서는 모든 시스템 리소스가 균일하게 관리되도록 이 두 런타임이 어떻게 통합되는지에 대해 설명합니다. 이 항목에서는 사용자 코드에 대한 안정적이고 안전한 실행 환경을 제공하기 위해 CLR CAS(코드 액세스 보안) 및 SQL Server 보안을 통합하는 방법에 대해서도 설명합니다.

CLR 아키텍처의 기본 개념

.NET Framework에서 프로그래머는 클래스의 구조(예: 클래스의 필드나 속성)와 메서드를 정의하여 클래스를 구현하는 고급 언어로 코드를 작성합니다. 이러한 메서드 일부는 정적 함수일 수 있습니다. 프로그램의 컴파일은 MSIL(Microsoft Intermediate Language)의 컴파일된 코드가 포함된 어셈블리라는 파일과 종속 어셈블리에 대한 모든 참조를 포함하는 매니페스트를 생성합니다.

참고

어셈블리는 CLR 아키텍처의 필수 요소로, .NET Framework에서 애플리케이션 코드를 패키징, 배포 및 버전 관리하는 단위입니다. 어셈블리를 사용하면 데이터베이스 안에 애플리케이션 코드를 배포하고 완전한 데이터베이스 애플리케이션을 일관된 방법으로 관리, 백업 및 복원할 수 있습니다.

어셈블리 매니페스트에는 프로그램에 정의되어 있는 모든 구조, 필드, 속성, 클래스, 상속 관계, 함수 및 메서드를 설명하는 어셈블리 메타데이터가 들어 있습니다. 어셈블리 매니페스트는 어셈블리의 ID를 설정하고, 어셈블리 구현을 구성하는 파일을 지정하고, 어셈블리를 구성하는 형식 및 리소스를 지정하며, 컴파일 타임의 다른 어셈블리에 대한 종속성을 항목별로 요약하고, 어셈블리가 제대로 실행되는 데 필요한 권한 집합을 지정합니다. 이 정보는 런타임에 참조를 확인하고, 버전 바인딩 정책을 적용하고, 로드된 어셈블리의 무결성을 확인하는 데 사용됩니다.

.NET Framework에서는 애플리케이션에서 메타데이터에 캡처할 수 있는 추가적인 정보를 클래스, 속성, 함수 및 메서드에 주석으로 추가할 수 있는 사용자 지정 특성을 지원합니다. 모든 .NET Framework 컴파일러는 이러한 주석을 해석 없이 사용하고 어셈블리 메타데이터로 저장합니다. 이러한 주석은 다른 메타데이터와 같은 방식으로 검사할 수 있습니다.

관리 코드는 운영 체제에서 직접 실행되는 대신 CLR에서 실행되는 MSIL입니다. 관리 코드 애플리케이션은 자동 가비지 수집, 런타임 형식 확인, 보안 지원 등과 같은 CLR 서비스를 얻습니다. 이러한 서비스는 관리 코드 애플리케이션의 일관된 플랫폼 및 언어 독립적인 동작을 제공하는 데 도움이 됩니다.

CLR 통합의 디자인 목표

사용자 코드가 SQL Server CLR 호스팅 환경 내에서 실행되는 경우(CLR 통합이라고 함) 다음 디자인 목표가 적용됩니다.

안정성(보안)

사용자 코드는 사용자 응답을 요청하는 메시지 상자를 표시하거나 프로세스를 종료하는 것과 같이 데이터베이스 엔진 프로세스의 무결성을 손상시키는 작업을 수행할 수 없습니다. 또한 사용자 코드는 데이터베이스 엔진 메모리 버퍼 또는 내부 데이터 구조를 덮어쓸 수 없습니다.

확장성

SQL Server 및 CLR에는 예약 및 메모리 관리를 위한 다양한 내부 모델이 있습니다. SQL Server 스레드가 주기적으로 또는 잠금 또는 I/O를 기다리는 경우 자발적으로 실행을 생성하는 협조적이고 선제적이지 않은 스레딩 모델을 지원합니다. 반면 CLR은 선점형 스레딩 모델을 지원합니다. SQL Server 내에서 실행되는 사용자 코드가 운영 체제 스레딩 기본 형식을 직접 호출할 수 있는 경우 SQL Server 작업 스케줄러에 잘 통합되지 않고 시스템의 확장성을 저하시킬 수 있습니다. CLR은 가상 메모리와 실제 메모리를 구분하지 않지만 SQL Server 실제 메모리를 직접 관리하며 구성 가능한 한도 내에서 실제 메모리를 사용해야 합니다.

수천 개의 동시 사용자 세션을 지원하도록 확장 가능한 RDBMS(관계형 데이터베이스 관리 시스템)의 경우에는 스레딩, 일정 예약 및 메모리 관리 모델이 다르기 때문에 통합하기 어렵습니다. 아키텍처에서는 스레딩, 메모리 및 동기화 기본 형식을 위한 API(응용 프로그래밍 인터페이스)를 직접 호출하는 사용자 코드로 인해 시스템의 확장성에 문제가 발생하지 않아야 합니다.

보안

데이터베이스에서 실행되는 사용자 코드는 테이블 및 열과 같은 데이터베이스 개체에 액세스할 때 SQL Server 인증 및 권한 부여 규칙을 따라야 합니다. 또한 데이터베이스 관리자는 데이터베이스에서 실행되는 사용자 코드를 통해 파일 같은 운영 체제 리소스에 대한 액세스 및 네트워크 액세스를 제어할 수 있어야 합니다. Transact-SQL과 같이 관리되지 않는 언어와 달리 관리되는 프로그래밍 언어는 이와 같은 리소스에 액세스하기 위한 API를 제공하기 때문에 액세스 제어가 중요합니다. 시스템은 사용자 코드가 데이터베이스 엔진 프로세스 외부의 컴퓨터 리소스에 액세스할 수 있는 안전한 방법을 제공해야 합니다. 자세한 내용은 CLR Integration Security을 참조하세요.

성능

데이터베이스 엔진에서 실행되는 관리되는 사용자 코드에는 서버 외부에서 실행되는 동일한 코드와 비교할 수 있는 계산 성능이 있어야 합니다. 관리되는 사용자 코드에서 데이터베이스 액세스는 네이티브 Transact-SQL만큼 빠르지 않습니다. 자세한 내용은 CLR 통합의 성능을 참조하세요.

CLR Services

CLR은 SQL SERVER CLR 통합의 디자인 목표를 달성하는 데 도움이 되는 다양한 서비스를 제공합니다.

형식 안전성 확인

형식 안전 코드는 명확하게 정의된 방법으로만 메모리 구조에 액세스하는 코드입니다. 예를 들어 올바른 개체 참조에 대해 형식 안전 코드는 실제 필드 멤버에 대응하는 고정 오프셋에서 메모리에 액세스할 수 있습니다. 그러나 개체에 속하는 메모리 범위 안이나 밖의 임의의 오프셋에서 메모리에 액세스하는 코드는 형식 안전 코드가 아닙니다. 어셈블리가 CLR에 로드되고 JIT(Just-In-Time) 컴파일을 사용하여 MSIL을 컴파일되기 전에 런타임에서는 코드의 형식 안전성을 검사하는 확인 단계를 수행합니다. 이 확인 과정을 통과한 코드는 형식 안전 코드라고 할 수 있습니다.

애플리케이션 도메인

CLR은 호스트 프로세스에서 관리 코드 어셈블리를 로드하고 실행할 수 있는 실행 영역이라는 개념으로 애플리케이션 도메인을 지원합니다. 애플리케이션 도메인 경계는 어셈블리 사이를 구분합니다. 어셈블리는 정적 변수와 데이터 멤버의 표시 유형 및 코드를 동적으로 호출할 수 있는지 여부를 기준으로 격리됩니다. 애플리케이션 도메인은 코드를 로드하고 언로드하는 메커니즘이기도 합니다. 메모리에서 코드를 언로드하는 유일한 방법은 애플리케이션 도메인을 언로드하는 것입니다. 자세한 내용은 애플리케이션 도메인 및 CLR 통합 보안을 참조하세요.

CAS(코드 액세스 보안)

CLR 보안 시스템을 사용하면 코드에 사용 권한을 할당하여 관리 코드로 수행할 수 있는 작업의 유형을 제어할 수 있습니다. 코드 액세스 권한은 코드 ID(예: 어셈블리의 서명 또는 코드 원본)를 기준으로 할당됩니다.

CLR에는 컴퓨터 관리자가 설정할 수 있는 컴퓨터 차원의 정책이 있습니다. 이 정책은 컴퓨터에서 실행되는 모든 관리 코드에 대한 권한 부여를 정의합니다. 또한 SQL Server 같은 호스트에서 관리 코드에 대한 추가 제한을 지정하는 데 사용할 수 있는 호스트 수준 보안 정책이 있습니다.

.NET Framework의 관리되는 API가 코드 액세스 권한으로 보호되는 리소스에 대한 작업을 노출할 경우, API는 리소스에 액세스하기 전에 해당 사용 권한을 요청합니다. 이 요청이 발생하면 CLR 보안 시스템에서는 호출 스택에 포함된 모든 코드 단위(어셈블리)에 대한 포괄적인 검사를 트리거합니다. 전체 호출 체인에 사용 권한이 있는 경우에만 리소스에 대한 액세스가 허용됩니다.

Reflection.Emit API를 사용하여 관리 코드를 동적으로 생성하는 기능은 SQL Server CLR 호스팅 환경 내에서 지원되지 않습니다. 이러한 코드는 적절한 CAS 권한을 가지고 있지 않기 때문에 런타임에 실패합니다. 자세한 내용은 CLR 통합 코드 액세스 보안을 참조하세요.

HPA(호스트 보호 특성)

CLR은 .NET Framework의 일부인 관리되는 API에 대해 CLR 호스트에서 유용할 수 있는 특성으로 주석을 지정하기 위한 메커니즘을 제공합니다. 이러한 특성의 예를 들면 다음과 같습니다.

  • SharedState: API가 공유 상태(예: 정적 클래스 필드)를 만들거나 관리하는 기능을 노출하는지 여부를 나타냅니다.

  • Synchronization: API가 스레드 간 동기화 기능을 노출하는지 여부를 나타냅니다.

  • ExternalProcessMgmt: API가 호스트 프로세스 제어 기능을 노출하는지 여부를 나타냅니다.

이러한 특성을 사용하면 호스트에서는 호스팅 환경에서 허용하지 않는 HPA 목록(예: SharedState 특성)을 지정할 수 있습니다. 이렇게 하면 CLR에서는 금지 목록에 포함된 HPA로 주석이 지정된 API를 호출하는 사용자 코드를 거부합니다. 자세한 내용은 호스트 보호 특성 및 CLR 통합 프로그래밍을 참조하세요.

SQL Server와 CLR이 함께 작동하는 방법

이 섹션에서는 SQL Server SQL Server 및 CLR의 스레딩, 일정 예약, 동기화 및 메모리 관리 모델을 통합하는 방법에 대해 설명합니다. 특히 이 섹션에서는 확장성, 안정성 및 보안 목표 측면에서의 통합을 검사합니다. SQL Server 기본적으로 SQL SERVER 내에서 호스트되는 CLR의 운영 체제 역할을 합니다. CLR은 스레딩, 일정 예약, 동기화 및 메모리 관리를 위해 SQL Server 구현한 하위 수준 루틴을 호출합니다. 이는 나머지 SQL Server 엔진에서 사용하는 것과 동일한 기본 형식입니다. 이 방식을 사용하면 확장성, 안정성 및 보안상 여러 가지 이점을 얻을 수 있습니다.

확장성: 일반적인 스레딩, 일정 및 동기화

CLR은 사용자 코드 실행 및 자체 내부 사용을 위해 스레드를 만들기 위해 SQL Server API를 호출합니다. 여러 스레드 간에 동기화하기 위해 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에서 "런어웨이" 스레드를 식별하고 우선 순위를 관리할 수 있음을 의미합니다. 이와 같은 런어웨이 스레드는 일시 중지되어 큐에 다시 배치됩니다. 런어웨이 스레드로 반복적으로 식별되는 스레드는 작업을 수행하는 다른 스레드가 실행될 수 있도록 일정 기간 동안 일시 중지됩니다.

참고

데이터에 액세스하거나 가비지 수집이 트리거될 정도로 많은 양의 메모리를 할당하는 장기 실행 관리 코드는 자동으로 해제됩니다. 반면 데이터에 액세스하지 않거나 가비지 수집이 트리거될 정도의 충분한 메모리를 할당하지 않는 장기 실행 관리 코드는 .NET Framework의 System.Thread.Sleep() 함수를 호출하여 명시적으로 해제해야 합니다.

확장성: 일반적인 메모리 관리

CLR은 메모리 할당 및 할당 해제를 위해 SQL Server 기본 형식을 호출합니다. CLR에서 사용하는 메모리는 시스템의 총 메모리 사용량에서 고려되기 때문에 SQL Server 구성된 메모리 제한 내에서 유지되고 CLR 및 SQL Server 메모리를 위해 서로 경쟁하지 않도록 할 수 있습니다. SQL Server 시스템 메모리가 제한될 때 CLR 메모리 요청을 거부하고 다른 작업에 메모리가 필요할 때 CLR에 메모리 사용을 줄이도록 요청할 수도 있습니다.

안정성: 애플리케이션 도메인 및 복구할 수 없는 예외

.NET Framework API의 관리 코드에서 메모리 부족 또는 스택 오버플로와 같은 중대한 예외가 발견되었을 때 이러한 오류를 복구하여 API 구현의 의미를 일관되고 올바르게 유지하지 못하는 경우도 있습니다. 이러한 API는 이와 같은 오류에 대한 응답으로 스레드 중단 예외를 발생시킵니다.

SQL Server 호스트되는 경우 이러한 스레드 중단은 다음과 같이 처리됩니다. CLR은 스레드 중단이 발생하는 애플리케이션 도메인에서 공유 상태를 검색합니다. CLR은 동기화 개체가 있는지 여부를 확인하여 이 작업을 수행합니다. 애플리케이션 도메인에 공유 상태가 있으면 애플리케이션 도메인 자체가 언로드됩니다. 애플리케이션 도메인이 언로드되면 해당 애플리케이션 도메인에서 현재 실행 중인 데이터베이스 트랜잭션이 중지됩니다. 공유 상태의 존재는 예외를 트리거하는 세션 이외의 사용자 세션에 대한 이러한 중요한 예외의 영향을 확대할 수 있으므로 SQL Server CLR은 공유 상태의 가능성을 줄이기 위한 조치를 취했습니다. 자세한 내용은 .NET Framework 설명서를 참조하십시오.

보안: 권한 집합

SQL Server 사용자가 데이터베이스에 배포된 코드에 대한 안정성 및 보안 요구 사항을 지정할 수 있습니다. 어셈블리가 데이터베이스에 업로드되면 어셈블리 작성자는 해당 어셈블리에 대한 SAFE, EXTERNAL_ACCESS 및 UNSAFE의 세 가지 권한 집합 중 하나를 지정할 수 있습니다.

권한 집합 SAFE EXTERNAL_ACCESS UNSAFE
코드 액세스 보안 실행 전용 실행 및 외부 리소스 액세스 제한 없음
프로그래밍 모델 제한 사항 제한 없음
안정성 요구 사항 Yes
네이티브 코드를 호출하는 기능 아니요

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 및 SynchronizationExternalProcessMgmt 호스트 보호 특성으로 주석이 추가된 .NET Framework API에 대한 호출을 SharedState허용하지 않습니다. 이렇게 하면 SAFE 및 EXTERNAL_ACCESS 어셈블리가 공유 상태를 사용하도록 설정하고 동기화를 수행하며 SQL Server 프로세스의 무결성에 영향을 주는 API를 호출할 수 없습니다. 자세한 내용은 CLR 통합 프로그래밍 모델 제한을 참조하세요.

참고 항목

CLR 통합 보안
통합된 CLR의 성능