构建快速文件传输工具,第二部分:使用 kTLS 将 rsync 提速 58%
I’m happy to translate the article for you, but I’ll need the full text you’d like translated. Could you please paste the content (excluding the source line you already provided) here? Once I have the article’s body, I’ll translate it into Simplified Chinese while preserving all formatting, markdown, and technical terms.
问题:SSH 成为瓶颈
在机器之间传输机器学习数据集时,使用 SSH 的 rsync 是首选工具:
rsync -az /data/ml_dataset user@server:/backup/
它能工作,但速度很慢。对于一个 9.7 GB(约 100 K 文件)的数据集,rsync 用时 390 秒 → 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 – 硬件加速且无需额外的上下文切换
实现
设置 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! */
基准结果
测试环境: 笔记本电脑 → GCP 虚拟机(公共互联网)
关键数据
| 数据集 | uring‑sync + kTLS | rsync (SSH) | 提升幅度 |
|---|---|---|---|
ml_small (60 MiB, 10 K 文件) | 2.98 s | 2.63 s | 大致相同 |
ml_large (589 MiB, 100 K 文件) | 16.4 s | 24.8 s | 快 34 % |
ml_images (9.7 GiB, 100 K 文件) | 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× slower。
调查
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() 可能对单个大文件有帮助,但对于机器学习数据集(许多小文件),仍然使用 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 from the shared secret
- 加密: AES‑128‑GCM via kTLS
- 传输: Simple TCP protocol (no HTTP, no gRPC)
Full source:
结论
| 指标 | uring‑sync | rsync |
|---|---|---|
| 速度提升 | 提升 58 % | – |
| 吞吐量 | 60 MB/s (2.4×) | 25 MB/s |
| CPU 使用率 | 更低(内核 AES‑NI) | 更高(用户空间 OpenSSL) |
*关键洞察: 对于大批量数据传输,SSH 的灵活性会带来额外开销。使用内核加密的专用工具更胜一筹。
附录:完整基准数据
测试环境
- 发送方: Ubuntu 笔记本电脑,本地 NVMe
- 接收方: GCP 虚拟机 (us‑central1‑a)
- 网络: 公共互联网
- 缓存: 冷缓存 (
echo 3 > /proc/sys/vm/drop_caches)
原始结果
| 数据集 | 文件数 | 大小 | kTLS 时间 | kTLS 速度 | rsync 时间 | rsync 速度 |
|---|---|---|---|---|---|---|
| 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 |
splice 调查 (ml_images)
| 模式 | 时间 | 速度 | 备注 |
|---|---|---|---|
| 明文 + 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 月运行。实际结果可能因网络状况和硬件而异。
标签: #linux #ktls #tls #rsync #performance #networking #encryption