-
Notifications
You must be signed in to change notification settings - Fork 729
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add network-bytes-out metric support for CLUSTER SLOT-STATS command (#20) #771
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,13 @@ | |
* SPDX-License-Identifier: BSD 3-Clause | ||
*/ | ||
|
||
#include "server.h" | ||
#include "cluster.h" | ||
#include "cluster_slot_stats.h" | ||
|
||
#define UNASSIGNED_SLOT 0 | ||
|
||
typedef enum { | ||
KEY_COUNT, | ||
NETWORK_BYTES_OUT, | ||
INVALID, | ||
} slotStatTypes; | ||
|
||
|
@@ -88,9 +88,16 @@ static void addReplySlotStat(client *c, int slot) { | |
addReplyArrayLen(c, 2); /* Array of size 2, where 0th index represents (int) slot, | ||
* and 1st index represents (map) usage statistics. */ | ||
addReplyLongLong(c, slot); | ||
addReplyMapLen(c, 1); /* Nested map representing slot usage statistics. */ | ||
addReplyMapLen(c, (server.cluster_slot_stats_enabled) ? 2 : 1); /* Nested map representing slot usage statistics. */ | ||
addReplyBulkCString(c, "key-count"); | ||
addReplyLongLong(c, countKeysInSlot(slot)); | ||
|
||
/* Any additional metrics aside from key-count come with a performance trade-off, | ||
* and are aggregated and returned based on its server config. */ | ||
if (server.cluster_slot_stats_enabled) { | ||
addReplyBulkCString(c, "network-bytes-out"); | ||
addReplyLongLong(c, server.cluster->slot_stats[slot].network_bytes_out); | ||
} | ||
} | ||
|
||
/* Adds reply for the SLOTSRANGE variant. | ||
|
@@ -113,6 +120,71 @@ static void addReplySortedSlotStats(client *c, slotStatForSort slot_stats[], lon | |
} | ||
} | ||
|
||
/* Resets applicable slot statistics. */ | ||
void clusterSlotStatReset(int slot) { | ||
/* key-count is exempt, as it is queried separately through countKeysInSlot(). */ | ||
server.cluster->slot_stats[slot].network_bytes_out = 0; | ||
} | ||
|
||
void clusterSlotStatResetAll(void) { | ||
if (server.cluster == NULL) return; | ||
|
||
memset(server.cluster->slot_stats, 0, sizeof(server.cluster->slot_stats)); | ||
} | ||
|
||
static int canAddNetworkBytesOut(client *c) { | ||
return server.cluster_slot_stats_enabled && server.cluster_enabled && c->slot != -1; | ||
} | ||
|
||
/* Accumulates egress bytes upon sending RESP responses back to user clients. */ | ||
void clusterSlotStatsAddNetworkBytesOutForUserClient(client *c) { | ||
if (!canAddNetworkBytesOut(c)) return; | ||
|
||
serverAssert(c->slot >= 0 && c->slot < CLUSTER_SLOTS); | ||
server.cluster->slot_stats[c->slot].network_bytes_out += c->net_output_bytes_curr_cmd; | ||
} | ||
|
||
/* Accumulates egress bytes upon sending replication stream. This only applies for primary nodes. */ | ||
void clusterSlotStatsAddNetworkBytesOutForReplication(int len) { | ||
client *c = server.current_client; | ||
if (c == NULL || !canAddNetworkBytesOut(c)) return; | ||
|
||
serverAssert(c->slot >= 0 && c->slot < CLUSTER_SLOTS); | ||
server.cluster->slot_stats[c->slot].network_bytes_out += (len * listLength(server.replicas)); | ||
} | ||
|
||
/* Upon SPUBLISH, two egress events are triggerred. | ||
* 1) Internal propagation, for clients that are subscribed to the current node. | ||
* 2) External propagation, for other nodes within the same shard (could either be a primary or replica). | ||
* This function covers the internal propagation component. */ | ||
void clusterSlotStatsAddNetworkBytesOutForShardedPubSubInternalPropagation(client *c, int slot) { | ||
/* For a blocked client, c->slot could be pre-filled. | ||
* Thus c->slot is backed-up for restoration after aggregation is completed. */ | ||
int _slot = c->slot; | ||
c->slot = slot; | ||
Comment on lines
+163
to
+164
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not clearly following this trick and seems dangerous. If we do an early exit on the following statement, we don't restore the value in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch, this was not done intentionally. The command should stay idempotent, irregardless of its early return condition. Update has been reflected on the other PR, which replaces this one; #720 |
||
if (!canAddNetworkBytesOut(c)) return; | ||
|
||
serverAssert(c->slot >= 0 && c->slot < CLUSTER_SLOTS); | ||
server.cluster->slot_stats[c->slot].network_bytes_out += c->net_output_bytes_curr_cmd; | ||
|
||
/* For sharded pubsub, the client's network bytes metrics must be reset here, | ||
* as resetClient() is not called until subscription ends. */ | ||
c->net_output_bytes_curr_cmd = 0; | ||
c->slot = _slot; | ||
} | ||
|
||
/* Upon SPUBLISH, two egress events are triggerred. | ||
* 1) Internal propagation, for clients that are subscribed to the current node. | ||
* 2) External propagation, for other nodes within the same shard (could either be a primary or replica). | ||
* This function covers the external propagation component. */ | ||
void clusterSlotStatsAddNetworkBytesOutForShardedPubSubExternalPropagation(size_t len) { | ||
client *c = server.current_client; | ||
if (c == NULL || !canAddNetworkBytesOut(c)) return; | ||
|
||
serverAssert(c->slot >= 0 && c->slot < CLUSTER_SLOTS); | ||
server.cluster->slot_stats[c->slot].network_bytes_out += len; | ||
} | ||
|
||
/* Adds reply for the ORDERBY variant. | ||
* Response is ordered based on the sort result. */ | ||
static void addReplyOrderBy(client *c, int order_by, long limit, int desc) { | ||
|
@@ -149,8 +221,10 @@ void clusterSlotStatsCommand(client *c) { | |
int desc = 1, order_by = INVALID; | ||
if (!strcasecmp(c->argv[3]->ptr, "key-count")) { | ||
order_by = KEY_COUNT; | ||
} else if (!strcasecmp(c->argv[3]->ptr, "network-bytes-out")) { | ||
order_by = NETWORK_BYTES_OUT; | ||
} else { | ||
addReplyError(c, "Unrecognized sort metric for ORDER BY. The supported metrics are: key-count."); | ||
addReplyError(c, "Unrecognized sort metric for ORDERBY."); | ||
return; | ||
} | ||
int i = 4; /* Next argument index, following ORDERBY */ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#include "server.h" | ||
#include "cluster.h" | ||
#include "cluster_legacy.h" | ||
|
||
void clusterSlotStatReset(int slot); | ||
void clusterSlotStatResetAll(void); | ||
void clusterSlotStatsAddNetworkBytesOutForUserClient(client *c); | ||
void clusterSlotStatsAddNetworkBytesOutForReplication(int len); | ||
void clusterSlotStatsAddNetworkBytesOutForShardedPubSubInternalPropagation(client *c, int slot); | ||
void clusterSlotStatsAddNetworkBytesOutForShardedPubSubExternalPropagation(size_t len); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,7 @@ | |
|
||
#include "server.h" | ||
#include "cluster.h" | ||
#include "cluster_slot_stats.h" | ||
#include "script.h" | ||
#include "fpconv_dtoa.h" | ||
#include "fmtargs.h" | ||
|
@@ -225,6 +226,7 @@ client *createClient(connection *conn) { | |
initClientMultiState(c); | ||
c->net_input_bytes = 0; | ||
c->net_output_bytes = 0; | ||
c->net_output_bytes_curr_cmd = 0; | ||
c->commands_processed = 0; | ||
return c; | ||
} | ||
|
@@ -442,6 +444,8 @@ void _addReplyToBufferOrList(client *c, const char *s, size_t len) { | |
return; | ||
} | ||
|
||
c->net_output_bytes_curr_cmd += len; | ||
|
||
/* We call it here because this function may affect the reply | ||
* buffer offset (see function comment) */ | ||
reqresSaveClientReplyOffset(c); | ||
|
@@ -2443,6 +2447,7 @@ void resetClient(client *c) { | |
c->slot = -1; | ||
c->flag.executing_command = 0; | ||
c->flag.replication_done = 0; | ||
c->net_output_bytes_curr_cmd = 0; | ||
|
||
/* Make sure the duration has been recorded to some command. */ | ||
serverAssert(c->duration == 0); | ||
|
@@ -2833,6 +2838,7 @@ int processCommandAndResetClient(client *c) { | |
client *old_client = server.current_client; | ||
server.current_client = c; | ||
if (processCommand(c) == C_OK) { | ||
clusterSlotStatsAddNetworkBytesOutForUserClient(c); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could also go into |
||
commandProcessed(c); | ||
/* Update the client's memory to include output buffer growth following the | ||
* processed command. */ | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.