중요합니다
이 기능은 프리뷰 상태입니다.
ADO.NET 애플리케이션이 데이터베이스 및 빅 데이터 플랫폼의 데이터에 연결하고 작업할 수 있도록 하는 .NET 에코시스템에서 널리 채택된 데이터 액세스 기술입니다.
패브릭용 Microsoft ADO.NET Driver Data Engineering을 사용하면 표준 ADO.NET 패턴의 안정성과 단순성으로 Microsoft Fabric에서 Spark 워크로드를 연결, 쿼리 및 관리할 수 있습니다. Microsoft Fabric의 Livy API를 기반으로 하는 이 드라이버는 친숙한 DbConnectionDbCommand추상화와 DbDataReader 추상화 기능을 사용하여 .NET 애플리케이션에 안전하고 유연한 Spark SQL 연결을 제공합니다.
주요 기능
-
ADO.NET 준수: ADO.NET 추상화의 전체 구현(
DbConnection,,DbCommand,DbDataReaderDbParameter,DbProviderFactory) - Microsoft Entra ID 인증: Azure CLI, 대화형 브라우저, 클라이언트 자격 증명, 인증서 기반 및 액세스 토큰 인증을 비롯한 여러 인증 흐름
- Spark SQL 네이티브 쿼리 지원: 매개 변수가 있는 쿼리를 사용하여 Spark SQL 문을 직접 실행
- 포괄적인 데이터 형식 지원: 복합 형식(ARRAY, MAP, STRUCT)을 비롯한 모든 Spark SQL 데이터 형식 지원
- 연결 풀링: 성능 향상을 위한 기본 제공 연결 풀 관리
- 세션 재사용: 시작 대기 시간을 줄이기 위한 효율적인 Spark 세션 관리
- 비동기 프리페치: 큰 결과 집합의 처리를 통해 성능을 향상시키는 백그라운드 데이터 로드
- 자동 다시 연결: 연결 실패 후 자동 세션 복구
메모
오픈 소스 Apache Spark에서는 데이터베이스 및 스키마가 동의어로 사용됩니다. 예를 들어 Fabric Notebook을 실행하거나 SHOW SCHEMAS 실행 SHOW DATABASES 하면 Lakehouse의 모든 스키마 목록인 동일한 결과가 반환됩니다.
사전 요구 사항
Microsoft 패브릭 데이터 엔지니어링용 Microsoft ADO.NET 드라이버를 사용하기 전에 다음이 있는지 확인합니다.
- .NET 런타임: .NET 8.0 이상
- Microsoft Fabric 액세스: 데이터 엔지니어링 기능을 사용하여 Microsoft Fabric 작업 영역에 액세스
- Azure Entra ID 자격 증명: 인증에 적합한 자격 증명
- 작업 영역 및 Lakehouse ID: 패브릭 작업 영역 및 레이크하우스의 GUID 식별자
- Azure CLI (선택 사항): Azure CLI 인증 방법에 필요
다운로드, 포함, 참조 및 확인
NuGet 패키지 다운로드
Microsoft Fabric Data Engineering용 Microsoft ADO.NET Driver 버전 1.0.0은 이러한 다운로드 센터 링크에서 다운로드할 수 있는 공개 미리 보기로 제공됩니다.
- Microsoft Fabric Data Engineering용 Microsoft ADO.NET 드라이버 다운로드(zip)
- Microsoft Fabric Data Engineering용 Microsoft ADO.NET 드라이버 다운로드(tar)
프로젝트에서 NuGet 패키지 참조
다운로드한 NuGet 패키지를 프로젝트에 포함하고 패키지 참조를 프로젝트 파일에 추가합니다.
<ItemGroup>
<PackageReference Include="Microsoft.Spark.Livy.AdoNet" Version="1.0.0" />
</ItemGroup>
설치 확인
포함 및 참조 후 프로젝트에서 패키지를 사용할 수 있는지 확인합니다.
using Microsoft.Spark.Livy.AdoNet;
// Verify the provider is registered
var factory = LivyProviderFactory.Instance;
Console.WriteLine($"Provider: {factory.GetType().Name}");
빠른 시작 예제
using Microsoft.Spark.Livy.AdoNet;
// Connection string with required parameters
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=AzureCli;";
// Create and open connection
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
Console.WriteLine("Connected successfully!");
// Execute a query
using var command = connection.CreateCommand();
command.CommandText = "SELECT 'Hello from Fabric!' as message";
using var reader = await command.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
Console.WriteLine(reader.GetString(0));
}
연결 문자열 형식
기본 형식
Microsoft ADO.NET 드라이버는 표준 ADO.NET 연결 문자열 형식을 사용합니다.
Parameter1=Value1;Parameter2=Value2;...
필수 매개 변수
| 매개 변수 | 설명 | 예시 |
|---|---|---|
Server |
Microsoft Fabric API 엔드포인트 | https://api.fabric.microsoft.com/v1 |
SparkServerType |
서버 유형 식별자 | Fabric |
FabricWorkspaceID |
Microsoft Fabric 작업 영역 식별자(GUID) | <workspace-id> |
FabricLakehouseID |
Microsoft Fabric Lakehouse 식별자(GUID) | <lakehouse-id> |
AuthFlow |
인증 방법 |
AzureCli, BrowserBased, ClientSecretCredential, ClientCertificateCredential, AuthAccessTokenFileToken |
선택적 매개 변수
연결 설정
| 매개 변수 | 유형 | 기본값 | 설명 |
|---|---|---|---|
LivySessionTimeoutSeconds |
정수 | 60 |
세션 생성을 기다리는 시간(초) |
LivyStatementTimeoutSeconds |
정수 | 600 |
문 실행을 기다리는 시간(초) |
SessionName |
스트링 | (자동) | Spark 세션의 사용자 지정 이름 |
AutoReconnect |
불리언 (Boolean) | false |
자동 세션 복구 사용 |
연결 풀 설정
| 매개 변수 | 유형 | 기본값 | 설명 |
|---|---|---|---|
ConnectionPoolEnabled |
불리언 (Boolean) | true |
연결 풀링 활성화 |
MinPoolSize |
정수 | 1 |
풀에서의 최소 연결 수 |
MaxPoolSize |
정수 | 20 |
풀의 최대 연결 |
ConnectionMaxIdleTimeMs |
정수 | 1800000 |
연결이 재활용되기 전의 최대 유휴 시간(30분) |
MaxLifetimeMs |
정수 | 3600000 |
풀된 연결의 최대 수명(60분) |
ValidateConnections |
불리언 (Boolean) | true |
사용하기 전에 연결 유효성 검사 |
ValidationTimeoutMs |
정수 | 5000 |
연결 유효성 검사에 대한 시간 제한 |
로깅 설정
| 매개 변수 | 유형 | 기본값 | 설명 |
|---|---|---|---|
LogLevel |
스트링 | Information |
로그 수준: Trace, Debug, Information, WarningError |
LogFilePath |
스트링 | (없음) | 파일 기반 로깅 경로 |
메모
교차 드라이버 별칭: 드라이버는 JDBC 및 ODBC 속성 이름뿐만 아니라 네이티브 ADO.NET 이름도 허용합니다 (예: WorkspaceId는 FabricWorkspaceID로 매핑되며, LakehouseId는 FabricLakehouseID로 매핑됩니다). 모든 속성 이름은 대/소문자를 구분하지 않습니다.
연결 문자열 예
기본 연결(Azure CLI 인증)
Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli
연결 풀링 옵션 사용
Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli;ConnectionPoolEnabled=true;MinPoolSize=2;MaxPoolSize=10
자동 다시 연결 및 로깅 사용
Server=https://api.fabric.microsoft.com/v1;SparkServerType=Fabric;FabricWorkspaceID=<workspace-id>;FabricLakehouseID=<lakehouse-id>;AuthFlow=AzureCli;AutoReconnect=true;LogLevel=Debug
인증
Microsoft ADO.NET 드라이버는 Microsoft Entra ID(이전의 Azure Active Directory)를 통해 여러 인증 방법을 지원합니다. 인증은 연결 문자열의 매개 변수를 AuthFlow 사용하여 구성됩니다.
인증 방법
| AuthFlow 값 | 설명 | 적합한 대상 |
|---|---|---|
AzureCli |
Azure CLI 캐시된 자격 증명 사용 | 개발 및 테스트 |
BrowserBased |
대화형 브라우저 기반 인증 | 사용자 친화적 애플리케이션 |
ClientSecretCredential |
클라이언트 암호를 사용하는 서비스 주체 | 자동화된 서비스, 백그라운드 작업 |
ClientCertificateCredential |
인증서가 있는 서비스 주체 | 엔터프라이즈 애플리케이션 |
AuthAccessToken |
미리 획득한 베어러 액세스 토큰 | 사용자 지정 인증 시나리오 |
Azure CLI 인증
최적 대상: 개발 및 테스트
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=AzureCli;";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
Prerequisites:
- Azure CLI 설치:
az --version - 로그인:
az login
대화형 브라우저 인증
최적 대상: 사용자 연결 애플리케이션
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=BrowserBased;" +
"AuthTenantID=<tenant-id>;";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync(); // Opens browser for authentication
동작:
- 사용자 인증을 위한 브라우저 창을 엽니다.
- 자격 증명은 후속 연결에 대해 캐시됩니다.
클라이언트 자격 증명(서비스 주체) 인증
최적 대상: 자동화된 서비스 및 백그라운드 작업
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=ClientSecretCredential;" +
"AuthTenantID=<tenant-id>;" +
"AuthClientID=<client-id>;" +
"AuthClientSecret=<client-secret>;";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
필수 매개 변수:
-
AuthTenantID: Azure 테넌트 ID -
AuthClientID: Microsoft Entra ID의 애플리케이션(클라이언트) ID -
AuthClientSecret: Microsoft Entra ID의 클라이언트 암호
인증서 기반 인증
최적 대상: 인증서 기반 인증이 필요한 엔터프라이즈 애플리케이션
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=ClientCertificateCredential;" +
"AuthTenantID=<tenant-id>;" +
"AuthClientID=<client-id>;" +
"AuthCertificatePath=C:\\certs\\mycert.pfx;" +
"AuthCertificatePassword=<password>;";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
필수 매개 변수:
-
AuthTenantID: Azure 테넌트 ID -
AuthClientID: 애플리케이션(클라이언트) ID -
AuthCertificatePath: PFX/PKCS12 인증서 파일 경로 -
AuthCertificatePassword: 인증서 암호
액세스 토큰 인증
최적 대상: 사용자 지정 인증 시나리오
// Acquire token through your custom mechanism
string accessToken = await AcquireTokenFromCustomSourceAsync();
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=AuthAccessToken;" +
$"AuthAccessToken={accessToken};";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
메모
코드에서 암호, 키, 비밀, 토큰 또는 인증서와 같은 하드 코딩 자격 증명을 사용하지 않는 것이 좋습니다. 대신 Azure Key Vault를 사용하여 이러한 값을 안전하게 저장하고 런타임에 검색합니다.
사용 예제
기본 연결 및 쿼리
using Microsoft.Spark.Livy.AdoNet;
string connectionString =
"Server=https://api.fabric.microsoft.com/v1;" +
"SparkServerType=Fabric;" +
"FabricWorkspaceID=<workspace-id>;" +
"FabricLakehouseID=<lakehouse-id>;" +
"AuthFlow=AzureCli;";
using var connection = new LivyConnection(connectionString);
await connection.OpenAsync();
Console.WriteLine($"Connected! Server version: {connection.ServerVersion}");
// Execute a query
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM employees LIMIT 10";
using var reader = await command.ExecuteReaderAsync();
// Print column names
for (int i = 0; i < reader.FieldCount; i++)
{
Console.Write($"{reader.GetName(i)}\t");
}
Console.WriteLine();
// Print rows
while (await reader.ReadAsync())
{
for (int i = 0; i < reader.FieldCount; i++)
{
Console.Write($"{reader.GetValue(i)}\t");
}
Console.WriteLine();
}
매개 변수가 있는 쿼리
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM orders WHERE order_date >= @startDate AND status = @status";
// Add parameters
command.Parameters.AddWithValue("@startDate", new DateTime(2024, 1, 1));
command.Parameters.AddWithValue("@status", "completed");
using var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
Console.WriteLine($"Order: {reader["order_id"]}, Total: {reader["total"]:C}");
}
단일 값에 대해 ExecuteScalar 메서드
using var command = connection.CreateCommand();
command.CommandText = "SELECT COUNT(*) FROM customers";
var count = await command.ExecuteScalarAsync();
Console.WriteLine($"Total customers: {count}");
DML 작업을 수행하는 ExecuteNonQuery 메서드
// INSERT
using var insertCommand = connection.CreateCommand();
insertCommand.CommandText = @"
INSERT INTO employees (id, name, department, salary)
VALUES (100, 'John Doe', 'Engineering', 85000)";
int rowsAffected = await insertCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Inserted {rowsAffected} row(s)");
// UPDATE
using var updateCommand = connection.CreateCommand();
updateCommand.CommandText = "UPDATE employees SET salary = 90000 WHERE id = 100";
rowsAffected = await updateCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Updated {rowsAffected} row(s)");
// DELETE
using var deleteCommand = connection.CreateCommand();
deleteCommand.CommandText = "DELETE FROM employees WHERE id = 100";
rowsAffected = await deleteCommand.ExecuteNonQueryAsync();
Console.WriteLine($"Deleted {rowsAffected} row(s)");
대용량 결과 집합 처리
using var command = connection.CreateCommand();
command.CommandText = "SELECT * FROM large_table";
using var reader = await command.ExecuteReaderAsync();
int rowCount = 0;
while (await reader.ReadAsync())
{
// Process each row
ProcessRow(reader);
rowCount++;
if (rowCount % 10000 == 0)
{
Console.WriteLine($"Processed {rowCount} rows...");
}
}
Console.WriteLine($"Total rows processed: {rowCount}");
스키마 발견
// List all tables
using var showTablesCommand = connection.CreateCommand();
showTablesCommand.CommandText = "SHOW TABLES";
using var tablesReader = await showTablesCommand.ExecuteReaderAsync();
Console.WriteLine("Available tables:");
while (await tablesReader.ReadAsync())
{
Console.WriteLine($" {tablesReader.GetString(0)}");
}
// Describe table structure
using var describeCommand = connection.CreateCommand();
describeCommand.CommandText = "DESCRIBE employees";
using var schemaReader = await describeCommand.ExecuteReaderAsync();
Console.WriteLine("\nTable structure for 'employees':");
while (await schemaReader.ReadAsync())
{
Console.WriteLine($" {schemaReader["col_name"]}: {schemaReader["data_type"]}");
}
LivyConnectionStringBuilder 사용
using Microsoft.Spark.Livy.AdoNet;
var builder = new LivyConnectionStringBuilder
{
Server = "https://api.fabric.microsoft.com/v1",
SparkServerType = "Fabric",
FabricWorkspaceID = "<workspace-id>",
FabricLakehouseID = "<lakehouse-id>",
AuthFlow = "AzureCli",
ConnectionPoolingEnabled = true,
MinPoolSize = 2,
MaxPoolSize = 10,
ConnectionTimeout = 60
};
using var connection = new LivyConnection(builder.ConnectionString);
await connection.OpenAsync();
DbProviderFactory 사용
using System.Data.Common;
using Microsoft.Spark.Livy.AdoNet;
// Register the provider factory (typically done at application startup)
DbProviderFactories.RegisterFactory("Microsoft.Spark.Livy.AdoNet", LivyProviderFactory.Instance);
// Create connection using factory
var factory = DbProviderFactories.GetFactory("Microsoft.Spark.Livy.AdoNet");
using var connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
await connection.OpenAsync();
using var command = factory.CreateCommand();
command.Connection = connection;
command.CommandText = "SELECT * FROM employees LIMIT 5";
using var reader = await command.ExecuteReaderAsync();
// Process results...
데이터 형식 매핑
드라이버는 Spark SQL 데이터 형식을 .NET 형식에 매핑합니다.
| Spark SQL 형식 | .NET 형식 | DbType |
|---|---|---|
| BOOLEAN | bool |
불리언 (Boolean) |
| TINYINT (타이니인트) | sbyte |
S바이트 (SByte) |
| 스몰인트 (SMALLINT) | short |
Int16 |
| INT | int |
Int32 |
| BIGINT | long |
Int64 |
| FLOAT | float |
Single |
| 두 배 | double |
두 배 |
| DECIMAL(p,s) | decimal |
Decimal |
| STRING | string |
스트링 |
| VARCHAR(n) | string |
스트링 |
| CHAR(n) | string |
스트링 |
| BINARY | byte[] |
바이너리 |
| DATE | DateTime |
날짜 |
| TIMESTAMP | DateTime |
날짜/시간 |
| ARRAY<T> |
T[] 또는 string (JSON) |
객체 |
| MAP<K,V> |
Dictionary<K,V> 또는 string (JSON) |
객체 |
| 구조 |
object 또는 string (JSON) |
객체 |
복합 유형 작업
복합 형식(ARRAY, MAP, STRUCT)은 기본적으로 JSON 문자열로 반환됩니다.
using System.Text.Json;
using System.Collections.Generic;
using var command = connection.CreateCommand();
command.CommandText = "SELECT array_column, map_column, struct_column FROM complex_table LIMIT 1";
using var reader = await command.ExecuteReaderAsync();
if (await reader.ReadAsync())
{
// Complex types returned as JSON strings
string arrayJson = reader.GetString(0); // e.g., "[1, 2, 3]"
string mapJson = reader.GetString(1); // e.g., "{\"key\": \"value\"}"
string structJson = reader.GetString(2); // e.g., "{\"field1\": 1, \"field2\": \"text\"}"
// Parse with System.Text.Json
var array = JsonSerializer.Deserialize<int[]>(arrayJson);
var map = JsonSerializer.Deserialize<Dictionary<string, string>>(mapJson);
}
Troubleshooting
이 섹션에서는 Microsoft Fabric Data Engineering용 Microsoft ADO.NET Driver를 사용할 때 발생할 수 있는 일반적인 문제를 해결하기 위한 지침을 제공합니다.
일반적인 문제
다음 섹션에서는 일반적인 문제 및 해당 솔루션에 대해 설명합니다.
연결 오류
문제: Microsoft Fabric에 연결할 수 없음
해결 방법:
-
FabricWorkspaceID및FabricLakehouseID가 올바른 GUID인지 확인하세요. - Azure CLI 인증 확인:
az account show - 적절한 패브릭 작업 영역 권한이 있는지 확인합니다.
-
api.fabric.microsoft.com에 대한 네트워크 연결 확인
인증 오류
문제: Azure CLI로 인증 실패
해결 방법:
- 실행
az login하여 자격 증명 새로 고침 - 올바른 테넌트 확인:
az account set --subscription <subscription-id> - 토큰 유효성 검사:
az account get-access-token --resource https://api.fabric.microsoft.com
쿼리 시간 제한
문제: 큰 테이블에서 쿼리 시간 초과
해결 방법:
- 쿼리 제한 시간 증가:
LivyStatementTimeoutSeconds=300 -
LIMIT절을 사용하여 개발 중 결과 크기 제한 - Spark 클러스터에 적절한 리소스가 있는지 확인
세션 만들기 시간 제한
문제: 세션을 만드는 동안 연결 시간이 초과됨
해결 방법:
- 세션 시간 제한 늘리기:
LivySessionTimeoutSeconds=120 - 패브릭 용량 가용성 확인
- 작업 영역이 세션 제한에 도달하지 않았는지 확인
로그 기록 활성화
문제를 해결할 때 자세한 로깅을 사용하도록 설정하면 문제의 근본 원인을 식별하는 데 도움이 될 수 있습니다. 연결 문자열을 통해 또는 프로그래밍 방식으로 로깅을 사용하도록 설정할 수 있습니다.
연결 문자열을 통해 자세한 로깅을 사용하도록 설정하려면 다음을 수행합니다.
LogLevel=Debug
또는 프로그래밍 방식으로 구성합니다.
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Debug);
});
// Logging is automatically integrated with the connection
로그 수준:
-
Trace: 가장 자세한, 모든 API 호출 포함 -
Debug: 자세한 디버깅 정보 -
Information: 일반 정보(기본값) -
Warning: 경고만 -
Error: 에러만