$30 off During Our Annual Pro Sale. View Details »

C# と HTTP/2 と gRPC

neno
March 25, 2023

C# と HTTP/2 と gRPC

.NET ラボ 2023/03/25 での発表資料

ブログ :
- C# と HTTP/2 と gRPC
- HTTP/2 と gRPC に対するよくある誤解。

neno

March 25, 2023
Tweet

More Decks by neno

Other Decks in Technology

Transcript

  1. C# と HTTP/2 と gRPC
    .NET ラボ 2023/03/25
    何縫ねの。

    View Slide

  2. 自己紹介
    1
    • 所属: NTTコミュニケーションズ
    イノベーションセンター
    • 趣味: C#, OSS, ドール, 一眼(α7 IV)
    • 執心領域
    • C# ⇔ TypeScript
    • SignalR
    何縫ねの。
    nenoNaninu
    nenoMake
    ブログ https://blog.neno.dev
    その他 https://neno.dev

    View Slide

  3. OSS 紹介
    2
    属性を付与するだけ
    Tapper
    • C# の型定義から TypeScript の型定義を生成する .NET Tool/ library
    • JSON / MessagePack 対応!
    https://github.com/nenoNaninu/Tapper

    View Slide

  4. OSS 紹介
    3
    • C# の SignalR Client を強く型付けするための Source Generator
    TypedSignalR.Client
    Before
    After (using TypedSignalR.Client)
    こんな SignalR の
    Hub と Receiver の interface が
    あったとして…
    脱文字列!
    全てが強く型付け!
    https://github.com/nenoNaninu/TypedSignalR.Client

    View Slide

  5. 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 紹介

    View Slide

  6. 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

    View Slide

  7. 今回の講演の注意事項!
    6
    • 細かいコードがしばしば出てきますが、登壇後にこのスライドを
    アップするので気になる方は是非、という趣旨で載せています。
    • 講演中は、細かいコードについては「ふ~ん」と雰囲気を
    つかめれば OK くらいの感覚で喋っています。

    View Slide

  8. HTTP/2 の基本
    7

    View Slide

  9. の前に HttpClient の基本
    8

    View Slide

  10. HttpClient の基本
    9
    • HttpClient のコンストラクタ
    意識するべき登場人物たち

    View Slide

  11. HttpClient の基本
    10
    • HttpClient のコンストラクタ
    意識するべき登場人物たち

    View Slide

  12. HttpClient の基本
    11
    • HttpClient のコンストラクタ
    意識するべき登場人物たち
    HttpMessageHandler は
    シンプルな abstract class

    View Slide

  13. HttpClient の基本
    12
    意識するべき登場人物たち
    • HttpClientHandler の中身

    View Slide

  14. HttpClient の基本
    13
    意識するべき登場人物たち
    • HttpClientHandler の中身

    View Slide

  15. HttpClient の基本
    14
    意識するべき登場人物たち
    • HttpClientHandler の中身
    SocketsHttpHandler
    この子が大事

    View Slide

  16. HttpClient の基本
    15
    HttpMessageHandler
    を継承している
    意識するべき登場人物たち
    • HttpClientHandler の中身
    SocketsHttpHandler
    この子が大事

    View Slide

  17. HttpClient の基本
    16
    意識するべき登場人物たち
    SocketsHttpHandler
    に対して HTTP/2 の
    設定とかを行う

    View Slide

  18. HttpClient の基本
    17
    • HttpClient のベースクラスに注目。
    意識するべき登場人物たち

    View Slide

  19. HttpClient の基本
    18
    • HttpClient のベースクラスに注目。
    意識するべき登場人物たち

    View Slide

  20. HttpClient の基本
    19
    意識するべき登場人物たち
    SendAsync しか使わないなら
    HttpMessageInvoker で十分

    View Slide

  21. HttpClient の基本
    20
    意識するべき登場人物たち
    SendAsync しか使わないなら
    HttpMessageInvoker で十分
    実際、GrpcChannel の
    既定の構成では
    HttpClient ではなく、
    HttpMessageInvoker が
    用いられる

    View Slide

  22. HTTP/2 の基本
    21

    View Slide

  23. HTTP/2 の基本
    22
    • 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

    View Slide

  24. 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

    View Slide

  25. 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
    注) このスライド中には
    分かりやすさのため、
    RFC 7540 から図を引用
    してる場合があります。

    View Slide

  26. TCP
    TCP
    TCP
    HTTP/2 の基本
    25
    • 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

    View Slide

  27. HTTP/2 の基本
    26
    • 当然、フレーミング。
    • 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

    View Slide

  28. HTTP/2 の基本
    27
    • 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

    View Slide

  29. 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

    View Slide

  30. Stream
    29

    View Slide

  31. HTTP/2 の Stream
    30
    • ストリームとは…
    • それぞれ独立している
    • 双方向なフレームの 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

    View Slide

  32. HTTP/2 の Stream
    31
    • Http2Stream という class が内部的には存在する。
    • が、Http2Connection という internal class に含まれる private class なので触る事はできない。
    • 普通に HTTP/2 を使う上では全く気にしなくていいところなので当然といえば当然。
    C# 的には?

    View Slide

  33. HTTP/2 の Stream
    32
    • 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

    View Slide

  34. HTTP/2 の Stream
    33
    Stream Identifier
    31 bit 分枯渇したらどうなる??

    View Slide

  35. HTTP/2 の Stream
    34
    • Http2Connection (internal class) のコンストラクタを眺める。
    • 標準ライブラリに含まれる実装。つまり client 側。
    • _nextStream = 1 で奇数。
    Stream Identifier

    View Slide

  36. HTTP/2 の Stream
    35
    • ストリームが追加された時、どんなことやってるか。
    • SendAsync から追ってみる。
    • SendHeadersAsync が Http2stream のインスタンスを返している。
    Stream Identifier

    View Slide

  37. HTTP/2 の Stream
    36
    • ストリームが追加された時、どんなことやってるか。
    • SendAsync から追ってみる。
    • SendHeadersAsync が Http2stream のインスタンスを返している。
    Stream Identifier

    View Slide

  38. HTTP/2 の Stream
    37
    • new Http2Stream() してる箇所ではなく、
    AddStream されているところで stream id は渡されている。
    Stream Identifier

    View Slide

  39. HTTP/2 の Stream
    38
    • new Http2Stream() してる箇所ではなく、
    AddStream されているところで stream id は渡されている。
    Stream Identifier

    View Slide

  40. HTTP/2 の Stream
    39
    Stream Identifier
    親切なコメントと共に +2
    されてる。

    View Slide

  41. HTTP/2 の Stream
    40
    Stream Identifier
    Stream id が
    渡されている
    親切なコメントと共に +2
    されてる。

    View Slide

  42. HTTP/2 の Stream
    41
    Stream Identifier _nextStream が max の時
    Shutdown() される
    親切なコメントと共に +2
    されてる。
    Stream id が
    渡されている

    View Slide

  43. HTTP/2 の Stream
    42
    Stream Identifier _nextStream が max の時
    Shutdown() される
    Shutdown() 内部で
    _shutdown が true になる
    親切なコメントと共に +2
    されてる。
    Stream id が
    渡されている

    View Slide

  44. HTTP/2 の Stream
    43
    Stream Identifier _nextStream が max の時
    Shutdown() される
    Shutdown() 内部で
    _shutdown が true になる
    例外が投げられる
    親切なコメントと共に +2
    されてる。
    Stream id が
    渡されている

    View Slide

  45. HTTP/2 の Stream
    44
    Stream Identifier _nextStream が max の時
    Shutdown() される
    Shutdown() 内部で
    _shutdown が true になる
    例外が投げられる
    親切なコメントと共に +2
    されてる。
    Stream id が
    渡されている

    View Slide

  46. HTTP/2 の Stream
    45
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?

    View Slide

  47. HTTP/2 の Stream
    46
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)

    View Slide

  48. HTTP/2 の Stream
    47
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)
    Http2Connection.SendAsync

    View Slide

  49. HTTP/2 の Stream
    48
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)
    Http2Connection.SendAsync

    View Slide

  50. HTTP/2 の Stream
    49
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)
    Http2Connection.SendAsync
    AddStream で投げた
    例外を catch

    View Slide

  51. HTTP/2 の Stream
    50
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)
    Http2Connection.SendAsync
    AddStream で投げた
    例外を catch
    リトライの回数を
    超えたら throw

    View Slide

  52. HTTP/2 の Stream
    51
    • HttpConnectionPool (internal class) の
    SendWithVersionDetectionAndRetryAsync メソッドに行きつく。
    Stream Id が枯渇した時、Retry はどこで…?
    while(true)
    Http2Connection.SendAsync
    AddStream で投げた
    例外を catch
    Eat exception
    (while true なので retry)
    リトライの回数を
    超えたら throw

    View Slide

  53. Frame Type
    52

    View Slide

  54. HTTP/2 のフレーム
    53
    • 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

    View Slide

  55. 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

    View Slide

  56. 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
    Type 一覧

    View Slide

  57. HTTP/2 のフレーム
    56
    • POST 等で送るサーバに送るデータや、レスポンスのコンテンツは
    DATA Frame に詰め込まれる
    • Flag
    • END_STREAM (0x1)
    • フレームがストリームの終端の場合に立つフラグ。
    • PADDED (0x8)
    DATA Frame (0x0)
    https://www.rfc-editor.org/rfc/rfc9113#section-6.1

    View Slide

  58. HTTP/2 のフレーム
    57
    • 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

    View Slide

  59. HTTP/2 のフレーム
    58
    GET の(殆どの)場合
    header
    type: HEADERS
    header
    type: DATA
    payload
    server
    client
    payload
    Flag: END_STREAM
    END_HEADERS
    payload
    header
    type: HEADERS

    View Slide

  60. HTTP/2 のフレーム
    59
    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
    ・・・

    View Slide

  61. HTTP/2 のフレーム
    60
    • サーバとクライアントそれぞれで最初に送信するフレーム。
    • コネクションレベルの設定を行う。
    • 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

    View Slide

  62. 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
    flow control
    の設定

    View Slide

  63. 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
    どっちが先に送ってもOK
    flow control
    の設定

    View Slide

  64. 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)
    SETTINGS フレームを受信し
    受信した側がその設定を反映できたら
    Length=0 (payload 無し), Flag= 0x1 で SETTINGS Frame を送る
    https://www.rfc-editor.org/rfc/rfc9113#section-6.5
    どっちが先に送ってもOK
    flow control
    の設定

    View Slide

  65. HTTP/2 のフレーム
    64
    • C# / Standard library (client-side) で設定可能な値
    • SETTINGS_INITIAL_WINDOW_SIZE のみ。
    SETTINGS Frame (0x4)

    View Slide

  66. HTTP/2 のフレーム
    65
    • C# / ASP.NET Core (server-side) で設定可能な値
    SETTINGS Frame (0x4)

    View Slide

  67. HTTP/2 のフレーム
    66
    • C# / ASP.NET Core (server-side) で設定可能な値
    SETTINGS Frame (0x4)
    これに注目

    View Slide

  68. HTTP/2 のフレーム
    67
    • 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

    View Slide

  69. 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
    殆どのブラウザは同一オリジンに対して
    TCP の接続を同時に 6 本開く

    View Slide

  70. 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 本開く
    100 か 128 が殆ど

    View Slide

  71. 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
    HTTP/1.x に比べて圧倒的改善
    殆どのブラウザは同一オリジンに対して
    TCP の接続を同時に 6 本開く
    100 か 128 が殆ど

    View Slide

  72. HTTP/2 のフレーム
    71
    Micro service 間は?

    View Slide

  73. HTTP/2 のフレーム
    72
    • 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

    View Slide

  74. 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

    View Slide

  75. 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

    View Slide

  76. HTTP/2 のフレーム
    75
    • 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

    View Slide

  77. HTTP/2 のフレーム
    76
    • Micro service 間の通信で HTTP/2 を使う場合、gRPC が殆ど。
    • GrpcChannel に HttpHandler を設定しないといけない?
    • 不要。
    SETTINGS_MAX_CONCURRENT_STREAMS
    この構成のためだけに
    handler を new して
    option として渡す必要はない

    View Slide

  78. HTTP/2 のフレーム
    77
    • grpc-dotnet 内部で EnableMultipleHttp2Connections を
    true にしてくれている。
    • ForAddress だけで問題なし
    SETTINGS_MAX_CONCURRENT_STREAMS
    https://github.com/grpc/grpc-dotnet/blob/v2.52.x/src/Shared/HttpHandlerFactory.cs

    View Slide

  79. HTTP/2 のフレーム
    78
    • その名の通り疎通確認するためのフレーム。
    • クライアントからでもサーバからでも飛ばしてOK
    • PING Frame が送られたら優先度高く PING Frame を送り返す必要がある。
    • Flag
    • ACK (0x1)
    • 応答の PING Frame には ACK フラグが立つ。
    PING Frame (0x6)
    https://www.rfc-editor.org/rfc/rfc9113#section-6.7

    View Slide

  80. HTTP/2 のフレーム
    79
    • Q : HTTP のレイヤーに必要?
    • A : 必要。
    • 特に gRPC で streaming を使っている場合、必須。
    PING Frame (0x6)
    https://www.rfc-editor.org/rfc/rfc9113#section-6.7
    server
    client
    Firewall,
    Load Balancer,
    etc.

    View Slide

  81. HTTP/2 のフレーム
    80
    • Q : HTTP のレイヤーに必要?
    • A : 必要。
    • 特に gRPC で streaming を使っている場合、必須。
    PING Frame (0x6)
    https://www.rfc-editor.org/rfc/rfc9113#section-6.7
    server
    client
    Firewall,
    Load Balancer,
    etc.
    一定時間何もデータが
    流れてこなかったらコネクションを
    切断してしまう

    View Slide

  82. HTTP/2 のフレーム
    81
    • 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 でいざデータを
    流そうとした時に失敗する

    View Slide

  83. 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.
    一定時間何もデータが
    流れてこなかったらコネクションを
    切断してしまう
    結果、streaming でいざデータを
    流そうとした時に失敗する
    PING フレームで
    接続を監視しつつ維持

    View Slide

  84. HTTP/2 のフレーム
    83
    • C# / Standard library (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

    View Slide

  85. HTTP/2 のフレーム
    84
    • C# / ASP.NET Core (server-side) で設定可能な値
    • client-side と違って、設定したら http2 connection 内に
    有効な stream が無くても問答無用で PING Frame が送られる。
    • KeepAlivePingPolicy のような気の利いたオプションは無い。(現時点では)
    PING Frame (0x6)

    View Slide

  86. Application-Layer
    Protocol Negotiation
    85

    View Slide

  87. Application-Layer Protocol Negotiation
    86
    • まずは単語の定義から
    https://www.rfc-editor.org/rfc/rfc7540#section-11.1

    View Slide

  88. Application-Layer Protocol Negotiation
    87
    • 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 事情が変わってくる

    View Slide

  89. Application-Layer Protocol Negotiation
    88
    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 を分ける他ない。

    View Slide

  90. Application-Layer Protocol Negotiation
    89
    https://www.rfc-editor.org/rfc/rfc7301
    ALPN の流れを非常にざっくり解説すると…
    • TLS の処理の流れの一部は以下のような事を行う。
    • ①TLS では、client は ClientHello で自分が扱える暗号化方式等の
    リストを server に渡す
    • ②server は ServerHello で実際の接続で利用する暗号化方式等を client に
    渡す
    • ClientHello / ServerHelloに
    暗号化方式等だけでなく、
    アプリケーション層の
    プロトコル選択も含ませたのが
    ALPN。

    View Slide

  91. Application-Layer Protocol Negotiation
    90
    ちょっと待てよ?

    View Slide

  92. Application-Layer Protocol Negotiation
    91
    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

    View Slide

  93. Application-Layer Protocol Negotiation
    92
    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

    View Slide

  94. Application-Layer Protocol Negotiation
    93
    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

    View Slide

  95. 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.
    TLS 終端
    https
    ALPN が使える ALPN が使えない…!
    app
    http

    View Slide

  96. Application-Layer Protocol Negotiation
    95
    HTTP/2 使えないのか…?

    View Slide

  97. Application-Layer Protocol Negotiation
    96
    そんな事はない

    View Slide

  98. Application-Layer Protocol Negotiation
    97
    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 のみ。

    View Slide

  99. Application-Layer Protocol Negotiation
    98
    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 を読んでください…

    View Slide

  100. Application-Layer Protocol Negotiation
    99
    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 ベース)

    View Slide

  101. Application-Layer Protocol Negotiation
    100
    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 が今まではいた。

    View Slide

  102. Application-Layer Protocol Negotiation
    101
    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

    View Slide

  103. 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 に完全に置き換わった
    • App Service Worker が Linux だろうと、その前端に IIS が今まではいた。
    FrontEndRole が IIS から YARP に
    我々の app が
    動いている VM

    View Slide

  104. 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 が今まではいた。
    FrontEndRole が IIS から YARP に
    この子が
    TLS 終端も担っている
    我々の app が
    動いている VM

    View Slide

  105. Application-Layer Protocol Negotiation
    104
    https://www.rfc-editor.org/rfc/rfc7301
    結果的に以下のようになったので end-to-end で
    HTTP/2 が使えるように。
    client YARP
    TLS 終端
    https
    ALPN が使える
    app
    Port 8080
    Port 9999

    View Slide

  106. Application-Layer Protocol Negotiation
    105
    https://www.rfc-editor.org/rfc/rfc7301
    結果的に以下のようになったので end-to-end で
    HTTP/2 が使えるように。
    client YARP
    TLS 終端
    https
    ALPN が使える
    ALPN が使えない…!
    だけど別々の port に
    リバプロで捌けば 問題なし!
    app
    Port 8080
    Port 9999

    View Slide

  107. Application-Layer Protocol Negotiation
    106
    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

    View Slide

  108. まとめ
    107
    • HttpClient / HttpMessageInvoker / SocketsHttpHandler
    • 何か設定したくなったら SocketsHttpHandler を確認!
    • Stream / stream identifier
    • stream id の枯渇とかは気にしないで OK.
    • Frame type
    • DATA Frame / HEADERS Frame
    • SETTINGS Frame / PING Frame
    • HTTP/2 特有の connection の設定/維持/監視などのお話
    • C# (standard lib, 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 を知らないと HTTP/3 も
    理解できないので頭に片隅に
    https://www.rfc-editor.org/rfc/rfc9114.html

    View Slide