阅读 744

从一次性能优化看https的性能

一,背景介绍

本次是对一个模块进行压测,该模块对外提供 https 接口,具体功能不用关注,本文主要是介绍整个压测过程中发现的性能优化点和优化思路。先会把压测结果抛出来,自己先思考为什么,所以把分析放在后面。

二,压测和分析

本次压测主要是对 CPU 进行压测,因为在过程中发现内存的波动和占用并不大。

2.1 信息告知

2.1.1 工具

火焰图工具:go-torch

https抓包工具:ssldump

压测工具:ab

2.1.2 服务资源配置

// 服务最高可用内存为2000Mi,最高可用CPU为4核
limits:
  cpu: "4"
  memory: 2000Mi
requests:
  cpu: "2"
  memory: 1000Mi
复制代码

2.2 https时候的压测

2.2.1 压测前

在连接数量极少的情况下,性能消耗主要是在json的序列化和反序列化。如下图:

2.2.2 压测

(1) 压测命令 此时的qps为500

ab -n 100000 -c 100  host
复制代码

(2) 火焰图 从下图可以看出,此时 json 的性能损毁也已经可以忽略不计,主要是在 https 的完全握手上了。

2.2.4 问题

  • 1,为什么 https 的握手性能消耗这么严重

2.3 http时候的压测

经过上面的分析,我们大致知道了是因为 https 导致的性能损耗,现在我把服务接口改成 http,再次进行压测,看看结果如何。

2.3.1 压测前

跟上面的一样,性能损耗都是在 json 上。

2.3.2 压测链路:直接访问链路

(1) 压测命令 此时的qps为8000

ab -n 100000 -c 100 host
复制代码

(2) 火焰图 从下图可以看出,此时 json 的性能损毁也已经可以忽略不计,性能主要消耗在网络资源获取,以及一些系统调用:gc,poll等。

三,性能分析

在继续往下看之前,希望你对 https 握手过程已经有了一定的理解。

3.1 https的性能损耗为什么这么严重

3.1.1 原因分析

一次完整的 https 握手,主要的计算点有:

  • 非对称密钥交换:使用 RSA, Diffie-Hellman, ECDHE等算法,经过高强度密钥生成算法,生成对称密钥
  • 对称加密解密:使用上面生成的对称密钥,对消息进行加密解密
  • 消息一致性验证:每一段加密的内容都会附加一个 MAC 消息,即消息认证码。简单地说就是对内容进行的安全哈希计算,接收方需要校验 MAC 码。
  • 证书签名验证:客户端验证服务端证书

从上面的火焰图我们可以看到,主要的性能消耗是在完全握手上,即非对称密钥交换过程,我们看看该过程为什么消耗这么大。 这里盗了个 ECDHE_RSA 密钥交换算法性能图

可以看到,ServerKeyExchange 用了2.4毫秒的时间, ServerKeyExchange 主要是将接下来要使用的密钥交换算法的参数进行签名,由于 RSA 算法会进行很多次的运算,对 CPU 消耗大。

使用 ssldump 抓包发现协商后的算法套件确实为:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

3.1.2 优化思路

优化思路有两种,一种是减少密钥交换时间的时间,一种是减少握手的次数。

(1) 并行计算

这个是为了减少握手的时间,目前这块我们线上使用的也是QAT加速卡来加速计算,把计算部分用专门的硬件加速卡来支持,减少CPU的计算量。这块不展开,详情可看intel QAT

(2) 使用sessionID

server 端会在收到 client hello 后生成一个 sessionID 发给 client 并缓存在本地(会加重 server 的负担),后续的 SSL 握手,client 在发送 client hello 时候可以带上,server 会进行查找,如果命中则说明可信任。但是目前我们都是多个 nginx,下一次的请求不一定能落到上一次的 nginx 上,所以可使用分布式 session cache 来支持。

(3) 使用sessionTicket

在完全握手结束前,server 会给 client 发送一个session ticket,由 client 端进行保存,下次握手时候可带上,如果 server 能够正确解密,则说明可以复用。但是这样在多个 nginx 的场景下,需要多个 nginx 使用相同的私钥。

四,其他优化点

4.1 gc

其实从http的时候的压测过程来看,此时gc已经占到一定的比重了,而且通过监控gc数据可知道,在压测过程gc每分钟达到70次,虽然每次gc耗时很短。这主要是因为使用了大量的临时对象导致的。后续的优化会使用对象池和选择合适GOGC参数。gc日志如下图,有兴趣的可以分析下

关注下面的标签,发现更多相似文章
评论