构建快速文件传输工具,第二部分:使用 kTLS 将 rsync 提速 58%

发布: (2026年1月8日 GMT+8 05:19)
7 min read
原文: Dev.to

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 需要:

  1. TLS 握手 – 交换密钥(我们使用预共享密钥 + HKDF)
  2. 配置内核setsockopt(SOL_TLS, TLS_TX, …) 并提供密码密钥
  3. 发送数据 – 常规的 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 + kTLSrsync (SSH)提升幅度
ml_small (60 MiB, 10 K 文件)2.98 s2.63 s大致相同
ml_large (589 MiB, 100 K 文件)16.4 s24.8 s快 34 %
ml_images (9.7 GiB, 100 K 文件)165 s390 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 + kTLS60 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‑syncrsync
速度提升提升 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_small10 K60 MB2.98 s20 MB/s2.63 s23 MB/s
ml_large100 K589 MB16.4 s36 MB/s24.8 s24 MB/s
ml_images100 K9.7 GB165 s60 MB/s390 s25 MB/s

splice 调查 (ml_images)

模式时间速度备注
明文 + read/send146 s68 MB/s最快(无加密)
明文 + splice157 s63 MB/s+8 % 开销
kTLS + read/send165 s60 MB/s+13 %(加密开销)
kTLS + splice428 s23 MB/s2.9× 更慢(已损坏)

基准测试于 2026 年 1 月运行。实际结果可能因网络状况和硬件而异。

标签: #linux #ktls #tls #rsync #performance #networking #encryption

Back to Blog

相关文章

阅读更多 »