Fix the wrong reisze of querybuf (#9003)

The initialize memory of `querybuf` is `PROTO_IOBUF_LEN(1024*16) * 2` (due to sdsMakeRoomFor being greedy), under `jemalloc`, the allocated memory will be 40k.
This will most likely result in the `querybuf` being resized when call `clientsCronResizeQueryBuffer` unless the client requests it fast enough.

Note that this bug existed even before #7875, since the condition for resizing includes the sds headers (32k+6).

## Changes
1. Use non-greedy sdsMakeRoomFor when allocating the initial query buffer (of 16k).
1. Also use non-greedy allocation when working with BIG_ARG (we won't use that extra space anyway)
2. in case we did use a greedy allocation, read as much as we can into the buffer we got (including internal frag), to reduce system calls.
3. introduce a dedicated constant for the shrinking (same value as before)
3. Add test for querybuf.
4. improve a maxmemory test by ignoring the effect of replica query buffers (can accumulate many ACKs on slow env)
5. improve a maxmemory by disabling slowlog (it will cause slight memory growth on slow env).
This commit is contained in:
sundb
2021-06-15 14:46:19 +03:00
committed by GitHub
parent eb15c456c9
commit e5d8a5eb85
8 changed files with 120 additions and 15 deletions
+1
View File
@@ -70,6 +70,7 @@ set ::all_tests {
unit/hyperloglog
unit/lazyfree
unit/wait
unit/querybuf
unit/pendingquerybuf
unit/tls
unit/tracking
+24 -2
View File
@@ -143,6 +143,18 @@ start_server {tags {"maxmemory external:skip"}} {
}
}
# Calculate query buffer memory of slave
proc slave_query_buffer {srv} {
set clients [split [$srv client list] "\r\n"]
set c [lsearch -inline $clients *flags=S*]
if {[string length $c] > 0} {
assert {[regexp {qbuf=([0-9]+)} $c - qbuf]}
assert {[regexp {qbuf-free=([0-9]+)} $c - qbuf_free]}
return [expr $qbuf + $qbuf_free]
}
return 0
}
proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline} {
start_server {tags {"maxmemory external:skip"}} {
start_server {} {
@@ -155,6 +167,9 @@ proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline}
set master_host [srv -1 host]
set master_port [srv -1 port]
# Disable slow log for master to avoid memory growth in slow env.
$master config set slowlog-log-slower-than -1
# add 100 keys of 100k (10MB total)
for {set j 0} {$j < 100} {incr j} {
$master setrange "key:$j" 100000 asdf
@@ -207,7 +222,13 @@ proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline}
set slave_buf [s -1 mem_clients_slaves]
set client_buf [s -1 mem_clients_normal]
set mem_not_counted_for_evict [s -1 mem_not_counted_for_evict]
set used_no_repl [expr {$new_used - $mem_not_counted_for_evict}]
set used_no_repl [expr {$new_used - $mem_not_counted_for_evict - [slave_query_buffer $master]}]
# we need to exclude replies buffer and query buffer of replica from used memory.
# removing the replica (output) buffers is done so that we are able to measure any other
# changes to the used memory and see that they're insignificant (the test's purpose is to check that
# the replica buffers are counted correctly, so the used memory growth after deducting them
# should be nearly 0).
# we remove the query buffers because on slow test platforms, they can accumulate many ACKs.
set delta [expr {($used_no_repl - $client_buf) - ($orig_used_no_repl - $orig_client_buf)}]
assert {[$master dbsize] == 100}
@@ -219,7 +240,8 @@ proc test_slave_buffers {test_name cmd_count payload_len limit_memory pipeline}
set killed_used [s -1 used_memory]
set killed_slave_buf [s -1 mem_clients_slaves]
set killed_mem_not_counted_for_evict [s -1 mem_not_counted_for_evict]
set killed_used_no_repl [expr {$killed_used - $killed_mem_not_counted_for_evict}]
# we need to exclude replies buffer and query buffer of slave from used memory after kill slave
set killed_used_no_repl [expr {$killed_used - $killed_mem_not_counted_for_evict - [slave_query_buffer $master]}]
set delta_no_repl [expr {$killed_used_no_repl - $used_no_repl}]
assert {$killed_slave_buf == 0}
assert {$delta_no_repl > -$delta_max && $delta_no_repl < $delta_max}
+48
View File
@@ -0,0 +1,48 @@
proc client_idle_sec {name} {
set clients [split [r client list] "\r\n"]
set c [lsearch -inline $clients *name=$name*]
assert {[regexp {idle=([0-9]+)} $c - idle]}
return $idle
}
# Calculate query buffer memory of slave
proc client_query_buffer {name} {
set clients [split [r client list] "\r\n"]
set c [lsearch -inline $clients *name=$name*]
if {[string length $c] > 0} {
assert {[regexp {qbuf=([0-9]+)} $c - qbuf]}
assert {[regexp {qbuf-free=([0-9]+)} $c - qbuf_free]}
return [expr $qbuf + $qbuf_free]
}
return 0
}
start_server {tags {"querybuf slow"}} {
# The test will run at least 2s to check if client query
# buffer will be resized when client idle 2s.
test "query buffer resized correctly" {
# Memory will increase by more than 32k due to client query buffer.
set rd [redis_deferring_client]
$rd client setname test_client
set orig_test_client_qbuf [client_query_buffer test_client]
assert {$orig_test_client_qbuf > 16384 && $orig_test_client_qbuf < 32768}
# Check that the initial query buffer is not resized if it is idle for more than 2s
wait_for_condition 1000 10 {
[client_idle_sec test_client] > 3 && [client_query_buffer test_client] == $orig_test_client_qbuf
} else {
fail "query buffer was resized"
}
# Fill query buffer to more than 32k
$rd set bigstring v ;# create bigstring in advance to avoid adding extra memory
$rd set bigstring [string repeat A 32768] nx
# Wait for query buffer to be resized to 0.
wait_for_condition 1000 10 {
[client_query_buffer test_client] == 0
} else {
fail "querybuf expected to be resized"
}
}
}