Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
C# と HTTP/2 と gRPC
Search
neno
March 25, 2023
Technology
2
8.1k
C# と HTTP/2 と gRPC
.NET ラボ 2023/03/25 での発表資料
ブログ :
-
C# と HTTP/2 と gRPC
-
HTTP/2 と gRPC に対するよくある誤解。
neno
March 25, 2023
Tweet
Share
More Decks by neno
See All by neno
C# 13 / .NET 9 の新機能 (RC 1 時点)
nenonaninu
1
1.8k
Re:ゼロから始める Observability
nenonaninu
2
770
Node-AI のリッチな WEB フロントエンドを支える技術
nenonaninu
3
1.4k
C# ではじめる OpenTelemetry
nenonaninu
0
4.2k
.NET 8 で既定で有効になった Dynamic PGO について
nenonaninu
2
7.5k
明日から使える ASP.NET Core ロギング術!
nenonaninu
0
8.8k
C# の async/await は実際にどうやって動いているか
nenonaninu
10
25k
SignalR を使ったアプリケーション開発をより快適に!
nenonaninu
1
2.2k
Roslyn とその活用法
nenonaninu
2
1.4k
Other Decks in Technology
See All in Technology
EventHub Startup CTO of the year 2024 ピッチ資料
eventhub
0
110
New Relicを活用したSREの最初のステップ / NRUG OKINAWA VOL.3
isaoshimizu
2
590
Amazon CloudWatch Network Monitor のススメ
yuki_ink
1
200
社内で最大の技術的負債のリファクタリングに取り組んだお話し
kidooonn
1
550
20241120_JAWS_東京_ランチタイムLT#17_AWS認定全冠の先へ
tsumita
2
250
Taming you application's environments
salaboy
0
180
Application Development WG Intro at AppDeveloperCon
salaboy
0
180
iOSチームとAndroidチームでブランチ運用が違ったので整理してます
sansantech
PRO
0
130
Terraform Stacks入門 #HashiTalks
msato
0
350
Oracle Cloud Infrastructureデータベース・クラウド:各バージョンのサポート期間
oracle4engineer
PRO
28
12k
SREによる隣接領域への越境とその先の信頼性
shonansurvivors
2
520
初心者向けAWS Securityの勉強会mini Security-JAWSを9ヶ月ぐらい実施してきての近況
cmusudakeisuke
0
120
Featured
See All Featured
Dealing with People You Can't Stand - Big Design 2015
cassininazir
364
24k
Embracing the Ebb and Flow
colly
84
4.5k
10 Git Anti Patterns You Should be Aware of
lemiorhan
654
59k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
4
370
RailsConf 2023
tenderlove
29
900
Thoughts on Productivity
jonyablonski
67
4.3k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
109
49k
A better future with KSS
kneath
238
17k
The Pragmatic Product Professional
lauravandoore
31
6.3k
How to Think Like a Performance Engineer
csswizardry
20
1.1k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
Typedesign – Prime Four
hannesfritz
40
2.4k
Transcript
C# と HTTP/2 と gRPC .NET ラボ 2023/03/25 何縫ねの。
自己紹介 1 • 所属: NTTコミュニケーションズ イノベーションセンター • 趣味: C#, OSS,
ドール, 一眼(α7 IV) • 執心領域 • C# ⇔ TypeScript • SignalR 何縫ねの。 nenoNaninu nenoMake ブログ https://blog.neno.dev その他 https://neno.dev
OSS 紹介 2 属性を付与するだけ Tapper • C# の型定義から TypeScript の型定義を生成する
.NET Tool/ library • JSON / MessagePack 対応! https://github.com/nenoNaninu/Tapper
OSS 紹介 3 • C# の SignalR Client を強く型付けするための Source
Generator TypedSignalR.Client Before After (using TypedSignalR.Client) こんな SignalR の Hub と Receiver の interface が あったとして… 脱文字列! 全てが強く型付け! https://github.com/nenoNaninu/TypedSignalR.Client
4 • TypeScript の SignalR Client を強く型付けするための .NET Tool /
library TypedSignalR.Client.TypeScript Before After (using TypedSignalR.Client.TypeScript) 脱文字列! 全てが強く型付け! TypeScript 用の型を C# から自動生成 MessagePack Hub Protocol 対応! https://github.com/nenoNaninu/TypedSignalR.Client.TypeScript 属性を付与するだけ! OSS 紹介
OSS 紹介 5 • SignalR 使ったアプリを快適に開発するための GUI を自動生成する library •
2 step で利用可能! • http pipeline に middleware の追加 • Hub と Receiver を定義してる interface に属性を付与 • JWT 認証 サポート • パラメータのユーザ定義型サポート • JSON で入力! SignalR 版 SwaggerUI TypedSignalR.Client.DevTools https://github.com/nenoNaninu/TypedSignalR.Client.DevTools
今回の講演の注意事項! 6 • 細かいコードがしばしば出てきますが、登壇後にこのスライドを アップするので気になる方は是非、という趣旨で載せています。 • 講演中は、細かいコードについては「ふ~ん」と雰囲気を つかめれば OK くらいの感覚で喋っています。
HTTP/2 の基本 7
の前に HttpClient の基本 8
HttpClient の基本 9 • HttpClient のコンストラクタ 意識するべき登場人物たち
HttpClient の基本 10 • HttpClient のコンストラクタ 意識するべき登場人物たち
HttpClient の基本 11 • HttpClient のコンストラクタ 意識するべき登場人物たち HttpMessageHandler は シンプルな
abstract class
HttpClient の基本 12 意識するべき登場人物たち • HttpClientHandler の中身
HttpClient の基本 13 意識するべき登場人物たち • HttpClientHandler の中身
HttpClient の基本 14 意識するべき登場人物たち • HttpClientHandler の中身 SocketsHttpHandler この子が大事
HttpClient の基本 15 HttpMessageHandler を継承している 意識するべき登場人物たち • HttpClientHandler の中身 SocketsHttpHandler
この子が大事
HttpClient の基本 16 意識するべき登場人物たち SocketsHttpHandler に対して HTTP/2 の 設定とかを行う
HttpClient の基本 17 • HttpClient のベースクラスに注目。 意識するべき登場人物たち
HttpClient の基本 18 • HttpClient のベースクラスに注目。 意識するべき登場人物たち
HttpClient の基本 19 意識するべき登場人物たち
HttpClient の基本 20 意識するべき登場人物たち SendAsync しか使わないなら HttpMessageInvoker で十分
HttpClient の基本 21 意識するべき登場人物たち SendAsync しか使わないなら HttpMessageInvoker で十分 実際、GrpcChannel の
既定の構成では HttpClient ではなく、 HttpMessageInvoker が 用いられる
HTTP/2 の基本 22
HTTP/2 の基本 23 • RFC 7540 : HTTP/2 の最初の RFC
• RFC 8740 : HTTP/2 を TLS 1.3 で使うための RFC • RFC 9113 : 2022年2月に新たに作られた RFC。現行の HTTP/2 の仕様。 HTTP/2 に関する RFC の歴史 https://www.rfc-editor.org/rfc/rfc9113
HTTP/2 の基本 24 • RFC 7540 : HTTP/2 の最初の RFC
• RFC 8740 : HTTP/2 を TLS 1.3 で使うための RFC • RFC 9113 : 2022年2月に新たに作られた RFC。現行の HTTP/2 の仕様。 HTTP/2 に関する RFC の歴史 https://www.rfc-editor.org/rfc/rfc9113
HTTP/2 の基本 25 • RFC 7540 : HTTP/2 の最初の RFC
• RFC 8740 : HTTP/2 を TLS 1.3 で使うための RFC • RFC 9113 : 2022年2月に新たに作られた RFC。現行の HTTP/2 の仕様。 HTTP/2 に関する RFC の歴史 https://www.rfc-editor.org/rfc/rfc9113 注) このスライド中には 分かりやすさのため、 RFC 7540 から図を引用 してる場合があります。
TCP TCP TCP HTTP/2 の基本 26 • HTTP/1.x HTTP/2 からリクエスト(ストリーム)が多重化された
• HTTP/2 server client server client /hoge.json /fuga.json /piyo.json TCP Stream 1 /hoge .json Stream 3 /huga .json Stream 5 /piyo .json Stream 1 /hoge .json Stream 5 /piyo .json Stream 3 /huga .json
HTTP/2 の基本 27 • 当然、フレーミング。 • TCP とかがやっているような事を HTTP/2 のレイヤーでもやるようになった、
と思えばスッと入ってくる。ハズ。 • HTTP/1.x はフレーミングは行わず、素朴にテキストをそのまま connection に投げ込んでいた。 多重化するためには何が必要? https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc9113#section-4.1 header payload
HTTP/2 の基本 28 • Length • ペイロードの長さ • 24 bit
確保されてるけど、SETTINGS_MAX_FRAME_SIZE を 設定しない限り 214 (=16,384) を超えてはいけない。 • Type • Payload がどんな種別かを示す。 • Flag • Frame Type にそれぞれ異なるフラグが定義されている。 • R • Reserved Bit。 使われてない。 • Stream Identifier • 31 bit の符号なし整数 全フレーム共通の固定長 header https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc7540#section-11.2
HTTP/2 の基本 29 • Length • ペイロードの長さ • 24 bit
確保されてるけど、SETTINGS_MAX_FRAME_SIZE を 設定しない限り 214 (=16,384) を超えてはいけない。 • Type • Payload がどんな種別かを示す。 • Flag • Frame Type にそれぞれ異なるフラグが定義されている。 • R • Reserved Bit。 使われてない。 • Stream Identifier • 31 bit の符号なし整数 全フレーム共通の固定長 header https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc7540#section-11.2
Stream 30
HTTP/2 の Stream 31 • ストリームとは… • それぞれ独立している • 双方向なフレームの
sequence • 頭に入れておきたい特徴 • 一つの HTTP/2 接続の中に、同時に複数の ストリームを開け、各 endpoint は複数の ストリームからフレームを接続に差し込める • 特定のストリームを処理している事を理由に、 他のストリームがコネクションにフレームを 差し込めない(≒書き込めない) という事は(仕様上)ない。 • ストリーム内でのフレームの順序は大事 • Stream は integer によって識別される HTTP/2 における stream とは? https://www.rfc-editor.org/rfc/rfc9113#section-5 https://www.rfc-editor.org/rfc/rfc9113#section-2.2 1 request 1 stream
HTTP/2 の Stream 32 • Http2Stream という class が内部的には存在する。 •
が、Http2Connection という internal class に含まれる private class なので触る事はできない。 • 普通に HTTP/2 を使う上では全く気にしなくていいところなので当然といえば当然。 C# 的には?
HTTP/2 の Stream 33 • Stream を作成するたびに発行される。 • Client 側が発行できる
stream id は奇数 • Server 側が発行できる stream id は偶数 • 基本的に server push を利用する場合に使われる。 • Stream id が 0 の stream は制御用ストリーム • 新しいストリームが作成されるごとに(つまり、リクエスト毎に) それぞれ +2 されていく。 • ストリームは使い捨て。再利用できない。 Stream Identifier server client Stream 1 /hoge .json Stream 3 /huga .json Stream 5 /piyo .json
HTTP/2 の Stream 34 Stream Identifier 31 bit 分枯渇したらどうなる??
HTTP/2 の Stream 35 • Http2Connection (internal class) のコンストラクタを眺める。 •
標準ライブラリに含まれる実装。つまり client 側。 • _nextStream = 1 で奇数。 Stream Identifier
HTTP/2 の Stream 36 • ストリームが追加された時、どんなことやってるか。 • SendAsync から追ってみる。 •
SendHeadersAsync が Http2stream のインスタンスを返している。 Stream Identifier
HTTP/2 の Stream 37 • ストリームが追加された時、どんなことやってるか。 • SendAsync から追ってみる。 •
SendHeadersAsync が Http2stream のインスタンスを返している。 Stream Identifier
HTTP/2 の Stream 38 • new Http2Stream() してる箇所ではなく、 AddStream されているところで
stream id は渡されている。 Stream Identifier
HTTP/2 の Stream 39 • new Http2Stream() してる箇所ではなく、 AddStream されているところで
stream id は渡されている。 Stream Identifier
HTTP/2 の Stream 40 Stream Identifier 親切なコメントと共に +2 されてる。
HTTP/2 の Stream 41 Stream Identifier Stream id が 渡されている
親切なコメントと共に +2 されてる。
HTTP/2 の Stream 42 Stream Identifier _nextStream が max の時
Shutdown() される 親切なコメントと共に +2 されてる。 Stream id が 渡されている
HTTP/2 の Stream 43 Stream Identifier _nextStream が max の時
Shutdown() される Shutdown() 内部で _shutdown が true になる 親切なコメントと共に +2 されてる。 Stream id が 渡されている
HTTP/2 の Stream 44 Stream Identifier _nextStream が max の時
Shutdown() される Shutdown() 内部で _shutdown が true になる 例外が投げられる 親切なコメントと共に +2 されてる。 Stream id が 渡されている
HTTP/2 の Stream 45 Stream Identifier _nextStream が max の時
Shutdown() される Shutdown() 内部で _shutdown が true になる 例外が投げられる 親切なコメントと共に +2 されてる。 Stream id が 渡されている
HTTP/2 の Stream 46 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…?
HTTP/2 の Stream 47 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true)
HTTP/2 の Stream 48 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true) Http2Connection.SendAsync
HTTP/2 の Stream 49 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true) Http2Connection.SendAsync
HTTP/2 の Stream 50 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true) Http2Connection.SendAsync AddStream で投げた 例外を catch
HTTP/2 の Stream 51 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true) Http2Connection.SendAsync AddStream で投げた 例外を catch リトライの回数を 超えたら throw
HTTP/2 の Stream 52 • HttpConnectionPool (internal class) の SendWithVersionDetectionAndRetryAsync
メソッドに行きつく。 Stream Id が枯渇した時、Retry はどこで…? while(true) Http2Connection.SendAsync AddStream で投げた 例外を catch Eat exception (while true なので retry) リトライの回数を 超えたら throw
Frame Type 53
HTTP/2 のフレーム 54 • Length • ペイロードの長さ • 24 bit
確保されてるけど、SETTINGS_MAX_FRAME_SIZE を 設定しない限り 214 (=16,384) を超えてはいけない。 • Type • Payload がどんな種別かを示す。 • Flag • Frame Type にそれぞれ異なるフラグが定義されている。 • R • Reserved Bit。 使われてない。 • Stream Identifier • 31 bit の符号なし整数 全フレーム共通の固定長 header https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc7540#section-11.2
HTTP/2 のフレーム 55 • Length • ペイロードの長さ • 24 bit
確保されてるけど、SETTINGS_MAX_FRAME_SIZE を 設定しない限り 214 (=16,384) を超えてはいけない。 • Type • Payload がどんな種別かを示す。 • Flag • Frame Type にそれぞれ異なるフラグが定義されている。 • R • Reserved Bit。 使われてない。 • Stream Identifier • 31 bit の符号なし整数 全フレーム共通の固定長 header https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc7540#section-11.2
HTTP/2 のフレーム 56 • Length • ペイロードの長さ • 24 bit
確保されてるけど、SETTINGS_MAX_FRAME_SIZE を 設定しない限り 214 (=16,384) を超えてはいけない。 • Type • Payload がどんな種別かを示す。 • Flag • Frame Type にそれぞれ異なるフラグが定義されている。 • R • Reserved Bit。 使われてない。 • Stream Identifier • 31 bit の符号なし整数 全フレーム共通の固定長 header https://www.rfc-editor.org/rfc/rfc7540#section-4.1 https://www.rfc-editor.org/rfc/rfc7540#section-11.2 Type 一覧
HTTP/2 のフレーム 57 • POST 等で送るサーバに送るデータや、レスポンスのコンテンツは DATA Frame に詰め込まれる •
Flag • END_STREAM (0x1) • フレームがストリームの終端の場合に立つフラグ。 • PADDED (0x8) DATA Frame (0x0) https://www.rfc-editor.org/rfc/rfc9113#section-6.1
HTTP/2 のフレーム 58 • GET リクエストだとヘッダーフレームだけ飛ぶことが殆ど。 • Flag • END_STREAM
(0x1) • 後ろに CONTINUATION Frame 以外のフレーム (DATA Frame 等) が 続かない場合に立つフラグ。 • END_HEADERS(0x4) • ヘッダーが 1 フレームに収まる場合に立つフラグ。 • 収まらなかった場合 CONTINUATION フレームが後ろに続く。 • PADDED (0x8) • PRIORITY (0x20) HEADERS Frame (0x1) https://www.rfc-editor.org/rfc/rfc9113#section-6.2
HTTP/2 のフレーム 59 GET の(殆どの)場合 header type: HEADERS header type:
DATA payload server client payload Flag: END_STREAM END_HEADERS payload header type: HEADERS
HTTP/2 のフレーム 60 POST の(殆どの)場合 header type: DATA header type:
DATA payload server client payload payload header type: HEADERS header type: HEADERS payload Flag: END_HEADERS Flag: END_STREAM ・・・
HTTP/2 のフレーム 61 • サーバとクライアントそれぞれで最初に送信するフレーム。 • コネクションレベルの設定を行う。 • Flag •
ACK (0x1) • Identifier • SETTINGS_HEADER_TABLE_SIZE (0x1) • SETTINGS_ENABLE_PUSH (0x2) • SETTINGS_MAX_CONCURRENT_STREAMS (0x3) • SETTINGS_INITIAL_WINDOW_SIZE (0x4) • SETTINGS_MAX_FRAME_SIZE (0x5) • SETTINGS_MAX_HEADER_LIST_SIZE (0x6) SETTINGS Frame (0x4) https://www.rfc-editor.org/rfc/rfc9113#section-6.5
HTTP/2 のフレーム 62 • サーバとクライアントそれぞれで最初に送信するフレーム。 • コネクションレベルの設定を行う。 • Flag •
ACK (0x1) • Identifier • SETTINGS_HEADER_TABLE_SIZE (0x1) • SETTINGS_ENABLE_PUSH (0x2) • SETTINGS_MAX_CONCURRENT_STREAMS (0x3) • SETTINGS_INITIAL_WINDOW_SIZE (0x4) • SETTINGS_MAX_FRAME_SIZE (0x5) • SETTINGS_MAX_HEADER_LIST_SIZE (0x6) SETTINGS Frame (0x4) https://www.rfc-editor.org/rfc/rfc9113#section-6.5 flow control の設定
HTTP/2 のフレーム 63 • サーバとクライアントそれぞれで最初に送信するフレーム。 • コネクションレベルの設定を行う。 • Flag •
ACK (0x1) • Identifier • SETTINGS_HEADER_TABLE_SIZE (0x1) • SETTINGS_ENABLE_PUSH (0x2) • SETTINGS_MAX_CONCURRENT_STREAMS (0x3) • SETTINGS_INITIAL_WINDOW_SIZE (0x4) • SETTINGS_MAX_FRAME_SIZE (0x5) • SETTINGS_MAX_HEADER_LIST_SIZE (0x6) SETTINGS Frame (0x4) https://www.rfc-editor.org/rfc/rfc9113#section-6.5 どっちが先に送ってもOK flow control の設定
HTTP/2 のフレーム 64 • サーバとクライアントそれぞれで最初に送信するフレーム。 • コネクションレベルの設定を行う。 • Flag •
ACK (0x1) • Identifier • SETTINGS_HEADER_TABLE_SIZE (0x1) • SETTINGS_ENABLE_PUSH (0x2) • SETTINGS_MAX_CONCURRENT_STREAMS (0x3) • SETTINGS_INITIAL_WINDOW_SIZE (0x4) • SETTINGS_MAX_FRAME_SIZE (0x5) • SETTINGS_MAX_HEADER_LIST_SIZE (0x6) SETTINGS Frame (0x4) SETTINGS フレームを受信し 受信した側がその設定を反映できたら Length=0 (payload 無し), Flag= 0x1 で SETTINGS Frame を送る https://www.rfc-editor.org/rfc/rfc9113#section-6.5 どっちが先に送ってもOK flow control の設定
HTTP/2 のフレーム 65 • C# / BCL (client-side) で設定可能な値 •
SETTINGS_INITIAL_WINDOW_SIZE のみ。 SETTINGS Frame (0x4)
HTTP/2 のフレーム 66 • C# / ASP.NET Core (server-side) で設定可能な値
SETTINGS Frame (0x4)
HTTP/2 のフレーム 67 • C# / ASP.NET Core (server-side) で設定可能な値
SETTINGS Frame (0x4) これに注目
HTTP/2 のフレーム 68 • 1つの Connection で幾つストリームを同時に実行できるかの設定。 • ブラウザの場合… •
HTTP/1.x • TCP を 1 本以上接続して、TCP のコネクション分同時にリクエスト • コネクション数以上のリクエストは1度キューに入って順次実行 • HTTP/2 • TCP を 1 本接続して、SETTINGS_MAX_CONCURRENT_STREAMS で設定された数だけ 同時にリクエスト • SETTINGS_MAX_CONCURRENT_STREAMS 以上のリクエストが必要な場合は、 一度キューに入って順次実行。 SETTINGS_MAX_CONCURRENT_STREAMS https://www.rfc-editor.org/rfc/rfc9113#section-6.5.2
HTTP/2 のフレーム 69 • 1つの Connection で幾つストリームを同時に実行できるかの設定。 • ブラウザの場合… •
HTTP/1.x • TCP を 1 本以上接続して、TCP のコネクション分同時にリクエスト • コネクション数以上のリクエストは1度キューに入って順次実行 • HTTP/2 • TCP を 1 本接続して、SETTINGS_MAX_CONCURRENT_STREAMS で設定された数だけ 同時にリクエスト • SETTINGS_MAX_CONCURRENT_STREAMS 以上のリクエストが必要な場合は、 一度キューに入って順次実行。 SETTINGS_MAX_CONCURRENT_STREAMS https://www.rfc-editor.org/rfc/rfc9113#section-6.5.2 殆どのブラウザは同一オリジンに対して TCP の接続を同時に 6 本開く
HTTP/2 のフレーム 70 • 1つの Connection で幾つストリームを同時に実行できるかの設定。 • ブラウザの場合… •
HTTP/1.x • TCP を 1 本以上接続して、TCP のコネクション分同時にリクエスト • コネクション数以上のリクエストは1度キューに入って順次実行 • HTTP/2 • TCP を 1 本接続して、SETTINGS_MAX_CONCURRENT_STREAMS で設定された数だけ 同時にリクエスト • SETTINGS_MAX_CONCURRENT_STREAMS 以上のリクエストが必要な場合は、 一度キューに入って順次実行。 SETTINGS_MAX_CONCURRENT_STREAMS https://www.rfc-editor.org/rfc/rfc9113#section-6.5.2 殆どのブラウザは同一オリジンに対して TCP の接続を同時に 6 本開く 100 か 128 が殆ど
HTTP/2 のフレーム 71 • 1つの Connection で幾つストリームを同時に実行できるかの設定。 • ブラウザの場合… •
HTTP/1.x • TCP を 1 本以上接続して、TCP のコネクション分同時にリクエスト • コネクション数以上のリクエストは1度キューに入って順次実行 • HTTP/2 • TCP を 1 本接続して、SETTINGS_MAX_CONCURRENT_STREAMS で設定された数だけ 同時にリクエスト • SETTINGS_MAX_CONCURRENT_STREAMS 以上のリクエストが必要な場合は、 一度キューに入って順次実行。 SETTINGS_MAX_CONCURRENT_STREAMS https://www.rfc-editor.org/rfc/rfc9113#section-6.5.2 HTTP/1.x に比べて圧倒的改善 殆どのブラウザは同一オリジンに対して TCP の接続を同時に 6 本開く 100 か 128 が殆ど
HTTP/2 のフレーム 72 Micro service 間は?
HTTP/2 のフレーム 73 • Micro service 間通信の場合… • SETTINGS_MAX_CONCURRENT_STREAMS はデフォルトで
100 とか 128 が多い。 • Micro service 間通信で 100 リクエスト以上同時に実行する事は普通。 • TCP 1本で接続して、同時に開くストリーム数が SETTINGS_MAX_CONCURRENT_STREAMS で設定されている数を超えた場合、 キューに積まれて待機させられる。 SETTINGS_MAX_CONCURRENT_STREAMS https://www.rfc-editor.org/rfc/rfc9113#section-6.5
HTTP/2 のフレーム 74 • Micro service 間通信の場合… • SETTINGS_MAX_CONCURRENT_STREAMS はデフォルトで
100 とか 128 が多い。 • Micro service 間通信で 100 リクエスト以上同時に実行する事は普通。 • TCP 1本で接続して、同時に開くストリーム数が SETTINGS_MAX_CONCURRENT_STREAMS で設定されている数を超えた場合、 キューに積まれて待機させられる。 SETTINGS_MAX_CONCURRENT_STREAMS つまり、ボトルネックになってしまう https://www.rfc-editor.org/rfc/rfc9113#section-6.5
HTTP/2 のフレーム 75 • Micro service 間通信の場合… • SETTINGS_MAX_CONCURRENT_STREAMS はデフォルトで
100 とか 128 が多い。 • Micro service 間通信で 100 リクエスト以上同時に実行する事は普通。 • TCP 1本で接続して、同時に開くストリーム数が SETTINGS_MAX_CONCURRENT_STREAMS で設定されている数を超えた場合、 キューに積まれて待機させられる。 SETTINGS_MAX_CONCURRENT_STREAMS つまり、ボトルネックになってしまう 当然、解決策は用意されている。 https://www.rfc-editor.org/rfc/rfc9113#section-6.5
HTTP/2 のフレーム 76 • EnableMultipleHttp2Connections • 同時に開いている stream が SETTINGS_MAX_CONCURRENT_STREAMS
に 達した場合、新しい HTTP/2 connection が作成される。 SETTINGS_MAX_CONCURRENT_STREAMS https://github.com/dotnet/runtime/issues/35088 https://github.com/dotnet/runtime/pull/39439
HTTP/2 のフレーム 77 • Micro service 間の通信で HTTP/2 を使う場合、gRPC が殆ど。
• GrpcChannel に HttpHandler を設定しないといけない? • 不要。 SETTINGS_MAX_CONCURRENT_STREAMS
HTTP/2 のフレーム 78 • Micro service 間の通信で HTTP/2 を使う場合、gRPC が殆ど。
• GrpcChannel に HttpHandler を設定しないといけない? • 不要。 SETTINGS_MAX_CONCURRENT_STREAMS この構成のためだけに handler を new して option として渡す必要はない
HTTP/2 のフレーム 79 • grpc-dotnet 内部で EnableMultipleHttp2Connections を true にしてくれている。
• ForAddress だけで問題なし SETTINGS_MAX_CONCURRENT_STREAMS https://github.com/grpc/grpc-dotnet/blob/v2.52.x/src/Shared/HttpHandlerFactory.cs
HTTP/2 のフレーム 80 • grpc-dotnet 内部で EnableMultipleHttp2Connections を true にしてくれている。
• ForAddress だけで問題なし SETTINGS_MAX_CONCURRENT_STREAMS https://github.com/grpc/grpc-dotnet/blob/v2.52.x/src/Shared/HttpHandlerFactory.cs
HTTP/2 のフレーム 81 • その名の通り疎通確認するためのフレーム。 • クライアントからでもサーバからでも飛ばしてOK • PING Frame
が送られたら優先度高く PING Frame を送り返す必要がある。 • Flag • ACK (0x1) • 応答の PING Frame には ACK フラグが立つ。 PING Frame (0x6) https://www.rfc-editor.org/rfc/rfc9113#section-6.7
HTTP/2 のフレーム 82 • Q : HTTP のレイヤーに必要? • A
: 必要。 • 特に gRPC で streaming を使っている場合、必須。 PING Frame (0x6) https://www.rfc-editor.org/rfc/rfc9113#section-6.7 server client Firewall, Load Balancer, etc.
HTTP/2 のフレーム 83 • Q : HTTP のレイヤーに必要? • A
: 必要。 • 特に gRPC で streaming を使っている場合、必須。 PING Frame (0x6) https://www.rfc-editor.org/rfc/rfc9113#section-6.7 server client Firewall, Load Balancer, etc. 一定時間何もデータが 流れてこなかったらコネクションを 切断してしまう
HTTP/2 のフレーム 84 • Q : HTTP のレイヤーに必要? • A
: 必要。 • 特に gRPC で streaming を使っている場合、必須。 PING Frame (0x6) https://www.rfc-editor.org/rfc/rfc9113#section-6.7 server client Firewall, Load Balancer, etc. 一定時間何もデータが 流れてこなかったらコネクションを 切断してしまう 結果、streaming でいざデータを 流そうとした時に失敗する
HTTP/2 のフレーム 85 • Q : HTTP のレイヤーに必要? • A
: 必要。 • 特に gRPC で streaming を使っている場合、必須。 PING Frame (0x6) https://www.rfc-editor.org/rfc/rfc9113#section-6.7 server client Firewall, Load Balancer, etc. 一定時間何もデータが 流れてこなかったらコネクションを 切断してしまう 結果、streaming でいざデータを 流そうとした時に失敗する PING フレームで 接続を監視しつつ維持
HTTP/2 のフレーム 86 • C# / BCL (client-side) で設定可能な値 •
KeepAlivePingPolicy • Always: 常に一定間隔で PING フレームを飛ばす • WithActiveRequests : 開いてるストリームがある場合のみ PING フレームを飛ばす • gRPC で streaming 使ってる場合のみ PING 飛ばしたかったらこっち。 PING Frame (0x6) https://github.com/dotnet/runtime/issues/31198 https://github.com/dotnet/runtime/pull/40257
HTTP/2 のフレーム 87 • C# / ASP.NET Core (server-side) で設定可能な値
• client-side と違って、設定したら http2 connection 内に 有効な stream が無くても問答無用で PING Frame が送られる。 • KeepAlivePingPolicy のような気の利いたオプションは無い。(現時点では) PING Frame (0x6)
Application-Layer Protocol Negotiation 88
Application-Layer Protocol Negotiation 89 • まずは単語の定義から https://www.rfc-editor.org/rfc/rfc7540#section-11.1
Application-Layer Protocol Negotiation 90 • h2の場合、HTTP/1.x と HTTP/2 を 1つのポートで
listen する事ができる。 • h2c の場合、HTTP/1.x とHTTP/2 を それぞれ別の port で listen する必要がある。 • h2c を用いる場合は、server-side に以下のような設定を行う必要がある。 appsettings.json 等に記述 C# で直接記述 h2 か h2c かで port 事情が変わってくる
Application-Layer Protocol Negotiation 91 https://www.rfc-editor.org/rfc/rfc7301 なぜこのような違いが? • アプリケーション層のプロトコルの選択 (HTTP/1.x か
HTTP/2 か) を TLS のレイヤで行っているから、h2 は 1 つの port で OK. • Application-Layer Protocol Negotiation (ALPN) のお仕事。 • TLS の仕事は暗号化だけではないのです…。 • h2c はアプリケーション層のプロトコルの選択ができないので port を分ける他ない。
Application-Layer Protocol Negotiation 92 https://www.rfc-editor.org/rfc/rfc7301 ALPN の流れを非常にざっくり解説すると… • TLS の処理の流れの一部は以下のような事を行う。
• ①TLS では、client は ClientHello で自分が扱える暗号化方式等の リストを server に渡す • ②server は ServerHello で実際の接続で利用する暗号化方式等を client に 渡す • ClientHello / ServerHelloに 暗号化方式等だけでなく、 アプリケーション層の プロトコル選択も含ませたのが ALPN。
Application-Layer Protocol Negotiation 93 ちょっと待てよ?
Application-Layer Protocol Negotiation 94 https://www.rfc-editor.org/rfc/rfc7301 世のホスティングサービスは app の前段で TLS 終端するよな…?
• Azure App Service / Cloud Run etc. • エンドユーザからのリクエストは https • Load balancer とかで TLS 終端 • App が動いてる VM / Container に届くリクエストは http (not https) client Load Balancer etc. https app http
Application-Layer Protocol Negotiation 95 https://www.rfc-editor.org/rfc/rfc7301 世のホスティングサービスは app の前段で TLS 終端するよな…?
• Azure App Service / Cloud Run etc. • エンドユーザからのリクエストは https • Load balancer とかで TLS 終端 • App が動いてる VM / Container に届くリクエストは http (not https) client Load Balancer etc. TLS 終端 https app http
Application-Layer Protocol Negotiation 96 https://www.rfc-editor.org/rfc/rfc7301 世のホスティングサービスは app の前段で TLS 終端するよな…?
• Azure App Service / Cloud Run etc. • エンドユーザからのリクエストは https • Load balancer とかで TLS 終端 • App が動いてる VM / Container に届くリクエストは http (not https) client Load Balancer etc. TLS 終端 https ALPN が使える app http
Application-Layer Protocol Negotiation 97 https://www.rfc-editor.org/rfc/rfc7301 世のホスティングサービスは app の前段で TLS 終端するよな…?
• Azure App Service / Cloud Run etc. • エンドユーザからのリクエストは https • Load balancer とかで TLS 終端 • App が動いてる VM / Container に届くリクエストは http (not https) client Load Balancer etc. TLS 終端 https ALPN が使える ALPN が使えない…! app http
Application-Layer Protocol Negotiation 98 HTTP/2 使えないのか…?
Application-Layer Protocol Negotiation 99 そんな事はない
Application-Layer Protocol Negotiation 100 https://azure.microsoft.com/en-us/updates/public-preview-grpc-support-in-azure-app-service/ Azure App Service は割とつい最近 gRPC
が public preview に • 2022/09/14 の記事 • ただし Linux のみ。
Application-Layer Protocol Negotiation 101 https://github.com/dotnet/aspnetcore/issues/9020 Azure App Service は割とつい最近 gRPC
が public preview に • 今まで何で出来なかったのか? • 2019/04 から ASP.NET Core にある issue (~2022/08) • IIS / HTTP.Sys がうんぬんかんぬん。 • 詳しくは極めて長いこの issue を読んでください…
Application-Layer Protocol Negotiation 102 https://github.com/microsoft/reverse-proxy https://www.infoq.com/news/2022/01/microsoft-releases-yarp/ https://techcommunity.microsoft.com/t5/apps-on-azure-blog/a-heavy-lift-bringing-kestrel-yarp-to-azure-app-services/ba-p/3607417 どうして出来るようになった? • IIS
が YARP に完全に置き換わった • 2022/08/24 の記事 YARP : C# で実装された 新しいリバースプロキシ (kestrel ベース)
Application-Layer Protocol Negotiation 103 https://github.com/microsoft/reverse-proxy https://www.infoq.com/news/2022/01/microsoft-releases-yarp/ https://techcommunity.microsoft.com/t5/apps-on-azure-blog/a-heavy-lift-bringing-kestrel-yarp-to-azure-app-services/ba-p/3607417 どうして出来るようになった? • IIS
が YARP に完全に置き換わった • App Service Worker が Linux だろうと、その前端に IIS が今まではいた。
Application-Layer Protocol Negotiation 104 https://github.com/microsoft/reverse-proxy https://www.infoq.com/news/2022/01/microsoft-releases-yarp/ https://techcommunity.microsoft.com/t5/apps-on-azure-blog/a-heavy-lift-bringing-kestrel-yarp-to-azure-app-services/ba-p/3607417 どうして出来るようになった? • IIS
が YARP に完全に置き換わった • App Service Worker が Linux だろうと、その前端に IIS が今まではいた。 我々の app が 動いている VM
Application-Layer Protocol Negotiation 105 https://github.com/microsoft/reverse-proxy https://www.infoq.com/news/2022/01/microsoft-releases-yarp/ https://techcommunity.microsoft.com/t5/apps-on-azure-blog/a-heavy-lift-bringing-kestrel-yarp-to-azure-app-services/ba-p/3607417 どうして出来るようになった? • IIS
が YARP に完全に置き換わった • App Service Worker が Linux だろうと、その前端に IIS が今まではいた。 FrontEndRole が IIS から YARP に 我々の app が 動いている VM
Application-Layer Protocol Negotiation 106 https://github.com/microsoft/reverse-proxy https://www.infoq.com/news/2022/01/microsoft-releases-yarp/ https://techcommunity.microsoft.com/t5/apps-on-azure-blog/a-heavy-lift-bringing-kestrel-yarp-to-azure-app-services/ba-p/3607417 どうして出来るようになった? • IIS
が YARP に完全に置き換わった • App Service Worker が Linux だろうと、その前端に IIS が今まではいた。 FrontEndRole が IIS から YARP に この子が TLS 終端も担っている 我々の app が 動いている VM
Application-Layer Protocol Negotiation 107 https://www.rfc-editor.org/rfc/rfc7301 結果的に以下のようになったので end-to-end で HTTP/2 が使えるように。
client YARP TLS 終端 https ALPN が使える app Port 8080 Port 9999
Application-Layer Protocol Negotiation 108 https://www.rfc-editor.org/rfc/rfc7301 結果的に以下のようになったので end-to-end で HTTP/2 が使えるように。
client YARP TLS 終端 https ALPN が使える ALPN が使えない…! だけど別々の port に リバプロで捌けば 問題なし! app Port 8080 Port 9999
Application-Layer Protocol Negotiation 109 https://github.com/dotnet/aspnetcore/issues/9020#issuecomment-566172172 https://cloud.google.com/run/docs/configuring/http2 Azure App Service、昔から HTTP/2
サポートしてなかったけ? • 実は end-to-end で HTTP/2 が使えていたわけではない。 • クライアントからのリクエストは HTTP/2 でも… • App の VM に届く前のタイミングで HTTP/1.1 に downgrade されていた。 • これだと gRPC は使えない。 • Cloud Run も既定はこのスタイル。 client IIS https HTTP/1.1 に downgrade! app http HTTP/1.x or HTTP/2
まとめ 110 • HttpClient / HttpMessageInvoker / SocketsHttpHandler • 何か設定したくなったら
SocketsHttpHandler を確認! • Stream / stream identifier • stream id の枯渇とかは気にしないで OK. • Frame type • DATA Frame / HEADERS Frame • SETTINGS Frame / PING Frame • HTTP/2 特有の connection の設定/維持/監視などのお話 • C# (BCL, ASP.NET Core, grpc-dotnet) で気を付けるポイントを紹介 • Application-Layer Protocol Negotiation • h2c (= w/o TLS) の場合に何故 port を分けないといけないのか • Azure App Service が gRPC をサポートしたが、その裏がどうなっているのか HTTP/3 の仕様は RFC 9114 で確定済だが HTTP/2 はこれからも利用される & 実用上 HTTP/2 に対する 深い理解は必須…! https://www.rfc-editor.org/rfc/rfc9114.html