HTTP の Keep-Alive について

HTTP の Keep-Alive について確認した時のメモです。

# 参考

+ [ 【図解】TCP Keep-Alive/http Keep-Aliveの仕組みと違い ～Client/Serverの挙動とメリット,設定～](https://milestone-of-se.nesuke.com/nw-basic/as-nw-engineer/keepalive-tcp-http/)
+ [Real World HTTP](https://www.oreilly.co.jp/books/9784873118048/)

# そもそも HTTP の Keep-Alive とは

+ HTTP の `Keep-Alive` は HTTP の下のレイヤーの TCP/IP 通信を効率化する仕組み
+ `Keep-Alive` を使わない場合、HTTP のリクエストの都度 TCP/IP の 3way handshake などの TCP/IP の接続開始・終了処理が必要
+ `Keep-Alive` を使うことで連続したリクエストの時に接続を再利用する
+ HTTPS の場合、下のレイヤーの SSL/TLS を利用し、こちらでも handshake 処理が必要な為、効率化の効果がある
+ HTTP/1.0 ではリクエストヘッダに `Connection: Keep-Alive` を使いする事で `Keep-Alive` の利用が出来る。HTTP/1.1 ではデフォルトで利用する
+ クライアントかサーバーが `Connection: Close` というヘッダーを付与して接続を切るか、タイムアウトするまで接続が維持される

# 確認してみる

実際に `curl` や `httpd` を使って動きを確認してみる
なお、`httpd` は 2.4 系で確認した

## httpd の Keep-Alive は on(デフォルト状態)

httpd 2.4 ではデフォルトで Keep-Alive は on になっている模様

[KeepAlive ディレクティブ](https://httpd.apache.org/docs/2.4/ja/mod/core.html#keepalive)

念の為確認する
`curl [host1] [host2]` とリクエストすることで `Keep-Alive` を使って複数のリクエストを続けて送れるようなのでこれを利用する

```bash
$curl http://localhost http://localhost -v
* Rebuilt URL to: http://localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:25:55 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Connection #0 to host localhost left intact
* Rebuilt URL to: http://localhost/
* Found bundle for host localhost: 0x2269c20 [can pipeline]
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:25:55 GMT
< Server: Apache/2.4.43 ()
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Connection #0 to host localhost left intact
```

最後に `Connection #0 to host localhost left intact` とあるので2回の HTTP リクエストは都度 TCP/IP の接続は開始・終了せずにやっているように見える。

ただ、よく分からないのでデフォルトで `Keep-Alive` が有効ではない `HTTP/1.0` を使って比較してみる。

```bash
$curl http://localhost http://localhost -v --http1.0
* Rebuilt URL to: http://localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.0
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:27:15 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade, close
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Closing connection 0
* Rebuilt URL to: http://localhost/
* Hostname localhost was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#1)
> GET / HTTP/1.0
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:27:15 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade, close
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Closing connection 1
```

HTTP リクエストの都度 `Closing connection 0` 及び `Closing connection 1` と出力されており、都度 TCP/IP の接続・終了を行っているように見える。
また、HTTP レスポンスについても `Connection: Upgrade, close` となっており、通信が接続されている事が分かる。

次に `HTTP/1.0` を使いつつ、明示的に HTTP リクエストのヘッダに `Connection: Keep-Alive` を付与しててみる。

```bash
$curl http://localhost http://localhost -v --http1.0 -H 'Connection:Keep-Alive'
* Rebuilt URL to: http://localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.0
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
> Connection:Keep-Alive
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:37:43 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade, Keep-Alive
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Keep-Alive: timeout=5, max=100
< Content-Type: text/html; charset=UTF-8
<
Hello
* Connection #0 to host localhost left intact
* Rebuilt URL to: http://localhost/
* Found bundle for host localhost: 0x1742c20 [can pipeline]
* Re-using existing connection! (#0) with host localhost
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.0
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
> Connection:Keep-Alive
>
< HTTP/1.1 200 OK
< Date: Wed, 26 Aug 2020 21:37:43 GMT
< Server: Apache/2.4.43 ()
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Keep-Alive: timeout=5, max=99
< Connection: Keep-Alive
< Content-Type: text/html; charset=UTF-8
<
Hello
* Connection #0 to host localhost left intact
```

この場合、`HTTP/1.1` の場合と同じような挙動となり、この場合も HTTP リクエストの都度 TCP/IP の開始・終了は行ってないようにみえる。

## httpd の Keep-Alive は off にする

`/etc/httpd/conf/httpd.conf` に以下を追加する

```/etc/httpd/conf/httpd.conf
KeepAlive Off
```

その後、`httpd` を再起動してから同じようにリクエストを連続して送る。

```
$curl http://localhost http://localhost -v
* Rebuilt URL to: http://localhost/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 27 Aug 2020 23:08:38 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade, close
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Closing connection 0
* Rebuilt URL to: http://localhost/
* Hostname localhost was found in DNS cache
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 80 (#1)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 27 Aug 2020 23:08:38 GMT
< Server: Apache/2.4.43 ()
< Upgrade: h2,h2c
< Connection: Upgrade, close
< Last-Modified: Wed, 26 Aug 2020 21:19:15 GMT
< ETag: "6-5adce5f2d1b80"
< Accept-Ranges: bytes
< Content-Length: 6
< Content-Type: text/html; charset=UTF-8
<
Hello
* Closing connection 1
```

動きとしては `HTTP/1.0` と同じ動きとなった。
`Keep-Alive` が効いておらず、都度 TCP/IP の接続をしているという状況のように見える。