빠른 파일 전송 도구 구축, 파트 2: kTLS로 rsync보다 58 % 빠르게
Source: Dev.to
위 링크에 있는 글 전체를 제공해 주시면, 해당 내용을 한국어로 번역해 드리겠습니다.
문제: SSH가 병목
머신 간에 ML 데이터셋을 전송할 때, SSH를 이용한 rsync가 기본 도구입니다:
rsync -az /data/ml_dataset user@server:/backup/
작동은 하지만 속도가 느립니다. 9.7 GB 데이터셋(≈ 100 K 파일)의 경우 rsync가 390 s → 25 MiB s⁻¹가 걸렸습니다.
병목 현상은 네트워크가 아니라 사용자 공간 암호화입니다.
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ File │────▶│ rsync │────▶│ SSH │────▶│ Network │
│ Read │ │ (delta) │ │ encrypt │ │ Send │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│
Context switches,
userspace copies,
CPU‑bound AES
모든 바이트가 SSH 프로세스를 거쳐 전송되며, 이 과정에서 OpenSSL을 사용해 사용자 공간에서 암호화됩니다. 여기에는 다음과 같은 작업이 포함됩니다:
- 커널과 사용자 공간 사이의 다중 컨텍스트 스위치
- 커널 버퍼와 사용자 공간 버퍼 간의 데이터 복사
- AES에 대한 CPU 시간 (AES‑NI가 있더라도)
솔루션: kTLS (커널 TLS)
Linux 4.13+은 kTLS를 지원합니다 – TLS 암호화가 커널에서 직접 처리됩니다. TLS 세션이 설정되면, 커널은 소켓을 통해 흐르는 데이터를 암호화합니다.
┌─────────┐ ┌─────────┐ ┌──────────────────┐
│ File │────▶│ read │────▶│ Socket (kTLS) │
│ │ │ │ │ encrypt + send │
└─────────┘ └─────────┘ └──────────────────┘
│
One kernel operation,
no userspace copies,
AES‑NI in kernel
장점
- 사용자 공간 암호화 프로세스 없음 – 커널이 직접 처리
- 복사 횟수 감소 – 데이터가 사용자 공간을 통과하지 않음
- 커널 내 AES‑NI – 추가 컨텍스트 전환 없이 하드웨어 가속 사용
Source: …
구현
kTLS를 설정하려면 다음이 필요합니다:
- TLS 핸드쉐이크 – 키 교환 (우리는 사전 공유 비밀 + HKDF를 사용합니다)
- 커널 구성 –
setsockopt(SOL_TLS, TLS_TX, …)로 암호화 키 지정 - 데이터 전송 – 일반
send()호출; 커널이 자동으로 암호화합니다
/* After deriving keys from the shared secret … */
struct tls12_crypto_info_aes_gcm_128 crypto_info = {
.info.version = TLS_1_2_VERSION,
.info.cipher_type = TLS_CIPHER_AES_GCM_128,
};
memcpy(crypto_info.key, key, 16);
memcpy(crypto_info.iv, iv, 8);
memcpy(crypto_info.salt, salt, 4);
setsockopt(sock, SOL_TLS, TLS_TX, &crypto_info, sizeof(crypto_info));
/* Now all send() calls are automatically encrypted! */
Source: …
벤치마크 결과
테스트 환경: Laptop → GCP VM (공용 인터넷)
핵심 수치
| 데이터셋 | uring‑sync + kTLS | rsync (SSH) | 향상 |
|---|---|---|---|
ml_small (60 MiB, 10 K files) | 2.98 s | 2.63 s | 거의 동일 |
ml_large (589 MiB, 100 K files) | 16.4 s | 24.8 s | 34 % 빠름 |
ml_images (9.7 GiB, 100 K files) | 165 s | 390 s | 58 % 빠름 |
패턴
Data size: 60 MiB → 589 MiB → 9.7 GiB
Improvement: 0 % → 34 % → 58 %
전송량이 클수록 kTLS의 이점이 커집니다.
이유: 연결당 오버헤드(핸드쉐이크, 키 파생)가 더 많은 데이터에 걸쳐 상쇄되는 반면, SSH의 사용자 공간 암호화 오버헤드는 데이터 크기에 비례해 선형적으로 증가합니다.
처리량 비교
| 방법 | 처리량 | CPU 사용량 |
|---|---|---|
| rsync (SSH) | 25 MiB s⁻¹ | 높음 (사용자 공간 암호화) |
| uring‑sync + kTLS | 60 MiB s⁻¹ | 낮음 (커널 암호화) |
kTLS는 rsync보다 2.4배 높은 처리량을 제공하면서 CPU 사용량은 더 적게 소모합니다.
왜 제로‑카피 splice()가 안 될까?
이론적으로 kTLS는 진정한 제로‑카피 전송을 위해 splice()를 지원합니다:
File → Pipe → kTLS Socket (no userspace copies!)
가장 빠른 경로가 될 것이라 기대하고 구현했지만, 실제로는 2.9× 느려졌습니다.
조사
strace가 병목 현상을 밝혀냈습니다:
splice(file → pipe): 27 µs ← instant
splice(pipe → socket): 33 ms ← 1000× slower!
splice(pipe → kTLS socket)는 TCP ACK를 기다리는 동안 블록됩니다. 커널은 일반 send() 호출에서처럼 공격적으로 버퍼링할 수 없습니다.
교훈
제로‑카피가 항상 더 빠른 것은 아닙니다. 파일이 많은 워크로드에서는:
- read / send – 커널이 버퍼링을 효율적으로 관리
- splice – 각 청크마다 블록되어 처리량이 크게 감소
splice()는 단일 대용량 파일에 대해서는 도움이 될 수 있지만, ML 데이터셋처럼 작은 파일이 많을 경우 read() + send()를 사용하는 것이 좋습니다.
언제 사용해야 할까
kTLS 파일 전송을 사용할 경우:
- 대용량 데이터셋 전송 (> 500 MiB)
- 네트워크에 여유 대역폭이 있는 경우
- 양쪽 엔드포인트를 직접 제어할 수 있는 경우
- 보안이 필요할 때 (VPN만으로는 부족)
rsync를 계속 사용할 경우:
- 델타 동기화가 필요할 때 (변경된 바이트만)
- 대상에 이미 일부 데이터가 있는 경우
- 기존 SSH 인프라가 충분할 때
- 단순함이 순수 속도보다 중요할 때
와이어 프로토콜
우리 프로토콜은 의도적으로 최소화되었습니다:
HELLO (secret hash) ──────────────────▶ Verify
◀────────────────── HELLO_OK (+ enable kTLS)
FILE_HDR (path, size, mode) ──────────▶ Create file
FILE_DATA (chunks) ───────────────────▶ Write data
FILE_END ──────────────────────────────▶ Close file
(repeat for all files)
ALL_DONE ──────────────────────────────▶ Complete
제2부 종료.
uring‑sync: kTLS를 이용한 빠른 암호화 파일 전송
델타 인코딩 없음, 체크섬 없음 – kTLS는 GCM을 통해 무결성을 제공합니다.
인증 및 암호화가 적용된 순수 파일 전송만 수행합니다.
사용법
# Receiver (on remote host)
uring-sync recv /backup --listen 9999 --secret mykey --tls
# Sender (on local host)
uring-sync send /data remote-host:9999 --secret mykey --tls
구현 세부 사항
- 키 파생: 공유 비밀에서 파생된 HKDF
- 암호화: kTLS를 통한 AES‑128‑GCM
- 전송: 단순 TCP 프로토콜 (HTTP, gRPC 없음)
전체 소스:
결론
암호화를 사용자 공간 SSH에서 커널 kTLS로 옮김으로써 다음을 달성했습니다:
| 지표 | uring‑sync | rsync |
|---|---|---|
| 속도 향상 | 58 % 더 빠름 | – |
| 처리량 | 60 MB/s (2.4×) | 25 MB/s |
| CPU 사용량 | 낮음 (커널 AES‑NI) | 높음 (사용자 공간 OpenSSL) |
핵심 인사이트: 대용량 데이터 전송에서는 SSH의 유연성이 오히려 오버헤드를 발생시킵니다. 커널 암호화를 활용한 목적에 맞게 설계된 도구가 더 우수합니다.
부록: 전체 벤치마크 데이터
테스트 환경
- 보내는 측: Ubuntu 노트북, 로컬 NVMe
- 받는 측: GCP VM (us‑central1‑a)
- 네트워크: 공용 인터넷
- 캐시: 콜드 캐시 (
echo 3 > /proc/sys/vm/drop_caches)
원시 결과
| Dataset | Files | Size | kTLS Time | kTLS Speed | rsync Time | rsync Speed |
|---|---|---|---|---|---|---|
| ml_small | 10 K | 60 MB | 2.98 s | 20 MB/s | 2.63 s | 23 MB/s |
| ml_large | 100 K | 589 MB | 16.4 s | 36 MB/s | 24.8 s | 24 MB/s |
| ml_images | 100 K | 9.7 GB | 165 s | 60 MB/s | 390 s | 25 MB/s |
스플라이스 조사 (ml_images)
| Mode | Time | Speed | Notes |
|---|---|---|---|
| 평문 + read/send | 146 s | 68 MB/s | 가장 빠름 (암호화 없음) |
| 평문 + splice | 157 s | 63 MB/s | +8 % 오버헤드 |
| kTLS + read/send | 165 s | 60 MB/s | +13 % (암호화 비용) |
| kTLS + splice | 428 s | 23 MB/s | 2.9배 느림 (문제 발생) |
벤치마크는 2026년 1월에 실행되었습니다. 네트워크 상황 및 하드웨어에 따라 결과가 달라질 수 있습니다.
Tags: #linux #ktls #tls #rsync #performance #networking #encryption