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 3447
tweak_thread_pool_min(struct vsb *vsb, const struct parspec *par,
58
    const char *arg)
59
{
60
61 3447
        if (tweak_generic_uint(vsb, par->priv, arg, par->min, par->max))
62 1
                return (-1);
63 3446
        MCF_ParamConf(MCF_MINIMUM, "thread_pool_max",
64
            "%u", mgt_param.wthread_min);
65 3446
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_reserve",
66 3446
            "%u", mgt_param.wthread_min * 950 / 1000);
67 3446
        return (0);
68
}
69
70
static int
71 1421
tweak_thread_pool_max(struct vsb *vsb, const struct parspec *par,
72
    const char *arg)
73
{
74
75 1421
        if (tweak_generic_uint(vsb, par->priv, arg, par->min, par->max))
76 1
                return (-1);
77 1420
        MCF_ParamConf(MCF_MAXIMUM, "thread_pool_min",
78
            "%u", mgt_param.wthread_max);
79 1420
        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_destroy_delay",
152
                tweak_timeout, &mgt_param.wthread_destroy_delay,
153
                "0.01", NULL,
154
                "Wait this long after destroying a thread.\n"
155
                "\n"
156
                "This controls the decay of thread pools when idle(-ish).",
157
                EXPERIMENTAL | DELAYED_EFFECT,
158
                "1", "seconds" },
159
        { "thread_pool_add_delay",
160
                tweak_timeout, &mgt_param.wthread_add_delay,
161
                "0", NULL,
162
                "Wait at least this long after creating a thread.\n"
163
                "\n"
164
                "Some (buggy) systems may need a short (sub-second) "
165
                "delay between creating threads.\n"
166
                "Set this to a few milliseconds if you see the "
167
                "'threads_failed' counter grow too much.\n"
168
                "\n"
169
                "Setting this too high results in insufficient worker threads.",
170
                EXPERIMENTAL,
171
                "0", "seconds" },
172
        { "thread_pool_fail_delay",
173
                tweak_timeout, &mgt_param.wthread_fail_delay,
174
                "10e-3", NULL,
175
                "Wait at least this long after a failed thread creation "
176
                "before trying to create another thread.\n"
177
                "\n"
178
                "Failure to create a worker thread is often a sign that "
179
                " the end is near, because the process is running out of "
180
                "some resource.  "
181
                "This delay tries to not rush the end on needlessly.\n"
182
                "\n"
183
                "If thread creation failures are a problem, check that "
184
                "thread_pool_max is not too high.\n"
185
                "\n"
186
                "It may also help to increase thread_pool_timeout and "
187
                "thread_pool_min, to reduce the rate at which treads are "
188
                "destroyed and later recreated.",
189
                EXPERIMENTAL,
190
                "0.2", "seconds" },
191
        { "thread_stats_rate",
192
                tweak_uint, &mgt_param.wthread_stats_rate,
193
                "0", NULL,
194
                "Worker threads accumulate statistics, and dump these into "
195
                "the global stats counters if the lock is free when they "
196
                "finish a job (request/fetch etc.)\n"
197
                "This parameters defines the maximum number of jobs "
198
                "a worker thread may handle, before it is forced to dump "
199
                "its accumulated stats into the global counters.",
200
                EXPERIMENTAL,
201
                "10", "requests" },
202
        { "thread_queue_limit", tweak_uint, &mgt_param.wthread_queue_limit,
203
                "0", NULL,
204
                "Permitted request queue length per thread-pool.\n"
205
                "\n"
206
                "This sets the number of requests we will queue, waiting "
207
                "for an available thread.  Above this limit sessions will "
208
                "be dropped instead of queued.",
209
                EXPERIMENTAL,
210
                "20", "" },
211
        { "thread_pool_stack",
212
                tweak_bytes, &mgt_param.wthread_stacksize,
213
                NULL, NULL,
214
                "Worker thread stack size.\n"
215
                "This will likely be rounded up to a multiple of 4k"
216
                " (or whatever the page_size might be) by the kernel.\n"
217
                "\n"
218
                "The required stack size is primarily driven by the"
219
                " depth of the call-tree. The most common relevant"
220
                " determining factors in varnish core code are GZIP"
221
                " (un)compression, ESI processing and regular"
222
                " expression matches. VMODs may also require"
223
                " significant amounts of additional stack. The"
224
                " nesting depth of VCL subs is another factor,"
225
                " although typically not predominant.\n"
226
                "\n"
227
                "The stack size is per thread, so the maximum total"
228
                " memory required for worker thread stacks is in the"
229
                " order of size = thread_pools x thread_pool_max x"
230
                " thread_pool_stack.\n"
231
                "\n"
232
                "Thus, in particular for setups with many threads,"
233
                " keeping the stack size at a minimum helps reduce"
234
                " the amount of memory required by Varnish.\n"
235
                "\n"
236
                "On the other hand, thread_pool_stack must be large"
237
                " enough under all circumstances, otherwise varnish"
238
                " will crash due to a stack overflow. Usually, a"
239
                " stack overflow manifests itself as a segmentation"
240
                " fault (aka segfault / SIGSEGV) with the faulting"
241
                " address being near the stack pointer (sp).\n"
242
                "\n"
243
                "Unless stack usage can be reduced,"
244
                " thread_pool_stack must be increased when a stack"
245
                " overflow occurs. Setting it in 150%-200%"
246
                " increments is recommended until stack overflows"
247
                " cease to occur.",
248
                DELAYED_EFFECT,
249
                NULL, "bytes" },        // default set in mgt_main.c
250
        { NULL, NULL, NULL }
251
};