-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathfile.architecture.html
153 lines (127 loc) · 7.02 KB
/
file.architecture.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
<!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'>
<meta name='viewport' content='width=device-width, initial-scale=1.0, user-scalable=no'>
<meta name='apple-touch-fullscreen' content='yes'>
<meta name='apple-mobile-web-app-capable' content='yes'>
<meta name='apple-mobile-web-app-status-bar-style' content='rgba(228,228,228,1.0)'>
<title>File: Architecture — Puma master</title>
<link rel='stylesheet' type='text/css' href='../css/y_fonts.css' />
<link rel='stylesheet' type='text/css' href='../css/highlight.github.css' />
<link rel='stylesheet' type='text/css' href='../css/y_style.css' />
<link rel='stylesheet' type='text/css' href='../css/y_list.css' />
<link rel='stylesheet' type='text/css' href='../css/y_color.css' />
<script type='text/javascript'>
var pathId = "architecture",
relpath = '';
var t2Info = {
CSEP: '.',
ISEP: '#',
NSEP: '::'
};
</script>
<script type='text/javascript' charset='utf-8' src='../js/highlight.pack.js'></script>
<script type='text/javascript' charset='utf-8' src='../js/y_app.js'></script>
</head>
<body>
<svg id='y_wait' class viewBox='0 0 90 90'></svg>
<div id='settings' class='hidden'></div>
<div id='y_list' class='d h'>
<header id='list_header'></header>
<nav id= 'list_nav' class='y_nav l_nav'>
<ul id='list_items'></ul>
</nav>
</div>
<div id='y_toc' class='f h'>
<header id='toc_header'></header>
<nav id= 'toc_nav' class='y_nav t_nav'>
<ol id='toc_items'></ol>
</nav>
</div>
<div id='y_main' tabindex='-1'>
<header id='y_header'>
<div id='y_menu'>
<a id='home_no_xhr' href='/'>Home</a> »
<a href='.'>Puma master</a> »
<a href='_index.html'>Index</a> »
<span class='title'><a id='t2_doc_top' href='#'>File: Architecture ▲</a></span>
</div>
<a id='list_href' href="class_list.html"></a>
<div id='y_measure_em' class='y_measure'></div>
<div id='y_measure_vh' class='y_measure'></div>
<span id='y_measure_50pre' class='y_measure'><code>123456789_123456789_123456789_123456789_123456789_</code></span>
</header>
<div id='content' class='file'>
<h1>Architecture</h1>
<h2>Overview</h2>
<p><img src="images/puma-general-arch.png" alt="https://bit.ly/2iJuFky"></p>
<p><a href="Puma.html" title="Puma (module)"><code>Puma</code></a> is a threaded Ruby HTTP application server processing requests across a TCP
and/or UNIX socket.</p>
<p><a href="Puma.html" title="Puma (module)"><code>Puma</code></a> processes (there can be one or many) accept connections from the socket via
a thread (in the <a href="../lib/puma/reactor.rb"><a href="Puma/Reactor.html" title="Puma::Reactor (class)"><code>Reactor</code></a></a> class). The connection,
once fully buffered and read, moves into the <code>todo</code> list, where an available
thread will pick it up (in the <a href="../lib/puma/thread_pool.rb"><a href="Puma/ThreadPool.html" title="Puma::ThreadPool (class)"><code>ThreadPool</code></a></a>
class).</p>
<p><a href="Puma.html" title="Puma (module)"><code>Puma</code></a> works in two main modes: cluster and single. In single mode, only one <a href="Puma.html" title="Puma (module)"><code>Puma</code></a>
process boots. In cluster mode, a <code>master</code> process is booted, which prepares
(and may boot) the application and then uses the <code>fork()</code> system call to create
one or more <code>child</code> processes. These <code>child</code> processes all listen to the same
socket. The <code>master</code> process does not listen to the socket or process requests -
its purpose is primarily to manage and listen for UNIX signals and possibly kill
or boot <code>child</code> processes.</p>
<p>We sometimes call <code>child</code> processes (or <a href="Puma.html" title="Puma (module)"><code>Puma</code></a> processes in <code>single</code> mode)
<em>workers</em>, and we sometimes call the threads created by Puma's
<a href="../lib/puma/thread_pool.rb"><a href="Puma/ThreadPool.html" title="Puma::ThreadPool (class)"><code>ThreadPool</code></a></a> <em>worker threads</em>.</p>
<h2>How Requests Work</h2>
<p><img src="images/puma-connection-flow.png" alt="https://bit.ly/2zwzhEK"></p>
<ul>
<li>Upon startup, <a href="Puma.html" title="Puma (module)"><code>Puma</code></a> listens on a TCP or UNIX socket.
<ul>
<li>The backlog of this socket is configured with a default of 1024, but the
actual backlog value is capped by the <code>net.core.somaxconn</code> sysctl value.
The backlog determines the size of the queue for unaccepted connections. If
the backlog is full, the operating system is not accepting new connections.</li>
<li>This socket backlog is distinct from the <code>backlog</code> of work as reported by
<a href="Puma.html#stats-class_method" title="Puma.stats (method)">Puma.stats</a> or the control server. The backlog that <a href="Puma.html#stats-class_method" title="Puma.stats (method)">Puma.stats</a> refers to
represents the number of connections in the process' <code>todo</code> set waiting for
a thread from the <a href="../lib/puma/thread_pool.rb"><a href="Puma/ThreadPool.html" title="Puma::ThreadPool (class)"><code>ThreadPool</code></a></a>.</li>
</ul></li>
<li>By default, a single, separate thread (created by the
<a href="../lib/puma/reactor.rb"><a href="Puma/Reactor.html" title="Puma::Reactor (class)"><code>Reactor</code></a></a> class) reads and buffers requests from the
socket.
<ul>
<li>When at least one worker thread is available for work, the reactor thread
listens to the socket and accepts a request (if one is waiting).</li>
<li>The reactor thread waits for the entire HTTP request to be received.</li>
<li>Puma exposes the time spent waiting for the HTTP request body to be
received to the Rack app as <code>env['puma.request_body_wait']</code>
(milliseconds).</li>
<li>Once fully buffered and received, the connection is pushed into the "todo"
set.</li>
</ul></li>
<li>Worker threads pop work off the "todo" set for processing.
<ul>
<li>The worker thread processes the request via <code>call</code>ing the configured Rack
application. The Rack application generates the HTTP response.</li>
<li>The worker thread writes the response to the connection. While Puma buffers
requests via a separate thread, it does not use a separate thread for
responses.</li>
<li>Once done, the thread becomes available to process another connection in the
"todo" set.</li>
</ul></li>
</ul>
<h3><code>queue_requests</code></h3>
<p><img src="images/puma-connection-flow-no-reactor.png" alt="https://bit.ly/2zxCJ1Z"></p>
<p>The <code>queue_requests</code> option is <code>true</code> by default, enabling the separate reactor
thread used to buffer requests as described above.</p>
<p>If set to <code>false</code>, this buffer will not be used for connections while waiting
for the request to arrive.</p>
<p>In this mode, when a connection is accepted, it is added to the "todo" queue
immediately, and a worker will synchronously do any waiting necessary to read
the HTTP request from the socket.</p>
<div id='footer'></div>
</div> <!-- content -->
</div> <!-- y_main -->
</body>
</html>