常用网络协议性能调研
1.调研目的
解决接口大并发量情况下,接口响应速度问题,提升接口QPS,主要方向在使用netty长连接、websocket协议、http2.0优化网络请求。
2.调研方向
2.1 netty长连接
http1.1默认支持tcp长连接,使用netty长连接在根本上没有太大区别。不做深入调研。
2.2 websocket
websocket最大的特点是建立服务器和客户端的平等对话,能够让服务器主动向客户端推送消息。与我们的调研目的不相符,不做深入调研。
2.3 HTTP/2
HTTP/2是现行的HTTP/1.x的替代,但它不是重写,HTTP方法/状态码/语义都与HTTP/1.x一样。HTTP/2基于SPDY,专注于性能,最大的一个目标是在用户和网站间只用一个连接(connection)。HTTP/2通过多路复用、二进制流、Header压缩等特性,极大的提高了性能。
HTTP/1.1和HTTP/2的区别,可以通过 https://http2.akamai.com/demo 直观感受。
综合上述,使用HTTP/2代替HTTP/1.1以提高接口响应的速度,以达到提高qps的目的是此次调研的方向
3.调研过程
3.1 HTTP/2相对于HTTP/1.1解决的问题
连接复用问题:
HTTP/1.1解决了HTTP/1.0的短连接问题,默认使用tcp长连接,减少了客户端请求接口数据时建立tcp连接的开销,但是HTTP/1.1协议中浏览器客户端在同一时间,针对同一域名下的的请求有一定的数量限制,超出限制会请求会被阻塞,一些网站围了解决此问题,配置多个静态资源CDN域名。HTTP/2通过多路复用的方式解决了此问题。
HTTP/1.1队头阻塞问题:
HTTP1.1允许客户端不用等待上一次请求的结果,就可以发起下一次请求,但是要求服务器必须按照接收请求的顺序响应客户端的请求,因此一旦队头请求出现延迟,会影响连接中所有的请求响应。HTTP/2基于多路复用+二进制分层帧的机制,使服务的请求和响应可以实现乱序发送,解决了此问题。
报头压缩
HTTP1.1对于HTTP1.0的很多功能优化和扩充其实是增加更多的请求头和响应头来实现的,一次请求的头部占有很大开销,HTTP/2的报头压缩,基于专门为首部压缩而设计的HPACK算法,能够很好的降低协议的开销。
3.2 HTTP2与HTTP/1.1的接口性能测试对比
3.2.1 服务端功能及代码
框架基于springboot2.3.1.RELEASE
1.编写一个用于测试的接口,针对每个请求会延迟100ms响应,对于特殊请求延迟500ms响应
@RestController
public class IndexController {
private static Integer oneNumber = 0;
private static Integer twoNumber = 0;
@GetMapping("/hello")
public String testHello(@RequestParam String key) {
try {
if ("1".equals(key)) {
oneNumber ++;
}
if ("2".equals(key)) {
twoNumber ++;
}
if (("1".equals(key) && oneNumber % 100 == 0) || ("2".equals(key) && twoNumber % 100 == 0)) {
Thread.sleep(500L);
} else {
Thread.sleep(100L);
}
System.out.println("请求响应 key:" + key);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello world";
}
}
IndexController.java
2.设置监听8443端口,使用HTTP/2协议
Jar包依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<!--移除掉了starter-web中的tomcat依赖-->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<!--注意这里使用undertow,移除掉了starter-web中的tomcat依赖-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
应用启动参数配置
#端口号
server.port=8443
#ip地址
server.address=0.0.0.0
#启用HTTP响应压缩
server.compression.enabled=true
# 启用http2
server.http2.enabled=true
# 启用ssl
server.ssl.enabled=true
#证书位置
server.ssl.key-store=classpath:keystore.p12
# 证书密码
server.ssl.key-store-password=123456
# 证书类型
server.ssl.key-store-type= PKCS12
# 协议类型
server.ssl.protocol=TLSv1.2
server.ssl.key-alias=undertow
注:这里需要生成一个密钥,因为HTTP2必须基于HTTPS才能使用
3.增加一个监听8080端口,使用HTTP/1.1协议
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
@Override
public void customize(UndertowServletWebServerFactory factory) {
factory.addBuilderCustomizers(new UndertowBuilderCustomizer() {
@Override
public void customize(Undertow.Builder builder) {
builder.addHttpListener(8080, "0.0.0.0");
}
});
}
}
3.2.2 使用Jmeter测试接口(测试HTTP/2需要配置插件)
线程数/单个线程请求次数 | HTTP/1.1平均响应时间(ms) | HTTP/2平均响应时间(ms) |
---|---|---|
10/500 | 187 | 141 |
200/30 | 520 | 246 |
600/10 | 1185 | 571 |
具体数据如图:
线程数10,单个线程请求次数500时分别对应HTTP/1.1、HTTP/2的呈现情况。
HTTP/2
线程数200,单个线程请求次数30时分别对应HTTP/1.1、HTTP/2的呈现情况。
HTTP/1.1
HTTP/2
线程数600,单个线程请求次数10时分别对应HTTP/1.1、HTTP/2的呈现情况。
HTTP/1.1
HTTP/2
4.调研结果
经过上述实验,对比使用HTTP/2及HTTP/1.1协议,在性能优化方面有很大提升,后续可以考虑将HTTP/1.1协议替换为HTTP/2协议。
上述实验使用的是mac笔记本实验,实验接口设置的100次请求平均sleep 104ms,而最后的平均响应时间HTTP/1.1达到了1185ms,HTTP/2达到了571ms,说明请求瓶颈在网络传输上,因此造成接口性能的优化能够达到原先一倍的情况,实际情况应该是网络传输效率HTTP2相对于HTTP/1.1能有很大的提高。实际使用到项目上时,需要考虑网络传输效率提高后对服务器处理请求造成的压力,整体请求的效果优化可能达不到上面实验中翻倍的提升情况。
5.使用风险
使用HTTP/2协议使用了多路复用解决了应用层队头阻塞的问题,建立的TCP连接数更加的少,客户端和服务器之间的数据传输在单个TCP连接上能跑进行更多传输,是HTTP/2的优势,同时也是HTTP/2的劣势,一旦发生数据包丢失的情况,整条TCP连接上的数据传输都会受到影响,这就是TCP的队头阻塞,此时HTTP/2就会受到很大影响。