为什么TLS变慢?
我应该预计SSL/TLS要添加多少开销?为什么TLS变慢?
我使用Ubuntu 14.04与OpenSSL 1.0.1f和Python 3.4.3。
test.py
from datetime import datetime
import socket
import ssl
with socket.socket() as server:
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('', 8001))
server.listen(1)
while True:
with server.accept()[0] as client:
start = datetime.now()
client = ssl.wrap_socket(client, 'key.pem', 'cert.pem', True)
end = datetime.now()
print('{:.0f}ms'.format((end - start).total_seconds() * 1000))
client.send(b'hello')
client.shutdown(socket.SHUT_RDWR)
启动服务器
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
$ python3 test.py
而且连接
$ for i in $(seq 20); do openssl s_client -cert cert.pem -key key.pem -connect localhost:8001; done
$ # output shows TLSv1.2 is being used
即使是同一台主机上, TLS协商正在为15ms。当我删除TLS时,我测量了整个连接,传输和关机为1ms的<。
我在这里没有太多的经验,但它似乎比我预期的要慢得多。这是数百万个时钟周期。从洛杉矶到纽约旅行比光慢。
(1)这种表现与我所期望的一致吗? (2)造成这种表现的限制因素是什么? (3)我可以更改此代码以使初始TLS协商更快吗?
- 因为TLS做7个TCP旅行建立加密层
- 因为没有涉及(RSA,DHE,...)加密
为15ms真的不算多。
如果使用普通TCP,则只有一个TCP握手(1 RTT),它在操作系统内核中完全处理,以减少延迟和资源使用。
鉴于使用TLS和您的代码,您还有此因为您的代码不会执行会话重复使用,所以始终会进行完整的TLS握手。这意味着2次RTT仅用于握手和每次密钥交换的重度加密(影响取决于密码)。并且在(内核内)TCP关闭的顶部还有一个额外的RTT用于有序的TLS关闭。同样,更多的数据传输比TCP握手和TLS握手全部在用户空间中完成,这导致由调度引起的额外延迟,许多系统调用读取和写入数据以及内核和用户空间之间的上下文切换和拷贝这些系统调用。另外,您每次都要设置新的SSL上下文,包括加载证书等,这会增加更多不必要的开销。
由于您的客户端和服务器位于同一个系统上,并且您还使用客户端证书,因此所有这些开销都在同一个系统上完成两次。 此外,您不会仅传输极少数据(远小于TLS握手所需的数据量),因此您只能测量TLS握手所需的时间,即TLS中最昂贵的部分。而且,由于你有一个单线程客户端和一个单线程服务器,其中每一个都可能是速度限制。
换句话说:您的基准测试并不反映TLS与TCP在实际普通情况下的实际开销。但是它表明,如果以一种过于简单的方式使用TLS,TLS会产生显着的影响,即没有通常由应用程序执行大量TLS所做的任何优化。
[本页](https:// zoompf。com/blog/2014/12/optimize-tls-handshake)声称由于网络延迟,250-500ms是典型的。在同一台主机上15ms似乎很好(是的,它可能使用几百万个时钟周期,因为DH密钥交换被认为是计算密集型的)。诀窍是将连接打开,所以你只需要做一次。 – kindall