Input output traffic stats and command process count for each client. (#327)
We already have global stats for input traffic, output traffic and how many commands have been executed. However, some users have the difficulty of locating the IP(s) which have heavy network traffic. So here some stats for single client are introduced. ``` tot-net-in // Total network input bytes read from the client tot-net-out // Total network output bytes sent to the client tot-cmds // Total commands the client has executed ``` These three stats are shown in `CLIENT LIST` and `CLIENT INFO`. Though the metrics are handled in hot paths of the code, personally I don't think it will slow down the server. Considering all other complex operations handled nearby, this is only a small and simple operation. However we do need to be cautious when adding more and more metrics, as discussed in redis/redis#12640, we may need to find a way to tell whether this has obvious performance degradation. --------- Signed-off-by: Chen Tianjie <TJ_Chen@outlook.com>
This commit is contained in:
parent
9ebbd5f038
commit
cc703aa3bc
@ -107,6 +107,7 @@ void updateStatsOnUnblock(client *c, long blocked_us, long reply_us, int had_err
|
||||
const ustime_t total_cmd_duration = c->duration + blocked_us + reply_us;
|
||||
c->lastcmd->microseconds += total_cmd_duration;
|
||||
c->lastcmd->calls++;
|
||||
c->commands_processed++;
|
||||
server.stat_numcommands++;
|
||||
if (had_errors)
|
||||
c->lastcmd->failed_calls++;
|
||||
|
@ -214,6 +214,9 @@ client *createClient(connection *conn) {
|
||||
c->mem_usage_bucket_node = NULL;
|
||||
if (conn) linkClient(c);
|
||||
initClientMultiState(c);
|
||||
c->net_input_bytes = 0;
|
||||
c->net_output_bytes = 0;
|
||||
c->commands_processed = 0;
|
||||
return c;
|
||||
}
|
||||
|
||||
@ -1991,6 +1994,7 @@ int writeToClient(client *c, int handler_installed) {
|
||||
} else {
|
||||
atomicIncr(server.stat_net_output_bytes, totwritten);
|
||||
}
|
||||
c->net_output_bytes += totwritten;
|
||||
|
||||
if (nwritten == -1) {
|
||||
if (connGetState(c->conn) != CONN_STATE_CONNECTED) {
|
||||
@ -2718,6 +2722,7 @@ void readQueryFromClient(connection *conn) {
|
||||
} else {
|
||||
atomicIncr(server.stat_net_input_bytes, nread);
|
||||
}
|
||||
c->net_input_bytes += nread;
|
||||
|
||||
if (!(c->flags & CLIENT_MASTER) &&
|
||||
/* The commands cached in the MULTI/EXEC queue have not been executed yet,
|
||||
@ -2874,7 +2879,10 @@ sds catClientInfoString(sds s, client *client) {
|
||||
" redir=%I", (client->flags & CLIENT_TRACKING) ? (long long) client->client_tracking_redirection : -1,
|
||||
" resp=%i", client->resp,
|
||||
" lib-name=%s", client->lib_name ? (char*)client->lib_name->ptr : "",
|
||||
" lib-ver=%s", client->lib_ver ? (char*)client->lib_ver->ptr : ""));
|
||||
" lib-ver=%s", client->lib_ver ? (char*)client->lib_ver->ptr : "",
|
||||
" tot-net-in=%U", client->net_input_bytes,
|
||||
" tot-net-out=%U", client->net_output_bytes,
|
||||
" tot-cmds=%U", client->commands_processed));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3734,8 +3734,14 @@ void call(client *c, int flags) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!(c->flags & CLIENT_BLOCKED))
|
||||
if (!(c->flags & CLIENT_BLOCKED)) {
|
||||
/* Modules may call commands in cron, in which case server.current_client
|
||||
* is not set. */
|
||||
if (server.current_client) {
|
||||
server.current_client->commands_processed++;
|
||||
}
|
||||
server.stat_numcommands++;
|
||||
}
|
||||
|
||||
/* Record peak memory after each command and before the eviction that runs
|
||||
* before the next command. */
|
||||
|
@ -1282,6 +1282,9 @@ typedef struct client {
|
||||
#ifdef LOG_REQ_RES
|
||||
clientReqResInfo reqres;
|
||||
#endif
|
||||
unsigned long long net_input_bytes; /* Total network input bytes read from this client. */
|
||||
unsigned long long net_output_bytes; /* Total network output bytes sent to this client. */
|
||||
unsigned long long commands_processed; /* Total count of commands this client executed. */
|
||||
} client;
|
||||
|
||||
/* ACL information */
|
||||
|
@ -7,7 +7,7 @@ start_server {tags {"introspection"}} {
|
||||
|
||||
test {CLIENT LIST} {
|
||||
r client list
|
||||
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=* lib-name=* lib-ver=*}
|
||||
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=* lib-name=* lib-ver=* tot-net-in=* tot-net-out=* tot-cmds=*}
|
||||
|
||||
test {CLIENT LIST with IDs} {
|
||||
set myid [r client id]
|
||||
@ -17,7 +17,76 @@ start_server {tags {"introspection"}} {
|
||||
|
||||
test {CLIENT INFO} {
|
||||
r client info
|
||||
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=* lib-name=* lib-ver=*}
|
||||
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=* lib-name=* lib-ver=* tot-net-in=* tot-net-out=* tot-cmds=*}
|
||||
|
||||
proc get_field_in_client_info {info field} {
|
||||
set info [string trim $info]
|
||||
foreach item [split $info " "] {
|
||||
set kv [split $item "="]
|
||||
set k [lindex $kv 0]
|
||||
if {[string match $field $k]} {
|
||||
return [lindex $kv 1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
proc get_field_in_client_list {id client_list filed} {
|
||||
set list [split $client_list "\r\n"]
|
||||
foreach info $list {
|
||||
if {[string match "id=$id *" $info] } {
|
||||
return [get_field_in_client_info $info $filed]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
test {client input output and command process statistics} {
|
||||
set info1 [r client info]
|
||||
set input1 [get_field_in_client_info $info1 "tot-net-in"]
|
||||
set output1 [get_field_in_client_info $info1 "tot-net-out"]
|
||||
set cmd1 [get_field_in_client_info $info1 "tot-cmds"]
|
||||
set info2 [r client info]
|
||||
set input2 [get_field_in_client_info $info2 "tot-net-in"]
|
||||
set output2 [get_field_in_client_info $info2 "tot-net-out"]
|
||||
set cmd2 [get_field_in_client_info $info2 "tot-cmds"]
|
||||
assert_equal [expr $input1+26] $input2
|
||||
assert {[expr $output1+300] < $output2}
|
||||
assert_equal [expr $cmd1+1] $cmd2
|
||||
# test blocking command
|
||||
r del mylist
|
||||
set rd [valkey_deferring_client]
|
||||
$rd client id
|
||||
set rd_id [$rd read]
|
||||
set info_list [r client list]
|
||||
set input3 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
|
||||
set output3 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
|
||||
set cmd3 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
|
||||
$rd blpop mylist 0
|
||||
set info_list [r client list]
|
||||
set input4 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
|
||||
set output4 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
|
||||
set cmd4 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
|
||||
assert_equal [expr $input3+34] $input4
|
||||
assert_equal $output3 $output4
|
||||
assert_equal $cmd3 $cmd4
|
||||
r lpush mylist a
|
||||
set info_list [r client list]
|
||||
set input5 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
|
||||
set output5 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
|
||||
set cmd5 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
|
||||
assert_equal $input4 $input5
|
||||
assert_equal [expr $output4+23] $output5
|
||||
assert_equal [expr $cmd4+1] $cmd5
|
||||
$rd close
|
||||
# test recursive command
|
||||
set info [r client info]
|
||||
set cmd6 [get_field_in_client_info $info "tot-cmds"]
|
||||
r eval "server.call('ping')" 0
|
||||
set info [r client info]
|
||||
set cmd7 [get_field_in_client_info $info "tot-cmds"]
|
||||
assert_equal [expr $cmd6+3] $cmd7
|
||||
}
|
||||
|
||||
test {CLIENT KILL with illegal arguments} {
|
||||
assert_error "ERR wrong number of arguments for 'client|kill' command" {r client kill}
|
||||
|
Loading…
x
Reference in New Issue
Block a user