varnish-cache/bin/varnishd/mgt/mgt_pool.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * We maintain a number of worker thread pools, to spread lock contention.
30
 *
31
 * Pools can be added on the fly, as a means to mitigate lock contention,
32
 * but can only be removed again by a restart. (XXX: we could fix that)
33
 *
34
 * Two threads herd the pools, one eliminates idle threads and aggregates
35
 * statistics for all the pools, the other thread creates new threads
36
 * on demand, subject to various numerical constraints.
37
 *
38
 * The algorithm for when to create threads needs to be reactive enough
39
 * to handle startup spikes, but sufficiently attenuated to not cause
40
 * thread pileups.  This remains subject for improvement.
41
 */
42
43
#include "config.h"
44
45
#include <stdio.h>
46
47
#include "mgt/mgt.h"
48
49
#include "mgt/mgt_param.h"
50
51
/*--------------------------------------------------------------------
52
 * The min/max values automatically update the opposites appropriate
53
 * limit, so they don't end up crossing.
54
 */
55
56
static int
57 4114
tweak_thread_pool_min(struct vsb *vsb, const struct parspec *par,
58
    const char *arg)
59
{
60
61 4114
        if (tweak_uint(vsb, par, arg))
62 2
                return (-1);
63
64 4112
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_max",
65 4112
            "%u", mgt_param.wthread_min);
66 4112
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_reserve",
67 4112
            "%u", mgt_param.wthread_min * 950 / 1000);
68 4112
        return (0);
69 4114
}
70
71
static int
72 1690
tweak_thread_pool_max(struct vsb *vsb, const struct parspec *par,
73
    const char *arg)
74
{
75
76 1690
        if (tweak_uint(vsb, par, arg))
77 2
                return (-1);
78
79 1688
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_min",
80 1688
            "%u", mgt_param.wthread_max);
81 1688
        return (0);
82 1690
}
83
84
/*--------------------------------------------------------------------
85
 * The thread pool parameter definitions used to generate the varnishd
86
 * manual. Check the generated RST after updating.
87
 */
88
89
struct parspec WRK_parspec[] = {
90
        { "thread_pools", tweak_uint, &mgt_param.wthread_pools,
91
                "1", NULL,
92
                "Number of worker thread pools.\n"
93
                "\n"
94
                "Increasing the number of worker pools decreases lock "
95
                "contention. Each worker pool also has a thread accepting "
96
                "new connections, so for very high rates of incoming new "
97
                "connections on systems with many cores, increasing the "
98
                "worker pools may be required.\n"
99
                "\n"
100
                "Too many pools waste CPU and RAM resources, and more than one "
101
                "pool for each CPU is most likely detrimental to performance.\n"
102
                "\n"
103
                "Can be increased on the fly, but decreases require a "
104
                "restart to take effect.",
105
                EXPERIMENTAL | DELAYED_EFFECT,
106
                "2", "pools" },
107
        { "thread_pool_max", tweak_thread_pool_max, &mgt_param.wthread_max,
108
                NULL, NULL,
109
                "The maximum number of worker threads in each pool.\n"
110
                "\n"
111
                "Do not set this higher than you have to, since excess "
112
                "worker threads soak up RAM and CPU and generally just get "
113
                "in the way of getting work done.",
114
                DELAYED_EFFECT,
115
                "5000", "threads",
116
                "thread_pool_min" },
117
        { "thread_pool_min", tweak_thread_pool_min, &mgt_param.wthread_min,
118
                NULL, NULL,
119
                "The minimum number of worker threads in each pool.\n"
120
                "\n"
121
                "Increasing this may help ramp up faster from low load "
122
                "situations or when threads have expired.\n"
123
                "\n"
124
                "Minimum is 10 threads.",
125
                DELAYED_EFFECT,
126
                "100", "threads",
127
                NULL, "thread_pool_max" },
128
        { "thread_pool_reserve", tweak_uint,
129
                &mgt_param.wthread_reserve,
130
                NULL, NULL,
131
                "The number of worker threads reserved for vital tasks "
132
                "in each pool.\n"
133
                "\n"
134
                "Tasks may require other tasks to complete (for example, "
135
                "client requests may require backend requests). This reserve "
136
                "is to ensure that such tasks still get to run even under high "
137
                "load.\n"
138
                "\n"
139
                "Increasing the reserve may help setups with a high number of "
140
                "backend requests at the expense of client performance. "
141
                "Setting it too high will waste resources by keeping threads "
142
                "unused.\n"
143
                "\n"
144
                "Default is 0 to auto-tune (currently 5% of thread_pool_min).\n"
145
                "Minimum is 1 otherwise.",
146
                DELAYED_EFFECT,
147
                "0", "threads",
148
                NULL, "95% of thread_pool_min" },
149
        { "thread_pool_timeout",
150
                tweak_timeout, &mgt_param.wthread_timeout,
151
                "10", NULL,
152
                "Thread idle threshold.\n"
153
                "\n"
154
                "Threads in excess of thread_pool_min, which have been idle "
155
                "for at least this long, will be destroyed.",
156
                EXPERIMENTAL | DELAYED_EFFECT,
157
                "300", "seconds" },
158
        { "thread_pool_watchdog",
159
                tweak_timeout, &mgt_param.wthread_watchdog,
160
                "0.1", NULL,
161
                "Thread queue stuck watchdog.\n"
162
                "\n"
163
                "If no queued work have been released for this long,"
164
                " the worker process panics itself.",
165
                EXPERIMENTAL,
166
                "60", "seconds" },
167
        { "thread_pool_destroy_delay",
168
                tweak_timeout, &mgt_param.wthread_destroy_delay,
169
                "0.01", NULL,
170
                "Wait this long after destroying a thread.\n"
171
                "\n"
172
                "This controls the decay of thread pools when idle(-ish).",
173
                EXPERIMENTAL | DELAYED_EFFECT,
174
                "1", "seconds" },
175
        { "thread_pool_add_delay",
176
                tweak_timeout, &mgt_param.wthread_add_delay,
177
                "0", NULL,
178
                "Wait at least this long after creating a thread.\n"
179
                "\n"
180
                "Some (buggy) systems may need a short (sub-second) "
181
                "delay between creating threads.\n"
182
                "Set this to a few milliseconds if you see the "
183
                "'threads_failed' counter grow too much.\n"
184
                "\n"
185
                "Setting this too high results in insufficient worker threads.",
186
                EXPERIMENTAL,
187
                "0", "seconds" },
188
        { "thread_pool_fail_delay",
189
                tweak_timeout, &mgt_param.wthread_fail_delay,
190
                "10e-3", NULL,
191
                "Wait at least this long after a failed thread creation "
192
                "before trying to create another thread.\n"
193
                "\n"
194
                "Failure to create a worker thread is often a sign that "
195
                " the end is near, because the process is running out of "
196
                "some resource.  "
197
                "This delay tries to not rush the end on needlessly.\n"
198
                "\n"
199
                "If thread creation failures are a problem, check that "
200
                "thread_pool_max is not too high.\n"
201
                "\n"
202
                "It may also help to increase thread_pool_timeout and "
203
                "thread_pool_min, to reduce the rate at which treads are "
204
                "destroyed and later recreated.",
205
                EXPERIMENTAL,
206
                "0.2", "seconds" },
207
        { "thread_stats_rate",
208
                tweak_uint, &mgt_param.wthread_stats_rate,
209
                "0", NULL,
210
                "Worker threads accumulate statistics, and dump these into "
211
                "the global stats counters if the lock is free when they "
212
                "finish a job (request/fetch etc.)\n"
213
                "This parameters defines the maximum number of jobs "
214
                "a worker thread may handle, before it is forced to dump "
215
                "its accumulated stats into the global counters.",
216
                EXPERIMENTAL,
217
                "10", "requests" },
218
        { "thread_queue_limit", tweak_uint, &mgt_param.wthread_queue_limit,
219
                "0", NULL,
220
                "Permitted request queue length per thread-pool.\n"
221
                "\n"
222
                "This sets the number of requests we will queue, waiting "
223
                "for an available thread.  Above this limit sessions will "
224
                "be dropped instead of queued.",
225
                EXPERIMENTAL,
226
                "20", "" },
227
        { "thread_pool_stack",
228
                tweak_bytes, &mgt_param.wthread_stacksize,
229
                NULL, NULL,
230
                "Worker thread stack size.\n"
231
                "This will likely be rounded up to a multiple of 4k"
232
                " (or whatever the page_size might be) by the kernel.\n"
233
                "\n"
234
                "The required stack size is primarily driven by the"
235
                " depth of the call-tree. The most common relevant"
236
                " determining factors in varnish core code are GZIP"
237
                " (un)compression, ESI processing and regular"
238
                " expression matches. VMODs may also require"
239
                " significant amounts of additional stack. The"
240
                " nesting depth of VCL subs is another factor,"
241
                " although typically not predominant.\n"
242
                "\n"
243
                "The stack size is per thread, so the maximum total"
244
                " memory required for worker thread stacks is in the"
245
                " order of size = thread_pools x thread_pool_max x"
246
                " thread_pool_stack.\n"
247
                "\n"
248
                "Thus, in particular for setups with many threads,"
249
                " keeping the stack size at a minimum helps reduce"
250
                " the amount of memory required by Varnish.\n"
251
                "\n"
252
                "On the other hand, thread_pool_stack must be large"
253
                " enough under all circumstances, otherwise varnish"
254
                " will crash due to a stack overflow. Usually, a"
255
                " stack overflow manifests itself as a segmentation"
256
                " fault (aka segfault / SIGSEGV) with the faulting"
257
                " address being near the stack pointer (sp).\n"
258
                "\n"
259
                "Unless stack usage can be reduced,"
260
                " thread_pool_stack must be increased when a stack"
261
                " overflow occurs. Setting it in 150%-200%"
262
                " increments is recommended until stack overflows"
263
                " cease to occur.",
264
                DELAYED_EFFECT,
265
                NULL, "bytes" },        // default set in mgt_main.c
266
        { NULL, NULL, NULL }
267
};