Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Streams APIとTCPフロー制御 / Web Streams API and TCP ...
Search
tasshi
October 31, 2024
Programming
2
370
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
Nihonbashi.js #9 のLT資料です。
イベント情報はこちら↓
https://nihonbashi-js.connpass.com/event/332328/
tasshi
October 31, 2024
Tweet
Share
More Decks by tasshi
See All by tasshi
GitHub Projectsを自動化するGitHub CLIテクニック / Automate GitHub Projects with GitHub CLI
tasshi
0
440
SDK開発チームのプロダクトオーナーが考えていること / Product management of SDK
tasshi
1
1.1k
Node.js製CLIツールのE2Eテストに取り組んでいます / Working on E2E testing of Node.js CLI tools
tasshi
0
1k
モダンな開発環境を用いた カンタン/安全なカスタマイズ開発 / kintone devCamp Boost! 2023
tasshi
0
660
Node Streamでメモリ性能改善、そしてWeb Streams APIへ / Improving memory performance of the CLI tool using Node Stream
tasshi
1
3.1k
グローバルチームことはじめ / Bootstrapping a global team
tasshi
1
3.4k
2年目サイボウズ社員とOSS / OSS development of junior engineer in Cybozu
tasshi
0
710
クレートを作ってcrates.ioに公開するまで / How to publishing to crates.io
tasshi
0
660
swarm modeで始める ゆるふわオーケストレーション / Starting Orchestration Softly with Swarm Mode
tasshi
0
3.1k
Other Decks in Programming
See All in Programming
PaaSとSaaSの境目で信頼性と開発速度を両立する 〜TROCCO®︎のこれまでとこれから〜
gtnao
5
5.7k
React への依存を最小にするフロントエンド設計
takonda
21
8.4k
距離関数を極める! / SESSIONS 2024
gam0022
0
340
N.E.X.T LEVEL
pluu
2
220
Cognitoが大型アップデート!Managed Loginとパスワードレスログインを実際に使ってみた@しむそくRadio Special Day1
tmhirai
2
140
5分ぐらいで分かる、トリミング機能の作り方
tsutsuitakumi
0
140
Swift Testing - iPlayground
chiaoteni
0
140
subpath importsで始めるモック生活
10tera
0
380
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
2.9k
我々のデザインシステムは Chakra v3 にアップデートします
shunya078
2
1.5k
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
160
Reckoner における Datadog Browser Test の活用事例 / Datadog Browser Test at Reckoner
nomadblacky
0
180
Featured
See All Featured
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
0
54
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
169
50k
Facilitating Awesome Meetings
lara
50
6.1k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
365
24k
Building Flexible Design Systems
yeseniaperezcruz
327
38k
How to train your dragon (web standard)
notwaldorf
88
5.7k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
27
2.1k
Designing Experiences People Love
moore
138
23k
Making Projects Easy
brettharned
115
5.9k
The Pragmatic Product Professional
lauravandoore
32
6.3k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
232
17k
Transcript
Streams APIと TCPフロー制御 2024.10.31 Nihonbashi.js #9 @tasshi_me 1
Stream APIとTCPフロー制御 - Nihonbashi.js #9 はじめに ⽥代雅治 (@tasshi_me) • 仕事
• サイボウズ株式会社 • kintone拡張基盤🧩チーム EM • 好きなもの • ⾃転⾞ 🚲 • ゲーム 🎮 • ⽝ 🐶 • 2024年9⽉に結婚しました💍 ⾃⼰紹介 2
Stream APIとTCPフロー制御 - Nihonbashi.js #9 はじめに • kintoneの拡張機能(プラグイン・連携サービス)向けの 開発基盤を開発・保守するチーム •
API開発 • SDK/CLIなどのOSS提供 など kintone拡張基盤🧩チーム 3
Streams API 4 WHATWGのStreams API (https://streams.spec.whatwg.org/)
Stream APIとTCPフロー制御 - Nihonbashi.js #9 Streams API • データ⼊出⼒を逐次的に、効率よく扱うためのAPI •
データを分割された断⽚(chunk)の連続した流れとして扱う • 概念⾃体はかなり古くからあり、多くの開発⾔語でストリーム操作はあります • 3種類のストリームオブジェクト(ReadableStream, WritableStream, TransformStream) • Stream同⼠をパイプ接続すると、chunkは流れるように終端まで処理される(パイプチェーン) Streams APIの概要 5 Transform Stream Readable Stream Writable Stream chunk データの読み込み データの変換 (読み込み+書き込み) データの書き込み chunk Source Sink
Stream APIとTCPフロー制御 - Nihonbashi.js #9 Streams API • ストリーム(オブジェクト)は未処理チャンクを保持する内部キューを持っている •
パイプチェーン上のストリーム間で処理速度に差がある場合、 内部キューにチャンクが溜まっていくことになる • => メモリを圧迫する︖ ストリームオブジェクト間の処理速度の違いとメモリ使⽤量 6 Transform Stream Readable Stream Writable Stream chunk chunk チャンクが溜まっていく︖ ここの処理が遅い場合 (DBアクセスなど)
Stream APIとTCPフロー制御 - Nihonbashi.js #9 Streams API • チャンクを受け⼊れられない場合、ストリームは上流に停⽌信号を出す •
停⽌信号を受けた上流のストリームはデータの送信を停⽌する • 下流のストリームが送信を指⽰(pull)すると再び処理が再開する => チャンクの流速が調整されてメモリを圧迫せずに処理できる 背圧 (Backpressure) 7 Transform Stream Readable Stream Writable Stream chunk chunk 内部キューが満杯 STOP! 内部キューが満杯 STOP!
Stream APIとTCPフロー制御 - Nihonbashi.js #9 Streams API • 背圧は内部キューの状態から、キューイング戦略に基づいて通知される •
現在は2種類のキューイング戦略が利⽤可能 キューイング戦略と最⾼⽔準点(highWaterMark) 8 キューに格納されたチャンク数で判定 キューに格納されたバイト数で判定 chunk chunk chunk chunk chunk chunk chunk chunk 3 最⾼⽔準点 (highWaterMark) 10KB CountQueuingStrategy ByteLengthQueuingStrategy
メモリリークと調査 9 ※このページ以降のデータ・グラフは再現リポジトリでの情報です。 (https://github.com/tasshi-playground/demo-stream-api-backpressure)
Stream APIとTCPフロー制御 - Nihonbashi.js #9 メモリリークと調査 • Webアプリケーションから全レコードを取得し、加⼯してDBに書き込んでいく • アプリケーションは全レコードをJSONL形式で返すAPIを持つ
• ストリームを使えばメモリに全レコードを載せずに効率よく処理できるはずだが、、、 全レコードへのバッチ処理 10 Text Decoder Stream Response JSON Parser Stream Line Splitter Stream ⾏ごとに 再分割 UTF-8 デコード DBに 書き込み レスポンスの 読み込み Writable Stream DBに 書き込み fetch DB
Stream APIとTCPフロー制御 - Nihonbashi.js #9 メモリリークと調査 • メモリを急速に圧迫した、なぜ︖ メモリリークの発⽣ 11
Stream APIとTCPフロー制御 - Nihonbashi.js #9 メモリリークと調査 • 終端ストリームを置き換え(DB => fs,
setTimeout)=> 効果なし • 中間ストリームを置き換え => 効果なし • 始端ストリームを置き換え(fetch => fs)=> 効果あり 原因箇所の特定 12 Response fetch Text Decoder Stream ここより前に原因がありそう
Stream APIとTCPフロー制御 - Nihonbashi.js #9 メモリリークと調査 • APIレスポンスはJSONL形式 (Content-Type: application/jsonl;
charset=utf-8) • HTTP/1.1 • Transfer-Encoding: chunked • ↑レスポンスはチャンク単位で送られてくる • => この通信に背圧が反映されないとResponse(ReadableStream)にチャンクが溜まるのでは︖ 通信の詳細 13 chunk Server chunk chunk Response STOP! STOP!…できてる︖
BackpressureとTCP通信 14 ※挙動ベースでの推察です (追ってNode.jsのコードを読んで裏付けしようと思います)
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • Server: JSONLを70MB返却するAPI •
Batch Runner: • APIを呼び出し、レスポンスをストリーム処理する • 終端のWritableStreamはチャンクを受け取ると⼀定時間待機する(背圧を発⽣させる) 検証環境 15 chunk Server (Express) Batch Runner chunk chunk HTTP WireShark キャプチャ
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • ウィンドウサイズはある程度⼤きい値を維持 • 受信側のチャンクサイズも⼩さい(受信速度より終端の処理速度が速い)
終端ストリームの遅延時間なしの場合 16 受信側のチャンクサイズ
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • ⼀定期間ごとにウィンドウサイズが急激に⼩さくなっていることが確認できた • チャンクサイズは上限値に張り付いていた
• => 背圧の発⽣がウィンドウサイズに反映されていると考えられる 終端ストリームの遅延時間100msの場合 17
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • Zero Windowが送信されていた •
ZeroWindow: ウィンドウサイズが0(通信⼀時停⽌) • ZeroWindowProveAck: 通信⼀時停⽌中の接続維持のためのACK • TCP Window Update: ウィンドウサイズが更新されて通信再開 • => よりキューの処理に時間がかかっていると考えられる 終端ストリームの遅延時間1000msの場合 18
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • Zero Window送信後、⻑時間に渡って通信再開せず •
=> 内部キューが処理できていないと考えられる 終端ストリームの遅延時間10000msの場合 19
Stream APIとTCPフロー制御 - Nihonbashi.js #9 BackpressureとTCP通信 • Streams APIの背圧はネットワークリクエストにも反映されると考えられる •
ウィンドウサイズが⼩さくなり、受信可能データ量を調整する • それでも処理しきれず受信を⽌める場合は、 サーバーにzero windowパケットが送信される • (HTTP/2での挙動も⾒てみたい) まとめ 20 chunk Server chunk chunk Response STOP! STOP! (zero window)
余談 21 メモリリークの原因はなんだったのか
Stream APIとTCPフロー制御 - Nihonbashi.js #9 22 メモリリークの原因
Stream APIとTCPフロー制御 - Nihonbashi.js #9 メモリリークの原因 • Node.js v22.7.0 (undici
v6.19.7)で修正された (nodejs/undici#3445) • v22ではメモリ使⽤量が300MB付近で横ばい • LTSへのbackport状況 • v20.x => v20.18.0にbackport済み、だが計測結果は× • v18.x => backportの予定は⾒つけられず undiciがメモリリークしていた 23
おわり 24 ご清聴ありがとうございました