我是靠谱客的博主 潇洒糖豆,最近开发中收集的这篇文章主要介绍Netty SSL性能调优,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.背景知识 1.1 协议史 1996: SSL3.0. 写成RFC,开始流行。目前(2015年)已经不安全,必须禁用。

1999: TLS1.0. 互联网标准化组织ISOC接替NetScape公司,发布了SSL的升级版TLS 1.0版。

2006: TLS1.1. 作为 RFC 4346 发布。主要fix了CBC模式相关的如BEAST攻击等漏洞。

2008: TLS1.2. 作为RFC 5246发布 。增进安全性,目前的主流版本。

2015之后: TLS 1.3,还在制订中。

1.2 TLS算法组合 在TLS中,5类算法组合在一起,称为一个CipherSuite:

认证算法 加密算法 消息认证码算法 简称MAC 密钥交换算法 密钥衍生算法 比较常见的算法组合是 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 和 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 都是ECDHE 做密钥交换,使用RSA做认证,SHA256做PRF算法。

一个使用AES128-CBC做加密算法,用HMAC做MAC。

一个使用AES128-GCM做加密算法,MAC由于GCM作为一种AEAD模式并不需要。

两者的差别,在于 Block Cipher+HMAC 类的算法都爆出了各种漏洞,下一代的TLS v1.3干脆只保留了Authenticated-Encryption 类的算法,主要就是AES-GCM,AEAD模式(Authenticated-Encryption With Addtional data)里Encrypt和MAC直接集成为一个算法,在算法内部解决好安全问题。

1.3 Java 对SSL的支持 JDK7的client端只支持TLS1.0,服务端则支持TLS1.2。

JDK8完全支持TLS1.2。

JDK7不支持GCM算法。

JDK8支持GCM算法,但性能极差极差极差,按Netty的说法:

Java 8u60以前多版本,只能处理1 MB/s。 Java 8u60 开始,10倍的性能提升,10-20 MB/s。 但比起 OpenSSL的 ~200 MB/s,还差着一个量级。 1.4 Netty 对SSL的支持 Netty既支持JDK SSL,也支持Google的boringssl, 这是OpenSSL 的一个fork,更少的代码,更多的功能。

依赖netty-tcnative-boringssl-static-linux-x86_64.jar即可,它里面已包含了相关的so文件,再也不用管Linux里装没装OpenSSL,OpenSSL啥版本了。

  1. 性能问题的出现及调优 2.1 性能问题的出现 忘掉前面所有的背景知识,重新来到问题现场:

JDK7的JMeter HTTPS客户端,连接JDK8的Netty服务端时,速度还可以。

JDK8的JMeter HTTPS客户端,则非常慢,非常慢,非常吃客户端的CPU。

按套路,在JMeter端增加启动参数 -Djavax.net.debug=ssl,handshake debug 握手过程。

(OpenSSL那边这个参数加了没用)

*** ClientHello, TLSv1.2,可以看到,Client端先发起协商,带了一堆可选协议

Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256…]

*** ServerHello, TLSv1.2 然后服务端回选定一个

Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

还可以看到,传输同样的数据,不同客户端/服务端组合下有不同的纪录:

Client: JDK7 JDK SSL + Server: JDK7/8 JDK SSL

**TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

WRITE: TLSv1 Application Data, length = 32

WRITE: TLSv1 Application Data, length = 304

READ: TLSv1 Application Data, length = 32

READ: TLSv1 Application Data, length = 96

READ: TLSv1 Application Data, length = 32

READ: TLSv1 Application Data, length = 10336

Client: JDK8 JDK SSL + Server: JDK8 Open SSL

** TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

Thread Group 1-1, WRITE: TLSv1.2 Application Data, length = 300

Thread Group 1-1, READ: TLSv1.2 Application Data, length = 92

Thread Group 1-1, READ: TLSv1.2 Application Data, length = 10337

2.2 原因分析 带着上面的记录,经过一晚的奋战,得出了文章一开始的背景信息,再回头分析就很好理解了,JMeter Https 用的是JDK8 SSL,很不幸的和服务端的OpenSSL协商出一个JDK8实现超慢的TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256。

对于服务端/客户端都是基于Netty + boringssl的RPC框架,使用TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 仍然是好的,毕竟更安全。

但Https接口,如果不确定对端的是什么,JDK7 SSL or JDK8 SSL or OpenSSL,为免协商出一个超慢的GCM算法,Server端需要通过配置,才决定要不要把GCM放进可选列表里。

2.3 实现 经过一轮学习,平时是这样写的:

SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) .sslProvider( SslProvider. OPENSSL).build();

如果想不要开GCM,那把ReferenceCountedOpenSslContext里面的DEFAULT_CIPHERS抄出来,删掉两个GCM的。

List ciphers = Lists.newArrayList(“ECDHE-RSA-AES128-SHA”, “ECDHE-RSA-AES256-SHA”, “AES128-SHA”, “AES256-SHA”, “DES-CBC3-SHA”);

SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()) .sslProvider( SslProvider. OPENSSL).ciphers(ciphers).build();

3 结论 OpenSSL(boringssl)在我们的测试用例里,比JDK SSL 快10倍,10倍!!! 所以Netty下尽量都要使用OpenSSL。 在确定两端都使用OpenSSL时,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 仍然是好的,毕竟更安全,也是主流。 对端如果是JDK8 SSL时,Server端要把GCM算法从可选列表里拿掉。 喜欢小编的可以关注一下哦

转载于:https://juejin.im/post/5b94d7b96fb9a05ce5767fe2

最后

以上就是潇洒糖豆为你收集整理的Netty SSL性能调优的全部内容,希望文章能够帮你解决Netty SSL性能调优所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(50)

评论列表共有 0 条评论

立即
投稿
返回
顶部