Skip to content

Commit f3a6dad

Browse files
authored
Merge pull request #19 from rfxn/codex/increase-serverlimit-for-process-overlap
Add ServerLimit headroom to prevent scoreboard full errors
2 parents 6dd3ef6 + 2973fad commit f3a6dad

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

README.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ Avg httpd proc size: 10 MB
8484
[OK] Client denials No Client denials observed in sampled lines.
8585
[--] Apache restarts 1 restart events; max 1/day across 1 day(s).
8686
------------------------------------------------
87-
Current vs Proposed (prefork) (current => proposed):
88-
ServerLimit 256 => 256
87+
Current vs Proposed (prefork) (current => proposed):
88+
ServerLimit 256 => 272
8989
MaxRequestWorkers 256 => 256
9090
StartServers 5 => 2
9191
MinSpareServers 5 => 2
@@ -100,7 +100,7 @@ MaxKeepAliveRequests 100
100100
KeepAliveTimeout 5
101101
102102
<IfModule prefork.c>
103-
ServerLimit 256
103+
ServerLimit 272
104104
MaxRequestWorkers 256
105105
StartServers 2
106106
MinSpareServers 2
@@ -128,7 +128,7 @@ JSON output mirrors the same data structure for pipelines:
128128
"apache_budget_pct": 0.35,
129129
"apache_budget_source": "tier",
130130
"log_file": "/var/log/apache-smart-tuner.log",
131-
"recommended_block": "# BEGIN APACHE_SMART_TUNER\n# Apache Smart Tuner v1.19.1 (Tier: LOW-MID, MPM: prefork)\nTimeout 120\nKeepAlive On\nMaxKeepAliveRequests 100\nKeepAliveTimeout 5\n\n<IfModule prefork.c>\n ServerLimit 256\n MaxRequestWorkers 256\n StartServers 2\n MinSpareServers 2\n MaxSpareServers 8\n MaxConnectionsPerChild 4000\n</IfModule>\n# END APACHE_SMART_TUNER\n",
131+
"recommended_block": "# BEGIN APACHE_SMART_TUNER\n# Apache Smart Tuner v1.19.1 (Tier: LOW-MID, MPM: prefork)\nTimeout 120\nKeepAlive On\nMaxKeepAliveRequests 100\nKeepAliveTimeout 5\n\n<IfModule prefork.c>\n ServerLimit 272\n MaxRequestWorkers 256\n StartServers 2\n MinSpareServers 2\n MaxSpareServers 8\n MaxConnectionsPerChild 4000\n</IfModule>\n# END APACHE_SMART_TUNER\n",
132132
"log_review": {
133133
"status": "ready",
134134
"message": "Analyzed last 15000 lines",
@@ -157,7 +157,7 @@ JSON output mirrors the same data structure for pipelines:
157157
"MaxConnectionsPerChild": "0"
158158
},
159159
"recommended": {
160-
"ServerLimit": "256",
160+
"ServerLimit": "272",
161161
"MaxRequestWorkers": "256",
162162
"ThreadsPerChild": "",
163163
"StartServers": "2",
@@ -170,6 +170,9 @@ JSON output mirrors the same data structure for pipelines:
170170
}
171171
```
172172

173+
## ServerLimit buffer and "scoreboard full" protection
174+
Apache keeps old children alive long enough to finish in-flight requests during graceful restarts or MaxConnectionsPerChild recycling. If ServerLimit is set to the exact active process count, those lingering children can temporarily exhaust the scoreboard and block Apache from spawning the replacements, resulting in brief "Scoreboard is full" errors and dropped requests. Apache Smart Tuner pads ServerLimit by a small buffer (5% with an 8-slot minimum) above the calculated MaxRequestWorkers/process count so new workers can come online while old ones drain, without raising steady-state concurrency.
175+
173176
## Safety details
174177
- **Backups:** Target include files are copied with a `.bk-YYYYmmddHHMMSS` suffix before any write.
175178
- **Scrub legacy blocks:** Existing `prefork.c`, `worker.c`, `event.c`, and `mpm_*` blocks inside the target include are removed before the new tuner block is written.

apache-tuner

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ RESTART_DAY_COUNT=0
6565
RESTART_MAX_PER_DAY=0
6666
LOG_SAMPLE_CONTENT=""
6767

68+
# Scoreboard safety defaults
69+
SERVER_LIMIT_BUFFER_PCT="0.05"
70+
MIN_SERVER_LIMIT_BUFFER=8
71+
6872
# Common error patterns to highlight during log review
6973
declare -A COMMON_ERROR_PATTERNS=(
7074
[segfaults]="segfault|segmentation fault|child process .*dumped core"
@@ -322,6 +326,37 @@ round_down_to_multiple_of_8() {
322326
fi
323327
}
324328

329+
round_up_to_multiple_of_8() {
330+
local VALUE=$1
331+
local MULTIPLE=8
332+
333+
if [[ -z "$VALUE" || "$VALUE" -le 0 ]]; then
334+
echo 0
335+
return
336+
fi
337+
338+
local REMAINDER=$(( VALUE % MULTIPLE ))
339+
if [[ "$REMAINDER" -eq 0 ]]; then
340+
echo "$VALUE"
341+
else
342+
echo $(( VALUE + MULTIPLE - REMAINDER ))
343+
fi
344+
}
345+
346+
calculate_server_limit_with_buffer() {
347+
local BASE_VALUE=$1
348+
349+
local RAW_BUFFER
350+
RAW_BUFFER=$(awk -v target="$BASE_VALUE" -v pct="$SERVER_LIMIT_BUFFER_PCT" 'BEGIN { printf "%.0f", (target * pct) }')
351+
352+
if [[ "$RAW_BUFFER" -lt "$MIN_SERVER_LIMIT_BUFFER" ]]; then
353+
RAW_BUFFER=$MIN_SERVER_LIMIT_BUFFER
354+
fi
355+
356+
local BUFFER=$(round_up_to_multiple_of_8 "$RAW_BUFFER")
357+
echo $(( BASE_VALUE + BUFFER ))
358+
}
359+
325360
# ----------------- Apache layout / env detection -----------------
326361

327362
detect_apache_layout() {
@@ -1070,7 +1105,7 @@ build_recommended_block() {
10701105
(( MAX_WORKERS > MRW_CAP_PREFORK )) && MAX_WORKERS=$MRW_CAP_PREFORK
10711106
(( MAX_WORKERS < 128 )) && MAX_WORKERS=128
10721107

1073-
SERVER_LIMIT=$MAX_WORKERS
1108+
SERVER_LIMIT=$(calculate_server_limit_with_buffer "$MAX_WORKERS")
10741109
MIN_SPARE_SERVERS=$(round_down_to_multiple_of_8 "$MIN_SPARE")
10751110
MAX_SPARE_SERVERS=$(round_down_to_multiple_of_8 "$MAX_SPARE")
10761111
START_SERVERS_ROUNDED=$(round_down_to_multiple_of_8 "$START_SERVERS")
@@ -1115,7 +1150,7 @@ build_recommended_block() {
11151150
MAX_PROCS=$(round_down_to_multiple_of_8 "$MAX_PROCS")
11161151
(( MAX_PROCS < 1 )) && MAX_PROCS=1
11171152
MAX_WORKERS=$(( MAX_PROCS * THREADS_PER_CHILD ))
1118-
SERVER_LIMIT="$MAX_PROCS"
1153+
SERVER_LIMIT=$(calculate_server_limit_with_buffer "$MAX_PROCS")
11191154

11201155
MIN_SPARE_THREADS=$(( MIN_SPARE * THREADS_PER_CHILD ))
11211156
MAX_SPARE_THREADS=$(( MAX_SPARE * THREADS_PER_CHILD ))
@@ -1129,7 +1164,7 @@ build_recommended_block() {
11291164
(( MIN_SPARE_THREADS > MAX_SPARE_THREADS )) && MIN_SPARE_THREADS=$MAX_SPARE_THREADS
11301165

11311166
MPM_BLOCK="<IfModule mpm_${MPM_TYPE}_module>\n"
1132-
MPM_BLOCK+=" ServerLimit $MAX_PROCS\n"
1167+
MPM_BLOCK+=" ServerLimit $SERVER_LIMIT\n"
11331168
MPM_BLOCK+=" StartServers $START_SERVERS_ROUNDED\n"
11341169
MPM_BLOCK+=" MaxRequestWorkers $MAX_WORKERS\n"
11351170
MPM_BLOCK+=" ThreadsPerChild $THREADS_PER_CHILD\n"

0 commit comments

Comments
 (0)