さくらの夕べ Tech Night #2 Onlineの発表資料です https://sakura-tokyo.connpass.com/event/182387/
いまさら聞けないNode.js小田島 太郎 @shimataro9992020/8/4 さくらの夕べ Tech Night #2 Online
View Slide
https://shimataro.me/自己紹介● 小田島 太郎 / https://shimataro.me/● ウェブエンジニア○ フロントエンドとかバックエンドとか○ インフラもちょこっとだけ● 趣味は手品○ 手品業界→ウェブ業界2
この発表について対象者● Node.js=サーバーサイドJSってことぐらいしか知らない● バックエンドをPHPとかRubyからNode.jsに書き直しを検討中● C10K問題のことをよく知らない3Node.js完全に理解したなにもわからないチョットデキルこのへん対象半分くらいこの説明です
この発表について目標● Node.jsが解決するものを理解する(何がうれしいの?)● 他の言語との違いを理解する(他とどう違うの?)● バックエンド開発の注意点を理解する(何に気をつければいいの?)4スライドは公開していますhttps://speakerdeck.com/shimatarohttps://shimataro.me/slides/
それでは始めます5
Node.jsとは?6
Node.jsとは?7JavaScriptの実行環境の1つ● コマンドラインからJavaScriptを実行できる● Chromeで使われているV8エンジンを搭載● C10K問題を解決するためのバックエンド言語として開発された● 名前の由来は “Node in Network”
Node.jsとは?8使われている場所● ウェブサービスのバックエンド● フロントエンド○ WebpackとかVue.jsのビルドとか● デスクトップアプリ○ Electron(Visual Studio CodeとかSlackとか)● 組み込み
C10K問題とは?9
C10K問題(クライアント1万台問題)とは?10突然ですが問題です。クライアント1万台問題とは何でしょう?
C10K問題(クライアント1万台問題)とは?11解答1: クライアントが1万台になると何かおかしくなる❌● 1万という数値には特別な意味はない○ 単に「クライアントの台数が多い」という意味○ 9999台まではOKで、1万台になった瞬間におかしくなるわけではない● 何がおかしくなる?○ サービスの応答が遅くなる
C10K問題(クライアント1万台問題)とは?12解答2: クライアントの数が多くなると応答が遅くなる❌● 「クライアントの数が多くなる」とは?○ 1秒に1台ずつ、1万秒かけて接続がある場合でも「クライアントが1万台」には変わりない○ 問題は同時接続数
C10K問題(クライアント1万台問題)とは?13解答3: クライアントの同時接続数が多くなると応答が遅くなる❌● なぜ遅くなる?○ マシンスペックが足りなくて応答が遅くなるのは当たり前■ そんなもんにわざわざ C10K問題なんて名前つける必要はない■ マシンを買い直せば済む話○ マシンスペック以外の原因があるからこそのC10K問題
C10K問題(クライアント1万台問題)とは?14解答4: マシンスペックは問題ないにもかかわらず、クライアントの同時接続数が多くなると応答が遅くなる ⭕● 何が原因?● どうすればいい?
C10K問題の原因15
C10K問題の原因1: プロセス数の上限16Apache HTTP Serverの駆動方式● 以前はprefork方式(1リクエスト1プロセス)が一般的OSのプロセス数制限● プロセスにはIDが割り当てられている○ 32bit Linuxでは32767が上限● OSごとに同時に実行できるプロセス数の上限が決まっているprefork方式では、OSごとに決められた数以上のリクエストを処理できない
ウェブサーバープロセスプロセスプロセスC10K問題の原因1: プロセス数の上限17リクエストプロセス プロセス上限オーバー!(処理できない!)リクエストリクエストリクエストプロセスIDを使い切った
【コンテキストスイッチ】CPUが複数のプロセスを並行処理するために、それまで実行していたプロセスの内容を記録し、新たなプロセスの内容を復元することC10K問題の原因2: コンテキストスイッチのコスト18時間軸プロセスA プロセスB プロセスCB復元A保存 C復元B保存コンテキストスイッチ
プロセスが増えると、コンテキストスイッチがCPUに対して占める割合が大きくなり、CPUリソースの大部分を消費するprefork方式(リクエストが増える=プロセスが増える)では、リクエストが増えるほどリクエストを捌けるリソースが少なくなるC10K問題の原因2: コンテキストスイッチのコスト19時間軸プロセスA プロセスB プロセスCB復元A保存 C復元B保存 プロセスDD復元C保存
【ファイルディスクリプター】OSが読み書きしているファイルのIDOS全体やプロセスごとに上限が決まっているLinuxでは、1プロセスにつき1024が上限のことが多いC10K問題の原因3: ファイルディスクリプターの上限20
Unix系OSでは、ファイルだけでなくネットワークアクセスにもファイルディスクリプターを使うDBとのコネクションにもファイルディスクリプターを使うリクエストごとにDBコネクションを張る構成だと、ファイルディスクリプターの上限を超える同時接続ができないC10K問題の原因3: ファイルディスクリプターの上限21
C10K問題の解決方法22
札束で解決● 1台で捌けないなら10台用意すればいい● 10台で捌けないなら100台用意すればいい● 用意したサーバーにいい感じに負荷分散するC10K問題の解決方法1: サーバーの台数を増やす23ロードバランサー側にもC10K問題が発生しないように注意
C10K問題の解決方法2: シングルプロセスで捌く頭のいい人は考えました「マルチプロセス方式でプロセスIDの上限に引っかかるなら、シングルプロセス・シングルスレッドで全リクエストを捌けばいいんじゃね?」「これならコンテキストスイッチも必要なくね?」「1つのDBコネクションを複数リクエストで使いまわせばファイルディスクリプターの問題もなくなるんじゃね?」24非同期・ノンブロッキングI/O
C10K問題の解決方法2: シングルプロセスで捌く【同期・ブロッキングI/O(従来型)】指示を出したら処理が終わるまでCPU側でひたすら待つ25炊飯洗濯指示炊飯指示 炊飯完了洗濯完了洗濯ゲーム料理アイロンがけ待機 待機
C10K問題の解決方法2: シングルプロセスで捌く【非同期・ノンブロッキングI/O】指示を出したら完了を待たずに別の処理を行う26洗濯指示炊飯指示 炊飯完了洗濯完了炊飯洗濯ゲーム 料理 アイロンがけ待機
C10K問題の解決方法2: シングルプロセスで捌く非同期・ノンブロッキングI/Oの特徴● ⭕処理の完了を待っている間に別の処理をできる○ CPUの待ち時間が減るので効率的● ⭕CPUを使わない複数の処理を並列で実行できる● ❌非同期処理の記述が複雑になりがち○ 投げっぱなしで済む処理はあまり多くないので、どこかで完了を待ち合わせる必要がある27
Node.jsのアプローチ28
Node.jsのアプローチ● シングルプロセス・シングルスレッド○ 処理がキューに追加され、先に入ったものから順次処理される○ コンテキストスイッチが発生しない● CPUを使わない処理(通信など)は非同期で行われる○ 処理が終わったらコールバック関数が呼ばれる○ コネクション(ファイルディスクリプター)を使いまわせる29(きちんとプログラミングすれば)C10K問題は発生しない
Node.jsのアプローチ30いい感じにHTML出力リクエストC リクエストB リクエストAキューリクエストC リクエストBリクエストA1. DBからデータを取り出す2. いい感じにHTML出力リクエストC リクエストB DB1. データ取得指示2. データ取得後に次の処理がキューに積まれるキューの処理はできるだけ短い時間で終わらせるのが鉄則
Node.jsを使うときの注意31
Node.jsを使うときの注意1: 非同期処理32● コールバック関数を使いまくるとネストが深くなって見づらい● コールバック方式だと例外処理を書きづらい○ Promiseやasync/awaitを使いこなそう● 面倒だからといって絶対に同期版を使わないこと○ 処理に時間がかかる=キューが詰まる=他のリクエストを処理できない他の言語からの移行者は要注意
Node.jsを使うときの注意2: グローバル変数33● Node.jsはシングルプロセス・シングルスレッド● つまりグローバル変数は全リクエストで共有される● つまりリクエストの内部状態をグローバル変数で管理すると別のリクエストによって突然書き換えられてしまう○ 例えばAccept-Languageの値(ja, en-US等)他の言語からの移行者は要注意
Node.jsを使うときの注意3: リソース管理34● Node.jsはシングルプロセス・シングルスレッド● つまりプロセスは動き続けることが前提● つまりリソースは自動的に解放されない=明示的に解放しないと枯渇し、新しいリクエストを処理できなくなる○ メモリーはGCが回収してくれるが…他の言語からの移行者は要注意
Node.jsを使うときの注意4: 一部のバグが全体に影響35● Node.jsはシングルプロセス・シングルスレッド● つまり接続が切れてもプロセスは実行され続ける● つまり間違えて無限ループを入れてしまったら最後、新しいリクエストを処理できなくなる○ マルチプロセスでは接続を切れば無限ループは消える他の言語からの移行者は要注意
Node.jsを使うときの注意5: CPUを使いまくる処理36● Node.jsはシングルプロセス・シングルスレッド● つまり1つの関数が終わるまで他のリクエストを処理できない● つまりCPUリソースを大量に消費する処理には不向き○ 別プロセスや別サービスとしてNode.jsの外側に置く工夫が必要他の言語からの移行者は要注意
まとめ37
まとめ● Node.jsはJavaScriptの実行環境だよ● C10K問題を解決できるよ● シングルプロセス・シングルスレッドだよ● 非同期I/Oを使ってるよ● 他の言語から移行するときは色々注意しようね● 手品に興味がある人はおはなししましょう38
まとめ目標(再掲)● Node.jsが解決するものを理解する(何がうれしいの?)● 他の言語との違いを理解する(他とどう違うの?)● バックエンド開発の注意点を理解する(何に気をつければいいの?)39お わ か り い た だ け た だ ろ う か
https://shimataro.me/40「さくらのナレッジ」にも投稿していますhttps://knowledge.sakura.ad.jp/24148/