Model Hub Core API Zero-Copy PhysicalFile One-Pass SHA-256

800GB AI 가중치 스트리밍과 무손실 원자적 무결성 검증: ZeliDesk.Server ModelsController의 Zero-Copy PhysicalFile, 원패스 CryptoStream 해시, 및 정수 정렬 merge-parts 파이프라인

"일반적인 웹 API에서 다루는 수 킬로바이트(KB)의 JSON 데이터와, AI 모델 허브에서 오가는 수 기가바이트(GB)의 딥러닝 텐서 가중치 바이너리는 차원이 다른 아키텍처를 요구합니다. 단 하나의 메모리 복사 버퍼링이나 파트 병합 순서 꼬임만으로도 서버 프로세스는 OOM(Out of Memory)으로 사망하거나, 클라이언트에서 수 시간 동안 다운로드한 모델이 쓰레기 값으로 변질되고 맙니다."

1. 서론: 수 기가바이트(GB) AI 모델 바이너리 배포의 메모리 폭발과 무결성 난제

ZeliDesk 생태계는 교실과 행정망의 로컬 PC에서 구동되는 온디바이스 SLM(Qwen 2.5, DeepSeek R1 GGUF), 고해상도 이미지 생성 모델(SD-Turbo, TripoSR), 그리고 NVIDIA Maxine VFX 바이너리를 포함하여 총 800GB에 달하는 거대한 모델 카탈로그를 보유하고 있습니다.

이와 같은 초대용량 바이너리를 클라우드(Azure App Service)에서 전국의 학교 단말기로 배포할 때, 서버 개발팀은 세 가지 치명적인 병목에 직면합니다:

  1. 메모리 고갈(OOM): 수십 대의 클라이언트가 동시에 4GB짜리 GGUF 모델을 요청할 때 유저 모드 힙에 버퍼링하면 서버 RAM이 즉시 폭발함.
  2. 무결성 검증의 I/O 2중 낭비: 대용량 파일을 업로드받은 뒤 해시를 계산하기 위해 디스크를 다시 읽으면 디스크 IOPS가 고갈됨.
  3. 클라우드 프록시 한계: Azure App Service 프론트엔드 프록시의 ~2GB 업로드 제한과 분할 파일 병합 시 발생하는 순서 왜곡.

ZeliDesk.Server의 ModelsController.cs는 이러한 엔터프라이즈 레벨의 난제들을 운영체제 커널 제로카피(Zero-Copy), 원패스 암호화 스트림(CryptoStream), 및 정규식 정수 정렬 병합 알고리즘을 통해 우아하게 해결했습니다.

2. 커널 레벨 제로카피: PhysicalFile과 enableRangeProcessing: true를 통한 0MB 메모리 스트리밍

ModelsController.DownloadFile 메서드는 파일 다운로드 요청을 처리할 때 바이트 배열을 메모리로 읽어들이는 File(byte[], ...)이나 FileStreamResult를 일절 사용하지 않습니다. 대신 ASP.NET Core가 제공하는 PhysicalFile(...)과 enableRangeProcessing: true를 강제합니다:

[HttpGet("{id}/files/{*fileName}")]
[HttpHead("{id}/files/{*fileName}")]
public async Task DownloadFile(string id, string fileName)
{
    // 1. 모델 및 경로 무결성 사전 검증...
    if (!TryResolveSafePath(id, fileName, out string filePath))
        return BadRequest(new { error = "잘못된 파일 경로입니다." });

    // 2. SHA-256 헤더 주입 및 다운로드 이름 결정...
    string downloadName = Path.GetFileName(fileName);

    // 3. 커널 레벨 Zero-Copy 스트리밍 반환
    return PhysicalFile(
        Path.GetFullPath(filePath),
        "application/octet-stream",
        downloadName,
        enableRangeProcessing: true);
}

PhysicalFile은 내부적으로 Windows 운영체제의 TransmitFile Win32 API를 활용합니다. 이는 유저 모드 애플리케이션의 메모리를 전혀 거치지 않고, 커널 공간의 파일 시스템 캐시에서 네트워크 카드(NIC) 하드웨어 버퍼로 데이터를 직접 전송(Zero-Copy DMA)합니다. 덕분에 10GB 크기의 거대 모델을 수십 명이 동시 다운로드하더라도 ZeliDesk.Server 프로세스의 RAM 점유율은 단 1MB도 증가하지 않는 경이로운 성능을 달성합니다.

3. 사전 크기 및 해시 프로빙: [HttpHead] 라우트와 단일 쿼리 원자적 다운로드 카운터(ExecuteUpdateAsync)

클라이언트 애플리케이션(ZelisLM, ZeliGen)은 대용량 다운로드를 시작하기 전에 디스크 용량이 충분한지 확인하고 이어받기(Resume) 가능 여부를 판단하기 위해 HTTP HEAD 요청을 먼저 전송합니다. 기존 표준 API들이 HEAD 요청에 405 Method Not Allowed를 반환하던 결함을 극복하기 위해, ZeliDesk.Server는 [HttpHead]를 완벽하게 통합 지원합니다.

또한, 이어받기 요청(HTTP 206) 시 수십 번씩 쪼개져 들어오는 Range 헤더 요청마다 다운로드 카운트를 증가시키면 DB 쓰기 락 경합이 발생하고 통계가 왜곡됩니다. ModelsController는 이를 정밀하게 필터링하여 전체 요청(Full Download)일 때만 EF Core 7+ ExecuteUpdateAsync를 통해 단일 SQL 쿼리로 원자적 카운팅을 수행합니다:

bool isRangeRequest = Request.Headers.ContainsKey("Range");
bool isHeadRequest = HttpMethods.IsHead(Request.Method);

// 부분 Range 요청과 사전 HEAD 프로빙은 카운트에서 배제
if (!isRangeRequest && !isHeadRequest)
{
    // Read-Modify-Write 대신 DB 커널 레벨 원자적 1회 업데이트
    await _db.Models.Where(m => m.Id == id)
        .ExecuteUpdateAsync(s => s.SetProperty(m => m.DownloadCount, m => m.DownloadCount + 1));
}

// 정확한 SHA-256 체크섬을 X-Sha256 응답 헤더로 클라이언트에 제공
if (fileRecord != null && !string.IsNullOrEmpty(fileRecord.Sha256))
    Response.Headers.Append("X-Sha256", fileRecord.Sha256);

4. 2중 디스크 I/O를 없앤 원패스(One-Pass) 업로드: CryptoStream 기반 실시간 SHA-256 파이프라인

대용량 파일을 서버로 업로드할 때 가장 흔히 저지르는 실수는 "1) 파일을 디스크에 저장한 뒤, 2) 저장된 파일을 다시 열어서 SHA-256 해시를 계산하는" 2-Pass 방식입니다. 이 경우 10GB 파일 하나를 저장하는 데 20GB의 디스크 I/O가 발생하여 서버 스토리지 대역폭이 순식간에 고갈됩니다.

ZeliDesk.Server의 UploadFile은 System.Security.Cryptography.CryptoStream을 도입하여 네트워크 스트림에서 디스크로 청크를 기록하는 동시에 단 한 번의 통과(One-Pass)로 SHA-256 체크섬을 실시간 계산합니다:

using var sha256 = SHA256.Create();
// 64KB 고속 버퍼를 가진 FileStream 생성
using var fileStream = new FileStream(tempPath, FileMode.Create, FileAccess.Write, FileShare.None, 65536);
// 쓰기 동작과 동시에 해시 다이제스트를 갱신하는 CryptoStream 래핑
using var cryptoStream = new CryptoStream(fileStream, sha256, CryptoStreamMode.Write);

await file.CopyToAsync(cryptoStream);
await cryptoStream.FlushFinalBlockAsync();

// 추가 디스크 읽기 0초: 스트림이 닫히는 즉시 계산된 최종 SHA256 해시 획득!
sha256Hash = BitConverter.ToString(sha256.Hash!).Replace("-", "").ToLowerInvariant();

이 원패스 파이프라인 덕분에 서버 스토리지 쓰기 부하는 정확히 50%로 절감되며, 업로드가 끝나는 0.001초 만에 데이터베이스 레코드와 동기화될 준비를 마칩니다.

5. 경로 조작(Path Traversal) 0초 차단: TryResolveSafePath 엄격 정규화 및 서브디렉터리 보존

인공지능 모델 패키지는 단일 파일뿐만 아니라, bin/NVVideoEffects.dll, tokenizer/tokenizer.json과 같이 서브디렉터리 계층 구조를 보존해야 하는 경우가 많습니다. 하지만 이를 무비판적으로 수용하면 악의적인 공격자가 ../../Windows/System32와 같은 경로 조작(Path Traversal) 공격을 시도할 수 있습니다.

ZeliDesk는 TryResolveSafePath 검증 알고리즘을 통해 경로 구분자(`\`와 `/`)를 정규화하고, 정규화된 절대 경로가 반드시 모델 저장소 루트의 하위인지를 엄격하게 판별합니다:

private bool TryResolveSafePath(string id, string relativeName, out string fullPath)
{
    fullPath = string.Empty;
    if (string.IsNullOrEmpty(relativeName)) return false;
    
    // 1. 모델 디렉토리의 절대 정규화 경로 계산
    string root = Path.GetFullPath(Path.Combine(_storagePath, id));
    // 2. 요청된 상대 경로를 결합한 대상의 절대 정규화 경로 계산
    string candidate = Path.GetFullPath(Path.Combine(_storagePath, id, relativeName));
    
    // 3. 대상 경로가 루트와 동일하거나, 반드시 루트 디렉터리 구분자로 시작해야 함
    if (!candidate.Equals(root, StringComparison.Ordinal) &&
        !candidate.StartsWith(root + Path.DirectorySeparatorChar, StringComparison.Ordinal))
    {
        return false; // 🚫 상위 디렉터리 탈출 시도 0초 즉시 차단!
    }
    
    fullPath = candidate;
    return true;
}

6. Azure 2GB 한계 돌파와 정수 정렬 병합: merge-parts의 정규식 정수 소팅 및 연속성 검증

Microsoft Azure App Service의 앞단 리버스 프록시(ARR)는 단일 HTTP 요청의 페이로드 크기를 약 2GB로 엄격히 제한하고 있습니다. 따라서 2.64GB 크기의 CPython PyTorch CUDA 런타임이나 대규모 LLM 가중치는 통째로 업로드할 수 없습니다.

ZeliDesk는 클라이언트에서 .part1, .part2로 분할 전송한 뒤, 서버 측 /api/models/{id}/merge-parts 엔드포인트를 통해 원자적으로 병합합니다. 이때 가장 주의해야 할 함정은 문자열 정렬(String Sorting)의 함정입니다:

⚠️ 문자열 정렬 vs 정수 정렬의 치명적 결함

분할 파트가 10개를 넘어갈 경우, 일반적인 파일명 문자열 정렬을 사용하면 .part1, .part10, .part2, .part3 ... 순서로 정렬됩니다. 이 상태로 파일을 이어붙이면 10번째 청크가 2번째 위치에 삽입되어 바이너리 전체가 완전히 오염(Corrupted)됩니다!

// 정규식을 통해 순수 숫자 접미사(\d+)만 추출
var partRegex = new System.Text.RegularExpressions.Regex(@"\.part(\d+)$");

// 정확히 .part{N}으로 끝나는 파일만 정수(int) 기준으로 물리적 정렬
var parts = Directory.GetFiles(searchDir, $"{Path.GetFileName(fileName)}.part*")
    .Select(f => (Path: f, Match: partRegex.Match(Path.GetFileName(f))))
    .Where(x => x.Match.Success)
    .Select(x => (x.Path, Num: int.Parse(x.Match.Groups[1].Value)))
    .OrderBy(x => x.Num) // ✅ 정수 기반 정렬: part1 ➔ part2 ... ➔ part10
    .Select(x => x.Path)
    .ToList();

// 파트 번호가 1..N으로 단 하나도 빠짐없이 연속인지 엄격 검증
var partNums = parts.Select(f => int.Parse(partRegex.Match(Path.GetFileName(f)).Groups[1].Value)).ToList();
for (int i = 0; i < partNums.Count; i++)
{
    if (partNums[i] != i + 1)
        return BadRequest(new { error = $"파트가 연속적이지 않습니다(.part{i + 1} 누락). 병합을 중단합니다." });
}

병합이 완료되면 파트 임시 파일들을 즉시 정리하고, 병합된 최종 바이너리의 전체 SHA-256을 재계산하여 DB 레코드 및 모델의 TotalSizeBytes를 원자적으로 동기화합니다.

7. 상태 충돌 원천 차단: 미러링 중복 방지(MirrorStatus)와 원자적 파일 교체(.uploading ➔ File.Move)

대용량 파일을 업로드하거나 병합하는 도중 네트워크가 끊기거나 서버가 재시작되면, 디스크에 불완전하게 쓰여진 손상된 파일이 남을 수 있습니다. 만약 클라이언트가 이 미완성 파일을 다운로드하게 된다면 시스템 장애로 이어집니다.

ZeliDesk.Server는 2단계 원자적 파일 교체(Atomic File Swap)를 강제합니다:

  • 업로드 시에는 반드시 {filePath}.uploading 임시 파일로 먼저 기록합니다.
  • 병합 시에는 {finalPath}.merging 임시 파일로 먼저 조립합니다.
  • 모든 쓰기와 SHA-256 검증이 100% 성공한 뒤에만 기존 파일을 삭제하고 System.IO.File.Move를 통해 운영체제 레벨에서 0.0001초 만에 원자적으로 타깃 경로로 승격시킵니다.
  • 만약 중간에 예외가 발생하면 catch 블록에서 임시 파일을 즉시 청소하여 미완성 찌꺼기 파일의 노출을 완벽하게 차단합니다.

8. 결론: 전국 학교와 군 전산실을 지탱하는 초고성능 AI 모델 배포 인프라의 표준

인공지능 모델의 크기가 나날이 커져가는 현대 소프트웨어 환경에서, 안정적인 고성능 바이너리 배포 파이프라인은 서비스의 성패를 가르는 절대적인 생명선입니다.

ZeliDesk.Server의 ModelsController는 커널 제로카피 스트리밍(PhysicalFile), 2중 I/O를 없앤 원패스 CryptoStream 해시 엔진, 상위 경로 탈출을 봉쇄한 TryResolveSafePath, 그리고 클라우드 한계를 극복한 정수 정렬 merge-parts 파이프라인을 통해 초대용량 AI 인프라의 기술적 정점을 완성했습니다.

이 견고한 전송 아키텍처가 있기에, 대한민국 전국의 초·중·고 교실과 군사 작전 기지들은 단 1바이트의 무결성 손상이나 다운타임 없이 최신 AI 런타임과 모델을 즉시 공급받을 수 있습니다.

← 이전 기술 백서 #855 4대 오피스(HWP·Excel·Word·PPT)를 지휘하는 AI 커맨드 라우터: ZeliOffice의 다형적 상태 머신, 지수적 백오프 재시도, 및 SemaphoreSlim 동시성 거버넌스 아키텍처 다음 기술 백서 → #853 RTX 5090부터 내장 그래픽 PC까지 아우르는 온디바이스 생성 AI: ZeliGen 확산 파이프라인의 CUDA 12.8 fp16 ↔ CPU float32 자동 Fallback, 1-Step 잠재 확산, 및 JSON-RPC 프로세스 상주 아키텍처
⚡ ZeliDesk 800GB 고성능 모델 허브 경험하기

커널 제로카피 스트리밍과 원패스 무결성 검증을 탑재한 ZeliDesk 인프라를 지금 만나보세요.

ZeliDesk Suite 무료 다운로드