RESTful风格的微服务-spring boot&HTTP/2

最近发布的Spring Boot 2.0中,其中一个新特性就是支持了HTTP/2,Spring Boot具有天生的易用性,现在再加上HTTP/2的高性能,还继承Spring框架的易拓展性,Spring Boot的未来应该是一片光明。本文将一步步教你配置Spring Boot项目支持HTTP/2。

00 前言

HTTP协议是一个很成功的协议,已经被广泛使用。然而,HTTP/1.1的底层传输方式的几个特性,已经对应用的整体性能产生了负面影响。特别是,HTTP/1.0在每次的TCP连接上只允许发送一次请求,在HTTP/1.1中增加了请求管线,但是这仅仅解决了部分的并发问题,并且仍然存在阻塞的现象,因此需要发送多个请求的HTTP/1.0和HTTP/1.1客户端就与服务器建立多个连接,以达到高并发低延迟的目的。

另外,HTTP请求头中的字段经常重复且冗长,带来不必要的网络流量,并会导致初始的TCP拥塞窗口被快速填满。当在一个新的TCP连接上发送多个请求时,这可能导致更大的延迟。

HTTP/2通过在底层连接上定义更优的HTTP语义来解决这些问题。具体来说,它允许在同一个连接上交错地传输请求和响应信息,并对HTTP请求头字段使用高效的压缩编码。它还允许对请求设置优先特权,让更重要的请求更快地完成,从而进一步提高性能。

目前大部分浏览器、服务器端软件、客户端工具以及各种http协议的相关工具都开始支持HTTP/2,具体的支持范围可以查看官方文档

已经使用HTTP/2协议的网站也很多,像Google、Twitter、Akamai等这些国外的公司早就支持HTTP/2了,国内的网站比如知乎、新浪、阿里、京东等也都已经全面支持HTTP/2,所以HTTP/2已经过了前期推广的阶段,开始逐渐普及了。

01 HTTP/2

HTTP协议从1991年的HTTP 0.9 到 HTTP 1.0、HTTP 1.1 再到 2015年开始至今的HTTP 2.0,每个版本都带来了惊人的升级体验。HTTP/2的惊人之处可以在这里体验一下,可以感受到相比HTTP 1.1在性能上的大幅提升。

HTTP/2的新特性:

  1. 新的二进制格式:HTTP 1.x的解析是基于文本,HTTP 2.0的解析是基于二进制,更加适用于服务器间信息传输了。
  2. 多路复用(MultiPlexing):也就是连接共享,每个请求都有一个ID,这样在一个连接上可以发送多个请求,并且它们在传输过程中是混杂在一起的,接收方可以根据请求的ID将请求再归属到不同的服务端请求里面。
  3. 请求优先级(request prioritization):HTTP/2中,一个源只有一个连接来实现多路复用,所有资源通过一个连接传输,为了避免线头堵塞(Head Of Line Block),这时资源传输的顺序就更重要了。优先加载重要资源,可以尽快渲染页面,提升用户体验。
  4. header压缩:通信上方各自缓存一份Header fields表,只传输压缩之后的相应编码,避免了重复的header传输。
  5. 服务端推送(server push):这个就很好理解了,HTTP 1.x都是只能从client拉取资源,HTTP/2支持从server端推送资源至client端。

HTPP 2.0的多路复用和HTTP 1.x的长连接的区别:

  • HTTP 1.0中一次请求响应就建立一次连接,用完关闭,每个请求都要建立一个连接。
  • HTTP 1.1 Pipeling解决方式,也是我们常说的Keep-Alive模式,建立一次连接之后,若干个请求排队串行化单线程处理,后面的请求等待前面的请求返回了获得执行机会,一旦有请求超时等待,后续的请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞(Head-of-Line Blocking)。
  • HTTP 2.0多路复用,多个请求同时在一个连接上并行执行,若某个请求任务耗时严重,不会影响到其它请求的正常执行。
HTTP 1.x 对比 HTTP 2.0

HTTP/2 & HTTPS

HTTPS是建构在SSL/TLS之上的HTTP协议,一种保证信息传输安全的协议,HTTP/2的定义本身是和HTTPS无关的。但是,在开放的互联网上HTTP/2将只用于https://网址,而 http://网址将继续使用HTTP/1.x,目的是在开放互联网上增加使用加密技术,以提供强有力的保护去遏制主动攻击。所以,在进行HTTP/2推广的同时也在强制推广HTTPS。

目前大部分HTTP/2的实现都是要强制使用HTTPS的,很少能见到有直接在TCP层之上实现的HTTP/2。

因此,可能会有人说建立在HTTPS之上会额外消耗很多性能,这个答案是肯定的。HTTP使用TCP三次握手建立连接,客户端和服务器需要交换3个包,HTTPS除了TCP的三个包,还要加上SSL/TLS握手需要的9个包,所以一共是12个包,增加了建立连接的时间。但是HTTP/2的多路复用技术,建立一次连接可以一直发送请求,因此HTTPS带来的性能影响可以忽略不计。

更加详细的HTTP/2的资料请参见HTTP/2官方网站

02 Spring Boot Server端配置HTTP/2

通过上面的介绍,我们知道HTTP/2是HTTP协议一次优秀的升级,因此作为服务端开发者怎能不尝试这种技术呢。正好前几天最新发布的Spring Boot 2.0中宣布支持HTTP/2,下面我们就配置体验一下吧。

由前面的介绍可以知道,HTTP/2的实现都是强制配置HTTPS的,Spring Boot的实现也不例外,因此我们先将HTTP配置成HTTPS,配置HTTPS有需要证书,所以下面就从生成证书开始介绍。

1. 生成证书的步骤:

  1. keystore以及服务器密钥对儿的生成:
    keytool -genkeypair -alias rabbitsslkey -keyalg RSA -validity 3650 -keystore rabbitkeystore.jks
  2. 验证新生成的keystore文件以及证书信息:
    keytool -list -v -keystore rabbitkeystore.jks
  3. 导出公钥证书:
    keytool -export -alias rabbitsslkey -keystore rabbitkeystore.jks -rfc -file rabbitcert.cer
  4. Truststore的生成以及公钥证书的导入:
    keytool -import -alias rabbitsslkey -file rabbitcert.cer -keystore rabbittruststore.jks
  5. 验证生成的truststore文件:
    keytool -list -v -keystore rabbittruststore.jks

关于生成证书更加详细的介绍请参见详细解释步骤

2. 为Spring Boot项目配置HTTPS

  1. 将上面生成的私钥证书rabbitkeystore.jks复制到项目的resource目录下。
  2. 在配置文件application.yaml中添加如下配置:
server:
  ssl:
    key-store: classpath:rabbitkeystore.jks
    key-store-password: rabbit
    key-password: rabbit
  1. 重启配置好的Spring Boot项目,即可使用HTTPS来访问你的服务了。

3. 为Spring Boot项目配置HTTP/2

使Spring Boot项目支持HTTP/2,只需要在application.yaml简单地配置server.http2.enabled: true就可以了。但是,在原生的JDK8中是不支持HTTP/2协议的,因此还需要选择支持HTTP/2的WEB服务器。

在Spring Boot应用中常用到的WEB服务器有:Undertow、Jetty、Tomcat三个,使用这三个WEB服务器都能配置出支持HTTP/2的Spring Boot服务,具体步骤参见官方文档。而我选用是Undertow,使用它的原因不止是配置HTTP/2最简单,而且它还是这三个中性能最好的内嵌servlet服务器。具体操作步骤如下:

  1. 在Spring Boot的依赖中排除默认的tomcat服务器,引入undertow服务器,方法是修改项目的POM文件,如下:
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  1. application.yaml中添加配置:
server:
  http2:
    enabled: true
  1. 完成配置,重启Spring Boot项目即可。
  2. 验证请求是否是HTTP/2协议,在Chrome浏览器中,可以在地址栏输入chrome://net-internals/#http2查看,结果如下图所示:
    HTTP/2验证结果

以上步骤就完成了为Spring Boot项目配置HTTP/2,具体更多信息请参见Spring Boot 的官方介绍

03 HTTP/2协议的服务如何调用

在昨天的文章(RESTful风格的微服务-Feign调用服务)中,介绍了Feign如何调用HTTP微服务。现在普通的HTTP微服务变成了安全加密的HTTPS和高性能的HTTP/2,我们该如何调用,需要怎样改造调用微服务的客户端?

1. 配置调用HTTPS的微服务的客户端

  1. 将带有公钥的rabbittruststore.jks复制到项目的resource目录下。
  2. 使用Apache httpcomponents编写Http client客户端:
package com.rabbit.boot.consumer.Util;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;

import javax.net.ssl.SSLContext;
import java.io.File;

/**
 * @Author: guoyankui
 * @DATE: 09/03/2018 5:17 PM
 */
public class HttpClientUtils {

    // 包含授信公钥文件路径
    static String trustStorePath = HttpClientUtils.class.getResource("/rabbittruststore.jks").getPath();

    /**
     *  获取安全的加密(Https)的HttpClient
     * @return
     */
    public static HttpClient getTLSHttpClient(){
        SSLContext sslcontext = null;
        // Trust own CA and all self-signed certs
        try {

            sslcontext = SSLContexts.custom()
                    .loadTrustMaterial(new File(trustStorePath), "rabbit".toCharArray(), new TrustSelfSignedStrategy())
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
        }

        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext, new String[] { "TLSv1" }, null,
                NoopHostnameVerifier.INSTANCE);

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        return httpclient;
    }
}
  1. 设置Feign客户端:
private PersonService personService = Feign.builder().client(new ApacheHttpClient(HttpClientUtils.getTLSHttpClient()))
            .encoder(new JacksonEncoder())
            .decoder(new JacksonDecoder()).target(PersonService.class, baseUrl);

这样就可以使用Feign + Http Client (apache httpcomponents) 调用HTTPS的微服务了。

2. 配置调用HTTP/2的微服务的客户端

  • Java自带的HTTP client,在JDK9才开始支持HTTP/2客户端;
  • HttpComponents HttpClient,在5.0版本才开始支持http2.0,目前5.0还是Beta版;
  • OkHttp,从OkHttp3开始支持HTTP/2,现在已经是v3.10.0版本;

关于配置编写调用HTTP/2的微服务的客户端还没有做出实践操作,各位朋友有建议的请评论区探讨。

04 总结

本文从HTTP/2协议的产生原因以及新特性开始讨论,由于个人也是刚开始学习相关知识,其中描述不尽全面,比如HTTP/2的ALPN(协议协商)原理未涉及。后面还介绍了在Spring Boot项目如何实现HTTP/2协议的服务,本文混杂这HTTP/2的原理和实践,希望能带您入门,更加深入的相关知识需要各位自己探索了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容