Slide 1

Slide 1 text

おまいらちゃんと おまいらちゃんと リソース解放してますか リソース解放してますか (2018/11/23) (2018/11/23) ⼩⽥島 太郎 / @shimataro 東京NODE 学園祭2018 DAY #1 東京NODE 学園祭2018 DAY #1

Slide 2

Slide 2 text

⾃⼰紹介 ⾃⼰紹介 / / / ウェブリオ株式会社所属(京都) サーバサイド / インフラエンジニア 趣味は⼿品 ⼿品業界→Web 業界 最近は ⼿打ちうどん にハマりかけてます ⼩⽥島 太郎 shimataro@GitHub odashima.taro@Facebook shimataro999@Twitter

Slide 3

Slide 3 text

この発表について この発表について 対象 Node.js で Web アプリ を作っている⼈ 他の⾔語からの転⼊⽣ 特に リクエストごとにプロセスやメモリ空間が 独⽴している世界 からの来訪者(e.g., PHP ) 技術レベル: 中級 ↓スライドはこちら↓ https://speakerdeck.com/shimataro https://shimataro.github.io/slides/

Slide 4

Slide 4 text

⽬次 ⽬次 最初に リソースの管理⽅法 その1 その2 その3 どうすればいいの? まとめ

Slide 5

Slide 5 text

それでは始めます それでは始めます

Slide 6

Slide 6 text

最初に 最初に

Slide 7

Slide 7 text

リソースとは リソースとは ここで⾔う リソースとは、プログラムが確保・解放 する必要がある メモリ以外の 資源を指す ファイルディスクリプタ コネクション 特に (R)DB コネクション についてのお話です メモリはGC が回収してくれるので今回の対象外

Slide 8

Slide 8 text

リソースの管理⽅法 リソースの管理⽅法 DB コネクションをどうやって管理してますか?

Slide 9

Slide 9 text

1. グローバルオブジェクト 1. グローバルオブジェクト グローバルなリソースを使いまわす const mysql = require("mysql"); // これを使いまわす const connection = mysql.createConnection(...);

Slide 10

Slide 10 text

1. グローバルオブジェクト 1. グローバルオブジェクト 利点 リソースは最⼩限 毎回確保する必要がないので⾼速 ⽋点 切断時の再接続処理が必要 瞬断 MySQL では8 時間アイドル状態だと切断される トランザクションが他のリクエストを巻き込む 開発時は気づきにくい

Slide 11

Slide 11 text

2. 都度確保・都度解放 2. 都度確保・都度解放 必要なときに確保、不要になったら解放 const mysql = require("mysql"); const pool = mysql.createPool(...); function someFunc() { try { const connection = pool.getConnection(); // 必要になったら確保 ... // 何か処理 } finally { connection.release(); // 使い終わったら解放 } }

Slide 12

Slide 12 text

2. 都度確保・都度解放 2. 都度確保・都度解放 利点 リクエスト間のトランザクションは独⽴する ⽋点 1 リクエスト中に 無駄に リソースを2 つ以上作成す る場合あり(関数のネスト等)

Slide 13

Slide 13 text

3. リクエスト内で使いまわす 3. リクエスト内で使いまわす リクエストオブジェクトにリソースを関連付け、この リソースを使いまわす (もしくはContinuation Local Storage を使⽤) const mysql = require("mysql"); const pool = mysql.createPool(...); function getConnection(req) { if(req.connection === undefined) { // req にリソースを関連付ける req.connection = pool.getConnection(); } return req.connection; }

Slide 14

Slide 14 text

3. リクエスト内で使いまわす 3. リクエスト内で使いまわす 利点 1 コネクション/ リクエスト 以下 ⽋点 解放忘れに注意 リクエスト処理の最後 で解放を忘れると…

Slide 15

Slide 15 text

3. リクエスト内で使いまわす 3. リクエスト内で使いまわす こうなります (転⼊⽣がハマる罠)

Slide 16

Slide 16 text

3. リクエスト内で使いまわす 3. リクエスト内で使いまわす 転⼊⽣のハマりどころ リクエストを捌き終えても プロセスは⾛り続ける 強制解放されない PHP とは違うのだよ デストラクタ/ ファイナライザがない GC でメモリは回収されるが、 それ以外のリソー スは回収されない

Slide 17

Slide 17 text

どうすればいいの? どうすればいいの? しばらく悩みました。 正常終了・異常終了で ⾶ぶイベントが異なる F5 連打されると イベントが⾶ばない (ことがあ る) リソース取得⾃体が⾮同期だとさらにややこしい

Slide 18

Slide 18 text

こうしとけ こうしとけ 3 箇所で解放 特に最後は⼤事(F5 連打対策) function middleware(req, res, next) { // Express.js のミドルウェア req.connection = ...; res .on("finish", () => { req.connection.release(); // 正常完了時 }) .on("close", () => { req.connection.release(); // 異常終了時(通信切断) }); if (res.socket.destroyed) { // すでに通信が切断されていた(イベントが発⽣しない) req.connection.release(); } }

Slide 19

Slide 19 text

簡単な⽅法 簡単な⽅法 on-finished パッケージを使うと楽 https://www.npmjs.com/package/on- nished const onFinished = require("on-finished"); function middleware(req, res, next) { // Express.js のミドルウェア req.connection = ...; onFinished(res, () => { req.connection.release(); // ここで解放するだけ! }); }

Slide 20

Slide 20 text

ちなみに… ちなみに… グローバルオブジェクトを使いまわす場合は 切断時にしっかり再接続して トランザクション時に新しくリソースを作る うまくやってくれるORM を使おう (e.g., Sequelize ) でも、処理完了のタイミングを知っておくのも役に⽴ ちます

Slide 21

Slide 21 text

まとめ まとめ リソース管理には注意しよう 他の⾔語から来た⼈は特に注意 処理完了の検知は 3 箇所 で! パッケージ を使うと楽だよ ORM を使うともっと楽だよ うどん が好きな⼈は声をかけてね!

Slide 22

Slide 22 text

おまけ おまけ

Slide 23

Slide 23 text

関⻄でもNODE 学園! 関⻄でもNODE 学園! 東⻄で盛り上げていきましょう! 関⻄Node 学園 梅⽥キャンパス 1 時限⽬(04/20 ) 関⻄Node 学園 梅⽥キャンパス 2 時限⽬(07/05 ) 関⻄Node 学園 3 時限⽬(08/03 ) 関⻄Node 学園 4 時限⽬(11/02 )

Slide 24

Slide 24 text

ありがとうございました ありがとうございました