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 19455
tweak_thread_pool_min(struct vsb *vsb, const struct parspec *par,
58
    const char *arg)
59
{
60
61 19455
        if (tweak_generic_uint(vsb, par->priv, arg, par->min, par->max))
62 5
                return (-1);
63 19450
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_max",
64
            "%u", mgt_param.wthread_min);
65 19450
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_reserve",
66 19450
            "%u", mgt_param.wthread_min * 950 / 1000);
67 19450
        return (0);
68
}
69
70
static int
71 8000
tweak_thread_pool_max(struct vsb *vsb, const struct parspec *par,
72
    const char *arg)
73
{
74
75 8000
        if (tweak_generic_uint(vsb, par->priv, arg, par->min, par->max))
76 5
                return (-1);
77 7995
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_min",
78
            "%u", mgt_param.wthread_max);
79 7995
        return (0);
80
}
81
82
/*--------------------------------------------------------------------*/
83
84
struct parspec WRK_parspec[] = {
85
        { "thread_pools", tweak_uint, &mgt_param.wthread_pools,
86
                "1", NULL,
87
                "Number of worker thread pools.\n"
88
                "\n"
89
                "Increasing the number of worker pools decreases lock "
90
                "contention. Each worker pool also has a thread accepting "
91
                "new connections, so for very high rates of incoming new "
92
                "connections on systems with many cores, increasing the "
93
                "worker pools may be required.\n"
94
                "\n"
95
                "Too many pools waste CPU and RAM resources, and more than one "
96
                "pool for each CPU is most likely detrimental to performance.\n"
97
                "\n"
98
                "Can be increased on the fly, but decreases require a "
99
                "restart to take effect.",
100
                EXPERIMENTAL | DELAYED_EFFECT,
101
                "2", "pools" },
102
        { "thread_pool_max", tweak_thread_pool_max, &mgt_param.wthread_max,
103
                NULL, NULL,
104
                "The maximum number of worker threads in each pool. The "
105
                "minimum value depends on thread_pool_min.\n"
106
                "\n"
107
                "Do not set this higher than you have to, since excess "
108
                "worker threads soak up RAM and CPU and generally just get "
109
                "in the way of getting work done.",
110
                DELAYED_EFFECT,
111
                "5000", "threads" },
112
        { "thread_pool_min", tweak_thread_pool_min, &mgt_param.wthread_min,
113
                NULL, NULL,
114
                "The minimum number of worker threads in each pool. The "
115
                "maximum value depends on thread_pool_max.\n"
116
                "\n"
117
                "Increasing this may help ramp up faster from low load "
118
                "situations or when threads have expired.\n"
119
                "\n"
120
                "Minimum is 10 threads.",
121
                DELAYED_EFFECT,
122
                "100", "threads" },
123
        { "thread_pool_reserve", tweak_uint, &mgt_param.wthread_reserve,
124
                0, NULL,
125
                "The number of worker threads reserved for vital tasks "
126
                "in each pool.\n"
127
                "\n"
128
                "Tasks may require other tasks to complete (for example, "
129
                "client requests may require backend requests). This reserve "
130
                "is to ensure that such tasks still get to run even under high "
131
                "load.\n"
132
                "\n"
133
                "Increasing the reserve may help setups with a high number of "
134
                "backend requests at the expense of client performance. "
135
                "Setting it too high will waste resources by keeping threads "
136
                "unused.\n"
137
                "\n"
138
                "Default is 0 to auto-tune (currently 5% of thread_pool_min).\n"
139
                "Minimum is 1 otherwise, maximum is 95% of thread_pool_min.",
140
                DELAYED_EFFECT,
141
                "0", "threads" },
142
        { "thread_pool_timeout",
143
                tweak_timeout, &mgt_param.wthread_timeout,
144
                "10", NULL,
145
                "Thread idle threshold.\n"
146
                "\n"
147
                "Threads in excess of thread_pool_min, which have been idle "
148
                "for at least this long, will be destroyed.",
149
                EXPERIMENTAL | DELAYED_EFFECT,
150
                "300", "seconds" },
151
        { "thread_pool_watchdog",
152
                tweak_timeout, &mgt_param.wthread_watchdog,
153
                "0.1", NULL,
154
                "Thread queue stuck watchdog.\n"
155
                "\n"
156
                "If no queued work have been released for this long,"
157
                " the worker process panics itself.",
158
                EXPERIMENTAL,
159
                "10", "seconds" },
160
        { "thread_pool_destroy_delay",
161
                tweak_timeout, &mgt_param.wthread_destroy_delay,
162
                "0.01", NULL,
163
                "Wait this long after destroying a thread.\n"
164
                "\n"
165
                "This controls the decay of thread pools when idle(-ish).",
166
                EXPERIMENTAL | DELAYED_EFFECT,
167
                "1", "seconds" },
168
        { "thread_pool_add_delay",
169
                tweak_timeout, &mgt_param.wthread_add_delay,
170
                "0", NULL,
171
                "Wait at least this long after creating a thread.\n"
172
                "\n"
173
                "Some (buggy) systems may need a short (sub-second) "
174
                "delay between creating threads.\n"
175
                "Set this to a few milliseconds if you see the "
176
                "'threads_failed' counter grow too much.\n"
177
                "\n"
178
                "Setting this too high results in insufficient worker threads.",
179
                EXPERIMENTAL,
180
                "0", "seconds" },
181
        { "thread_pool_fail_delay",
182
                tweak_timeout, &mgt_param.wthread_fail_delay,
183
                "10e-3", NULL,
184
                "Wait at least this long after a failed thread creation "
185
                "before trying to create another thread.\n"
186
                "\n"
187
                "Failure to create a worker thread is often a sign that "
188
                " the end is near, because the process is running out of "
189
                "some resource.  "
190
                "This delay tries to not rush the end on needlessly.\n"
191
                "\n"
192
                "If thread creation failures are a problem, check that "
193
                "thread_pool_max is not too high.\n"
194
                "\n"
195
                "It may also help to increase thread_pool_timeout and "
196
                "thread_pool_min, to reduce the rate at which treads are "
197
                "destroyed and later recreated.",
198
                EXPERIMENTAL,
199
                "0.2", "seconds" },
200
        { "thread_stats_rate",
201
                tweak_uint, &mgt_param.wthread_stats_rate,
202
                "0", NULL,
203
                "Worker threads accumulate statistics, and dump these into "
204
                "the global stats counters if the lock is free when they "
205
                "finish a job (request/fetch etc.)\n"
206
                "This parameters defines the maximum number of jobs "
207
                "a worker thread may handle, before it is forced to dump "
208
                "its accumulated stats into the global counters.",
209
                EXPERIMENTAL,
210
                "10", "requests" },
211
        { "thread_queue_limit", tweak_uint, &mgt_param.wthread_queue_limit,
212
                "0", NULL,
213
                "Permitted request queue length per thread-pool.\n"
214
                "\n"
215
                "This sets the number of requests we will queue, waiting "
216
                "for an available thread.  Above this limit sessions will "
217
                "be dropped instead of queued.",
218
                EXPERIMENTAL,
219
                "20", "" },
220
        { "thread_pool_stack",
221
                tweak_bytes, &mgt_param.wthread_stacksize,
222
                NULL, NULL,
223
                "Worker thread stack size.\n"
224
                "This will likely be rounded up to a multiple of 4k"
225
                " (or whatever the page_size might be) by the kernel.\n"
226
                "\n"
227
                "The required stack size is primarily driven by the"
228
                " depth of the call-tree. The most common relevant"
229
                " determining factors in varnish core code are GZIP"
230
                " (un)compression, ESI processing and regular"
231
                " expression matches. VMODs may also require"
232
                " significant amounts of additional stack. The"
233
                " nesting depth of VCL subs is another factor,"
234
                " although typically not predominant.\n"
235
                "\n"
236
                "The stack size is per thread, so the maximum total"
237
                " memory required for worker thread stacks is in the"
238
                " order of size = thread_pools x thread_pool_max x"
239
                " thread_pool_stack.\n"
240
                "\n"
241
                "Thus, in particular for setups with many threads,"
242
                " keeping the stack size at a minimum helps reduce"
243
                " the amount of memory required by Varnish.\n"
244
                "\n"
245
                "On the other hand, thread_pool_stack must be large"
246
                " enough under all circumstances, otherwise varnish"
247
                " will crash due to a stack overflow. Usually, a"
248
                " stack overflow manifests itself as a segmentation"
249
                " fault (aka segfault / SIGSEGV) with the faulting"
250
                " address being near the stack pointer (sp).\n"
251
                "\n"
252
                "Unless stack usage can be reduced,"
253
                " thread_pool_stack must be increased when a stack"
254
                " overflow occurs. Setting it in 150%-200%"
255
                " increments is recommended until stack overflows"
256
                " cease to occur.",
257
                DELAYED_EFFECT,
258
                NULL, "bytes" },        // default set in mgt_main.c
259
        { NULL, NULL, NULL }
260
};