HTTPS 之 TLS 性能优化详述
HTTPS(HTTP over SSL)是以安全为目标的 HTTP 通道,可以理解为 HTTP + SSL/TLS,即在 HTTP 下加入 SSL/TLS 层作为安全基础。其中 TLS 的前身是 SSL,目前广泛使用的是 TLS 1.2。
TLS性能调优
TLS 被普遍认为会使服务变慢,主要是早期 CPU 还很慢,只有少数站点买得起加密服务。但是今天计算能力不再是 TLS 的瓶颈。2010年,Google 默认情况下对其电子邮件服务上启用了加密,之后他们表示 SSL/TLS 不再花费昂贵的计算成本:
在我们的前端服务上,SSL/TLS 计算只占 CPU 负载的不到 1%,每个连接只占不到 10KB 的内存,以及不到 2% 的网络开销。
1. 延迟和连接管理
网络通讯的速度由两个主要因素决定:带宽和延迟。
带宽:用来衡量在单位时间内有多少数据可发送
延迟:描述一个消息从一端发送到另一端接收所需的时间
其中,带宽是次要因素,因为通常你可以随时购买更多带宽;而延迟则是无法避免的,因为它是在数据通过网络连接传输时被强加的限制。
延迟对 TLS 影响特别大,因为它有自己精心设计的握手,在连接初始化的时候额外增加了两个往返。
1.1 TCP优化
每个 TCP 连接都有一个称为 拥塞窗口 的速度极限,这个窗口最初时较小,在可靠性能保证的情况下随时间增长。这种机制被称为 慢启动。
因此,对于所有的 TCP 连接,启动速度很慢,对于 TLS 连接情况则更糟糕,因为 TLS 握手协议消耗了宝贵的初始连接字节(当拥塞窗口较小时)。如果拥塞窗口足够大,那么慢启动不会有额外的延迟。但是,如果较长的握手协议超过了拥塞窗口的大小,发送方必须将它拆分为两块,先发送一块,等待确认(一个往返),增加拥塞窗口,然后再发送剩下的部分。
1.1.1 拥塞窗口调优
启动速度限制被称为 初始拥塞窗口。RFC6928 建议初始拥塞窗口设置为10个网络段(约15KB)。早期的建议是使用2-4个网络段起步。
在旧版本的Linux平台上,可以改变路由的初始拥塞窗口:
# ip route | while read p; do ip route change $p initcwnd 10; done
1.1.2 防止空闲时慢启动
慢启动可以作用于一段时间内没有任何流量的连接上,降低其速度,并且速度下降地非常快。 在 Linux 上,可以在连接空闲时禁用慢启动:
# sysctl -w net.ipv4.tcp_slow_start_after_idle=0可以通过将该设置添加到 /etc/sysctl.conf 配置使其永久生效。
1.2 长连接
大部分情况下 TLS 性能影响集中在每一个连接的开始握手阶段。一个重要的优化技术是在连接数允许的情况下尽可能保持每个连接不断开。
现在的趋势是使用事件驱动的 WEB 服务器,通过使用固定的线程池(甚至单个线程)处理所有通讯,从而减少每个连接的成本以及被攻击的可能性。
长连接的缺点是在最后一个 HTTP 连接完成之后,服务器在关闭连接之前会等待一定时间,虽然一个连接不会消耗太多的资源,但是降低了服务器的总体伸缩性。长连接适用于客户端突发大量请求的场景。
当配置较大的长连接超时时间时,限制并发连接数以免服务器超负荷是至关重要的。通过测试调整服务器,使其运行在容量限制内。如果 TLS 是由 OpenSSL 处理的,请确保服务器正确设置 SSL_MODE_RELEASE_BUFFERS 标识。
1.3 HTTP/2.0
HTTP/2.0 是 二进制协议,具备 多路复用 和 头部压缩 等特性,可以提升性能。
1.4 CDN
使用 CDN 可以实现世界级的性能,它利用地理上分散的服务器提供边缘缓存和流量优化。
当用户离你的服务器越远,访问网络就越慢,在这种情况下连接建立是一个很大的限制因素。为了服务器尽可能靠近最终用户,CDN 经营着大量的地理分布的服务器,它可以提供两种降低延迟的方式,即边缘缓存和连接管理。
1.4.1 边缘缓存
由于 CDN 服务器贴近用户,可以将你的文件提供给用户,就像你的服务器真的在那里一样。
1.4.2 连接管理
如果你的内容是动态的、用户特定的,那么久无法通过 CDN 缓存数据。但是,一个不错的 CDN 即使没有任何缓存,也能通过连接管理提供帮助,那就是它可以通过长时间保持的长连接消除大部分建立连接的成本。
建立连接期间大部分的时间都花在等待上面。为了尽量较少等待,CDN 通过自己的基础设置将流量路由到距离目的地最近的一个点。因为是 CDN 自己完全可控的服务器,它可以内部保持长连接很长一段时间。
当使用 CDN 时,用户连接到最近的 CDN 节点,这只有很短的距离,TLS 握手的网络延迟也很短;而 CDN 与服务器之间可以直接复用已有的远距离长连接。这意味着与 CDN 快速初始 TLS 握手后,用户与服务器就建立了有效连接。
2. TLS协议优化
在连接管理之后我们可以专注于 TLS 的性能特征,具备对 TLS 协议进行安全和速度调优的知识。
2.1 密钥交换
使用 TLS 最大的成本除了延迟以外,就是用于安全参数协商的 CPU 密集型加密操作。这部分通讯称为密钥交换(key exchange)。密钥交换的 CPU 消耗很大程度上取决于服务器选择的私钥算法、私钥长度和密钥交换算法。
密钥长度
破解密钥的难度取决于密钥的长度,密钥越长越安全。但较长的密钥同时也意味着需要花费更多时间进行加密和解密。
密钥算法
目前有两种密钥算法可用:RSA 和 ECDSA。当前 RSA密钥算法推荐最小长度2048位(112位加密强度),将来更多会部署3072位(128位加密强度)。ECDSA在性能和安全性上要优于 RSA,256位的 ECDSA (128位加密强度)提供和 3072位的 RSA 一样的安全性,却有更好地性能。
密钥交换
目前有两种可用的密钥交换算法:DHE 和 ECDHE。其中 DHE 太慢不推荐使用。 密钥交换算法的性能取决于配置的协商参数长度。对于 DHE,常用的1024和2048位,分别提供80和112位安全等级。对于 ECDHE,安全和性能取决于一种称为 **曲线** 的东西。secp256r1提供128位安全等级。
你在实践中不能随意组合密钥钥和密钥交换算法,但可以使用由协议指定的组合。
2.2 证书
一次完整的 TLS 握手期间,服务器会把它的证书链发送给客户端验证。证书链的长度和正确性对握手的性能有很大影响。
使用尽可能少的证书
证书链里的每个证书都会增大握手数据包,证书链中包含太多证书有可能导致 TCP 初始拥塞窗口溢出。
只包含必需的证书
证书链里包含非必需证书是个常见错误,每个这样的证书会给握手协议额外增加1-2KB。
提供完整的证书链
服务器必须提供一个被根证书信任的完整证书链。
使用椭圆曲线证书链
因为 ECDSA 私钥长度使用更少的位,所以 ECDSA 证书会更小。
避免同一张证书绑定过多域名
每增加一个域名都会增加证书的大小,对于大量域名来说会有明显的影响。
2.3 吊销检查
虽然证书吊销状态在不断变化,并且用户代理对证书吊销的行为差异很大,但是作为服务器,要做的就是尽可能快地传递吊销信息。
使用 OCSP
信息的证书 OCSP 被设计用于提供实时查询,允许用户代理只请求访问网站的吊销信息,查询简短而快速(一个HTTP请求)。相比之下 CRL 是一个包含大量被吊销证书的列表。
使用具有快速且可靠的 OCSP 响应程序的 CA
不同 CA 之间的 OCSP 响应程序性能不同,在你向 CA 提交之前先检查他们的历史 OCSP 响应程序。 另一个选择 CA 的标准是它更新 OCSP 响应程序的速度。
部署 OCSP stapling
OCSP stapling 是一种允许在 TLS 握手中包含吊销信息(整个OCSP响应)的协议功能。启用之后,通过给予用户代理进行吊销检查的全部信息以带来更好地性能,可以省去用户代理通过独立的连接获取 CA 的 OCSP 响应程序来查询吊销信息。
2.4 协议兼容
如果你的服务器与一些新版本协议的特性(例如TLS 1.2)不兼容,浏览器可能需要通过与服务器进行多次尝试,才能协商一个加密的连接。确保良好的 TLS 性能的最好方式是升级最新的 TLS 协议栈以支持较新的协议版本和扩展。
2.5 硬件加速
随着 CPU 速度的不断提高,基于软件的 TLS 实现在普通 CPU 上已经运行得足够快,无需专门的加密硬件就能处理大量的 HTTPS 请求。但安装加速卡或许能够提升速度。