teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

脈絡が無いので取り消し、記述差し替え。

2019/10/27 00:29

投稿

dodox86
dodox86

スコア9416

answer CHANGED
@@ -64,7 +64,7 @@
64
64
  ```
65
65
  4つ目のリクエストによるレスポンスが、接続はWEBサーバーであるnginxに受け付けられるものの、実際にUnicornのワーカープロセスの処理に制御に移るのは、1つ目のリクエストの処理が終わったPID=3881のプロセスによるものであることが分かります。
66
66
 
67
- 大量の同時リクエストがあったとしてもプロセス数の制限を設けることで堅牢性やメモリ占有率を担保しようとする(<たぶん)Unicornのような形態をとるWEBアプリでは、ワーカープロセスの終了まで長時間占有するような処理はご法度、と言うことですね。数に制限のあるスレッドプールなどにも言えそうです。なお、CPUコアの数が依然として関係ないのは前の回答と同様のはずです。なぜならば、Unicorn自体がプロセス数の制限を担っているからです。
67
+ 大量の同時リクエストがあったとしてもプロセス数の制限を設けることで堅牢性やメモリ占有率を担保しようとする(<たぶん)Unicornのような形態をとるWEBアプリでは、ワーカープロセスの終了まで長時間占有するような処理はご法度、と言うことですね。数に制限のあるスレッドプールなどにも言えそうです。なお、CPUコアの数が依然として関係ないのは前の回答と同様のはずです。~~なぜならば、Unicorn自体がプロセス数の制限を担っているからです。~~ご質問に提示されたコードと私のコードは、CPUコア数の多少に影響されるものではありません。
68
68
 
69
69
  技術的な疑問から出た今回のご質問だったと思いますが、1プロセスで長時間占有するようなWEBアプリの処理は考えたことも無かったので、私も勉強になりました。
70
70
 

1

Unicornのワーカープロセスについて追記

2019/10/27 00:29

投稿

dodox86
dodox86

スコア9416

answer CHANGED
@@ -4,4 +4,98 @@
4
4
 
5
5
  まず、`sleep`を実行したときから、そのアプリケーションはOSに制御を委ねます。文字通りそのアプリケーションは眠った状態になります。OSは別のプロセスに制御を移します。`sleep`で指定した時間が満了すると、OSはまたそのアプリケーションに制御を移し、そのアプリケーションの実行が再開されます。上記の説明は`sleep`と言うメソッドの実行を契機として別のプロセスが動く例ですが、、実際はさらに、各プロセスに割り当てた細かい時間単位で制御が移り渡っていきます(時分割/タイムスライス)。スレッドが関係すればさらに細かくなります。
6
6
 
7
- CPUがシングルコアではなく、マルチコア、メニイコアの場合は、良くWEBの記事ではコア1つに対して1スレッドなどと説明がありますが、そうとも限りません。割り当てられなければ1つのコアで複数のスレッドが時分割されて動きますし、反対に複数のコアでもスレッドが1つしか使われないようなケースもあります。
7
+ CPUがシングルコアではなく、マルチコア、メニイコアの場合は、良くWEBの記事ではコア1つに対して1スレッドなどと説明がありますが、そうとも限りません。割り当てられなければ1つのコアで複数のスレッドが時分割されて動きますし、反対に複数のコアでもスレッドが1つしか使われないようなケースもあります。
8
+
9
+ ---
10
+ **コメントを受けて追記しました:2019-10-27 09:02**
11
+
12
+ ※回答欄へのコメントより引用:
13
+ > (ここでのワーカーはunicornなどでのワーカーです)
14
+
15
+ 前提がそうであると、上記の私の回答は該当しませんね。この場合は質問者さんの疑問どおり、
16
+ 「ワーカー数3で起動していた場合、3人が同時にアクセスしてきて、sleep処理を実行していると4人目は誰かの待機処理及びfunc_Bが終わるまでfunc_Aも実行されない状態」になります。
17
+
18
+ 手間取りましたが、Ubuntu16上でRuby Sinatra + Unicorn + nginxを使って確認してみました。
19
+ unicornを起動した状態が、以下のようであるとします。ワーカープロセスは3881, 3883, 3886の3つです。
20
+ ```bash
21
+ $ unicorn -c unicorn.conf -D
22
+
23
+ $ ps -ax
24
+ ...
25
+ 3879 pts/19 Sl+ 0:00 unicorn master -c unicorn.conf
26
+ 3881 pts/19 Sl+ 0:00 unicorn worker[0] -c unicorn.conf
27
+ 3883 pts/19 Sl+ 0:00 unicorn worker[1] -c unicorn.conf
28
+ 3886 pts/19 Sl+ 0:00 unicorn worker[2] -c unicorn.conf
29
+ ```
30
+ この状況で Sinatraで造ったWEBアプリを動作させます。`http://<server>/test1`へのGETで、10秒`sleep`するだけするものです。処理の前後でタイムスタンプを保存し、レスポンス中にプロセスIDと共にデータとして載せます。
31
+ ```
32
+ $ cat config.ru
33
+
34
+ require 'rubygems'
35
+ require 'sinatra/base'
36
+
37
+ class HelloApp < Sinatra::Base
38
+ get '/test1' do
39
+ now1 = Time.now
40
+ sleep(10)
41
+ now2 = Time.now
42
+ ts = now1.strftime("%H:%M:%S")
43
+ te = now2.strftime("%H:%M:%S")
44
+ s = "PID=#{Process.pid}, s=#{ts}, e=#{te}"
45
+ return s
46
+ end
47
+ end
48
+ run HelloApp
49
+ ```
50
+ この状態で、クライアント側から`wget`コマンドで3つのリクエストを送ります。3つが受け付けられた後、更に1つのリクエストを送出します。すると、以下のような結果が得られました。
51
+
52
+ ```
53
+ # 1つ目のリクエストでのレスポンス内容
54
+ PID=3881, s=08:13:33, e=08:13:43
55
+
56
+ # 2つ目のリクエストでのレスポンス内容
57
+ PID=3886, s=08:13:34, e=08:13:44
58
+
59
+ # 3つ目のリクエストでのレスポンス内容
60
+ PID=3883, s=08:13:36, e=08:13:46
61
+
62
+ # 4つ目のリクエスト
63
+ PID=3881, s=08:13:43, e=08:13:53
64
+ ```
65
+ 4つ目のリクエストによるレスポンスが、接続はWEBサーバーであるnginxに受け付けられるものの、実際にUnicornのワーカープロセスの処理に制御に移るのは、1つ目のリクエストの処理が終わったPID=3881のプロセスによるものであることが分かります。
66
+
67
+ 大量の同時リクエストがあったとしてもプロセス数の制限を設けることで堅牢性やメモリ占有率を担保しようとする(<たぶん)Unicornのような形態をとるWEBアプリでは、ワーカープロセスの終了まで長時間占有するような処理はご法度、と言うことですね。数に制限のあるスレッドプールなどにも言えそうです。なお、CPUコアの数が依然として関係ないのは前の回答と同様のはずです。なぜならば、Unicorn自体がプロセス数の制限を担っているからです。
68
+
69
+ 技術的な疑問から出た今回のご質問だったと思いますが、1プロセスで長時間占有するようなWEBアプリの処理は考えたことも無かったので、私も勉強になりました。
70
+
71
+ 参考に、確認に使ったunicorn.confの内容とnginxの設定内容を記しておきます。
72
+
73
+ unicorn.confの内容:
74
+ ```
75
+ worker_processes 3
76
+ listen '/tmp/unicorn.sock'
77
+ stderr_path File.expand_path('unicorn.log', File.dirname(__FILE__))
78
+ stdout_path File.expand_path('unicorn.log', File.dirname(__FILE__))
79
+ preload_app true
80
+ ```
81
+ nginxのconfの内容:(/etc/nginx/sites-available/default)
82
+ ```
83
+ upstream unicornapps {
84
+ server unix:tmp/unicorn.sock;
85
+ }
86
+
87
+ server {
88
+ listen 80 default_server;
89
+ listen [::]:80 default_server;
90
+
91
+ root /var/www/html;
92
+
93
+ index index.html index.htm index.nginx-debian.html;
94
+
95
+ server_name _;
96
+
97
+ location / {
98
+ proxy_pass http://unicornapps;
99
+ }
100
+ }
101
+ ```