4. 后量子密码协议集成中的性能建模
把后量子密码(PQC)算法接入 TLS 1.3、QUIC、IPsec 或 SSH 之后,系统最直观的变化往往不是“能不能连上”,而是“连得慢了多少、多占了多少带宽、握手时 CPU 和内存峰值抬高了什么程度、失败率有没有变化”。因此,PQC 协议集成的性能工作不能停留在“跑一次压测看 QPS”,而要把一次完整握手拆成可建模、可测量、可归因的指标集合。本节围绕四类核心指标——握手延迟、带宽放大、CPU/内存占用、连接建立成功率——说明如何建立参数化模型,以及如何用可复现的方法测量并交叉验证。
一、先定义测量边界:一次握手到底包含什么
性能建模的第一步是统一“一次握手”的边界。以 TLS 1.3 为例,客户端发出 ClientHello 到收到 Finished 并完成密钥确认,通常经历 1-RTT;若使用 HelloRetryRequest(HRR)或会话恢复失败,则可能变成 2-RTT 或更多。PQC 集成会改变这个边界内的内容:ClientHello 中要携带 ML-KEM 的封装公钥(约 1184 字节)或混合密钥共享;ServerHello 中返回密文(约 1088 字节);证书链中可能包含 ML-DSA 或 SLH-DSA 公钥与签名,其中 SLH-DSA 签名可达数千字节。这些尺寸直接决定带宽放大,也间接影响分片、重传和 CPU 处理时间。
建模时建议把一次握手表示为若干阶段的串联:密钥交换计算、证书验证、对称密钥派生、网络往返。每个阶段都有独立的耗时和字节数,总延迟是各阶段之和加上网络 RTT 的整数倍。这样,当算法从 X25519 换成 X25519+ML-KEM-768 时,可以只替换密钥交换阶段的参数,而不必重新拟合整个模型。
二、握手延迟建模:把算法耗时与网络 RTT 分开
握手延迟可写成:
T_handshake = N_rtt × RTT + T_kex + T_cert + T_kdf + T_queuing
其中 N_rtt 是往返次数,RTT 是网络往返时延,T_kex 是密钥交换的本地计算时间,T_cert 是证书签名验证时间,T_kdf 是密钥派生时间,T_queuing 是服务端排队与调度开销。PQC 的影响集中在 T_kex 和 T_cert:ML-KEM 的封装/解封装在普通 x86 上通常在几十微秒量级,但 SLH-DSA 验签可能达到毫秒级;如果服务端每连接都要做一次 SLH-DSA 验签,高并发下 T_queuing 会显著上升。
测量时不能只测端到端总时间,否则无法归因。推荐用“分段计时”方式:在客户端记录 ClientHello 发出时间、ServerHello 到达时间、Finished 发出时间;在服务端记录收到 ClientHello、完成密钥交换、完成证书验证、发出 Finished 的时间戳。两端时间戳通过同一次连接的唯一标识关联,即可把网络 RTT 与本地计算时间分离。若无法修改协议栈,可用 eBPF 或内核 tracepoint 在 socket 读写处打点,至少拿到“发出/收到”的粗粒度分段。
三、带宽放大:不仅看字节数,还要看分片与重传
带宽放大通常定义为“握手阶段传输的总字节数 / 应用层有效载荷字节数”,但在 PQC 场景下更实用的定义是“PQC 握手总字节数 / 经典握手总字节数”。以 TLS 1.3 为例,经典 ECDHE 握手的 ClientHello 约 300 字节,ServerHello+证书约 3–5 KB;换成 ML-KEM-768 混合密钥交换后,ClientHello 增加约 1.2 KB,ServerHello 增加约 1.1 KB;若证书改用 ML-DSA-65,证书链可能再增加 3–5 KB。总放大倍数可能达到 2–4 倍。
更隐蔽的问题是分片:当 ClientHello 超过链路 MTU(常见 1500 字节)时,会被拆成多个 TCP 段或 QUIC 包。如果其中任一分片丢失,整个 ClientHello 需要重传,实际带宽放大可能远高于静态字节数计算。因此测量带宽放大时,应同时采集:握手总字节数、分片数量、重传次数、重传字节数。在 Linux 上可用 ss -i 查看重传,用 tcpdump 统计握手包总长度;在 QUIC 场景可用 qlog 记录每个包的帧类型与大小。
四、CPU 与内存占用:区分峰值与均值
PQC 的 CPU 开销主要来自密钥生成、封装/解封装、签名/验签。ML-KEM 相对轻量,ML-DSA 验签中等,SLH-DSA 验签较重。建模时可按“每连接操作次数 × 单次操作耗时”估算:若服务端每连接做 1 次 ML-KEM 解封装 + 1 次 ML-DSA 验签,单次耗时分别为 40 μs 和 300 μs,则每连接约 340 μs CPU 时间;在 8 核机器上,理论吞吐上限约为 8 / 340 μs ≈ 23,500 连接/秒,实际还要扣除排队和内存分配开销。
内存占用要区分“每连接峰值”和“稳态均值”。PQC 算法本身的工作内存通常不大,但证书链和握手缓冲区会随公钥/签名尺寸增大而增大。例如,若把每个连接的握手缓冲区从 8 KB 提高到 32 KB,在 10,000 并发连接下,仅缓冲区就多占约 240 MB。测量时可用 /proc/<pid>/status 的 VmRSS 观察进程内存,用 valgrind --tool=massif 或 heaptrack 定位峰值来源;服务端还应记录每连接握手阶段的内存分配次数,避免因频繁分配大缓冲区导致碎片化。
五、连接建立成功率:把失败原因分类
成功率不能只记一个百分比,而要按失败阶段分类:ClientHello 解析失败、密钥交换失败、证书验证失败、超时、对端不支持。PQC 集成后,常见的新增失败包括:对端不支持 ML-KEM 组导致协商失败;证书链过大导致分片丢失或超时;SLH-DSA 验签超时触发握手超时。测量时应在服务端日志中为每个失败连接记录失败阶段和错误码,并统计各阶段失败率。若成功率从 99.9% 降到 99.5%,需要判断是算法本身失败,还是分片/超时等工程问题。
六、把模型落到测量:一个可复现的示例流程
假设我们要评估“X25519+ML-KEM-768 混合密钥交换 + ML-DSA-65 证书”在 TLS 1.3 下的性能。可以按以下方式组织测量:
- 基线采集:先用纯 X25519 + ECDSA P-256 跑 1000 次握手,记录 T_handshake 分布、握手总字节数、服务端 CPU 时间、VmRSS 峰值、成功率。
- PQC 替换:保持网络、并发、客户端实现不变,仅替换密钥交换组和证书算法,重复同样 1000 次。
- 分段对比:对比 T_kex、T_cert、握手总字节数、分片数、重传次数、成功率。若 T_handshake 增加 8 ms,其中 6 ms 来自 T_cert,则说明证书验签是主要瓶颈,可考虑改用 ML-DSA-44 或缓存验签结果。
- 压力测试:逐步提高并发连接数,观察 T_queuing 和成功率变化。若成功率在 5000 并发时从 99.9% 降到 98%,同时重传次数上升,则优先排查分片与超时,而不是算法本身。
七、常见误区与判断依据
第一个误区是“只测总延迟”。总延迟受网络波动影响大,无法区分算法开销与网络开销。判断依据是:若同一机房内 RTT 稳定在 0.5 ms,而 T_handshake 增加 10 ms,则增量几乎全部来自本地计算或排队,应进一步分段定位。
第二个误区是“只算静态字节数”。PQC 公钥和签名变大后,握手包更容易超过 MTU,分片丢失会导致重传,实际带宽放大可能比静态计算高 30% 以上。判断依据是:对比“静态字节数放大倍数”与“tcpdump 统计的实际握手字节放大倍数”,若后者明显更高,应检查分片与重传。
第三个误区是“把成功率下降归因于算法”。PQC 算法本身很少导致握手失败,更多是协商不支持、证书链过大、验签超时等工程问题。判断依据是:按失败阶段分类统计,若失败集中在“证书验证”或“超时”,应优先检查证书链大小和超时阈值,而不是更换算法。
最后,性能建模的价值在于“可归因、可预测、可验证”。模型中的每个参数都应对应一个可测量的量:T_kex 对应密钥交换基准测试,T_cert 对应验签基准测试,N_rtt 对应抓包统计,成功率对应服务端日志。只有把模型与测量点一一对应,才能在 PQC 算法升级、证书替换或并发规模变化时,快速判断性能变化来自哪里,并决定是优化算法参数、调整缓冲区,还是修改协议配置。